Score:0

iptable's ip forwarding results in weird behaviour

cn flag

My target is simple : Build a high volume, fast, low latency soft switch using IP forwarding. I have a server test 'Server' and 2 test clients : 'Client1' & 'Client2'. 'Client1:c1' is sending udp packets to 'Server:s1' & 'Client2:c2' is sending udp packets to 'Server:s2'. I just wanna forward 'Client:c1' packets to 'Client:c2' and vice versa. Wouldn't mind if this is possible using only 1 port in sevrer. 'Client1' & 'Client2' is currently a simple udp sender thread which is sending udp packet continiously. Now I am applying rule :

sudo iptables --table nat --append PREROUTING --protocol udp --destination 'Server' --dport 's1' --jump DNAT --to-destination 'Client2:c2'

sudo iptables --table nat --append PREROUTING --protocol udp --destination 'Server' --dport 's2' --jump DNAT --to-destination 'Client1:c1'

sudo iptables --table nat --append POSTROUTING --protocol udp --destination 'Client2' --dport 'c2' --jump SNAT --to-source 'Server:s0'

sudo iptables --table nat --append POSTROUTING --protocol udp --destination 'Client1' --dport 'c1' --jump SNAT --to-source 'Server:s0' 

And If I apply this rule at once and then start both 'Client1' & 'Client2' thread, it works just fine. Even if I delete all rules at once it also works fine but the problem starts if I start adding/deleting this rules 1 by 1 in the time where 'Client1' & 'Client2' is continiously sending data.

behaviour 1 : 'Client1' & 'Client2' running (nothing is happening as no rules are applied) and then I apply the 4 rules to 'Server' at once, then it should work just like previous, but not.. now 'Server' is only forwarding 'Client1' packets to 'Client2' and even SNAT isn't working for that. though after some indefinite time it works though. Other behaviour is just like this, when I am applying some rule to 'Server' iptable, the rule isn't taking effect immediately if 'Client1' & 'Client2' is running.

behaviour 2 : It also happened to me that I flushed the nat table and server was still forwarding for some time.

behaviour 3 : when applying/deleting per rule 1 by 1 while 'Client1' & 'Client2' is still sending/receiving, it wasn't taking effect randomly

I searched and found out in several post that iptables rule takes effect immediately, but for our case it isn't, specially some rules working and some not suddenly and what we are doing wrong here? is there some kind of cache 'Server' iptable maintaing or does it need reload though I found there is no option for reloading? ** I am not interested in 'socat' as it takes the packets to user-space which has bottleneck for high volume packets.** Thanks in advance for any help..!

Nikita Kipriyanov avatar
za flag
**Routing and forwarding was never iptables job.** It only does the firewall and NAT, and I don't understand why you are doing NAT at all. The way you presented the problem leads to the idea you need to put systems into the same network, and possibly configure some routing (which could be software router, but iptables is not involved in this). What are addresses of those clients, are they in the same network, or different networks, do they have public IPs or are they behind some NAT boxes, where is the server relative to clients, and so on?
Nafiul Alam Fuji avatar
cn flag
It's simple ip forwarding with only 2 clients..! the reason : high volume,low latency & fast - this is not possible with packets processing in user-space. I tried with actual server client setup (server is in public ip then 2 client from 2 PC). I am currently simulating this in VMware.If I apply all rules then start client1 & client2 then it works fine. But if client1 and client2 is already running and then applies the rules 1 by 1 then it isn't taking effect immediately. only the 1st rule takes effect and others take effect after some indefinite time. what's wrong here actually..!
Nikita Kipriyanov avatar
za flag
Are clients remote from the server and each other?
Nafiul Alam Fuji avatar
cn flag
yeah. Though in VMware setup they are in local network. But when I tried with actual server client, the results were quite same
Nafiul Alam Fuji avatar
cn flag
clients can be in same/remote network considering each other but the server is always remote in respect to the clients.
Score:1
za flag

The following will redirect anything going from client1:port1 to server:ports to be delivered to the client2:port2, where it appears as coming from the server:ports:

iptables -t nat -A PREROUTING -p udp -s client1 --sport port1 -d server --dport ports -j DNAT --to-destination client2:port2
iptables -t nat -A POSTROUTING -p udp -s client1 --sport port1 -d client2 --dport port2 -j SNAT --to-source server:ports

The first rule changes the destination from server:ports to client2:port2 (because it is DNAT rule), the second rule changes the source from client1:port1 to server:ports. By the time packet is going through second rule, it has the destination already changed, but source isn't, so the matches in the rule might look strange. Replies will undergo the reverse translation automatically.

If you want conversations initiated on client2 (not replies) to work similarly, you need to add the mirror rules:

iptables -t nat -A PREROUTING -p udp -s client2 --sport port2 -d server --dport ports -j DNAT --to-destination client1:port1
iptables -t nat -A POSTROUTING -p udp -s client2 --sport port2 -d client1 --dport port1 -j SNAT --to-source server:ports

If server has any filtering, you'll need to add rules permitting forwarded packets to pass:

