Wireguard - changes the default route although not configured

  • Hello Team,


    Thanks for implementing wireguard in the latest release of LibreElec!


    I followed the example from here and here


    I tried to replace my site-to-site VPN from the addon tinc to wg, but somehow it keeps replacing the default route from eth0 to wg0 even though the AllowedIPs is limited to the remote subnet. If I connmanctl disconnect <vpnname> it properly restores the former default route.


    I'm not sure where to look. This is the config file ~/.config/wireguard/wireguard.config:



    I understood from the docs, that wg would only set the default route to the tunnel, if AllowedIPs would be 0.0.0.0/0 - but it isn't.


    After connmanctl connect, the route table looks like this (the other side of the wg-end is not yet configured, so don't mind the missing route for the target subnet):



    The output of wg correctly limits to the configured target subnet.


    After "connmanctl disconnect <vpnname>" the ip route looks like this:


    Code
    1. ~/.config/wireguard # ip route
    2. default via 192.168.110.100 dev eth0
    3. 192.168.110.0/24 dev eth0 scope link src 192.168.110.15
    4. 192.168.110.100 dev eth0 scope link
    5. 255.255.255.255 via 192.168.110.100 dev eth0



    I do not understand why it replaced the default route to wg0, the config file does not tell it to do so. Is this maybe a temporary state until the tunnel is established? Because that is not the case at this moment.


    Can someone give me a hint where to look?


    EDIT: I found there is a file ~/.cache/connman/<vpnname>/settings, which contains this line:

    SplitRouting=false

    This probably has something to do with it. I can not set it to "true", because it gets overwritten automatically by some other mechanism as soon as I "connmanctl connect <vpnname>". This mechanism probably is hardcoded to forcetunnel (route 0.0.0.0/0) into wireguard, isn't it?

  • The issue has been raised a couple of times. I've flagged it to the connman developers. We have to see what they say..

  • I've been told the AllowedIP setting is for internal WireGuard logic and WireGuard is not controlling the routing table. However, the WG connection is higher in the list of connman services (as it was created most recently) which means it becomes the primary service and default route. To change this we can change the service order via connmanctl, e.g.

    Code
    1. connmanctrl move-after vpn_138_116_14_12_wg_domain_tld ethernet_1cf05e0b93f0_cable
    2. Moved vpn_138_116_14_12_wg_domain_tld after ethernet_1cf05e0b93f0_cable

    So syntax is: connmanctl move-after <service_to_move> <service_to_move_it_after>


    So for scenarios where you want to connect via WireGuard to access content on a remote server, but otherwise still want/need the Internet connection to be as-normal from the local network, we can add another ExecStart in the connman.service file, e.g.

    Code
    1. [Service]
    2. Type=oneshot
    3. RemainAfterExit=yes
    4. ExecStart=/usr/bin/connmanctl connect vpn_138_116_14_12_wg_domain_tld
    5. ExecStart=/usr/bin/connmanctl move-after vpn_138_116_14_12_wg_domain_tld ethernet_1cf05e0b93f0_cable
    6. ExecStop=/usr/bin/connmanctl disconnect vpn_138_116_14_12_wg_domain_tld

    NB: I haven't tested this, but it makes sense to me, so please have a play and report back.


    NOTE: I have subsequently been told that the move-after changes are persistent, so would only need to be done once.

  • Thanks for getting back. The move-after has to be executed twice to work for me:



    As you can see, the second move-after actually changed the Interface of the default route. So I adopted the service-file:


    This way, it works. But I'm not sure why.


    Anyway, the service does not come up during boot. How can I troubleshoot this? systemctl status wireguard shows some weird errors (the wrong timestamps seem to be the case as this service gets started before the time was fixed - maybe this is also the problem here, it gets started too early?):



    If I login with root and "systemctl stop wireguard" and "systemctl start wireguard" it seems to work.

    Any ideas?

  • From what I've read WireGuard requires monotonic time, i.e. time can change but must always move forwards, so it shouldn't be affected by the time-jump seen when NTP kicks in (unlike TLS certs which are invalid until current time is greater than cert start dateTime) as time starts from libc compile time (some date in April?) but I'm not an expert in these things. I suspect the timing/sequencing for WireGuard in the .service file could be improved as I'm a novice with systemd things.

  • Thanks, I managed to work around with that issue by just sleeping for 5 seconds before starting with wireguard stuff upon boot. This works for me. I also tried with some other dependencies (connman.service, bluetooth.service), but that did not help. I guess I could restore the defaults there ...


    I am still wondering why this move-after has to be executed twice (for me). On the other side of the LibreElec this also not helps in every case, he sometimes need to stop / start wireguard.service several times until it works.

  • Having done a bit more reading I have a suspicion we need to start using systemd to handle NTP as this adds a new systemd .target for when the initial NTP sync has completed, which would be useful in this scenario. That's something for the master branch though, I wouldn't risk that kind of change being backported to 9.2 at this stage in the release lifecycle.

  • Having done a bit more reading I have a suspicion we need to start using systemd to handle NTP as this adds a new systemd .target for when the initial NTP sync has completed, which would be useful in this scenario.

    Or conman start to support /run/systemd/timesync/synchonized for reliability ...


    On RPIs (or any other devices without RTC) time-sync.target already may work today. Start enabling the needed service:

    Code
    1. systemctl enable systemd-time-wait-sync

    Reboot a few times and check:

    Code
    1. systemctl status systemd-time-wait-sync
    2. systemctl status time-sync.target

    If time-sync.target is always reached the dependency can be added to the wireguard unit.

  • mglae some early testing is positive. I've enabled systemd-time-wait-sync and added time-sync.target to "After" in wireguard.service. If we see a few more positive reports I'll push some changes.

  • chewitt systemd-time-wait-sync does hang randomly on Generic because ntp slew adjusts are not detected. There has to be a jump adjust in the beginning (only be used if the time error is >0.5sec).


    Assuming the initial RTC value is always "good enough" we can disable systemd-time-wait-sync on this platform with a drop-in file:

    Code
    1. [Unit]
    2. ConditionArchitecture=!x86-64