3

I'm curious to see how I can create a UDP proxy server using the async module. I tried earlier today with Twisted, but wasn't making much headway. I did find some simple solutions here on stackoverflow using sockets directly, but i'm wondering if this is possible using the async lib.

For clarity, what I'm looking for is:

Step 1: client A (can be many) speaks to proxy B Step 2: proxy B sends the request along to server C. Step 3: Server C responds to proxy B Sep 4: Proxy B responds to client A.

Here's what I have so far:

import asyncio

class EchoServerProtocol(asyncio.DatagramProtocol):
    def connection_made(self, transport):
        self.transport = transport

    def datagram_received(self, data, addr, args=None):
        message = data
        server_addr = ('localhost', 27015)
        print('Received %r from %s' % (message, addr))
        print('Send %r to %s' % (message, server_addr))
        self.transport.sendto(data, server_addr)

loop = asyncio.get_event_loop()
print("Starting UDP server")
# One protocol instance will be created to serve all client requests
listen = loop.create_datagram_endpoint(
    EchoServerProtocol,
    local_addr=('0.0.0.0', 27016),
)
transport, protocol = loop.run_until_complete(listen)

try:
    loop.run_forever()
except KeyboardInterrupt:
    pass

transport.close()
loop.close()

The above is basically this:

https://docs.python.org/3/library/asyncio-protocol.html#udp-echo-server-protocol

What I have will get you to step 3, but of course fails at step 4. It sends it back to server C.

You will note that one of the other protocol examples, EchoServerClientProtocol, creates a new instance for each connection. I assume I need to create a new instance for every connection, I believe, because then I can store the original address in the instance, and return that. I assume this doesn't apply to create_datagram_endpoint, or I can't figure out how to do it.

There might be a better approach though.

4
  • How is server B supposed to know where to forward the server C replies? Also, UDP does not make much sense for a request/reply pattern, since packets can get lost. Commented Jan 31, 2017 at 20:33
  • @Vincent I'm very much a UDP novice, but is it possible to retain the original sender using socks5? Commented Feb 1, 2017 at 22:21
  • 1
    I don't know much about it, but relaying UDP packets with socks5 requires a TCP connection to the proxy and special headers for the datagrams. Commented Feb 2, 2017 at 10:22
  • @JamesR I'll need to build on the UDP proxy implementation you describe here. Can you share what worked for you? Commented Mar 31, 2020 at 22:14

1 Answer 1

4

You need a local endpoint for server B, plus a remote endpoint to server C for each client A.

Here is a possible implementation.

Also, you might be interested in this module providing high-level UDP endpoints for asyncio.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.