HOWTO: wireguard tunnel to server only

I have an openwrt router (O; 172.16.0.2/16) with wg, up and running to my ubuntu server (U; 172.16.0.1/16; public IP 1.2.3.4).
From O, I ONLY want all traffic with destination U (1.2.3.4) to pass thru wg0, everyting else directly from O to the web via eth0.
Or, vice versa: All traffic from U to O via wg0.
O is the router for WiFi clients, or src of traffic, like DNS.
Imagine an office router, which either connects directly to web, OR forces all traffic via wg to the companies server.
For the sake of learning, no wg-quick to be used, and no LuCi.
Any ideas ?

Typically, routing (where does this packet get sent next, and by what link) is done based on the packet's final destination. In this case, you're not asking for anything different. (Many people discussing VPNs here want source-based routing, where "who you are" determines where the packet gets sent next.)

ip route will give you what you need, a "static route" to 1.2.3.4 via wg0 on the OpenWRT box. Static routes can be configured in /etc/config/network

Now, how the other end handles it gets tricky. Hopefully, its Wireguard instance sets up the routes properly so return packets "just work". As a "remote" host, you can't specify how that host is going to try to reach you if it tries, beyond your IP address. Even there, you're at the whim of how it interprets DNS results (which may be more than one IP address per family) and how it prioritizes IPv4 and IPv6.

I tried already
ip route 1.2.3.4 dev wg0
on O without success.
No received data (bytes) to be seen using wg on O, only transmitted bytes,
and no received data (bytes) to be seen using wg on server.
No handshake done, according to wg on both ends.

I'm not sure which is the Wireguard client and which is the server, but my guess is that you'll eventually find that the server config isn't quite right.

Looking at the routing tables on both would provide insight. ip -4 route will give you those. If they're "right" then you should see the most specific route on each to the other being via wg0 (assuming it is so-named on both).

Another tool of value to learn would be tcpdump (the tcpdump-mini package on OpenWRT is usually sufficient). It will let you "see" the source and destination addresses of the packets that are flowing (or not) over an interface. Looking to see what is sent and received on both boxes (rather than just a byte count) is often very helpful.

tcpdump -ni wg0

as a starter.

On the Ubuntu box, wireshark is a super-charged version of tcpdump that can not only filter on-the-fly, but also group packets by connection, and look at multiple interfaces at the same time. displaying the results in a GUI.

It sounds like you need a policy route.

I think...you want this to pass through WAN, since it's UNTUNNELED...and carrying the encrypted traffic... but I'll write it as you stated:

#add to /etc/config/network
 
 config route
	option interface '<wireguard_interface>'
	option target '1.2.3.4'
	option netmask '255.255.255.255'
	option table '2'

config rule
	option dest '1.2.3.4'
	option priority '2'
	option lookup '2'

lleachii,
Some progress, but still no complete success.

  1. Using chrome, there is a glitch in the LuCi interface.
    On http://192.168.1.1/cgi-bin/luci/admin/network/network/wg0
    the field "Private key" often resets to the root password.
    Very inconvenient.
    OK in FF, though.
  2. I added your lines to /etc/config/network, and also added '1.2.3.4' in next line.
    network.@wireguard_wg0[0].allowed_ips='172.16.0.0/16' '1.2.3.4'

This gives me then at least one handshake

root@OpenWrt:~# wg
interface: wg0
  public key: .......
  private key: (hidden)
  listening port: 5555

peer: ....
  endpoint: 1.2.3.4:5555
  allowed ips: 1.2.3.4/32, 172.16.0.0/16
  latest handshake: 10 minutes, 17 seconds ago
  transfer: 92 B received, 148 B sent
  persistent keepalive: every 25 seconds

But thats it. Ping 1.2.3.4 times out.

To verify:

root@OpenWrt:~# ip rule show
0:      from all lookup local
2:      from all lookup 2
32766:  from all lookup main
32767:  from all lookup default

root@OpenWrt:~# ip route show table 2
1.2.3.4 dev wg0 proto static scope link

root@OpenWrt:~# ip address show wg0
16: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1
    link/none
    inet 172.16.18.32/32 brd 255.255.255.255 scope global wg0
       valid_lft forever preferred_lft forever

root@OpenWrt:~# ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP mode DEFAULT group default qlen 1000
    link/ether e4:95:6e:43:18:31 brd ff:ff:ff:ff:ff:ff
3: eth1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel master br-lan state DOWN mode DEFAULT group default qlen 1000
    link/ether e4:95:6e:43:18:31 brd ff:ff:ff:ff:ff:ff
