Skip to content

Instantly share code, notes, and snippets.

@ckcr4lyf
Last active September 3, 2024 13:58
Show Gist options
  • Save ckcr4lyf/bc9910944924f08f9ff37165dd12ed98 to your computer and use it in GitHub Desktop.
Save ckcr4lyf/bc9910944924f08f9ff37165dd12ed98 to your computer and use it in GitHub Desktop.

Network Setup / Topology

Assuming internet facing server (VPS) is Public IP 1.2.3.4 , which is VPN server internally at 10.10.0.1

Assuming home PC is VPN client internally at 10.10.0.2 (Public IP doesn't matter)

We want to expose home PC port 6969 to the internet via the VPS's port 6969.

+---------------------+                   +----------------------+                       +----------------------+
|                     |                   |                      |                       |                      |
|  Client on          +------------------>|    Your VPS          +---------------------->|   your home PC       |
|  Internet           |                   |                      |                       |                      |
|                     |                   |    1.2.3.4           |                       |                      |
|  e.g. 4.4.4.4       |                   |                      |                       |                      |
|                     |<------------------+    (10.10.0.1)       |<----------------------+   (10.10.0.2)        |
|                     |                   |                      |                       |                      |
+---------------------+                   +----------------------+                       +----------------------+

IPtables Rules

iptables -A FORWARD -d 10.10.0.2/32 -p tcp -m tcp --dport 6969 -j ACCEPT
iptables -A PREROUTING -d 1.2.3.4/32 -p tcp -m tcp --dport 6969 -j DNAT --to-destination 10.10.0.2:6969 -t NAT
iptables -A POSTROUTING -o eth0 -j MASQUERADE -t NAT

From point of view of internet client

They don't see anything. They send a packet to 1.2.3.4:6969:

+------------------------------+
|                              |
|     IP Packet                |
|                              |
|                              |
|     From: 4.4.4.4:XXXX       |
|                              |
|     To: 1.2.3.4:6969         |
|                              |
|                              |
+------------------------------+

And get a response from 1.2.3.4:6969:

+------------------------------+
|                              |
|     IP Packet                |
|                              |
|                              |
|     From: 1.2.3.4:6969       |
|                              |
|     To: 4.4.4.4:XXXX         |
|                              |
|                              |
+------------------------------+

From point of view of Home PC

It sees an incoming packet, on their VPN internal IP, from 4.4.4.4:XXXX:

+------------------------------+
|                              |
|     IP Packet                |
|                              |
|                              |
|     From: 4.4.4.4:XXXX       |
|                              |
|     To: 10.10.0.2:6969       |
|                              |
|                              |
+------------------------------+

they process it (e.g. HTTP server or whatever),

and they send the reply to 4.4.4.4:XXXX, from their VPN internal IP:

+------------------------------+
|                              |
|     IP Packet                |
|                              |
|                              |
|     From: 10.10.0.2:6969     |
|                              |
|     To: 4.4.4.4:XXXX         |
|                              |
|                              |
+------------------------------+

From point of view of VPS (This is the good stuff)

Note: I am not an IPTABLES / Netfilter expert, so at the lower level this may not be exactly how it works. If there is anything wrong please correct me.

  1. It sees an incoming packet for 1.2.3.4:6969 . In the NAT table, it matches the rule PREROUTING -d 1.2.3.4/32 -p tcp -m tcp --dport 6969 -j DNAT --to-destination 10.10.0.2:6969 -t NAT as follows: see the destination IP is 1.2.3.4/32 and the port is 6969.
+------------------------------+
|                              |
|     IP Packet                |
|                              |
|                              |
|     From: 4.4.4.4:XXXX       |
|                              |
|     To: 1.2.3.4:6969         |
|                              |
|                              |
+------------------------------+
  1. It applies DNAT aka Destination Network Address Translation, meaning it rewrites the destination to 10.10.0.2:6969.
+------------------------------+
|                              |
|     IP Packet                |
|                              |
|                              |
|     From: 4.4.4.4:XXXX       |
|                              |
|     To: 10.10.0.2:6969       |
|                              |
|                              |
+------------------------------+
  1. Next, in FILTER (default) table, the rule iptables -A FORWARD -d 10.10.0.2/32 -p tcp -m tcp --dport 6969 -j ACCEPT allows the packet to be forwarded to the home PC.

  2. It then gets the reply from the Home PC, with destination 4.4.4.4:XXXX.

+------------------------------+
|                              |
|     IP Packet                |
|                              |
|                              |
|     From: 10.10.0.2:6969     |
|                              |
|     To: 4.4.4.4:XXXX         |
|                              |
|                              |
+------------------------------+
  1. it applies the POSTROUTING -o eth0 -j MASQUERADE -t NAT rule, and rewrites the source IP to the VPS's external IP automatically.
+------------------------------+
|                              |
|     IP Packet                |
|                              |
|                              |
|     From: 1.2.3.4:6969       |
|                              |
|     To: 4.4.4.4:XXXX         |
|                              |
|                              |
+------------------------------+
  1. It then sends the packet back out to the internet!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment