Making Keep-Alive on by default
Some checks are pending
/ build (macos-latest, 3.8) (push) Waiting to run
/ build (ubuntu-latest, pypy-2.7) (push) Waiting to run
/ build (windows-latest, 3.14) (push) Waiting to run

This commit is contained in:
Miroslav Štampar 2026-06-21 01:59:23 +02:00
parent 6d306ba50d
commit 9d653d2d50
8 changed files with 70 additions and 28 deletions

View file

@ -3614,7 +3614,7 @@ def setOptimize():
"""
# conf.predictOutput = True
conf.keepAlive = True
# Note: persistent (Keep-Alive) connections are now used by default (see _setHTTPHandlers)
conf.threads = 3 if conf.threads < 3 and cmdLineOptions.threads is None else conf.threads
conf.nullConnection = not any((conf.data, conf.textOnly, conf.titles, conf.string, conf.notString, conf.regexp, conf.tor))

View file

@ -1241,23 +1241,22 @@ def _setHTTPHandlers():
handlers.append(_urllib.request.HTTPCookieProcessor(conf.cj))
# Reference: http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html
if conf.keepAlive:
warnMsg = "persistent HTTP(s) connections, Keep-Alive, has "
warnMsg += "been disabled because of its incompatibility "
# Note: persistent (Keep-Alive) connections are used by default; '--no-keep-alive' opts out,
# and they are automatically disabled when incompatible (HTTP(s) proxy, authentication methods,
# or chunked transfer-encoding of the request body - handled by a dedicated, non-pooling handler)
conf.keepAlive = not conf.noKeepAlive and not conf.proxy and not conf.authType and not conf.chunked
if conf.proxy:
warnMsg += "with HTTP(s) proxy"
logger.warning(warnMsg)
elif conf.authType:
warnMsg += "with authentication methods"
logger.warning(warnMsg)
else:
# Note: persistent connections for both HTTP and HTTPS; the keep-alive
# HTTPS handler supersedes the regular one (reusing its SSL connection)
if httpsHandler in handlers:
handlers.remove(httpsHandler)
handlers.append(keepAliveHandler)
handlers.append(keepAliveHandlerHTTPS)
if conf.keepAlive:
# persistent connections for both HTTP and HTTPS; the keep-alive HTTPS
# handler supersedes the regular one (reusing its SSL connection)
if httpsHandler in handlers:
handlers.remove(httpsHandler)
handlers.append(keepAliveHandler)
handlers.append(keepAliveHandlerHTTPS)
elif not conf.noKeepAlive and (conf.proxy or conf.authType or conf.chunked):
reason = "an HTTP(s) proxy" if conf.proxy else ("authentication methods" if conf.authType else "chunked transfer-encoding")
debugMsg = "persistent (Keep-Alive) connections were disabled (incompatible with %s)" % reason
logger.debug(debugMsg)
opener = _urllib.request.build_opener(*handlers)
opener.addheaders = [] # Note: clearing default "User-Agent: Python-urllib/X.Y"

View file

@ -79,6 +79,7 @@ optDict = {
"optimize": "boolean",
"predictOutput": "boolean",
"keepAlive": "boolean",
"noKeepAlive": "boolean",
"nullConnection": "boolean",
"threads": "integer",
},

View file

@ -20,7 +20,7 @@ from lib.core.enums import OS
from thirdparty import six
# sqlmap version (<major>.<minor>.<month>.<monthly commit>)
VERSION = "1.10.6.133"
VERSION = "1.10.6.134"
TYPE = "dev" if VERSION.count('.') > 2 and VERSION.split('.')[-1] != '0' else "stable"
TYPE_COLORS = {"dev": 33, "stable": 90, "pip": 34}
VERSION_STRING = "sqlmap/%s#%s" % ('.'.join(VERSION.split('.')[:-1]) if VERSION.count('.') > 2 and VERSION.split('.')[-1] == '0' else VERSION, TYPE)

View file

@ -64,7 +64,7 @@ def vulnTest():
("-u <url> -p id --flush-session --proof", ("sqlmap proved exploitation of the following injection point", "Parameter: id (GET)", "Technique: boolean-based blind", "TRUE (5/5)", "repeatably", "Retrieved: back-end DBMS banner '3.")), # --proof: report-grade proof in the injection-point style - forces the boolean technique (so a multi-technique point still proves), and actively reads a value out as the strongest proof
("-r <request> --flush-session -v 5 --test-skip=\"heavy\" --save=<config>", ("CloudFlare", "web application technology: Express", "possible DBMS: 'SQLite'", "User-Agent: foobar", "~Type: time-based blind", "saved command line options to the configuration file")),
("-c <config>", ("CloudFlare", "possible DBMS: 'SQLite'", "User-Agent: foobar", "~Type: time-based blind")),
("-l <log> --flush-session --keep-alive --skip-waf -vvvvv --technique=U --union-from=users --banner --parse-errors", ("banner: '3.", "ORDER BY term out of range", "~xp_cmdshell", "Connection: keep-alive")),
("-l <log> --flush-session --skip-waf -vvvvv --technique=U --union-from=users --banner --parse-errors", ("banner: '3.", "ORDER BY term out of range", "~xp_cmdshell", "Connection: keep-alive")),
("-l <log> --offline --banner -v 5", ("banner: '3.", "~[TRAFFIC OUT]")),
("-u <base> --flush-session --data=\"id=1&_=Eewef6oh\" --chunked --randomize=_ --random-agent --banner", ("fetched random HTTP User-Agent header value", "Parameter: id (POST)", "Type: boolean-based blind", "Type: time-based blind", "Type: UNION query", "banner: '3.")),
("-u <base64> -p id --base64=id --data=\"base64=true\" --flush-session --banner --technique=B", ("banner: '3.",)),

View file

@ -315,8 +315,9 @@ def cmdLineParser(argv=None):
optimization.add_argument("--predict-output", dest="predictOutput", action="store_true",
help="Predict common queries output")
optimization.add_argument("--keep-alive", dest="keepAlive", action="store_true",
help="Use persistent HTTP(s) connections")
# Note: persistent (Keep-Alive) connections are used by default; this opts out
optimization.add_argument("--no-keep-alive", dest="noKeepAlive", action="store_true",
help="Disable persistent HTTP(s) connections (Keep-Alive)")
optimization.add_argument("--null-connection", dest="nullConnection", action="store_true",
help="Retrieve page length without actual HTTP response body")

View file

@ -144,6 +144,12 @@ class _KeepAliveHandler(object):
if not hasattr(response, "getcode"):
response.getcode = lambda response=response: response.status
# Note: Python 2's httplib.HTTPResponse lacks readline()/readlines(), which urllib2's
# error wrapping (addinfourl, for any non-2xx response) requires; provide them over read()
if not hasattr(response, "readline"):
response.readline = _makeReadline(response)
response.readlines = _makeReadlines(response)
# Note: must come last as on Python 3 'msg' initially aliases the headers
response.msg = response.reason
@ -264,3 +270,38 @@ def _sendRequest(conn, req):
if data is not None:
conn.send(data)
def _makeReadline(response):
"""
A buffered readline() over response.read() (Python 2 httplib.HTTPResponse lacks one)
"""
buffer = {"data": b""}
def readline(*args, **kwargs):
while b"\n" not in buffer["data"]:
chunk = response.read(8192)
if not chunk:
break
buffer["data"] += chunk
data = buffer["data"]
index = data.find(b"\n")
if index == -1:
buffer["data"] = b""
return data
buffer["data"] = data[index + 1:]
return data[:index + 1]
return readline
def _makeReadlines(response):
def readlines(*args, **kwargs):
result = []
while True:
line = response.readline()
if not line:
break
result.append(line)
return result
return readlines