13: br-lan: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether e4:95:6e:43:18:31 brd ff:ff:ff:ff:ff:ff
15: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-lan state UP mode DEFAULT group default qlen 1000
    link/ether e4:95:6e:43:18:31 brd ff:ff:ff:ff:ff:ff
16: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
    link/none

ip route
root@OpenWrt:~# ip route
default via 192.168.178.1 dev eth0 proto static src 192.168.178.49
172.16.0.0/16 dev wg0 proto static scope link
1.2.3.4 dev wg0 proto static scope link
192.168.1.0/24 dev br-lan proto kernel scope link src 192.168.1.1
192.168.178.0/24 dev eth0 proto kernel scope link src 192.168.178.49

root@OpenWrt:~# ip route show table all
1.2.3.4 dev wg0 table 2 proto static scope link
default via 192.168.178.1 dev eth0 proto static src 192.168.178.49
172.16.0.0/16 dev wg0 proto static scope link
1.2.3.4 dev wg0 proto static scope link
192.168.1.0/24 dev br-lan proto kernel scope link src 192.168.1.1
192.168.178.0/24 dev eth0 proto kernel scope link src 192.168.178.49
broadcast 127.0.0.0 dev lo table local proto kernel scope link src 127.0.0.1
local 127.0.0.0/8 dev lo table local proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo table local proto kernel scope host src 127.0.0.1
broadcast 127.255.255.255 dev lo table local proto kernel scope link src 127.0.0.1
local 172.16.18.32 dev wg0 table local proto kernel scope host src 172.16.18.32
broadcast 192.168.1.0 dev br-lan table local proto kernel scope link src 192.168.1.1
local 192.168.1.1 dev br-lan table local proto kernel scope host src 192.168.1.1
broadcast 192.168.1.255 dev br-lan table local proto kernel scope link src 192.168.1.1
broadcast 192.168.178.0 dev eth0 table local proto kernel scope link src 192.168.178.49
local 192.168.178.49 dev eth0 table local proto kernel scope host src 192.168.178.49
broadcast 192.168.178.255 dev eth0 table local proto kernel scope link src 192.168.178.49
fd54:768d:c69c::/64 dev br-lan proto static metric 1024 pref medium
unreachable fd54:768d:c69c::/48 dev lo proto static metric 2147483647 error -148 pref medium
fe80::/64 dev eth0 proto kernel metric 256 pref medium
fe80::/64 dev wlan0 proto kernel metric 256 pref medium
fe80::/64 dev br-lan proto kernel metric 256 pref medium
unreachable default dev lo proto kernel metric 4294967295 error -128 pref medium
local ::1 dev lo table local proto unspec metric 0 pref medium
local fd54:768d:c69c:: dev lo table local proto unspec metric 0 pref medium
local fd54:768d:c69c::1 dev lo table local proto unspec metric 0 pref medium
local fe80:: dev lo table local proto unspec metric 0 pref medium
local fe80:: dev lo table local proto unspec metric 0 pref medium
local fe80:: dev lo table local proto unspec metric 0 pref medium
local fe80::e695:6eff:fe43:1831 dev lo table local proto unspec metric 0 pref medium
local fe80::e695:6eff:fe43:1831 dev lo table local proto unspec metric 0 pref medium
local fe80::e695:6eff:fe43:1831 dev lo table local proto unspec metric 0 pref medium
ff00::/8 dev br-lan table local metric 256 pref medium
ff00::/8 dev eth0 table local metric 256 pref medium
ff00::/8 dev wlan0 table local metric 256 pref medium
ff00::/8 dev wg0 table local metric 256 pref medium
unreachable default dev lo proto kernel metric 4294967295 error -128 pref medium

May be, you have another good idea to follow on the path to success ?

This is what I was afraid of...you cannot have the Tunnel Enpoint IP both INSIDE AND OUTSIDE OF THE TUNNEL. It's impossible to send the wg traffic to 1.2.3.4 OUTSIDE THE TUNNEL when you make a route to reach 1.2.3.4 INSIDE THE TUNNEL AS WELL. (or would require a very complex routing policy)

It appears you may need to add a route and rule for 172.16.0.0/16.

Sorry, but I do not want both routes, just one: Inside the tunnel. I added 1.2.3.4/32, because without it did not work at all. No data transfere.
As I wrote in beginning, imagine a wifi-router, which allows direct access to the web (eth0) for all the LAN/WLAN-clients, with one exception: To the companies server. All traffic to the companies server 1.2.3.4 routed via wg0, for simple data protection.

