1

problem:

I have a TCP server and client that each listen on port 9000. I have the server and client deployed on two different hosts where traffic can only pass through port 80 between them. I want the source port (9000) to be maintained when packets are sent between them (see the SNAT rule below) so that the PREROUTING rule can identify the packets with --source-port.

approach:

I'm trying to setup iptables rules such that the server routes its traffic from port 9000 to port 80, and a complimentary rule for the client where the incoming traffic on port 80 is routed to 9000 locally.

I've come up with this script to apply the rules. I've tried this with a few variations and packets seem to get accepted by the server host, but not accepted by the PREROUTING (inbound) rule.

       #!/bin/bash

       apply_inbound_rules() {
            # Allow incoming server traffic from port 80 to the TCP client
            sudo iptables -t nat \
                -I PREROUTING \
                -p tcp --destination-port $PROXY_PORT \
                -j REDIRECT --to-port $TCP_PORT
        }

        apply_outbound_rules() {
            # Setup outgoing packets created by the TCP server to route through local port 80 
            # and received on port 80 on the client host
            sudo iptables -t nat \
                -I OUTPUT \
                -p tcp --destination-port $TCP_PORT \
                -j DNAT --to-destination :$PROXY_PORT

            # To maintain the TCP_PORT
            sudo iptables -t nat \
                -I POSTROUTING \
                -p tcp --destination-port $PROXY_PORT \
                -j SNAT --to-source :$TCP_PORT 
        }

        apply_inbound_rules
        apply_outbound_rules

Does anyone have experience creating rules like this? It seems like it would be a common problem but I can't seem to figure it out.

  • Should the inbound rule use --source-port, then? – Ralph Rönnquist Dec 30 '17 at 8:59
  • I want to use source port, the issue is that the packet's source port is a random port. I'm trying to setup a rule so that the packet's source port is maintained when it leaves the client so that when it reaches the server it can be identified from other TCP traffic with different source ports. The SNAT rule doesn't seem to set the source port – delos Dec 30 '17 at 9:02
  • I suppose you've already tried with MASQUERADE instead of SNAT? – Ralph Rönnquist Dec 30 '17 at 10:19
  • I've looked into it, though I can't seem to figure out why/how to use it in this context. I thought it was for when the destination IP could change? My guess from your suggestion is to replace the SNAT rule with iptables -t nat -I POSTROUTING -j MASQUERADE? – delos Dec 30 '17 at 15:05
2

This is a translation of my comment into a response.

The rules should be adjusted to rely on an outbound MASQUERADE of source port to handle return packets. Thus, outgoing packets should be DNAT-ed with the rule you have, and MASQUERADE-ed with a rule:

iptables -t nat -A POSTROUTING -p tcp --destination-port $PROXY_PORT -j MASQUERADE --to-ports $TCP_PORT

Use that rule instead of your SNAT rule.

Incoming packets relating to those that have been MASQUERADE-ed will get their destination ports duly return-mapped.

(corrected as per comment)

  • That rule works well, but it maintains the PROXY_PORT instead of the original TCP_PORT. I've tried a few variations of the rule you listed and can't seem to find one that maintains the TCP_PORT from a client connection. Do you know how to modify the rule to maintain the TCP_PORT? – delos Dec 31 '17 at 6:09
  • Read over the masquerade documentation and got the rule working iptables -t nat -I POSTROUTING -p tcp --destination-port $PROXY_PORT -j MASQUERADE --to-ports $TCP_PORT. Thank you! – delos Dec 31 '17 at 6:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.