diff --git a/docs/transparent.rst b/docs/transparent.rst index eb77c76cb..dc41f40f3 100644 --- a/docs/transparent.rst +++ b/docs/transparent.rst @@ -1,5 +1,6 @@ .. _transparent: +==================== Transparent Proxying ==================== @@ -20,5 +21,20 @@ destination of the TCP connection. At the moment, mitmproxy supports transparent proxying on OSX Lion and above, and all current flavors of Linux. +Fully transparent mode +======= +By default mitmproxy will use its own local ip address for its server-side connections. +In case this isn't desired, the --spoof-source-address argument can be used to +use the client's ip address for server-side connections. + +This mode does require root privileges though. There's a wrapper in the examples directory +called 'mitmproxy_shim.c', which will enable you to use this mode with dropped priviliges. +It can be used as follows: + +gcc examples/mitmproxy_shim.c -o mitmproxy_shim -lcap +sudo chown root:root mitmproxy_shim +sudo chmod u+s mitmproxy_shim +./mitmproxy_shim $(which mitmproxy) -T --spoof-source-address + .. _iptables: http://www.netfilter.org/ .. _pf: https://en.wikipedia.org/wiki/PF_\(firewall\) diff --git a/mitmproxy/contrib/mitmproxy_shim.c b/examples/mitmproxy_shim.c similarity index 100% rename from mitmproxy/contrib/mitmproxy_shim.c rename to examples/mitmproxy_shim.c diff --git a/mitmproxy/cmdline.py b/mitmproxy/cmdline.py index 2191cd952..09866f5b6 100644 --- a/mitmproxy/cmdline.py +++ b/mitmproxy/cmdline.py @@ -478,7 +478,7 @@ def proxy_options(parser): group.add_argument( "--spoof-source-address", action="store_true", dest="spoof_source_address", - help="Use client's IP for the server-side connection" + help="Use the client's IP for server-side connections" ) def proxy_ssl_options(parser): diff --git a/mitmproxy/protocol/base.py b/mitmproxy/protocol/base.py index eed0b292e..206999ef4 100644 --- a/mitmproxy/protocol/base.py +++ b/mitmproxy/protocol/base.py @@ -117,9 +117,11 @@ class ServerConnectionMixin(object): self.server_conn = None if self.config.options.spoof_source_address: - self.server_conn = models.ServerConnection(server_address, (self.ctx.client_conn.address.host, 0), True) + self.server_conn = models.ServerConnection( + server_address, (self.ctx.client_conn.address.host, 0), True) else: - self.server_conn = models.ServerConnection(server_address, (self.config.options.listen_host, 0)) + self.server_conn = models.ServerConnection( + server_address, (self.config.options.listen_host, 0)) self.__check_self_connect() @@ -162,10 +164,11 @@ class ServerConnectionMixin(object): self.channel.tell("serverdisconnect", self.server_conn) if self.config.options.spoof_source_address: - self.server_conn = models.ServerConnection(address, (self.ctx.client_conn.address.host, 0), True) + self.server_conn = models.ServerConnection( + address, (self.ctx.client_conn.address.host, 0), True) else: - self.server_conn = models.ServerConnection(address, (self.server_conn.source_address.host, 0)) - + self.server_conn = models.ServerConnection( + address, (self.server_conn.source_address.host, 0)) def connect(self): """ diff --git a/netlib/exceptions.py b/netlib/exceptions.py index dec79c22a..795926f11 100644 --- a/netlib/exceptions.py +++ b/netlib/exceptions.py @@ -58,3 +58,6 @@ class InvalidCertificateException(TlsException): class Timeout(TcpException): pass + +class ProtocolException(NetlibException): + pass diff --git a/netlib/tcp.py b/netlib/tcp.py index aaea9459e..374607439 100644 --- a/netlib/tcp.py +++ b/netlib/tcp.py @@ -731,10 +731,11 @@ class TCPClient(_Connection): try: connection = socket.socket(self.address.family, socket.SOCK_STREAM) if self.spoof_source_address: - if os.geteuid() != 0: - raise RuntimeError("Insufficient privileges to set socket option") - else: + try: connection.setsockopt(socket.SOL_IP, 19, 1) + except socket.error as e: + raise exceptions.ProtocolException( + "Failed to spoof the source address: " + e.strerror) if self.source_address: connection.bind(self.source_address()) connection.connect(self.address()) @@ -874,6 +875,7 @@ class BaseHandler(_Connection): class Counter: + def __init__(self): self._count = 0 self._lock = threading.Lock()