I think the issue is that the packets to 1.2.3.4 are sent down the tunnel and encrypted, now where are the encrypted packets sent?

you might be able to get around the fact that the encrypted packets also need to be sent down the tunnel by using some policy routing for packets generated on the router.

ip route add 1.2.3.4 dev wg0
ip route add 1.2.3.4 dev eth0 table 1000
ip rule add prio 2 from ROUTERIP table 1000

Which sends all packets via wg0 except those from ROUTERIP which go via eth0

for example.

1 Like

WG should make a route to 1.2.3.4/32 via WAN because it's a VPN...from there, the OP has to make a custom rule if the server cannot be reached via a tunnel IP instead...but please note, the route via wg will always have issues.

Note that this whole issue wouldn't come up if the wireguard endpoint weren't the same as the service endpoint... For example if there were a "vpn server" at 1.2.3.4 and then you wanted to reach 1.2.3.5 and 1.2.3.6 down the tunnel, it's just that in this case both the wg daemon and the daemons for the other services are using the same IP to listen.

It really does make sense to give the services a private IP

Many people get the impression that an IP is something associated to a particular box, or a VPS or something. Like you can only have one. As in "the IP of the server is x.y.z.q" but that's a wrong impression. An IP is just an address that some process listens on or talks on and a given computer can have zillions of them. IPv6 makes this super clear, you could give a million IPs to your desktop computer without breaking a sweat. EDIT: the only reason people don't do that with ipv4 is that the addresses are so scarce you wouldn't give more than at most a handful of public ones to a given computer.

1 Like

Frankly speaking, I am a bit lost. I gave an example of the application, which is not so far fetched, I think.
So, please either clearly specify, what to do, for an "amateur" like me, or simply say: "Impossible".
May be, some iptables rules might help, like DNAT ?

OK...Setup your server it can be reached via a private IP address inside the tunnel.

The "typical" kind of application for a VPN tunnel between two sites is something like

10.0.1.n/24 private net 1
        |
10.0.1.1 gateway on portal 1
        |
internal VPN interface in portal 1
        | (encrypted)
198.51.100.27 public IP of portal 1
        | (encrypted)
public Internet
        | (encrypted)
203.0.113.123 public IP of portal 2
        | (encrypted)
internal VPN interface in portal 2
        |
10.0.2.1 gateway on portal 2
        |
10.0.2.n/24 private net 1
  • The VPN tunnel itself uses the public route to the other portal
  • Internal traffic in either private net use the attached portal as their router
  • Portal 1 has a route to private net 2 over the VPN interface
  • Portal 2 has a route to private net 1 over the VPN interface

It's very strange for a public IP address to be only reachable by a VPN tunnel whose endpoint is also the same public IP address. That is far-fetched, because normally if you have a public IP, then packets arrive at it via the public routed internet.

If you have your remote server provide services on an IP which is on a subnet associated with your VPN tunnel, and have the remote server's VPN daemon listen for encrypted packets on the public IP then this is normally what makes sense.

add an IP like 10.x.y.z to your remote wg0 interface, and tell your remote server daemons to listen on that IP, then tunnel to that IP using wireguard.

Think of it like this, you have a remote server, how does information arrive at it? It is sent over the public internet to the public IP, 1.2.3.4

Now, what will the remote server do with it? It needs to reject disallowed packets, and use the allowed packets. There are two kinds of allowed packets:

  1. encrypted packets that form the tunnel
    1a) packets created by decrypting encrypted packets
  2. unencrypted packets requesting services over the internet

Suppose you only want to provide services to people who send you encrypted packets. Fine, then your local router needs to:

  1. Take packets destined for 1.2.3.4 and send them over wg0 to encrypt them
  2. Take the encrypted packet and make it the payload of an unencrypted packet destined for the remote wireguard which is listening on 1.2.3.4
  3. Send the packet from (2) to the remote address over a regular eth0 type link

So the router needs to distinguish between those packets going to 1.2.3.4 that need to get encrypted first and sent via wg0 and the alternative already encrypted packets created by wg0 being sent as the payload in a packet to 1.2.3.4 over the internet

so not all packets going to 1.2.3.4 are treated the same, and hence you are in policy routing territory where the routing is dependent on something other than the destination.

That's not normally "amateur" technology you're talking about. An application that requires policy routing at least should be done by someone who understands what policy routing is and why policy routing is required. If you don't see why its required here, then either:

  1. Add a private IP to the remote server and route that via wg which eliminates the ambiguous handling of 1.2.3.4
  2. Read up on policy routing.

Thank you very much, this makes it clearer for me. Continue working on this one.