def get_upstream_server(self, client_conn): try: # Parse Client Greeting client_greet = socks.ClientGreeting.from_file(client_conn.rfile) self._assert_socks5(client_greet) if socks.METHOD.NO_AUTHENTICATION_REQUIRED not in client_greet.methods: raise socks.SocksError( socks.METHOD.NO_ACCEPTABLE_METHODS, "mitmproxy only supports SOCKS without authentication") # Send Server Greeting server_greet = socks.ServerGreeting( socks.VERSION.SOCKS5, socks.METHOD.NO_AUTHENTICATION_REQUIRED) server_greet.to_file(client_conn.wfile) client_conn.wfile.flush() # Parse Connect Request connect_request = socks.Message.from_file(client_conn.rfile) self._assert_socks5(connect_request) if connect_request.msg != socks.CMD.CONNECT: raise socks.SocksError( socks.REP.COMMAND_NOT_SUPPORTED, "mitmproxy only supports SOCKS5 CONNECT.") # We do not connect here yet, as the clientconnect event has not # been handled yet. connect_reply = socks.Message( socks.VERSION.SOCKS5, socks.REP.SUCCEEDED, socks.ATYP.DOMAINNAME, # dummy value, we don't have an upstream connection yet. client_conn.address) connect_reply.to_file(client_conn.wfile) client_conn.wfile.flush() ssl = bool(connect_request.addr.port in self.sslports) return ssl, ssl, connect_request.addr.host, connect_request.addr.port except socks.SocksError as e: msg = socks.Message(5, e.code, socks.ATYP.DOMAINNAME, repr(e)) try: msg.to_file(client_conn.wfile) except: pass raise ProxyError(502, "SOCKS5 mode failure: %s" % str(e))
def __call__(self): try: # Parse Client Greeting client_greet = socks.ClientGreeting.from_file(self.client_conn.rfile, fail_early=True) client_greet.assert_socks5() if socks.METHOD.NO_AUTHENTICATION_REQUIRED not in client_greet.methods: raise socks.SocksError( socks.METHOD.NO_ACCEPTABLE_METHODS, "mitmproxy only supports SOCKS without authentication" ) # Send Server Greeting server_greet = socks.ServerGreeting( socks.VERSION.SOCKS5, socks.METHOD.NO_AUTHENTICATION_REQUIRED ) server_greet.to_file(self.client_conn.wfile) self.client_conn.wfile.flush() # Parse Connect Request connect_request = socks.Message.from_file(self.client_conn.rfile) connect_request.assert_socks5() if connect_request.msg != socks.CMD.CONNECT: raise socks.SocksError( socks.REP.COMMAND_NOT_SUPPORTED, "mitmproxy only supports SOCKS5 CONNECT." ) # We always connect lazily, but we need to pretend to the client that we connected. connect_reply = socks.Message( socks.VERSION.SOCKS5, socks.REP.SUCCEEDED, connect_request.atyp, # dummy value, we don't have an upstream connection yet. connect_request.addr ) connect_reply.to_file(self.client_conn.wfile) self.client_conn.wfile.flush() except (socks.SocksError, TcpException) as e: raise Socks5ProtocolException("SOCKS5 mode failure: %s" % repr(e)) # https://github.com/mitmproxy/mitmproxy/issues/839 address_bytes = (connect_request.addr.host.encode("idna"), connect_request.addr.port) self.server_conn.address = tcp.Address(address_bytes, connect_request.addr.use_ipv6) layer = self.ctx.next_layer(self) try: layer() finally: if self.server_conn: self.disconnect()
def test_no_connect(self): """ mitmproxy doesn't support UDP or BIND SOCKS CMDs """ p = self.pathoc() with p.connect(): socks.ClientGreeting( socks.VERSION.SOCKS5, [socks.METHOD.NO_AUTHENTICATION_REQUIRED]).to_file(p.wfile) socks.Message(socks.VERSION.SOCKS5, socks.CMD.BIND, socks.ATYP.DOMAINNAME, ("example.com", 8080)).to_file(p.wfile) p.wfile.flush() p.rfile.read(2) # read server greeting f = p.request( "get:/p/200" ) # the request doesn't matter, error response from handshake will be read anyway. assert f.status_code == 502 assert b"SOCKS5 mode failure" in f.content
def test_message_unknown_atyp(): raw = tutils.treader("\x05\x02\x00\x02\x7f\x00\x00\x01\xDE\xAD\xBE\xEF") tutils.raises(socks.SocksError, socks.Message.from_file, raw) m = socks.Message(5, 1, 0x02, tcp.Address(("example.com", 5050))) tutils.raises(socks.SocksError, m.to_file, StringIO())