Simple socket forwarding in linux

12,866

Solution 1

You don't need threads. Take a look at select(), epoll() or kqueue() in order to manage multiple sockets without any thread (if you're on Windows, it's the completion port).

This is an example of a select-based server, it will be a good start.

Solution 2

You can use iptables to do port forwarding. It's not a c solution, but it is a 2-line that has good performance and which will have minimal debugging.

From the second link:

iptables -A PREROUTING -t nat -i eth1 -p tcp \
         --dport 80 -j DNAT --to 192.168.1.50:80

iptables -A INPUT -p tcp -m state --state NEW \
         --dport 80 -i eth1 -j ACCEPT

The first line forward from port 80 to port 80 on 192.168.1.50 and the second accepts the connection, keeping iptables from dropping it.

You can add additional constraints with other iptables flags such as -s 10.0.3.0/24 would catch all the addresses with a source of 10.0.3.0 to 10.0.3.255

Solution 3

One user level solution is using socat. For example, to accept connections on port 8080 and forward them to 192.168.1.50:9090 you can use:

socat TCP-LISTEN:8080,fork TCP:192.168.1.50:9090

The fork option makes socat permit multiple connections.

Solution 4

For simple socket forwarding, let the kernel do it. Use iptables, or one of the frontends to configure it.

If you need complicated data sniffing/mangling/forwarding for real-world use, write an iptables module.

If you need to tee (duplicate/split) the data stream, or inspect or modify the data, then read on.

Linux 2.6.17 and later, with glibc 2.5 and later, do provide a couple of nice functions: splice() and tee(). You can use these to avoid having the payload copied to and from userspace, telling the kernel to transfer a specific amount of bytes from one descriptor to another. (tee() does not consume the data, allowing you to send one or more copies of the data to other descriptors.)

You could use your two threads per connection (one per direction), and have each thread read inspect/mangle/tee the data stream as necessary. When you know you have N incoming bytes to forward to one outgoing socket, use splice(). If you have more than one outgoing socket, use nonblocking outgoing sockets, tee() small chunks at a time (but use splice() for the last outgoing socket for each chunk).

Your threads can read some/all of the incoming data to decide what to do with it, but remember that you need to write() or send() the part you already read that needs to be sent, before using splice() or tee(); they don't magically pick up already consumed data.

Share:
12,866
opc0de
Author by

opc0de

a life full of mistakes is better than a life full of regrets!

Updated on June 06, 2022

Comments

  • opc0de
    opc0de almost 2 years

    The scenario is pretty simple:

    Using TCP/IP I have a client which connects to me (server) I want to forward the data the socket sends me to another socket which I opened and the data I received from that socket backwards.Just like a proxy.

    Right now I have 1 thread one who listens from incoming connection and spawns another 2 when a connection from the client is established. I must use a mechanism for communicating in the threads.

    Is there anything simpler which I can use to act as a TCP/IP proxy ? Does Linux have socket forwarding or some kind of mechanism ?