How to choose a random wireguard server?

confirming that

wg set <interface> peer <public key> endpoint "<host>:<port>" allowed-ips <cidr>

works, and connects immediately.

Could this be done using DNS? For example, configure wireward with a single domain name as a server, then make dnsmasq resolve that name into multiple IP addresses.

From wireguard's side most certainly, every time the abovementioned wg command is issued it re-resolves the hostname. However, I don't know how to make dnsmasq give out random/round-robin results. I would have to refer that to someone more knowledgeable.

Whilst hostname resolution could be randomised using DNS, you'd still need to know the host in order to set the corresponding public key.

1 Like

Here you go, dnsmasq-based random:

cp /etc/dnsmasq.conf /etc/dnsmasq.conf.bak
cat << "EOF" > /etc/dnsmasq.conf
host-record=wg0,185.16.85.130
host-record=wg0,141.98.252.130
ptr-record=185.16.85.130,gb2
ptr-record=141.98.252.130,gb4
txt-record=gb2,"gEor1tjIW4DmKfF24A8j8Ongw7B9pnhZ2n09xR5mH1o="
txt-record=gb4,"IJJe0TQtuQOyemL4IZn6oHEsMKSPqOuLfD5HoAWEPTY="
EOF
/etc/init.d/dnsmasq restart

cat << "EOF" > wg_rand.sh
#!/bin/sh
CON_ID="${1:-wg0}"
RESOLVER="${2:-localhost}"
HOST_ADDR="$(nslookup "${CON_ID}" "${RESOLVER}" \
| sed -n -e "/^Address\s1:\s/s///p")"
HOST_ID="$(nslookup -q PTR "${HOST_ADDR}" "${RESOLVER}" \
| sed -n -e "/^.*\sname\s=\s/s///p")"
HOST_KEY="$(nslookup -q TXT "${HOST_ID}" "${RESOLVER}" \
| sed -n -e "/^.*\stext\s=\s/s///;s/\"//gp")"
uci set network.${CON_ID}.description="${HOST_ID}"
uci set network.${CON_ID}.endpoint_host="${HOST_ADDR}"
uci set network.${CON_ID}.public_key="${HOST_KEY}"
/etc/init.d/network reload
ifup ${CON_ID}
EOF
2 Likes

Woah! That's awesome.

As per @takimata's suggestion, an alternative to:

uci set network.${CON_ID}.description="${HOST_ID}"
uci set network.${CON_ID}.endpoint_host="${HOST_ADDR}"
uci set network.${CON_ID}.public_key="${HOST_KEY}"
/etc/init.d/network reload
ifup ${CON_ID}

would be:

wg set "$CON_ID" peer "$HOST_KEY" endpoint "$HOST_ADDR:51820" allowed-ips 0.0.0.0/0

I'm not sure I'll have time to try this out today, but I'd hope to test it out during the week.

1 Like

This method has some issues:

  • UCI, LuCI and ubus might not see the changes made by low-level commands.
  • You might be disconnected or even get locked if you are connected via WG and restart the network service without fallback config.

True. It's a hack either way, though. You won't be able to reconfigure the interface with the UCI-based randomizer running.

I fail to see how this is a shortcoming of my approach, but not of reconfiguration through UCI and network reload.

Edit: I don't think this is worth getting into an argument over. Do UCI, I really don't care either way. As long as you don't commit to flash, it should be just fine.

1 Like

It's more like a limitation to not face a collision with netifd.
Refraining from WG interface declaration solves the issue.

After a bit of tweaking, I think we have two working options.

Using dnsmasq
cp /etc/dnsmasq.conf /etc/dnsmasq.conf.bak
cat << "EOF" > /etc/dnsmasq.conf
host-record=wg0,185.16.85.130
host-record=wg0,141.98.252.130
ptr-record=185.16.85.130,gb2
ptr-record=141.98.252.130,gb4
txt-record=gb2,"gEor1tjIW4DmKfF24A8j8Ongw7B9pnhZ2n09xR5mH1o="
txt-record=gb4,"IJJe0TQtuQOyemL4IZn6oHEsMKSPqOuLfD5HoAWEPTY="
EOF
service dnsmasq restart

cat << "EOF" > wg_rand.sh
#!/bin/sh
WGINTERFACE="${1:-mullvad}"
WGPEER="${2:-wireguard_mullvad}"
CON_ID="${3:-wg0}"
RESOLVER="${4:-localhost}"
HOST_ADDR="$(nslookup "${CON_ID}" "${RESOLVER}" \
    | sed -n -e "/^Address\s1:\s/s///p")"
HOST_ID="$(nslookup -q PTR "${HOST_ADDR}" "${RESOLVER}" \
    | sed -n -e "/^.*\sname\s=\s/s///p")"
HOST_KEY="$(nslookup -q TXT "${HOST_ID}" "${RESOLVER}" \
    | sed -n -e "/^.*\stext\s=\s/s///;s/\"//gp")"
uci set network.@"$WGPEER"[0].description="${HOST_ID}"
uci set network.@"$WGPEER"[0].endpoint_host="${HOST_ADDR}"
uci set network.@"$WGPEER"[0].public_key="${HOST_KEY}"
/etc/init.d/network reload
ifup "${WGINTERFACE}"
EOF
Using an auxiliary file
cat << "EOF" > servers.conf
gb2,185.16.85.130,gEor1tjIW4DmKfF24A8j8Ongw7B9pnhZ2n09xR5mH1o=
gb4,141.98.252.130,IJJe0TQtuQOyemL4IZn6oHEsMKSPqOuLfD5HoAWEPTY=
EOF

cat << "EOF" > wg_rand.sh
#!/bin/sh
WGINTERFACE="${1:-mullvad}"
WGPEER="${2:-wireguard_mullvad}"
FILE="servers.conf"
IN=$(sed -n "$(awk 'END {srand(); r=rand()*NR; if (r<NR)
{sub(/\..*/,"",r); r++;}; print r}' $FILE)p" $FILE)
IFS="," read -r DESCRIPTION HOST PUBKEY << EOF2
${IN}
EOF2
uci set network.@"$WGPEER"[0].description="${DESCRIPTION}"
uci set network.@"$WGPEER"[0].endpoint_host="${HOST}"
uci set network.@"$WGPEER"[0].public_key="${PUBKEY}"
/etc/init.d/network reload
ifup "${WGINTERFACE}"
EOF

Ultimately, I'm not sure there are any benefits to using one method over the other, but I'm going to use the dnsmasq-based version; rotating my wg server once every 7 days, or something.

1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.