Last active
November 9, 2024 17:32
-
-
Save se35710/6fe9512301781dd12c42da7dc6749ed3 to your computer and use it in GitHub Desktop.
Script that generates a unique local address (ULA) with a /48 prefix using a Pseudo-Random Global ID Algorithm from RFC 4193
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# The script generates a unique local address (ULA) with a /48 prefix | |
# using a Pseudo-Random Global ID Algorithm from RFC 4193 | |
PATH=/usr/local/bin:/bin:/usr/bin:/usr/sbin:/sbin | |
DEBUG=0 | |
log () { | |
if [ ! -z "${DEBUG}" ] && [ "${DEBUG}" == "1" ]; then | |
echo "$1" >&2 | |
fi | |
} | |
INTERFACE=$1 | |
if [ -z "${INTERFACE}" ]; then | |
echo "Usage: ${0} interface" | |
exit 1 | |
fi | |
if [ ! -f "/sys/class/net/${INTERFACE}/address" ]; then | |
echo "Interface ${INTERFACE} not found!" | |
exit 1 | |
fi | |
for CMD in date sha1sum sed cut; do | |
if hash "${CMD}" 2>/dev/null; then | |
eval "${CMD^^}"='$(command -v ${CMD})' | |
log "Command ${CMD} found!" | |
else | |
echo "${CMD} not found!" | |
exit 1 | |
fi | |
done | |
# The algorithm described below is intended to be used for locally | |
# assigned Global IDs. In each case the resulting global ID will be | |
# used in the appropriate prefix as defined in RFC 4193 Section 3.2. | |
# 1) Obtain the current time of day in 64-bit NTP format (RFC 1305). | |
NTPDATE=$(printf "%08x%08x\n" $(($(${DATE} +%s) + 2208988800)) $(${DATE} +%N | ${SED} "s/0*//")) | |
log "64-bit NTP format: ${NTPDATE}" | |
# 2) Obtain an EUI-64 identifier from the system running this | |
# algorithm. If an EUI-64 does not exist, one can be created from | |
# a 48-bit MAC address as specified in RFC 3513. If an EUI-64 | |
# cannot be obtained or created, a suitably unique identifier, | |
# local to the node, should be used (e.g., system serial number). | |
IFS=':'; set $(</sys/class/net/${INTERFACE}/address); unset IFS | |
EUI64=$(printf "fe80%x%x%x%x%x" $(( 0x${1} ^ 0x02 )) 0x${2} 0x${3}ff 0xfe${4} 0x${5}${6}) | |
log "EUI-64: ${EUI64}" | |
# 3) Concatenate the time of day with the system-specific identifier | |
# in order to create a key. | |
CONCAT="${NTPDATE}${EUI64}" | |
log "Concatenated: ${CONCAT}" | |
# 4) Compute an SHA-1 digest on the key as specified in RFC 3174; | |
# the resulting value is 160 bits. | |
DIGEST=$(echo ${CONCAT} | ${SHA1SUM} | ${CUT} -c1-40) | |
log "SHA-1 digest: ${DIGEST}" | |
# 5) Use the least significant 40 bits as the Global ID. | |
GLOBALID=$(echo ${DIGEST} | ${CUT} -c31-40) | |
log "Global ID: ${GLOBALID}" | |
# 6) Concatenate FC00::/7, the L bit set to 1, and the 40-bit Global | |
# ID to create a Local IPv6 address prefix. | |
IPV6=$(echo fd${GLOBALID} | ${SED} "s|\(....\)\(....\)\(....\)|\1:\2:\3::/48|" | ${SED} "s/:0*/:/g") | |
log "IPv6: ${IPV6}" | |
echo ${IPV6} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Line 51 should be:
EUI64=$(printf "fe80%x%x%x%x%x" $(( 0x${1} ^ 0x02 )) 0x${2} 0x${3}ff 0xfe${4} 0x${5}${6})