Hello,
I have a question regarding how TCP connections are established and kept open with regards to NATing. Let me know if I'm asking in the wrong place!
I'm not sure how much of this is OS-specific, but I'm currently running debian 9, the code examples are python 3, and I'm using wireshark from the debian repo for some of the analysis.
Here is my server code:
server
#!/usr/bin/env python3 import socket host = '127.0.0.7' port = 8888 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind((host, port)) sock.listen() print("Listening on:", host, port) conn, addr = sock.accept() print('Connected to:', addr[0], addr[1]) conn.send(conn.recv(1024)) sock.close()
So basically all the server does is listen on 127.0.0.7:8888, accept a single connection, print out the connection information, then receive and send back a single payload.
Here is my client code:
client
#!/usr/bin/env python3 import socket host = '127.0.0.7' port = 8888 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((host, port)) sock.send(b"hello") print(sock.recv(1024)) sock.close()
All the client code does is connect to 127.0.0.7:8888, send a single "hello" payload, receive that payload, and print out the result.
Without any sort of NATing, running this code gives the following (run server in one terminal first and then client in another):
# In one terminal first run: $ ./server Listening on: 127.0.0.7 8888 Connected to: 127.0.0.1 54944 # In second terminal next run: $ ./client b'hello'
Next say that I NAT any connection from 127.0.0.1 to 127.0.0.7 and change it so that the source IP becomes 127.0.0.5 as follows:
# iptables -t nat -N experiment # iptables -t nat -I POSTROUTING 1 -j experiment # iptables -t nat -A experiment -s "127.0.0.1" -d "127.0.0.7" -j SNAT --to-source "127.0.0.5"
Next I run the code just as before:
# In one terminal first run: $ ./server Listening on: 127.0.0.7 8888 Connected to: 127.0.0.5 55024 # In second terminal next run: $ ./client b'hello'
Notice that the server did correctly pick up that the source IP is now different. The following is a wireshark trace of that previous twn TCP connections. The first 10 packets correspond to the first case without NATing and the second 10 corresponds to the second case with NATing:
No. Time Source Destination Protocol Length Info 1 0.000000000 127.0.0.1 127.0.0.7 TCP 74 54944 → 8888 [SYN] Seq=0 Win=43690 Len=0 MSS=65495 SACK_PERM=1 TSval=3363671 TSecr=0 WS=128 2 0.000019292 127.0.0.7 127.0.0.1 TCP 74 8888 → 54944 [SYN, ACK] Seq=0 Ack=1 Win=43690 Len=0 MSS=65495 SACK_PERM=1 TSval=3363671 TSecr=3363671 WS=128 3 0.000034033 127.0.0.1 127.0.0.7 TCP 66 54944 → 8888 [ACK] Seq=1 Ack=1 Win=43776 Len=0 TSval=3363671 TSecr=3363671 4 0.000062098 127.0.0.1 127.0.0.7 TCP 71 54944 → 8888 [PSH, ACK] Seq=1 Ack=1 Win=43776 Len=5 TSval=3363671 TSecr=3363671 5 0.000070039 127.0.0.7 127.0.0.1 TCP 66 8888 → 54944 [ACK] Seq=1 Ack=6 Win=43776 Len=0 TSval=3363671 TSecr=3363671 6 0.000171745 127.0.0.7 127.0.0.1 TCP 71 8888 → 54944 [PSH, ACK] Seq=1 Ack=6 Win=43776 Len=5 TSval=3363671 TSecr=3363671 7 0.000194540 127.0.0.1 127.0.0.7 TCP 66 54944 → 8888 [ACK] Seq=6 Ack=6 Win=43776 Len=0 TSval=3363671 TSecr=3363671 8 0.000271575 127.0.0.1 127.0.0.7 TCP 66 54944 → 8888 [FIN, ACK] Seq=6 Ack=6 Win=43776 Len=0 TSval=3363671 TSecr=3363671 9 0.002113577 127.0.0.7 127.0.0.1 TCP 66 8888 → 54944 [FIN, ACK] Seq=6 Ack=7 Win=43776 Len=0 TSval=3363672 TSecr=3363671 10 0.002131779 127.0.0.1 127.0.0.7 TCP 66 54944 → 8888 [ACK] Seq=7 Ack=7 Win=43776 Len=0 TSval=3363672 TSecr=3363672 [ ... (non-NATed) above this line is the first connection and below is the second (NATed) connection ...] [ ... Note: The mix of 127.0.0.1 and 127.0.0.5 below and why it's not a problem is what confuses me ...] 11 110.813671399 127.0.0.5 127.0.0.7 TCP 74 55024 → 8888 [SYN] Seq=0 Win=43690 Len=0 MSS=65495 SACK_PERM=1 TSval=3391375 TSecr=0 WS=128 12 110.813703198 127.0.0.7 127.0.0.1 TCP 74 8888 → 55024 [SYN, ACK] Seq=0 Ack=1 Win=43690 Len=0 MSS=65495 SACK_PERM=1 TSval=3391375 TSecr=3391375 WS=128 13 110.813726412 127.0.0.5 127.0.0.7 TCP 66 55024 → 8888 [ACK] Seq=1 Ack=1 Win=43776 Len=0 TSval=3391375 TSecr=3391375 14 110.813766283 127.0.0.5 127.0.0.7 TCP 71 55024 → 8888 [PSH, ACK] Seq=1 Ack=1 Win=43776 Len=5 TSval=3391375 TSecr=3391375 15 110.813779670 127.0.0.7 127.0.0.1 TCP 66 8888 → 55024 [ACK] Seq=1 Ack=6 Win=43776 Len=0 TSval=3391375 TSecr=3391375 16 110.814030105 127.0.0.7 127.0.0.1 TCP 71 8888 → 55024 [PSH, ACK] Seq=1 Ack=6 Win=43776 Len=5 TSval=3391375 TSecr=3391375 17 110.814093611 127.0.0.5 127.0.0.7 TCP 66 55024 → 8888 [ACK] Seq=6 Ack=6 Win=43776 Len=0 TSval=3391375 TSecr=3391375 18 110.814154118 127.0.0.5 127.0.0.7 TCP 66 55024 → 8888 [FIN, ACK] Seq=6 Ack=6 Win=43776 Len=0 TSval=3391375 TSecr=3391375 19 110.817083948 127.0.0.7 127.0.0.1 TCP 66 8888 → 55024 [FIN, ACK] Seq=6 Ack=7 Win=43776 Len=0 TSval=3391376 TSecr=3391375 20 110.817109573 127.0.0.5 127.0.0.7 TCP 66 55024 → 8888 [ACK] Seq=7 Ack=7 Win=43776 Len=0 TSval=3391376 TSecr=3391376
The trace makes it seem like the source IP address is only getting NATed when going from client to server, but not in the other direction. However, the code itself works correctly (i.e. the payload itself makes the full round trip). How does this work? How is it that the TCP connection is staying open? Is it the case that the return trip actually is NATed, but wireshark somehow misses it? Is it the case that there is other metadata that is used to identify the TCP connection and keep it working?
Thanks for any help you can provide! Ask any questions if you have them!
/Thomas
No comments:
Post a Comment