iptables -t filter -A FORWARD -p udp -s client1 --sport port1 -d client2 --dport port2 -j ACCEPT
iptables -t filter -A FORWARD -p udp -s client2 --sport port2 -d client1 --dport port1 -j ACCEPT

Addresses appear half-translated here too, because the packets always traverse the firewall in the following order: PREROUTING, FORWARD, POSTROUTING.

Now the client1 will be in the full confidence that it talks with server:ports (at least, on the network level; of course packets could contain something that hints on who is really answering). The same is true for client2, who'll be sure that it talks with server:ports.

Also remember, that once the conversation had begun, the firewall remembers its state; the removal or addition of rules won't have any immediate effect on established connections, because the nat table is always traversed only by the first packet in the connection; the result of the translation is stored in the state table which is used to translate replies and subsequent packets. That state table could be seen by cat /proc/net/nf_conntrack or using utilities from the conntrack-tools package. In case of UDP, the "connection" is defined by the addresses, ports and timeout in the conversation, and "ends" when no packet is seen in any direction for a certain amount of time, 30 seconds by default.

I also want to state this in clear: the forwarding or routing is never performed by the iptables. The routing and forwarding will be performed regardless of any iptables rules in place, according to the routing policy database rules and routing tables contents. It is simply incorrect to say "iptables's ip forwarding", as iptables only sets translations. It configures the in-kernel firewall filtering rules and network address and port translation rules, e.g. how the kernel will change addresses in packets, which apparently could influence its routing decisions (because routing decisions are based on addresses).

Nafiul Alam Fuji avatar
cn flag
I exactly did this except additionally adding the src ip and src port. And it is working fine (tried with VMware) as always if I add rules then start client1 and client2 thread. But then I deleted all rules which stopped forwarding. Now when client1 and client2 running I again tried to add the 1st rule and amazingly all 4 rules got activated though there is only the 1st rule in nat table.I guess this is because of saved state you mentioned on established connection.How would I delete any saved state on certain port before I append rules again so new rules on that port will work immediately?
Nikita Kipriyanov avatar
za flag
Please read the answer in full, I explained that. Use `conntrack-tools`. There also was a `top`-like `iptstate` program, which displays a "menu" of all established connections and the has the way to interactively select and kill them.
Nafiul Alam Fuji avatar
cn flag
Thanks a lot for pointing out the problem.. let me try those and report back. I was just interested that if I wanna simply forward couple of ip's for udp packets then whats the problem in that? does it have any bad impact in future or in other area? I needed to use iptables as I found this to be the fastes way to do so, any alternative you can suggest in that case?
Nikita Kipriyanov avatar
za flag
I suggest to match packets as tightly as possible, like that I did with all addresses and ports. That way any impact will be limited to those addresses and ports, and overall you'd not face any unexpected translations taking place. However, in principle there shouldn't be any.
Nafiul Alam Fuji avatar
cn flag
Oh yeah, I understand that now
Gerrit avatar
cn flag
I am noticing specific ports being set inside --to-source. This is likely to be counterproductive. Especially if you map too many udp streams on too few source ports. Let iptables select a free source port for the connection it is tracking.
Gerrit avatar
cn flag
If this is the only forwarding in use, you could also just switch general ip forwarding to on/off according to your need and leave iptables rules as they are.
Nikita Kipriyanov avatar
za flag
As I understood the problem, this server is not a simple next hop for clients. Everything is remote. We need address translations to shortcut clients packets to each other. And, likewise, we need certain ports to be used, so they indeed appear in --to-source, In other words, this is intentional.
Gerrit avatar
cn flag
Ok, I took client:c1 as just an example, but if it is actually a requirement to have a specific source port for the connection, then yes it would need to be included. Good call.
Nafiul Alam Fuji avatar
cn flag
If I consider the 4 rule as : clientt1->server->(client1->)client2 & client2->server->(client2->)client1 : this actually indicates a single call. I am planning to run high volume call here by mapping 1 single call to a single specific port and destroy the connection as soon as call terminates. I dont want the iptable to keep established connection data for some time, I will handle that.
Gerrit avatar
cn flag
This is out of scope of course. But the UDP protocol is not a natural match for state changing requests.
Nikita Kipriyanov avatar
za flag
This looks like an attempt to renivent SIP...
Nafiul Alam Fuji avatar
cn flag
actually,my UDP packets are SIP packets and my goal is to enable my switch to handle large volume of calls.Currently we can only manage 5k concurrent calls but I believe it can go upto 30k+. We have java media app which actually assigns media port and through it (goal to high throughput) I added iptable rule when a call starts and deletes when finished. But this performance was also not as expected.It went upto 15k-20k but iptable rules became messy, sometimes rules were not being added properly and taking much time(conn refresh).Should I try the same formula with go or there are other ways?
Nafiul Alam Fuji avatar
cn flag
You can say my goal is to build a TURN server for SIP with our logics which can handle large amount of concurrent calls and whose responsibility is simply to relay audio streams. But as far as I understand for large amount of concurrent packet transfer, application layer is a burden,so we were trying with iptables so it will be done in kernel level. we also tried "socat"- application layer implementation for same type thing but it has the same result as iptables one.I am just not sure whether I am in the right way of searching or not.please shed a light on these if you have any advice on this.
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.