Why can WireGuard peer only be set to an IP address vs FQDN?

Currently in VyOS when setting the peer endpoint, for eg. set interfaces wireguard wg1 peer peer1 address 2001:db8::1 it’s not possible to set it to a domain name.
But using domains is supported in almost every WireGuard client including the official INI configuration file format.

Is there a specific reason this was excluded in VyOS or is it just waiting for someone to add support for it?

More details at ⚓ T1700 Wireguard FQDN endpoint doesn't work after reboot and ⚓ T5850 Wireguard Peer should allow endpoint to be specified by hostname

2 Likes

OK thanks, it seems like an intermediate solution would be to leave the address option empty and create a cronjob resolves the DNS name and sets the address on a peer and commits the change.

This feature on our roadmap

3 Likes

Sorry to be bringing this back up.
I just ran into this blocker on my setup, where the site to site tunnel I’m configuring, has both with public dynamic IPs, as such, I need to us a FQDN.

Is there any update regarding adding this capability since 2020?

Thanks.

There are no updates

ok, thanks for the confirmation.

I’ve been looking at every feature in VyOS to try to understand what supports FQDNs and what doesn’t.
Was thinking on telling Wireguard to just send the traffic to a local address and than have that translated or routed to the actual destination.
NAT doesn’t seem to support FQDN from what I can tell.

Is there any routing or service in VyOS that would be capable of doing this?

I understand some of the arguments on another post regarding FQDNs, Wireguard issues - #7 by hagbard, where it mentions things such as that dynamic re-creation will cause packet loss.
Well, if the IP changes on the target endpoint, the entire tunnel connection will go down.

Also considering exploring setting a Task Scheduler to directly change the config when an IP change is detected, but haven’t read the docs on that in detail yet.

Any ideas or workaround would be appreciated.

I made this for this purpose. Place both of these in the /config/scripts folder:

wgcheck.sh
#!/bin/vbash
source /opt/vyatta/etc/functions/script-template
source <(/config/scripts/wgcheck.py)
wgcheck.py
#!/usr/bin/env python3

import subprocess
import socket
import syslog

# list of tunnels. Format: [interface_name, peer_name, fqdn, ip_to_check, ip_version]
tunnels = [
    ["wg0", "TEST1", "l0crian1.test", "10.5.1.1", "ipv4"],
    ["wg1", "TEST2", "l0crian2.test", "10.5.1.5", "ipv4"]
]

def log_message(message, level=syslog.LOG_INFO):
    # Open syslog
    syslog.openlog("wgcheck.py", syslog.LOG_PID)

    # Log the message
    syslog.syslog(level, message)

    # Close syslog (not necessary unless you need to change the identifier or options)
    syslog.closelog()
    
def ping(ip, count=1, timeout=1):
    """Ping an IP address to check connectivity."""
    try:
        response = subprocess.run(
            ["ping", "-c", str(count), "-W", str(timeout), ip],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True
        )
        return response.returncode == 0  # Return True if ping succeeds, else False
    except Exception as e:
        return False

def resolve_fqdn(fqdn, ip_version='ipv4'):
    """Resolve FQDN to IP using DNS based on IP version."""
    family = socket.AF_INET if ip_version == 'ipv4' else socket.AF_INET6
    try:
        return socket.getaddrinfo(fqdn, None, family)[0][4][0]
    except socket.gaierror as e:
        return None

def check_tunnels(tunnels):
    global new_ip
    
    """Check each tunnel and perform actions based on ping results."""
    for i in tunnels:
        if ping(i[3]):
            pass
        else:
            # Get current configured endpoint address
            try:
                current_ip = subprocess.run(f"cli-shell-api showCfg --show-active-only | vyos-config-to-commands | grep 'set interfaces wireguard {i[0]} peer {i[1]} address'", cwd="/usr/libexec/vyos/op_mode/", stdout=subprocess.PIPE, shell=True, text=True).stdout.encode('utf-8').decode('utf-8').split()[-1].replace("'","")
            except:
                log_message(f"Could not find configured endpoint for {i[0]} peer {i[1]}", syslog.LOG_INFO)
                continue
            
            new_ip = resolve_fqdn(i[2], i[4])
            if new_ip:
                if new_ip != current_ip:
                    log_message(f"Updated endpoint to {new_ip} for {i[0]} peer {i[1]}", syslog.LOG_INFO)
                    config_list.append(i)

config_list = []
check_tunnels(tunnels)

if config_list:
    print('configure')
    for interface, peer_name, fqdn, ip_to_check, ip_version in config_list:
        print(f"set interfaces wireguard {interface} peer {peer_name} address {new_ip}")

    print('commit')   

Here’s the task scheduler config:

Task Scheduler config
set system task-scheduler task wgcheck executable path '/config/scripts/wgcheck.sh'
set system task-scheduler task wgcheck interval '1m'

Make sure you make the scripts executable.

You need to populate the list on the top of the wgcheck.py script with any tunnel/peer you want to check. Just use the current list as an example.

This will check every minute. The script will perform these functions:

  • Attempt to ping other side of tunnel
    • If ping is successful, no further action is taken
  • Check DNS of supplied FQDN
    • If returned IP is different than configured IP, the configuration is updated
7 Likes

I updated the python script above to send messages to the log in case you wanted to setup alerts on changes:

vyos@vyos# run show log | match wgcheck.py
Apr 23 15:38:03 wgcheck.py[19821]: Updated endpoint to 10.5.1.5 for wg0 peer TEST1
Apr 23 15:38:04 wgcheck.py[19821]: Could not find configured endpoint for wg1 peer TEST2
1 Like