LUCI is generating incorrect wireguard peer configs

I see in 22.03.2 that the QRCode peer config generator for Wireguard in LUCI is now incorporating private keys and pre-shared keys. Also it is getting the peer's endpoint hostname from ddns config and this was a stroke of genius. However the config that it is generating is actively incorrect.

Basically, what is being sent to the peer as its config file reverses what is going into [Interface] -> Address and what is going into [Peer] -> AllowedIPs. This means that the peer ends up thinking it's IP address is actually the OpenWrt Wireguard interface's IP address.

[Peer] -> AllowedIPs should probably also contain the br-lan subnet.

1 Like
2 Likes

I found that Bug too... its not generating correct QR code... hope for a fix in future updates...

Can you please clarify? I don't fully understand this. The generated configuration contains no Address = ... setting at all so how is the peer "thinking" that it using the OpenWrt's WireGuard interface IP?

By default, the generated config should contain AllowedIPs 0.0.0.0/0, ::/0 which should satisfy the typical road warrior setups this feature is tailored for.

Also note that the AllowedIPs you configure on the OpenWrt side per peer are not the values that are supposed to end up in the peer's configuration, they're the allowed/routed IPs from OpenWrt's point of view towards the peer. The allowed IPs within the generated peer config should contain the allowed/routed IPs from the peers point of view towards OpenWrt, either wildcard (for road warrior kind of setups) or a specific list including OpenWrt's wg0 interface address (and potentially the lan subnet too).

There's been a recent change (https://github.com/openwrt/luci/pull/6079) that introduced the ability to customize the allowed IPs when generating the config.

Also note that currently there's no address management at all for peers, so you will need to assign a wireguard-internal IP yourself when importing the configuration.

1 Like

So I have noticed this as well...
My comments are based on the road-warrior type configuration where the 'server' side peer is at the home/office and the remote/'client' peer is a phone or camera enabled device. I assume this is the most relevant use-case for this QR code method.

