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
    ~/.config/wireguard # ip route
    default via 192.168.110.100 dev eth0
    192.168.110.0/24 dev eth0 scope link  src 192.168.110.15
    192.168.110.100 dev eth0 scope link
    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?

    Edited 3 times, last by chemical1979 (April 29, 2020 at 10:14 PM).

  • Go to Best Answer
    • Official Post

    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
    connmanctrl move-after vpn_138_116_14_12_wg_domain_tld ethernet_1cf05e0b93f0_cable
    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
    [Service]
    Type=oneshot
    RemainAfterExit=yes
    ExecStart=/usr/bin/connmanctl connect vpn_138_116_14_12_wg_domain_tld
    ExecStart=/usr/bin/connmanctl move-after vpn_138_116_14_12_wg_domain_tld ethernet_1cf05e0b93f0_cable
    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?

    • Official Post

    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.

    • Official Post

    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
    systemctl enable systemd-time-wait-sync

    Reboot a few times and check:

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

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

  • 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
    [Unit]
    ConditionArchitecture=!x86-64
  • As far as I understand, the suggested solution needs a specific service (such as ethernet) that can be used as "move-after" target. But what happens if the ethernet cable is unplugged and the device is using wifi to access the internet? Is there a solution that works for both wifi and cable?

  • I tried to make it a bit more resilient to changes and different scenarios.

    I found it to be not reliable when started through systemd. therefore i used autoexec.py in /storage/.kodi/userdata/autoexec.py with the following content:

    Python
    from subprocess import call
    call("/storage/connect_vpn.sh")

    And for the actual connection if have this in /storage/connect_vpn.sh:

    Hth. A fix in connman would certainly be nicer!

    Edited once, last by nativemad (January 8, 2022 at 9:07 PM).

  • This is quite hard to use reliably. Even with nativemad's script when I'm trying to connect to my rpi from an external network using the external ip (not through wireguard), I have multiple "connmanctl move-after" commands every five seconds. This makes the connection really unstable.

    On a different but related note, I've also tried using a docker container as a wireguard client (since it works very well for a wireguard server), but apparently LibreElec doesn't include the iptables_raw kernel module so it's not possible to set AllowedIps as 0.0.0.0/0.

    I'm not really good with networking, but is there any way to actually load this module, or to force the metric of the vpn as really high so the route will have a low priority? I'm kind of stuck here.

    Edit: In the end I just configured wireguard manually with wg. Not ideal but it works...

    Edited once, last by reyqn (February 19, 2022 at 1:59 PM).

  • After a few days I managed to solve default route issue. Below there are my scripts with descriptions.

    WG configuration:

    /storage/.config/wireguard/wg0.conf

    Code
    [Interface]
    ListenPort = <port>
    PrivateKey = <privkey>
    
    [Peer]
    PublicKey = <publkey>
    AllowedIPs = 0.0.0.0/0
    Endpoint = <endpoint hostname>:<port>

    Wireguard startup script:

    /storage/.config/wgconnect.sh

    Stop Wireguard connection:

    /storage/.config/wgdisconnect.sh

    Bash
    #!/bin/bash
    ip link set down dev wg0

    Systemd service:

    /storage/.config/system.d/wireguard.service

    Then all traffic routes via default eth0 interface and several ip's via wg0. Routes look as follows:

    At least, it works for me.

  • In case anyone else is looking for a solution. I got this working to add a network "lock" with iptables to ensure all non-LAN internet traffic goes over wireguard by adding the following in /storage/.config/iptables/rules.v4

    I believe you need to also first allow custom firewall rules in Kodi with:

    1) Set kodi's network/firewall config to custom
    2) Reboot

  • hello,

    I need help with my wireguard configuration..

    I have subscribed to a paid subscription at protonvpn and I have the possibility of creating wireguard configs..

    I will try to describe my problem.

    I created a file with nano in storage/.config/wireguard/wireguard.config

    I have replaced the necessary information with that of my supplier.

    [provider_wireguard]

    Type=WireGuard

    Name = WireGuard VPN Tunnel

    Host = 188.241.xx.xxx

    WireGuard.Address = 10.2.0.2/32

    WireGuard.ListenPort = 51820

    WireGuard.PrivateKey = MGWKhrENy0r3soBHkJf0UGqYaxxxxxxxxxxxxxxxx=

    WireGuard.PublicKey=LVsKLsUOqzeYK3ATkN8xxxxxxxxxxxxxx=

    #WireGuard.PresharedKey = DfEYeVs04HS9XhKGM4/ZXHG3Qc4MFKxxxxxxxxx=

    WireGuard.DNS=10.2.0.1

    WireGuard.AllowedIPs = 0.0.0.0/0

    WireGuard.EndpointPort = 51820

    WireGuard.PersistentKeepalive = 25

    the connection is made and my public ip changes but when I do a test with the dnsleak plugin I find the dns of my internet provider..

    I have circumvented the problem temporarily with pihole or an alternative dns but I would like to solve the problem.

    someone to help me?

  • laurent734 LE probably needs to use ConnMan with the built-in DNS proxy to avoid DNS leaks at source; but we deliberately don't use the DNS proxy because it means Kodi GUI (correctly) shows 127.0.0.1 as the system DNS server and then we drown in annoyiing user support posts that point fingers at "networking is broken, it shows 127.0.0.1 not my real DNS server" posts from users. The workaround is to force traffic using iptables (read a few posts above).

  • laurent734 LE probably needs to use ConnMan with the built-in DNS proxy to avoid DNS leaks at source; but we deliberately don't use the DNS proxy because it means Kodi GUI (correctly) shows 127.0.0.1 as the system DNS server and then we drown in annoyiing user support posts that point fingers at "networking is broken, it shows 127.0.0.1 not my real DNS server" posts from users. The workaround is to force traffic using iptables (read a few posts above).

    hello,

    Thank you for your reply ..

    I followed your advice and I managed to remove the dns leaks..

    1: I edited the rules.v4 file with the command:

    nano /storage/.config/iptables/rules.v4

    I used the loopy123 file and I replaced

    2:PORT_FROM_WG_CONFIG with my provider's port and

    3:WG_CONFIG_IP with address 10.2.0.2

    4: I recorded with nano

    5:I ran:

    iptables-save >/storage/.config/iptables/rules.v4 to make it permanent

    6: I then activated the personalized firewall in the graphical interface and restarted

    after these steps I still had dns leaks.

    I therefore configure a fixed ip with the 1st dns 10.2.0.1 and the second pihole.

    miracle after test with the nslookup command I get:

    nslookup google.fr

    Server: 10.2.0.1

    Address 1: 10.2.0.1

    Name: google.fr

    Address 1: 142.251.39.99 ams15s48-in-f3.1e100.net

    I also did a test with the dnsleak pluggin which confirms the only use of a single dns that of proton.

    to conclude I do not know if iptables help me or if I simply had to force the dns 10.2.0.1 but the essential and that it works.

    I specify that I useful coreelec in nexus beta1 version wireguard donations works very well on nexus

    thanks to loopy123 for his file and to you for your advice :)