From fbfedbdc8f02bc36191d3fbf0f5cb7756331c89d Mon Sep 17 00:00:00 2001 From: smill Date: Sun, 4 Sep 2016 01:30:27 +0000 Subject: Improved error-handling / supplemented documention. --- docs/transparent.rst | 16 ++++++++ examples/mitmproxy_shim.c | 79 ++++++++++++++++++++++++++++++++++++++ mitmproxy/cmdline.py | 2 +- mitmproxy/contrib/mitmproxy_shim.c | 79 -------------------------------------- mitmproxy/protocol/base.py | 13 ++++--- netlib/exceptions.py | 3 ++ netlib/tcp.py | 8 ++-- 7 files changed, 112 insertions(+), 88 deletions(-) create mode 100644 examples/mitmproxy_shim.c delete mode 100644 mitmproxy/contrib/mitmproxy_shim.c diff --git a/docs/transparent.rst b/docs/transparent.rst index eb77c76c..dc41f40f 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/examples/mitmproxy_shim.c b/examples/mitmproxy_shim.c new file mode 100644 index 00000000..9688bb41 --- /dev/null +++ b/examples/mitmproxy_shim.c @@ -0,0 +1,79 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +int set_caps(cap_t cap_struct, cap_value_t *cap_list, size_t bufsize) { + int cap_count = bufsize / sizeof(cap_list[0]); + + if (cap_set_flag(cap_struct, CAP_PERMITTED, cap_count, cap_list, CAP_SET) || + cap_set_flag(cap_struct, CAP_EFFECTIVE, cap_count, cap_list, CAP_SET) || + cap_set_flag(cap_struct, CAP_INHERITABLE, cap_count, cap_list, CAP_SET)) { + if (cap_count < 2) { + fprintf(stderr, "Cannot manipulate capability data structure as user: %s.\n", strerror(errno)); + } else { + fprintf(stderr, "Cannot manipulate capability data structure as root: %s.\n", strerror(errno)); + } + return -1; + } + + if (cap_count < 2) { + if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_RAW, 0, 0)) { + fprintf(stderr, "Failed to add CAP_NET_RAW to the ambient set: %s.\n", strerror(errno)); + return -2; + } + } + + if (cap_set_proc(cap_struct)) { + if (cap_count < 2) { + fprintf(stderr, "Cannot set capabilities as user: %s.\n", strerror(errno)); + } else { + fprintf(stderr, "Cannot set capabilities as root: %s.\n", strerror(errno)); + } + return -3; + } + + if (cap_count > 1) { + if (prctl(PR_SET_KEEPCAPS, 1L)) { + fprintf(stderr, "Cannot keep capabilities after dropping privileges: %s.\n", strerror(errno)); + return -4; + } + if (cap_clear(cap_struct)) { + fprintf(stderr, "Cannot clear capability data structure: %s.\n", strerror(errno)); + return -5; + } + } +} + +int main(int argc, char **argv, char **envp) { + cap_t cap_struct = cap_init(); + cap_value_t root_caps[2] = { CAP_NET_RAW, CAP_SETUID }; + cap_value_t user_caps[1] = { CAP_NET_RAW }; + uid_t user = getuid(); + int res; + + if (setresuid(0, 0, 0)) { + fprintf(stderr, "Cannot switch to root: %s.\n", strerror(errno)); + return 1; + } + + if (res = set_caps(cap_struct, root_caps, sizeof(root_caps))) + return res; + + if (setresuid(user, user, user)) { + fprintf(stderr, "Cannot drop root privileges: %s.\n", strerror(errno)); + return 2; + } + + if (res = set_caps(cap_struct, user_caps, sizeof(user_caps))) + return res; + + if (execve(argv[1], argv + 1, envp)) { + fprintf(stderr, "Failed to execute %s: %s\n", argv[1], strerror(errno)); + return 3; + } +} diff --git a/mitmproxy/cmdline.py b/mitmproxy/cmdline.py index 2191cd95..09866f5b 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/contrib/mitmproxy_shim.c b/mitmproxy/contrib/mitmproxy_shim.c deleted file mode 100644 index 9688bb41..00000000 --- a/mitmproxy/contrib/mitmproxy_shim.c +++ /dev/null @@ -1,79 +0,0 @@ -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include - -int set_caps(cap_t cap_struct, cap_value_t *cap_list, size_t bufsize) { - int cap_count = bufsize / sizeof(cap_list[0]); - - if (cap_set_flag(cap_struct, CAP_PERMITTED, cap_count, cap_list, CAP_SET) || - cap_set_flag(cap_struct, CAP_EFFECTIVE, cap_count, cap_list, CAP_SET) || - cap_set_flag(cap_struct, CAP_INHERITABLE, cap_count, cap_list, CAP_SET)) { - if (cap_count < 2) { - fprintf(stderr, "Cannot manipulate capability data structure as user: %s.\n", strerror(errno)); - } else { - fprintf(stderr, "Cannot manipulate capability data structure as root: %s.\n", strerror(errno)); - } - return -1; - } - - if (cap_count < 2) { - if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_RAW, 0, 0)) { - fprintf(stderr, "Failed to add CAP_NET_RAW to the ambient set: %s.\n", strerror(errno)); - return -2; - } - } - - if (cap_set_proc(cap_struct)) { - if (cap_count < 2) { - fprintf(stderr, "Cannot set capabilities as user: %s.\n", strerror(errno)); - } else { - fprintf(stderr, "Cannot set capabilities as root: %s.\n", strerror(errno)); - } - return -3; - } - - if (cap_count > 1) { - if (prctl(PR_SET_KEEPCAPS, 1L)) { - fprintf(stderr, "Cannot keep capabilities after dropping privileges: %s.\n", strerror(errno)); - return -4; - } - if (cap_clear(cap_struct)) { - fprintf(stderr, "Cannot clear capability data structure: %s.\n", strerror(errno)); - return -5; - } - } -} - -int main(int argc, char **argv, char **envp) { - cap_t cap_struct = cap_init(); - cap_value_t root_caps[2] = { CAP_NET_RAW, CAP_SETUID }; - cap_value_t user_caps[1] = { CAP_NET_RAW }; - uid_t user = getuid(); - int res; - - if (setresuid(0, 0, 0)) { - fprintf(stderr, "Cannot switch to root: %s.\n", strerror(errno)); - return 1; - } - - if (res = set_caps(cap_struct, root_caps, sizeof(root_caps))) - return res; - - if (setresuid(user, user, user)) { - fprintf(stderr, "Cannot drop root privileges: %s.\n", strerror(errno)); - return 2; - } - - if (res = set_caps(cap_struct, user_caps, sizeof(user_caps))) - return res; - - if (execve(argv[1], argv + 1, envp)) { - fprintf(stderr, "Failed to execute %s: %s\n", argv[1], strerror(errno)); - return 3; - } -} diff --git a/mitmproxy/protocol/base.py b/mitmproxy/protocol/base.py index eed0b292..206999ef 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 dec79c22..795926f1 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 aaea9459..37460743 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() -- cgit v1.2.3