update pydivert, fix #1749
This commit is contained in:
parent
ebff5f2466
commit
f644665cd9
|
@ -8,8 +8,8 @@ import threading
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import configargparse
|
import configargparse
|
||||||
from pydivert import enum
|
import pydivert
|
||||||
from pydivert import windivert
|
import pydivert.consts
|
||||||
import pickle
|
import pickle
|
||||||
import socketserver
|
import socketserver
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ class TransparentProxy:
|
||||||
Limitations:
|
Limitations:
|
||||||
|
|
||||||
- No IPv6 support. (Pull Requests welcome)
|
- No IPv6 support. (Pull Requests welcome)
|
||||||
- TCP ports do not get re-used simulateously on the client, i.e. the proxy will fail if application X
|
- TCP ports do not get re-used simultaneously on the client, i.e. the proxy will fail if application X
|
||||||
connects to example.com and example.org from 192.168.0.42:4242 simultaneously. This could be mitigated by
|
connects to example.com and example.org from 192.168.0.42:4242 simultaneously. This could be mitigated by
|
||||||
introducing unique "meta-addresses" which mitmproxy sees, but this would remove the correct client info from
|
introducing unique "meta-addresses" which mitmproxy sees, but this would remove the correct client info from
|
||||||
mitmproxy.
|
mitmproxy.
|
||||||
|
@ -197,13 +197,10 @@ class TransparentProxy:
|
||||||
self.api_thread = threading.Thread(target=self.api.serve_forever)
|
self.api_thread = threading.Thread(target=self.api.serve_forever)
|
||||||
self.api_thread.daemon = True
|
self.api_thread.daemon = True
|
||||||
|
|
||||||
self.driver = windivert.WinDivert()
|
|
||||||
self.driver.register()
|
|
||||||
|
|
||||||
self.request_filter = custom_filter or " or ".join(
|
self.request_filter = custom_filter or " or ".join(
|
||||||
("tcp.DstPort == %d" %
|
("tcp.DstPort == %d" %
|
||||||
p) for p in redirect_ports)
|
p) for p in redirect_ports)
|
||||||
self.request_forward_handle = None
|
self.request_forward_handle = None # type: pydivert.WinDivert
|
||||||
self.request_forward_thread = threading.Thread(
|
self.request_forward_thread = threading.Thread(
|
||||||
target=self.request_forward)
|
target=self.request_forward)
|
||||||
self.request_forward_thread.daemon = True
|
self.request_forward_thread.daemon = True
|
||||||
|
@ -212,18 +209,18 @@ class TransparentProxy:
|
||||||
self.trusted_pids = set()
|
self.trusted_pids = set()
|
||||||
self.tcptable2 = MIB_TCPTABLE2(0)
|
self.tcptable2 = MIB_TCPTABLE2(0)
|
||||||
self.tcptable2_size = ctypes.wintypes.DWORD(0)
|
self.tcptable2_size = ctypes.wintypes.DWORD(0)
|
||||||
self.request_local_handle = None
|
self.request_local_handle = None # type: pydivert.WinDivert
|
||||||
self.request_local_thread = threading.Thread(target=self.request_local)
|
self.request_local_thread = threading.Thread(target=self.request_local)
|
||||||
self.request_local_thread.daemon = True
|
self.request_local_thread.daemon = True
|
||||||
|
|
||||||
# The proxy server responds to the client. To the client,
|
# The proxy server responds to the client. To the client,
|
||||||
# this response should look like it has been sent by the real target
|
# this response should look like it has been sent by the real target
|
||||||
self.response_filter = "outbound and tcp.SrcPort == %d" % proxy_port
|
self.response_filter = "outbound and tcp.SrcPort == %d" % proxy_port
|
||||||
self.response_handle = None
|
self.response_handle = None # type: pydivert.WinDivert
|
||||||
self.response_thread = threading.Thread(target=self.response)
|
self.response_thread = threading.Thread(target=self.response)
|
||||||
self.response_thread.daemon = True
|
self.response_thread.daemon = True
|
||||||
|
|
||||||
self.icmp_handle = None
|
self.icmp_handle = None # type: pydivert.WinDivert
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setup(cls):
|
def setup(cls):
|
||||||
|
@ -241,25 +238,33 @@ class TransparentProxy:
|
||||||
# Block all ICMP requests (which are sent on Windows by default).
|
# Block all ICMP requests (which are sent on Windows by default).
|
||||||
# In layman's terms: If we don't do this, our proxy machine tells the client that it can directly connect to the
|
# In layman's terms: If we don't do this, our proxy machine tells the client that it can directly connect to the
|
||||||
# real gateway if they are on the same network.
|
# real gateway if they are on the same network.
|
||||||
self.icmp_handle = self.driver.open_handle(
|
self.icmp_handle = pydivert.WinDivert(
|
||||||
filter="icmp",
|
filter="icmp",
|
||||||
layer=enum.Layer.NETWORK,
|
layer=pydivert.Layer.NETWORK,
|
||||||
flags=enum.Flag.DROP)
|
flags=pydivert.Flag.DROP
|
||||||
|
)
|
||||||
|
self.icmp_handle.open()
|
||||||
|
|
||||||
self.response_handle = self.driver.open_handle(
|
self.response_handle = pydivert.WinDivert(
|
||||||
filter=self.response_filter,
|
filter=self.response_filter,
|
||||||
layer=enum.Layer.NETWORK)
|
layer=pydivert.Layer.NETWORK
|
||||||
|
)
|
||||||
|
self.response_handle.open()
|
||||||
self.response_thread.start()
|
self.response_thread.start()
|
||||||
|
|
||||||
if self.mode == "forward" or self.mode == "both":
|
if self.mode == "forward" or self.mode == "both":
|
||||||
self.request_forward_handle = self.driver.open_handle(
|
self.request_forward_handle = pydivert.WinDivert(
|
||||||
filter=self.request_filter,
|
filter=self.request_filter,
|
||||||
layer=enum.Layer.NETWORK_FORWARD)
|
layer=pydivert.Layer.NETWORK_FORWARD
|
||||||
|
)
|
||||||
|
self.request_forward_handle.open()
|
||||||
self.request_forward_thread.start()
|
self.request_forward_thread.start()
|
||||||
if self.mode == "local" or self.mode == "both":
|
if self.mode == "local" or self.mode == "both":
|
||||||
self.request_local_handle = self.driver.open_handle(
|
self.request_local_handle = pydivert.WinDivert(
|
||||||
filter=self.request_filter,
|
filter=self.request_filter,
|
||||||
layer=enum.Layer.NETWORK)
|
layer=pydivert.Layer.NETWORK
|
||||||
|
)
|
||||||
|
self.request_local_handle.open()
|
||||||
self.request_local_thread.start()
|
self.request_local_thread.start()
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
|
@ -272,17 +277,16 @@ class TransparentProxy:
|
||||||
self.icmp_handle.close()
|
self.icmp_handle.close()
|
||||||
self.api.shutdown()
|
self.api.shutdown()
|
||||||
|
|
||||||
def recv(self, handle):
|
def recv(self, handle: pydivert.WinDivert) -> pydivert.Packet:
|
||||||
"""
|
"""
|
||||||
Convenience function that receives a packet from the passed handler and handles error codes.
|
Convenience function that receives a packet from the passed handler and handles error codes.
|
||||||
If the process has been shut down, (None, None) is returned.
|
If the process has been shut down, (None, None) is returned.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
raw_packet, metadata = handle.recv()
|
return handle.recv()
|
||||||
return self.driver.parse_packet(raw_packet), metadata
|
|
||||||
except WindowsError as e:
|
except WindowsError as e:
|
||||||
if e.winerror == 995:
|
if e.winerror == 995:
|
||||||
return None, None
|
return None
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
@ -306,7 +310,7 @@ class TransparentProxy:
|
||||||
|
|
||||||
def request_local(self):
|
def request_local(self):
|
||||||
while True:
|
while True:
|
||||||
packet, metadata = self.recv(self.request_local_handle)
|
packet = self.recv(self.request_local_handle)
|
||||||
if not packet:
|
if not packet:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -321,49 +325,47 @@ class TransparentProxy:
|
||||||
pid = self.addr_pid_map.get(client, None)
|
pid = self.addr_pid_map.get(client, None)
|
||||||
|
|
||||||
if pid not in self.trusted_pids:
|
if pid not in self.trusted_pids:
|
||||||
self._request(packet, metadata)
|
self._request(packet)
|
||||||
else:
|
else:
|
||||||
self.request_local_handle.send((packet.raw, metadata))
|
self.request_local_handle.send(packet, recalculate_checksum=False)
|
||||||
|
|
||||||
def request_forward(self):
|
def request_forward(self):
|
||||||
"""
|
"""
|
||||||
Redirect packages to the proxy
|
Redirect packages to the proxy
|
||||||
"""
|
"""
|
||||||
while True:
|
while True:
|
||||||
packet, metadata = self.recv(self.request_forward_handle)
|
packet = self.recv(self.request_forward_handle)
|
||||||
if not packet:
|
if not packet:
|
||||||
return
|
return
|
||||||
|
|
||||||
self._request(packet, metadata)
|
self._request(packet)
|
||||||
|
|
||||||
def _request(self, packet, metadata):
|
def _request(self, packet: pydivert.Packet):
|
||||||
# print(" * Redirect client -> server to proxy")
|
# print(" * Redirect client -> server to proxy")
|
||||||
# print("%s:%s -> %s:%s" % (packet.src_addr, packet.src_port, packet.dst_addr, packet.dst_port))
|
# print("%s:%s -> %s:%s" % (packet.src_addr, packet.src_port, packet.dst_addr, packet.dst_port))
|
||||||
client = (packet.src_addr, packet.src_port)
|
client = (packet.src_addr, packet.src_port)
|
||||||
server = (packet.dst_addr, packet.dst_port)
|
server = (packet.dst_addr, packet.dst_port)
|
||||||
|
|
||||||
if client in self.client_server_map:
|
if client in self.client_server_map:
|
||||||
# Force re-add to mark as "newest" entry in the dict.
|
self.client_server_map.move_to_end(client)
|
||||||
del self.client_server_map[client]
|
else:
|
||||||
while len(self.client_server_map) > self.connection_cache_size:
|
while len(self.client_server_map) > self.connection_cache_size:
|
||||||
self.client_server_map.popitem(False)
|
self.client_server_map.popitem(False)
|
||||||
|
|
||||||
self.client_server_map[client] = server
|
self.client_server_map[client] = server
|
||||||
|
|
||||||
packet.dst_addr, packet.dst_port = self.proxy_addr, self.proxy_port
|
packet.dst_addr, packet.dst_port = self.proxy_addr, self.proxy_port
|
||||||
metadata.direction = enum.Direction.INBOUND
|
packet.direction = pydivert.consts.Direction.INBOUND
|
||||||
|
|
||||||
packet = self.driver.update_packet_checksums(packet)
|
|
||||||
# Use any handle thats on the NETWORK layer - request_local may be
|
# Use any handle thats on the NETWORK layer - request_local may be
|
||||||
# unavailable.
|
# unavailable.
|
||||||
self.response_handle.send((packet.raw, metadata))
|
self.response_handle.send(packet)
|
||||||
|
|
||||||
def response(self):
|
def response(self):
|
||||||
"""
|
"""
|
||||||
Spoof source address of packets send from the proxy to the client
|
Spoof source address of packets send from the proxy to the client
|
||||||
"""
|
"""
|
||||||
while True:
|
while True:
|
||||||
packet, metadata = self.recv(self.response_handle)
|
packet = self.recv(self.response_handle)
|
||||||
if not packet:
|
if not packet:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -373,11 +375,11 @@ class TransparentProxy:
|
||||||
server = self.client_server_map.get(client, None)
|
server = self.client_server_map.get(client, None)
|
||||||
if server:
|
if server:
|
||||||
packet.src_addr, packet.src_port = server
|
packet.src_addr, packet.src_port = server
|
||||||
|
packet.recalculate_checksums()
|
||||||
else:
|
else:
|
||||||
print("Warning: Previously unseen connection from proxy to %s:%s." % client)
|
print("Warning: Previously unseen connection from proxy to %s:%s." % client)
|
||||||
|
|
||||||
packet = self.driver.update_packet_checksums(packet)
|
self.response_handle.send(packet, recalculate_checksum=False)
|
||||||
self.response_handle.send((packet.raw, metadata))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
Loading…
Reference in New Issue