Get ipv6 address of server for ddns update

If you want to address your own server publicly via ipv6 you do not register the WAN interface address with some DDNS provider out the actual public permananent address of the server. The Dynamic DNS module of OpenWRT support several methods to determine the IP address that should be registered, but for IPv6 servers it is kinda non-obvious how to determine the address of the server.

I would not be good to put the address in statically, since the ipv6 prefix might change if you switch to a(nother) 6in4 tunnel.

So what I would prefer is a dynamic method to determine the server address and send it off to the DDNS provider.

I can see that in the LUCI interface are known the IPv6 address leases, but I don't know how to query those in a script (what command is actually providing that information?).

I read in the forum that dnsmasq should also record the names with the ipv6 leases, but for me it does not, so i cannot use DNS for this purpose.

Apart from that it may make sense to also provide a DNS lookup as a IP determination method to offer on the DDNS LUCI interface (more comfy than making a script).

Typically, you don't really need to specify your public IP address directly as it can be fetched automatically from the specified interface:

1 Like

Maybe it was not clear enough. The OpenWRT is not my server and in my opinion it should not be. It is "just" a router and that's enough.
So it is not at all helping if it determines the IPv6 of one of its own interfaces (incl. that of the WAN6 interface).
What I really need it to do is determine the IPv6 of my server dynamically and send that to the DDNS provider.

So thank you cordially for your contribution. Unfortnately that solution is exactly what I do not need.

1 Like

Getting closer. Is there any parser specialized on those files onboard that helps extracting the right IPv6?

