Cozy Camp owu.se Mountain(´∀`)

WireGuard as IPv6 Tunnel with 1:1 Port Forwarding

It’s quite unbelievable that in this era of the 25th and most part of the world still doesn’t have IPv6 working1, either intentionally or technology limitation. But anyways, nerds like you reader and me sure need dualstack right??….right?

¯\_(ツ)_/¯ Welp If you are, then you’re at the right place!

This blog will cover on topics of:

TLDR Full Configuration at the bottom

graph.png

Prepare the HOST’s system

Requirements

Setup secondary IPv6 Address

Add the additional IPv6 Address alongside your main one, if your provider doesn’t give you more than 1 IPv6 Address by default(sad) please check on your provider’s panel on the information about the additional address or to assign them

iface eth0 inet6 static
        address PublicIPv6Address::1/64 # Main IPv6 Address(::1 this example)
        address PublicIPv6Address::ClientAddress/64 # Client IP
        gateway IPv6Gateway

PS. while this blog mainly focuses on /etc/network/interfaces but regardless of netplan or whatever you’re using. There shouldn’t be a significants differences between configuration

Basic WireGuard Setup

I know this part is quite boring as most people would expect the finished or completed version but i made it almost step by step to make people understand how it’s work and atleast aware of what they’re doing

We’ll start by a simple standard WireGuard setup like this AKA the basic version

And in this tutorial, i assigned 10.10.0.1/24 and fd10:10:10::1/64 to be a WireGuard interface’s IP Address

Host’s :

net.ipv6.conf.all.forwarding is set to 1 to allow forwarding IPv6 packets cross interfaces2, which make it possible for WireGuard Client to access internet via Host’s Network AKA VPN for general internet activity

and assigned 10.10.0.4 and fd10:10:10::123 to be “Client A” Addrress then filled the RED highlighted with respective Host’s PrivateKey and Client’s PublicKey

[Interface]
Address = 10.10.0.1/24, fd10:10:10::1/64
ListenPort = 51820
PrivateKey = Server_PrivateKey

# IPv6 forwarding
PreUp = sysctl -w net.ipv6.conf.all.forwarding=1

# client A
[Peer]
PublicKey = Client_PublicKey
AllowedIPs = 10.10.0.4/32, fd10:10:10::123/64

Client’s :

Now to the Client part, we set Address to 10.10.0.4 and fd10:10:10::123 as we assigned in the Server

We set AllowedIPs to ::/0 which is basically all IPv6, to route all IPv6 traffic(in this ::/0 scenario) via secure WireGuard tunnel to remote server which is defined by the endpoint section

The PersistentKeepalive is set to make Peer behind NAT or FireWall to be reachable by another peers3

then filled the RED highlighted with respective Client’s PrivateKey and Host’s PublicKey

[Interface]
Address = 10.10.0.4/24, fd10:10:10::123/64
DNS = 1.1.1.1, 1.0.0.1
PrivateKey = Client_PrivateKey

[Peer]
PublicKey = Server_publicKey
AllowedIPs = ::/0
Endpoint = EndPoint
PersistentKeepalive = 25

Port Forwarding

As you may notice in the Basic WireGuard Setup part net.ipv6.conf.all.forwarding=1 is set to allow forwarding IPv6 packets cross interfaces2 Which might be enough for some, but if we wanted to allow Port Forwarding from Client? This part we’ll right into it!

Mark packets

in Iptables, we can mark packets using MARK target in the mangle table for traffic filtering purposes which we’ll use this to manage our traffic in later stage.4

In this case, we’ll mark traffic into our wireguard interface with 0x30 but you can change it to whatever you like

PS. we might see %i in ip6tables rules, this is copied from WireGuard configuration where interface name is supplied by WireGuard itself, so, please don’t forget to replace the interface name if you’re going to use it anywhere else

Add

ip6tables -t mangle -A PREROUTING -i %i -j MARK --set-mark 0x30

Delete

ip6tables -t mangle -D PREROUTING -i %i -j MARK --set-mark 0x30

1:1 Port Forwarding

here’s the fun part…..or the part you’re waiting for idk but anyways

READ More -> POST/PRE ROUTING graph for nerds: Link via linuxquestions

SNAT

Rewrite Source Address for MARKED traffic to Public_IPv6 before the packet leaves via any interface except the WireGuard interface, this is where the traffic marker become useful

Add

ip6tables -t nat -A POSTROUTING ! -o %i -m mark --mark 0x30 -j SNAT --to-source Public_IPv6

Delete

ip6tables -t nat -D POSTROUTING ! -o %i -m mark --mark 0x30 -j SNAT --to-source Public_IPv6

DNAT

FORWARD IN traffic into Public_IPv6 via network_interface(eth0 in most case) to Client’s WireGuard interface IP, which is fd10:10:10::123

Add

ip6tables -t nat -A PREROUTING -i network_interface(eth0 etc.) -d Public_IPv6 -j DNAT --to-destination fd10:10:10::123

Delete

ip6tables -t nat -D PREROUTING -i network_interface(eth0 etc.) -d Public_IPv6 -j DNAT --to-destination fd10:10:10::123

(Optional) Specific Port Forward

In case you don’t want to 1:1 Port Forwarding and instead, just wanted to forward a specific port to Public_IPv6

SNAT

Rewrite source address for marked traffic same as above but only for PORT

Add

ip6tables -t nat -A POSTROUTING ! -o %i -m mark --mark 0x30 -p protocol(tcp/udp) --sport PORT -j SNAT --to-source Public_IPv6

Delete

ip6tables -t nat -D POSTROUTING ! -o %i -m mark --mark 0x30 -p protocol(tcp/udp) --sport PORT -j SNAT --to-source Public_IPv6

DNAT

FORWARD IN traffic into Public_IPv6 via network_interface like above but just for PORT and to [fd10:10:10::123]:PORT

Add

ip6tables -t nat -A PREROUTING -i network_interface(eth0 etc.) -d Public_IPv6 -p tcp --dport PORT -j DNAT --to-destination [fd10:10:10::123]:PORT

Delete

ip6tables -t nat -D PREROUTING -i network_interface(eth0 etc.) -d Public_IPv6 -p tcp --dport PORT -j DNAT --to-destination [fd10:10:10::123]:PORT


Full Configuration:

Don’t want to read all those yapping? just copy configuration below :D

Server

[Interface]
Address = 10.10.0.1/24, fd10:10:10::1/64
ListenPort = 51820
PrivateKey = Server_PrivateKey

# IPv6 forwarding
PreUp = sysctl -w net.ipv6.conf.all.forwarding=1
# IPv6 masquerading
PreUp = ip6tables -t mangle -A PREROUTING -i %i -j MARK --set-mark 0x30
PreUp = ip6tables -t nat -A POSTROUTING ! -o %i -m mark --mark 0x30 -j SNAT --to-source Public_IPv6
PreUp = ip6tables -t nat -A PREROUTING -i network_interface(eth0 etc.) -d Public_IPv6 -j DNAT --to-destination fd10:10:10::123
PostDown = ip6tables -t mangle -D PREROUTING -i %i -j MARK --set-mark 0x30
PostDown = ip6tables -t nat -D POSTROUTING ! -o %i -m mark --mark 0x30 -j SNAT --to-source Public_IPv6
PostDown = ip6tables -t nat -D PREROUTING -i network_interface(eth0 etc.) -d Public_IPv6 -j DNAT --to-destination fd10:10:10::123

# client A
[Peer]
PublicKey = Client_PublicKey
AllowedIPs = 10.10.0.4/32, fd10:10:10::123/64

Client

[Interface]
Address = 10.10.0.4/24, fd10:10:10::123/64
DNS = 1.1.1.1, 1.0.0.1
PrivateKey = Client_PrivateKey

[Peer]
PublicKey = Server_publicKey
AllowedIPs = ::/0
Endpoint = EndPoint
PersistentKeepalive = 25

#Blog #Network #Wireguard