Skip to content

Instantly share code, notes, and snippets.

@ryot4
Last active May 3, 2020 15:52
Show Gist options
  • Save ryot4/f359a2db51bbba4e7144361e51e1557b to your computer and use it in GitHub Desktop.
Save ryot4/f359a2db51bbba4e7144361e51e1557b to your computer and use it in GitHub Desktop.
Generate IPv6 Unique Local Address prefix (https://tools.ietf.org/html/rfc4193#section-3.2.2)
#!/bin/sh
# Copyright (c) 2020 ryot4
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
set -e
interface=
mac_addr=
ntp_server=localhost
timestamp=
quiet=0
while getopts hi:m:s:t:q opt; do
case "${opt}" in
h)
echo "$0 [-q] [-i interface] [-m mac_addr] [-s ntp_server] [-t timestamp]"
exit
;;
i)
interface="${OPTARG}"
;;
m)
mac_addr="${OPTARG}"
;;
s)
ntp_server="${OPTARG}"
;;
t)
timestamp="${OPTARG}"
;;
q)
quiet=1
;;
esac
done
for cmd in bc sha1sum; do
if ! which "${cmd}" > /dev/null 2>&1; then
echo "${cmd} command is not found" 1>&2
exit 1
fi
done
if [ -z "${timestamp}" ]; then
if ! which ntpq > /dev/null 2>&1; then
echo 'timestamp not specified and ntpq command is not found' 1>&2
exit 1
fi
timestamp=$(ntpq -c 'rv 0 clock' "${ntp_server}" | sed -e 's/^clock=\([0-9a-f]\+\)\.\([0-9a-f]\+\).*$/\1\2/')
fi
if [ -z "${mac_addr}" ]; then
if ! which ip > /dev/null 2>&1; then
echo 'mac_addr not specified and ip command is not found' 1>&2
exit 1
fi
if [ -n "${interface}" ]; then
mac_addr=$(ip -br link show "${interface}" | awk '{ print $3 }')
else
mac_addr=$(ip -br link show | grep -v LOOPBACK | grep UP | head -1 | awk '{ print $3 }')
fi
fi
# See RFC4193 Section 3.2.2 for the algorithm.
# Invert the seventh bit from the left
# 0 (0000) <-> 2 (0010)
# 1 (0001) <-> 3 (0011)
# 4 (0100) <-> 6 (0110)
# 5 (0101) <-> 7 (0111)
# 8 (1000) <-> a (1010)
# 9 (1001) <-> b (1011)
# c (1100) <-> e (1110)
# d (1101) <-> f (1111)
first_octet=$(echo ${mac_addr} | cut -d: -f1 | tr '[:lower:]' '[:upper:]')
case "${first_octet}" in
*[014589CD])
first_octet_inverted=$(echo "obase=16; ibase=16; ${first_octet}+2" | bc -q | tr '[:upper:]' '[:lower:]')
;;
*[2367ABEF])
first_octet_inverted=$(echo "obase=16; ibase=16; ${first_octet}-2" | bc -q | tr '[:upper:]' '[:lower:]')
;;
esac
second_to_third_octet=$(echo ${mac_addr} | cut -d: -f2-3)
fourth_to_sixth_octet=$(echo ${mac_addr} | cut -d: -f4-6)
eui64=$(echo "${first_octet_inverted}:${second_to_third_octet}:ff:fe:${fourth_to_sixth_octet}" | tr -d :)
global_id=$(printf '%s%s' "${timestamp}" "${eui64}" | sha1sum | cut -c31-40)
ula_prefix=$(echo "fd${global_id}" | sed 's,\(....\)\(....\)\(....\),\1:\2:\3::\/48,')
if [ ${quiet} -eq 0 ]; then
echo "NTP timestamp: ${timestamp}"
echo "MAC address: ${mac_addr}"
echo "EUI-64 identifier: ${eui64}"
echo "ULA Prefix: ${ula_prefix}"
else
echo "${ula_prefix}"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment