b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | #!/bin/sh |
| 2 | # |
| 3 | # script to determine and return SLAAC ipv6 address using prefix from a locally configured interface and the MAC address of the device |
| 4 | # (c) 2018 Keve Mueller <keve at keve dot hu> |
| 5 | # |
| 6 | # activated inside /etc/config/ddns by setting |
| 7 | # |
| 8 | # option ip_source 'script' |
| 9 | # option ip_script '/usr/lib/ddns/slaac_sample.sh br-lan AA:BB:CC:DD:EE:FF' |
| 10 | # |
| 11 | # the script is executed (not parsed) inside get_local_ip() function |
| 12 | # of /usr/lib/ddns/dynamic_dns_functions.sh |
| 13 | # |
| 14 | # useful when this box is the only DDNS client in the network and other clients use SLAAC |
| 15 | # so no need to install ddns client on every "internal" box |
| 16 | # |
| 17 | # NB: this will not catch the actual IPV6 used by the host when it is configured to use temporary addresses |
| 18 | |
| 19 | #NB: we need a valid MAC address that is fully expanded with leading zeroes on all positions |
| 20 | format_eui_64() { |
| 21 | local macaddr="$1" |
| 22 | echo ${macaddr:0:1}$(echo ${macaddr:1:1}|tr 0123456789abcdefABCDEF 23016745ab89efcd89efcd)${macaddr:3:2}:${macaddr:6:2}ff:fe${macaddr:9:2}:${macaddr:12:2}${macaddr:15:2} |
| 23 | } |
| 24 | |
| 25 | # expand :: in an ipv6 address specification to the appropriate series of 0: |
| 26 | # result will have 8 ipv6 fragments separated by single colon |
| 27 | # NB: input must be a valid IPv6 address, e.g. ::1 |
| 28 | # NB: numbers are not prepended with leading zeroes |
| 29 | expand_ipv6_colons() { |
| 30 | local ipv6=$1 |
| 31 | # we need :: to be in the middle, so prepend a 0 if the input starts with : and append 0 if it ends with it |
| 32 | if [ "${ipv6:0:1}" = ":" ]; then ipv6=0${ipv6}; fi |
| 33 | if [ "${ipv6: -1:1}" = ":" ]; then ipv6=${ipv6}0; fi |
| 34 | # retain only the real colons |
| 35 | local colons=${ipv6//::|[0123456789abcdefABCDEF]/} |
| 36 | # count them |
| 37 | local num_colons=${#colons} |
| 38 | local filler=":0:0:0:0:0:0:" |
| 39 | # replace the :: with the appropriate substring from filler |
| 40 | local ipv6_x=${ipv6/::/${filler:0:(7-$num_colons)*2-1}} |
| 41 | echo $ipv6_x |
| 42 | } |
| 43 | |
| 44 | # obtain the first ipv6 address of the device passed in $1 |
| 45 | addr_net=$(ip -6 -o addr show dev $1 scope global up | cut -d" " -f 7 | head -1) |
| 46 | #addr_net=$1 |
| 47 | addr=${addr_net%/*} |
| 48 | # TODO: we assume /64 subnet |
| 49 | # get the first 64 bits of the address |
| 50 | prefix=$(expand_ipv6_colons $addr | cut -d: -f -4) |
| 51 | # compute the SLAAC 64 bits from the MAC |
| 52 | suffix=$(format_eui_64 "$2") |
| 53 | |
| 54 | echo -n $prefix:$suffix |
| 55 | exit 0 |
| 56 | |
| 57 | #echo "Should never come here" >&2 |
| 58 | #exit 2 |
| 59 | |