Skip to content

Commit 17ff3f0

Browse files
authored
HTTP: fix forwarding of HEAD sessions (#4908)
1 parent 64aba81 commit 17ff3f0

File tree

3 files changed

+19
-10
lines changed

3 files changed

+19
-10
lines changed

scapy/fwdmachine.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ def cb_sni(sock, server_name, _):
414414
# Wrap the sockets
415415
sock = self.sockcls(sock, self.cls)
416416
ss = self.sockcls(ss, self.cls)
417+
sock.streamsession = ss.streamsession
417418
try:
418419
while True:
419420
# Listen on both ends of the connection

scapy/layers/http.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ def dispatch_hook(cls, _pkt=None, *args, **kargs):
649649

650650
# tcp_reassemble is used by TCPSession in session.py
651651
@classmethod
652-
def tcp_reassemble(cls, data, metadata, _):
652+
def tcp_reassemble(cls, data, metadata, session):
653653
detect_end = metadata.get("detect_end", None)
654654
is_unknown = metadata.get("detect_unknown", True)
655655
# General idea of the following is explained at
@@ -674,8 +674,12 @@ def tcp_reassemble(cls, data, metadata, _):
674674
# use it. When the total size of the frags is high enough,
675675
# we have the packet
676676

677+
if session.pop("head_request", False):
678+
# Answer to a HEAD request.
679+
detect_end = lambda dat: dat.find(b"\r\n\r\n")
680+
677681
# Subtract the length of the "HTTP*" layer
678-
if http_packet.payload.payload or length == 0:
682+
elif http_packet.payload.payload or length == 0:
679683
http_length = len(data) - http_packet.payload._original_len
680684
detect_end = lambda dat: len(dat) - http_length >= length
681685
else:
@@ -693,13 +697,18 @@ def tcp_reassemble(cls, data, metadata, _):
693697
if chunked:
694698
detect_end = lambda dat: dat.endswith(b"0\r\n\r\n")
695699
# HTTP Requests that do not have any content,
696-
# end with a double CRLF. Same for HEAD responses
700+
# end with a double CRLF.
697701
elif isinstance(http_packet.payload, cls.clsreq):
698702
detect_end = lambda dat: dat.endswith(b"\r\n\r\n")
699703
# In case we are handling a HTTP Request,
700704
# we want to continue assessing the data,
701705
# to handle requests with a body (POST)
702706
metadata["detect_unknown"] = True
707+
if (
708+
isinstance(http_packet.payload, cls.clsreq)
709+
and http_packet.Method == b"HEAD"
710+
):
711+
session["head_request"] = True
703712
elif is_response and http_packet.Status_Code == b"101":
704713
# If it's an upgrade response, it may also hold a
705714
# different protocol data.
@@ -888,8 +897,7 @@ def request(
888897
self._connect_or_reuse(host, port=port, tls=tls, timeout=timeout)
889898

890899
# Build request
891-
if ((tls and port != 443) or
892-
(not tls and port != 80)):
900+
if (tls and port != 443) or (not tls and port != 80):
893901
host_hdr = "%s:%d" % (host, port)
894902
else:
895903
host_hdr = host

test/scapy/layers/http.uts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,11 @@ assert HTTPRequest in a[3]
9090
assert a[3].Method == b"HEAD"
9191
assert a[3].User_Agent == b'curl/7.88.1'
9292

93-
assert HTTPResponse in a[6]
94-
assert a[6].Content_Type == b'text/html; charset=UTF-8'
95-
assert a[6].Expires == b'Mon, 01 Apr 2024 22:25:38 GMT'
96-
assert a[6].Reason_Phrase == b'Moved Permanently'
97-
assert a[6].X_Frame_Options == b"SAMEORIGIN"
93+
assert HTTPResponse in a[5]
94+
assert a[5].Content_Type == b'text/html; charset=UTF-8'
95+
assert a[5].Expires == b'Mon, 01 Apr 2024 22:25:38 GMT'
96+
assert a[5].Reason_Phrase == b'Moved Permanently'
97+
assert a[5].X_Frame_Options == b"SAMEORIGIN"
9898

9999
= HTTP build with 'chunked' content type
100100

0 commit comments

Comments
 (0)