The good:

  • now that you can create a key pair for the peer, it makes importing into a mobile device super simple. It is no longer necessary to transfer the public key from the mobile/remote peer to the OpenWrt device. (this does assume you trust the OpenWrt side to have the remote peer's private key 'on file')
  • Key exchange is the most difficult/annoying/error prone part of the process (especially because there is no human readable way to determine the difference between a private, public, and pre-shared key, so things can be swapped easily). This makes it trivially easy.
  • Being able to specify the endpoint for the peer means that it will be pre-populated on the remote peer.

The bad:

  • As it stands now (based on an installation of 22.03.2 on Nov 28, 2022), the allowed IP's specified in the 'server' end up in the allowed IP's field on the remote/'client' peer when using the QR code. This should be transferred to the 'Addresses' field of the remote peer's interface definition.
  • The 'client' peer's address field is left empty.
  • There is no option to specify the allowed IPs that should actually be used on the remote peer side. This doesn't auto-populate 0.0.0.0/0 or anything useful because of the above situation.
  • There are no options to specify the MTU and DNS fields for the remote peer.

It sounds like the allowed IPs issue will be resolved when that PR makes it into a stable release (or sooner if for those on snapshot).

It already is in stable. But could you explain why OpenWrt allowed IPs for the peer should end up in the peer configs „Adresses“? This does not sound right to me.

Maybe a more concrete example would help

[EDIT] With apologies for the length of this - I was obviously not good at being both precise and brief.

Sorry, my mistake. You are correct. What I should have said is that what should be in the [Interface] Address = field in the remote's generated config is instead being put in the remote's [peer] -> AllowedIP =. That is backwards and can never work.

Ok, I'll explain. To try and avoid the confusing over-use of 'peer' below, I'm going to use "remote" to mean a device remoting in to my OpwnWrt router, and "router" to mean the device acting as the VPN server.

My network topology: Standard cable-modem -> OpenWrt router. On the router the LAN is 192.168.2.1/24 and the wireguard interface is set up on 10.6.0.1/24.

Here are the relevant parts of /etc/config/network:

config interface 'lan'
        option ipaddr '192.168.2.1'
        option netmask '255.255.255.0'

config interface 'vpn'
        option proto 'wireguard'
        option private_key 'krouterprivatekey='
        option listen_port '12345'
        list addresses '10.6.0.1/24'

config wireguard_vpn
        option description 'CursorToo3'
        option public_key 'kremotepublickey='
        option private_key 'kremoteprivatekey='
        option preshared_key 'Kremotepresharedkey='
        option route_allowed_ips '1'
        option persistent_keepalive '25'
        list allowed_ips '10.6.0.3/32'

Here is one of my actual, working (but obviously redacted) remote device's wireguard configs:

[interface[
Address = 10.6.0.3/32
DNS = 192.168.2.1
PrivateKey = kremoteprivatekey=

[Peer]
AllowedIPs = 10.6.0.0/24, 192.168.2.0/24
Endpoint = myddnsaddress.dynamodns.info:12345
PersistentKeepalive = 25
PreSharedKey = Kremotepresharedkey=
PublicKey = krouterpuiblickey=

This tells the remote it's own IP address is 10.6.0.3, and tells the remote that it's allowed to send anything to addresses 192.168.2.0/24 and 10.6.0.0/24 to its peer (the remote's peer is obviouisly the router).

Here is the remote's config that OpenWrt actually generates:

[Interface]
PrivateKey = Kremotepresharedkey=
# ListenPort not defined

[Peer]
PublicKey = krouterprivatekey=
PresharedKey = Kremotepresharedkey=
AllowedIPs = 10.6.0.3/32
Endpoint = myddnsaddress.dynamodns.info:12345
PersistentKeepAlive = 25

Allowed IP for the peer configuration on the router should not be the allowed IP for the peer configuration on the remote. That is telling both the router and the remote to send to the same address. This makes no sense and can never work.

What it should be:

/etc/config/network
config wireguard_vpn
        option description 'CursorToo3'
        list allowed_ips '10.6.0.3/32'  --->
Generated config:
[Interface]
Address = <--- router's PEER allowed_ips goes here

but never

Generated config:
[Peer]
AllowedIPs = <--- never never never there

And even better would be to make:

/etc/config/network
config interface 'vpn'
        list addresses '10.6.0.1/24'  ---->

This is what should be going

Generated config:
[Peer]
AllowedIPs = <---- router's VPN interface address should go here

I know I describe it with road-warrior topology, but if done as I describe, it will work with any topology because the it's router's VPN interface address and the router's VPN peer addresses/allowed_ips that change, not the position of where they go in the generated file.

I think that @VA1DER has summarized the issues well, but I would be happy to generate some complete configs (using demo/throw-away keys, but fully valid for testing purposes) to share here along with the qr code to demonstrate the behavior I am describing in my post above. I may not get to this until tomorrow at the earliest (today is a travel day), but let me know if that would be helpful.

This part makes no sense to me. Allowed IPs could be subnets, unrelated IPs and multiple entries to begin with. How is that supposed to translate to a single address entry? Which entry to select in case there’s multiple allowed ip entries? Which host address to select in case an allowed IP entry is a CIDR referring to a network address?

This should be already fixed in master and stable

1 Like

As was noted earlier, there is a fundamental issue of the expectations of what this QR code should actually do given the different contexts for wireguard use and configuration options, due in part to the fact that peers are peers and there is no formal server/client distinction. That said, I suspect that my expectations are similar to @VA1DER ‘s, and I will post some examples when I have a chance. It is certainly possible that people will disagree about the value of implementing against the use case and expectations I will detail, but hopefully it will at least be well understood.

Ok... so, I stand corrected about one aspect -- the QR code based setup with allowed IPs is populating properly based on the options in the QR code generator page.

However, the interface IP is not being populated the way I (personally) would expect. There may be a good reason for this that isn't currently known to me.

In the following configuration, the OpenWrt peer is acting as a 'server' for a road warrior type configuration. In this context, a mobile device would use the WG tunnel to gain access to local network resources and/or the internet as a whole via the tunnel. Therefore, the peer as defined in the OpenWrt configuration for the mobile device would have an address in the allowed IPs (/32). The mobile device's WG interface address should then correspond to the allowed IPs field from the OpenWrt peer config.

config interface 'rdwarrior'
	option proto 'wireguard'
	option private_key 'QAg4c0vgV2dX1uCvmtE/QYR8FX6Lc+5n8L3ZwpHvPHs='
	option listen_port '51820'
	list addresses '192.168.9.1/24'

config wireguard_rdwarrior
	option description 'iPhone'
	option public_key '3YifDh+i7J/pYpsG+NGgkBn6u7cEMbYweVKZpor7cRk='
	option private_key '0HcP+73jguRERM6zSaVMzfiTxNcpcot366ItHB9QWXE='
	list allowed_ips '192.168.9.2/32'
	option route_allowed_ips '1'
	option persistent_keepalive '25'

And here's the QR code that is generated:

Finally, here's the iPhone import of that QR code:

I would argue that the issue with the above image is that there is no interface address on the iPhone after the QR code is used. That address is "strongly recommended" per the text in the screenshot, but if I'm not mistaken, it is actually required for the connection to work at all. Therefore, I would suggest that it should look like this, instead (this required a manual edit of the WG configuration on the iPhone):

This is obviously not difficult to edit, but it does mean that the QR code method doesn't setup a fully functional wireguard configuration on the mobile peer. I am wondering why the address is not populating based on the allowed IPs from OpenWrt. Are there other contexts where the QR code might be used that would make this an inappropriate thing to auto-populate?

NOTE: The above configuration is purely for demonstration purposes. The keys are valid, but disposable. Feel free to use the configuration for experimentation purposes, but do not use these keys on the internet because they are obviously publicly available and therefore not secure.

I guess I'm hoping to have something that, out of the box, Just Works™ for the people in the middle of the bell curve. You're not going to be generating a config, for example, for a commercial VPN you are connecting your lan to over WireGuard. If someone is using a QR-code generated config, it's generally going to be with with a phone or a tablet. In these cases, the router peer's configured allowed IPs will almost certainly be a single address, because that is all you want the router sending to that peer. That right there is I suspect 90% of all uses of a generated config.

If there are multiple subnets on the allowed ip list, then this is sticky, but certainly one of them is usually going to be the remote peer's actual address. All we have to do is mandate that the remote peer's IP is the first in the router's peer config allowed ip list, and then use the first one.

Or, alternatively, if you don't like that, then put a field into each router peer's config for "Addresses" like you do for the interface. You already allow to store the peer's private key, just for generated config purposes. Store its Addresses too. But I think this is unnecessary. For almost all situations, the peer's IP address will be the only entry, or one of the entries in, the router peer's allowed_ips.

Thank-you. In stable I see the extra fields in the generator for allowed_ips and the list to select from. This is great! For me it was populated only with 0.0.0.0/0. Please consider populating that list with the router's wireguard interface address, and possibly the br-lan subnet address, for ease of use for those who do not want to route all traffic through the connection.

Thanks for the clarification. The crucial piece of information for me was that people apparently treat the per-peer allowed ip setting as a kind of address management option because for many scenarios it happens to be identical to the peers wireguard interface ip.

LuCI currently makes no such assumption for the reason explained above (e.g. how to turn allowed ip „192.168.67.0/24 10.20.30.0/24 fdca:1234:4567:890::/64“ into a single address).

There currently is no per-peer address management implemented at all, which is likely what is confusing people. This is tracked as a feature request here but raised more, yet unanswered questions:

As an interim solution we could start using the allowed IPs value as Address option in the generated config when it refers to a host address (e.g. 192.168.44.5 or 172.16.24.9/32 or 10.99.45.12/24 but not 192.168.44.0/24) and falls within the OpenWrt wg0 interface subnet.

Peer side allowed IPs currently default to 0.0.0.0/0, ::/0 - we could add a second predefined choice which contains the OpenWrt wg0 interface subnet(s) as well as another choice containing the current lan subnet (in case there is a lan interface - maybe we shouldn’t assume „lan“ and simply add one choice for each downstream/static network).

It is unclear to me how to populate DNS though, setting it to the OpenWrt wg0 interface IP might work, but only if dnsmasq was not reconfigured or replaced. Setting it to OpenWrt‘s own upstream servers would require even more allowed IP entries and a working routing/nat setup outside of the scope of the wireguard configuration.

2 Likes