简述
使用python来发送http请求非常简单,我们可以撸一个简单的脚本,指定参数方式运行,用pyinstaller打包成exe,就可以分享给其他小伙伴了。
先来看效果:
python3 http_client.py -h
usage: http_client.py [-h] --ip IP [--proto PROTO] [--port PORT]
[--source_ip SOURCE_IP]
[--source_ip_count SOURCE_IP_COUNT] [--method METHOD]
[--data DATA] [--data_len DATA_LEN] [--count COUNT]
[--one_connect ONE_CONNECT] [--urls URLS [URLS ...]]
[--headers HEADERS [HEADERS ...]]
optional arguments:
-h, --help show this help message and exit
--ip IP target IP address, support IPv4 and IPv6
--proto PROTO default is http, also you can use https
--port PORT target port
--source_ip SOURCE_IP
source address, default is auto, choose source ip
address auto, you can assign like 20.1.1.10, if use
source ip address, per ip use a thread.
--source_ip_count SOURCE_IP_COUNT
source address count, default is 1
--method METHOD default is GET
--data DATA upload data
--data_len DATA_LEN upload data length
--count COUNT default is 1, if set to 0, then run continuous
--one_connect ONE_CONNECT
if set 1, then send all req in one tcp connection
--urls URLS [URLS ...]
url list, example: / /index.html
--headers HEADERS [HEADERS ...]
custom headers, example: Host:aaa.com User-Agent:pythontest
这里对参数简要说明一下:
-
比较特别的一点是这个脚本支持指定源IP(当然源IP也要先配置到网卡上),其中source_ip 是基础源IP,source_ip_count 是指定源IP的个数,每个源IP会自动启用一个线程去运行HTTP 请求。
-
–one_connect参数设置为1后,当urls参数后面指定了多个uri时,会在一个tcp连接中发送所有的http请求
-
count参数设置为0的时候,会不停请求,需要ctrl+c中断
使用举例:
python3 http_client.py --ip 1.0.0.20 --one_connect 1 --urls /index.html /abcd.php --headers Host:www.test.com --method GET --count 10
python3 http_client.py --ip 3ffe:1111::abcd --one_connect 1 --urls /index.html /abcd.php --headers Host:www.test.com --method GET --count 10
python3 http_client.py --ip 3ffe:1::b --urls /index.html --source_ip 3ffe:1::a01 --source_ip_count=100 --headers Host:www.test.com --data_len 2000 --method POST
源代码
import argparse
import ipaddress
from http import client
from threading import Thread
def http_req(ip, port, uri_list, proto='http', method='GET', saddr=None, timeout=5, data=None, headers=None,
one_connection=0):
fail_count = 0
if one_connection:
if proto == 'http':
conn = client.HTTPConnection(host=ip, port=port, source_address=saddr, timeout=timeout)
elif proto == 'https':
conn = client.HTTPSConnection(host=ip, port=port, source_address=saddr, timeout=timeout)
else:
return fail_count
try:
for uri in uri_list:
conn.request(method, uri, body=data, headers=headers)
conn.getresponse().read()
except KeyboardInterrupt:
return fail_count
except Exception as e:
print('request failed: ', e)
fail_count += 1
return fail_count
else:
for uri in uri_list:
if proto == 'http':
conn = client.HTTPConnection(host=ip, port=port, source_address=saddr, timeout=timeout)
elif proto == 'https':
conn = client.HTTPSConnection(host=ip, port=port, source_address=saddr, timeout=timeout)
else:
return 0
try:
conn.request(method, uri, body=data, headers=headers)
conn.getresponse().read()
except KeyboardInterrupt:
return fail_count
except Exception as e:
print('request failed: ', e)
fail_count += 1
continue
return fail_count
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--ip', type=str, required=True, help="target IP address, support IPv4 and IPv6")
parser.add_argument('--proto', type=str, required=False, default='http',
help="default is http, also you can use https")
parser.add_argument('--port', type=int, required=False, default=80, help="target port")
parser.add_argument('--source_ip', type=str, required=False, default='auto',
help="source address, default is auto, choose source ip address auto, you can assign like 20.1.1.10, if use source ip address, per ip use a thread.")
parser.add_argument('--source_ip_count', type=int, required=False, default=1,
help="source address count, default is 1")
parser.add_argument('--method', type=str, required=False, default='GET', help="default is GET")
parser.add_argument('--data', type=str, required=False, default=None, help="upload data")
parser.add_argument('--data_len', type=int, required=False, default=0, help="upload data length")
parser.add_argument('--count', type=int, required=False, default=1,
help="default is 1, if set to 0, then run continuous")
parser.add_argument('--one_connect', type=int, required=False, default=0,
help="if set 1, then send all req in one tcp connection")
parser.add_argument('--urls', type=str, required=False, default='/', nargs='+',
help="url list, example: / /index.html")
parser.add_argument('--headers', type=str, required=False, default=None, nargs='+',
help="custom headers, example: Host:aaa.com User-Agent:pythontest")
args = parser.parse_args()
urls = ['/']
headers = {}
if isinstance(args.urls, list):
urls = args.urls
if isinstance(args.headers, list):
for i in args.headers:
headers[i.split(':')[0]] = i.split(':')[1]
if args.data_len != 0:
data = '#' * args.data_len
else:
data = args.data
def run_req(count, saddr):
fail_count = 0
if count == 0:
while 1:
fail_count += http_req(ip=args.ip,
port=args.port,
uri_list=urls,
proto=args.proto,
method=args.method,
saddr=saddr,
timeout=5,
data=data,
headers=headers,
one_connection=args.one_connect)
else:
for _ in range(count):
fail_count += http_req(ip=args.ip,
port=args.port,
uri_list=urls,
proto=args.proto,
method=args.method,
saddr=saddr,
timeout=5,
data=data,
headers=headers,
one_connection=args.one_connect)
print("run count: %s, failed count: %s " % (count, fail_count))
if args.source_ip != 'auto':
if args.source_ip.find(':') != -1:
# ipv6 仅支持地址最后一段数字变化
assert args.ip.find(':') != -1, "source ip and target ip must be ipv6!"
for i in range(args.source_ip_count):
Thread(target=run_req, args=(args.count, (str(ipaddress.IPv6Address(args.source_ip) + i), 0))).start()
else:
for i in range(args.source_ip_count):
Thread(target=run_req, args=(args.count, (str(ipaddress.IPv4Address(args.source_ip) + i), 0))).start()
else:
run_req(args.count, saddr=None)