1 Like
cat << "EOF" > get_ip6.sh
#!/bin/sh
HOST="${1}"
NET_IF="lan"
. /lib/functions/network.sh
network_flush_cache
network_find_wan6 NET_IF
network_get_prefix6 NET_PFX "${NET_IF}"
network_get_device NET_DEV "${NET_IF}"
eval $(ubus call dhcp ipv6leases \
| jsonfilter -e "ADDR=$['device']
['${NET_DEV}']['leases']
[@['hostname']='${HOST}']
['ipv6-addr'][@]['address']")
for ADDR in ${ADDR}
do if echo "${ADDR}" \
| grep -q -e "${NET_PFX%/*}"
then echo "${ADDR}"
fi
done
EOF
chmod +x get_ip6.sh
./get_ip6.sh hostname
2 Likes

Great that works but I do have to know at what index the address is located. could it be selectable by lifetime?

That just gives all addresses that node has for ipv6.
What I meant was if one could specifiy the lifetime of the address to select. usually the ULA addresses have lifetime -1 and the provider prefix based addresses something else.

I have a similar setup, the scripts extracts IPv6 address using the MAC address, updates the firewall to allow incoming connection and updates DDNS when the IP address change is detected. The cron job runs every couple of hours.

Thank you so much. The script works not completely.
There seems to be a mistake in the selection of the public address:

  if echo "${ADDR}" | grep -q "${NET_PREF6%/*}"

The public address is not selected.

Another problem for me now is that the server disappeared from the active dhcpv6 lease list... so the script will return empty anyway (but I tested it with a different host name that is in the dhcpv6 list).

How could that happen. The server is up and running.

I think this happens when odhcpd (or whatever dhcp server you use) gets restarted.
Then the leases are cleared but the clients are still maintaining an active lease.
Maybe it is better to assign static DHCP leases (so the last bits of the address are always the same) and then use a mask in your IPv6 firewall rule to only match certain bits of the IPv6 address.
(like ISP prefix (first 32 bits or less) + static DHCP Part (last 64 bits), excluding your delegated prefix because that maybe changes)
Example ip6tables rule:

ip6tables -I zone_wan_prerouting -t nat -d 1234:5678::10:0:0:1/ffff:ffff::ffff:ffff:ffff:ffff -p tcp -m tcp --dport 443 -j DNAT --to-destination :1234

But be aware if you use multiple sub nets don't use the same DHCP static addresses otherwise you end up forwarding traffic you don't want to.

And hardcode the DDNS Update with the DHCP static address. (e.g. only extract the ISP prefix + the delegated prefix and append the DHCP static address to it.)

And the jsonfilter in openwrt is a bit limited...but there is "a trick" (that also works four other sources)
You can remove all line breaks from the string that you want to parse, so that you end up with one big line. Then you can grep over it more easily.

You can also use ip neigh command (and grep by MAC address) and then filter out the unwanted addresses.

Here is my simple script that I use with OpenWRTs DDNS scripts:

#!/bin/sh

. /lib/functions/network.sh

INTERFFACE="lan"
ISP_PREFIX="1234:5678"
HOST_ID=":10::1"

network_get_subnets6 LAN_PREFIXES "${INTERFFACE}"

if LAN_PREFIX="$(echo "${LAN_PREFIXES}" | grep "${ISP_PREFIX}" | cut -d ':' -f 1-4)" \
&& [ -n "${LAN_PREFIX}" ]; then
  HOST_IP="${LAN_PREFIX}${HOST_ID}"
  if ip -6 route get "${HOST_IP}"/128 >/dev/null 2>&1; then
    echo "${HOST_IP}"
    exit 0
  else
    exit 1
  fi
else
  exit 1
fi

1 Like

Would it not make more sense to do this on the server itself? I mean you can probably fudge it on the router but this seems a case of making things more difficult than it needs to be...

1 Like

I tried that but the server does not support that ddns provider.

Set up dynamic prefix forwarding:
Port forwarding to a dynamic IPv6 address - #2 by vgaetera

Then extract the prefix and append the suffix:

NET_IF="wan6"
NET_SFX="23"
. /lib/functions/network.sh
network_flush_cache
network_get_subnets6 NET_SUB "${NET_IF}"
for NET_SUB in ${NET_SUB}
do if [ "${NET_SUB::2}" != "fd" ]
then
echo "${NET_SUB%::*}::${NET_SFX}"
break
fi
done

This script works standalone.
However when using it in DDNS LUCI there is a problem:

Advanced Settings - IP address source [IPv6]: can not detect local IP. Please select a different Source combination

LUCI highlights the Script option for IP address source [IPv6]

Another thing is that the script always uses the wan6 prefix. What I need is to determine the prefix for a different interface because the server is NOT the router but a separate devide that is on a different interface than wan6 (see my earlier clarification).

Is it possible to replace network_find_wan6 with something else where we can specify for which interface we want the prefix?

The ipv6 address was malformed due to a spurious "/". It now works for wan6, but not for other interfaces. not sure why.

HOST_SFX6=$1
NET_IF6=$2

. /lib/functions/network.sh
network_flush_cache
network_get_prefix6 NET_PFX6 "${NET_IF6}"
echo "${NET_PFX6%/*}${HOST_SFX6}"
1 Like

I don't know whether it is such a strange thing to to, but - get this - wait for it - again - I do not want the prefix of wan6! I want the prefix of another interface. And this does not seem to work. Look at the script above, I did already what you proposed, but it only works for wan6!

And then even the DDNS UI complains: "Advanced Settings - IP address source [IPv6]: can not detect local IP. Please select a different Source combination"

{
	"up": true,
	"pending": false,
	"available": true,
	"autostart": true,
	"dynamic": false,
	"uptime": 143626,
	"l3_device": "eth123",
	"proto": "static",
	"device": "eth123",
	"updated": [
		"addresses"
	],
	"metric": 0,
	"dns_metric": 0,
	"delegation": true,
	"ipv4-address": [
		{
			"address": "redacted",
			"mask": 24
		}
	],
	"ipv6-address": [
		
	],
	"ipv6-prefix": [
		
	],
	"ipv6-prefix-assignment": [
		{
			"address": "redacted::",
			"mask": 64,
			"preferred": 462980,
			"valid": 1067780,
			"local-address": {
				"address": "redacted::1",
				"mask": 64
			}
		},
		{
			"address": "redacted:1::",
			"mask": 64,
			"local-address": {
				"address": "redacted:1::1",
				"mask": 64
			}
		}
	],

OK I see the point.
You seem to know this all in and out. This is what I had so far:

NET_IF6=$1
HOST_SFX6=$2

. /lib/functions/network.sh
network_flush_cache
network_get_prefix6 NET_PFX6 "${NET_IF6}"
echo "${NET_PFX6%/*}${HOST_SFX6}"

I would probably find out how to get the address, but the trimming part is more obscure (I don't do scripting usually, so for me it is alot of looking around man and web pages to get these special parts done).

1 Like

I now have this:

NET_IF6="${1}"
HOST_SFX6="${2}"

. /lib/functions/network.sh
network_flush_cache
network_get_subnet6 NET_ADDR6 "${NET_IF6}"
echo "${NET_ADDR6%::*}::${HOST_SFX6}"

But as you say, I need to ge the right address. By change this returns the right address, but can I be sure that the provider prefix address is always the first address being returned or could that also be the ULA address sometimes while WAN6 is up and running?

And still DDNS LUCI is complaining:
Advanced Settings - IP address source [IPv6]: can not detect local IP. Please select a different Source combination

Any idea why that is ???

Great the script works. Still some questions:

  • for what is sed -n -e "1p" needed?
  • why is DDNS LUCI still complaining Advanced Settings - IP address source [IPv6]: can not detect local IP. Please select a different Source combination

Does the script option for DDNS work at all? Is this a bug?