mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-23 08:11:00 +00:00
linux: support IPv6 destinations in transparent mode
This fixes #2869 with the help of @aniketpanjwani.
This commit is contained in:
parent
baf4b5dc03
commit
9e86764ce3
@ -1,12 +1,34 @@
|
|||||||
import socket
|
import socket
|
||||||
import struct
|
import struct
|
||||||
|
import typing
|
||||||
|
|
||||||
# Python socket module does not have this constant
|
# Python's socket module does not have these constants
|
||||||
SO_ORIGINAL_DST = 80
|
SO_ORIGINAL_DST = 80
|
||||||
|
SOL_IPV6 = 41
|
||||||
|
|
||||||
|
|
||||||
def original_addr(csock: socket.socket):
|
def original_addr(csock: socket.socket) -> typing.Tuple[str, int]:
|
||||||
odestdata = csock.getsockopt(socket.SOL_IP, SO_ORIGINAL_DST, 16)
|
# Get the original destination on Linux.
|
||||||
_, port, a1, a2, a3, a4 = struct.unpack("!HHBBBBxxxxxxxx", odestdata)
|
# In theory, this can be done using the following syscalls:
|
||||||
address = "%d.%d.%d.%d" % (a1, a2, a3, a4)
|
# sock.getsockopt(socket.SOL_IP, SO_ORIGINAL_DST, 16)
|
||||||
return address, port
|
# sock.getsockopt(SOL_IPV6, SO_ORIGINAL_DST, 28)
|
||||||
|
#
|
||||||
|
# In practice, it is a bit more complex:
|
||||||
|
# 1. We cannot rely on sock.family to decide which syscall to use because of IPv4-mapped
|
||||||
|
# IPv6 addresses. If sock.family is AF_INET6 while sock.getsockname() is ::ffff:127.0.0.1,
|
||||||
|
# we need to call the IPv4 version to get a result.
|
||||||
|
# 2. We can't just try the IPv4 syscall and then do IPv6 if that doesn't work,
|
||||||
|
# because doing the wrong syscall can apparently crash the whole Python runtime.
|
||||||
|
# As such, we use a heuristic to check which syscall to do.
|
||||||
|
is_ipv4 = "." in csock.getsockname()[0] # either 127.0.0.1 or ::ffff:127.0.0.1
|
||||||
|
if is_ipv4:
|
||||||
|
# the struct returned here should only have 8 bytes, but invoking sock.getsockopt
|
||||||
|
# with buflen=8 doesn't work.
|
||||||
|
dst = csock.getsockopt(socket.SOL_IP, SO_ORIGINAL_DST, 16)
|
||||||
|
port, raw_ip = struct.unpack_from("!2xH4s", dst)
|
||||||
|
ip = socket.inet_ntop(socket.AF_INET, raw_ip)
|
||||||
|
else:
|
||||||
|
dst = csock.getsockopt(SOL_IPV6, SO_ORIGINAL_DST, 28)
|
||||||
|
port, raw_ip = struct.unpack_from("!2xH4x16s", dst)
|
||||||
|
ip = socket.inet_ntop(socket.AF_INET6, raw_ip)
|
||||||
|
return ip, port
|
||||||
|
Loading…
Reference in New Issue
Block a user