├── .gitignore ├── README.md ├── prior_art ├── generate-rfc4193-addr └── gen-ula.sh └── gen-ula.sh /.gitignore: -------------------------------------------------------------------------------- 1 | oui.txt 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bash ULA Generator 2 | Generate an IPv6 Unique Local Address prefix 3 | 4 | Alexandre de Verteuil 5 | 2017-06-20 6 | 7 | Based on scripts from **Shinsuke Suzuki** and **Holger Zuleger**, available under the `prior_art` directory. 8 | 9 | ## Usage 10 | 11 | Simply run in a bash shell. You will be prompted for your physical MAC address (guessing "eth0" is no longer relevant in 2017). 12 | 13 | ## Requirements 14 | 15 | `wget`, `ntpq` 16 | 17 | ## Improvements over other scripts 18 | 19 | - Not a CGI script 20 | - Computes the SHA1 hash of bytes, not their hex representation 21 | - Better text output 22 | 23 | ## References 24 | 25 | - [RFC 4193 — Unique Local IPv6 Unicast Addresses](https://tools.ietf.org/html/rfc4193) 26 | - [Unique local address](https://en.wikipedia.org/wiki/Unique_local_address) on Wikipedia 27 | -------------------------------------------------------------------------------- /prior_art/generate-rfc4193-addr: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # @(#) generate-rfc4193-addr.sh (ULA) (c) Sep 2004 - Jun 2011 Holger Zuleger 4 | # 5 | # do what the name suggest 6 | # 7 | # firstpart = 64-Bit NTP time 8 | # secondpart = EUI-64 Identifier or 48 Bit MAC-Adress 9 | # sha1sum ($firstpart | $secondpart ) 10 | # use least significant 40 Bits of sha1sum 11 | # build global prefix (locally assigned == FD00::/8) 12 | # 13 | # (M1) 11. May 2006 14 | # - a check added to complain if firstpart or secondpart is empty 15 | # - firstpart calculation changed in such a way, that only one transmit 16 | # time is stored (ntpdate since version 4.2.0 use a list of ntp servers) 17 | # 18 | # (M2) 27. Aug 2006 19 | # Fixed bug in using reference time instead of transmit timestamp. 20 | # Thanks to Marc A. Donges for finding this out 21 | # 22 | # (M3) 4. Sep 2006 23 | # Use ntpq instead of ntpdate because the latter is deprecated. 24 | # This requires a local running and syncronized ntpd, but 25 | # speeds up the execution time 26 | # 27 | # (M4) 29. Dec 2006 28 | # set LC_ALL=C at the beginning of the script, to be sure the grep command 29 | # used to scan the output of the ifconfig command finds the expected string 30 | # Thanks to Ted Percival for finding this out 31 | # 32 | # (M5) 5. Jun 2011 33 | # tr command added to remove the trailing newline from the sha1 calculation 34 | # Thanks to Reinard Max for the fix 35 | # 36 | PATH=/usr/local/bin:/bin:/usr/bin:/usr/sbin:/sbin 37 | 38 | debug=0 39 | USE_NTPQ=1 40 | NTPSERVER=pool.ntp.org 41 | 42 | #(M4) 43 | LC_ALL=C 44 | export LC_ALL 45 | 46 | #(M3) 47 | if test $USE_NTPQ -eq 1 48 | then 49 | if time=`ntpq -c rv | grep clock=` 50 | then 51 | test $debug -eq 1 && echo "$time" 52 | firstpart=`echo $time | sed -e "s/clock=//" -e "s/ .*//" -e "s/\.//"` 53 | else 54 | echo "no local ntpd running" 1>&2 55 | exit 1 56 | fi 57 | else 58 | #(M1) 59 | #(M2) 60 | firstpart=`ntpdate -d -q $NTPSERVER 2>/dev/null | sed "/transmit timestamp/q" | 61 | sed -n "/transmit time/s/^transmit timestamp: *\([^ ]*\) .*/\1/p" | 62 | tr -d "."` 63 | fi 64 | 65 | secondpart=`ifconfig eth0 | 66 | grep "inet6 addr: fe80" | 67 | sed -n "s|^.*::\([^/]*\)/.*|\1|p" | 68 | tr -d ":"` 69 | 70 | #(M1) 71 | if test -z "$firstpart" -o -z "$secondpart" 72 | then 73 | echo "$0: installation error: check if ntpdate and ifconfig is in search path" 74 | exit 1 75 | fi 76 | 77 | test $debug -eq 1 && echo "Firstpart: $firstpart" 78 | test $debug -eq 1 && echo "Secondpart: $secondpart" 79 | test $debug -eq 1 && echo "123456789o123456789o123456789o123456789o123456789o123456789o" 80 | test $debug -eq 1 && echo ${firstpart}${secondpart} | sha1sum 81 | 82 | #(M5) 83 | globalid=`echo ${firstpart}${secondpart} | tr -d "\012" | sha1sum | cut -c31-40` 84 | test $debug -eq 1 && echo $globalid 85 | 86 | 87 | echo fd${globalid} | sed "s|\(....\)\(....\)\(....\)|\1:\2:\3::/48|" 88 | -------------------------------------------------------------------------------- /gen-ula.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # ULA Generator 4 | # Alexandre de Verteuil 5 | # 2017-06-20 6 | # 7 | # Based on scripts from Shinsuke Suzuki and Holger Zuleger, 8 | # available under the prior_art directory. 9 | # 10 | # Usage: simply run in a bash shell. You will be prompted for your 11 | # physical MAC address. Guessing eth0 is no longer relevant in 2017. 12 | # 13 | # Requirements: wget, ntpq 14 | # 15 | # Improvements over other scripts: 16 | # - Not a CGI script 17 | # - Computes the SHA1 hash of bytes, not their hex representation 18 | # - Better text output 19 | # 20 | # References: 21 | # 22 | # RFC 4193 -- Unique Local IPv6 Unicast Addresses 23 | # https://tools.ietf.org/html/rfc4193 24 | # 25 | # Unique local address 26 | # https://en.wikipedia.org/wiki/Unique_local_address 27 | 28 | 29 | function die() { 30 | echo 31 | echo "== Error ==" 32 | echo "$@" 33 | exit 1 34 | } 35 | 36 | read -p "MAC address: " mac 37 | mac=$(echo $mac | tr -d :-) 38 | if [ ${#mac} -ne 12 ]; then 39 | die "MAC address \"${mac}\" is invalid" 40 | fi 41 | 42 | echo "For a deterministic calculation, you may enter the ntp clock time." 43 | echo "Leave empty to query an NTP server." 44 | read -p "Clock: " clock 45 | if [ -z "${clock}" ]; then 46 | clock=$(ntpq -c "rv 0 clock" 0.pool.ntp.org | cut -c7-23) 47 | # Input: "clock=dcf4268b.208dd000 Tue, Jun 20 2017 18:56:11.127" 48 | # Output: "dcf4268b.208dd000" 49 | fi 50 | clock=$(tr -d . <<< "${clock}") 51 | if [ "${#clock}" -ne 16 ]; then 52 | die "Time in NTP format is 64 bits, "\ 53 | "or 16 characters in hex representation. "\ 54 | "You entered: \"${clock}\"." 55 | fi 56 | 57 | 58 | if [ ! -r "oui.txt" ]; then 59 | wget "http://standards-oui.ieee.org/oui.txt" 60 | fi 61 | 62 | # MAC Vendor check 63 | machexvendor=$(tr a-f A-F <<< "${mac:0:6}") 64 | macvendor=$(grep "^$machexvendor" oui.txt | sed -r "s/.*\t([^\r\n]*).*/\1/") 65 | if [ -z "$macvendor" ]; then 66 | die "MAC address \"${mac}\" is not registered to IEEE. "\ 67 | "Please use a REAL MAC address." 68 | fi 69 | 70 | # Generate an EUI64 from the MAC address 71 | # as described in RFC 3513 72 | # https://tools.ietf.org/html/rfc3513 73 | 74 | first=`echo $mac | cut -c1-1` 75 | second=`echo $mac | cut -c2-2` 76 | macu=`echo $mac | cut -c3-6` 77 | macl=`echo $mac | cut -c7-12` 78 | 79 | # reversing u/l bit 80 | case $second in 81 | [13579bdf]) 82 | die "MAC-address \"${mac}\" is a group MAC address" 83 | ;; 84 | 0) 85 | second_rev=2 86 | ;; 87 | 2) 88 | second_rev=0 89 | ;; 90 | 4) 91 | second_rev=6; 92 | ;; 93 | 6) 94 | second_rev=4; 95 | ;; 96 | 8) 97 | second_rev=a; 98 | ;; 99 | a) 100 | second_rev=8; 101 | ;; 102 | c) 103 | second_rev=e; 104 | ;; 105 | e) 106 | second_rev=c; 107 | ;; 108 | *) 109 | #impossible 110 | die "MAC address \"${mac}\" is registered to the IEEE database, "\ 111 | "but the first octet (${first}${second}) is regarded as invalid. "\ 112 | "(probably a bug in this script...)" 113 | esac 114 | eui64="${first}${second_rev}${macu}fffe${macl}" 115 | 116 | # Convert from hex string representation to bytes before sha1sum 117 | # https://unix.stackexchange.com/a/82766 118 | globalid=$(echo -ne $(sed "s/../\\x&/g" <<< ${date}${eui64}) | sha1sum | cut -c23-32) 119 | ula=$(echo fd${globalid} | sed "s|\(....\)\(....\)\(....\)|\1:\2:\3::/48|") 120 | 121 | echo 122 | echo "## Inputs ##" 123 | echo "MAC address = ${mac} (${macvendor})" 124 | echo "NTP time = ${clock}" 125 | echo 126 | echo "## Intermediary values ##" 127 | echo "EUI64 address = ${eui64}" 128 | echo 129 | echo "## Generated ULA ##" 130 | echo "${ula}" 131 | echo 132 | -------------------------------------------------------------------------------- /prior_art/gen-ula.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # ULA Generator 4 | # SUZUKI, Shinsuke 5 | # based on Holger Zuleger's script 6 | # @(#) generate-uniq-local-ipv6-unicast-addr.sh 7 | # (c) Sep 2004 Holger Zuleger 8 | # 9 | # Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, and 2002 WIDE Project. 10 | # All rights reserved. 11 | # 12 | # Redistribution and use in source and binary forms, with or without 13 | # modification, are permitted provided that the following conditions 14 | # are met: 15 | # 1. Redistributions of source code must retain the above copyright 16 | # notice, this list of conditions and the following disclaimer. 17 | # 2. Redistributions in binary form must reproduce the above copyright 18 | # notice, this list of conditions and the following disclaimer in the 19 | # documentation and/or other materials provided with the distribution. 20 | # 3. Neither the name of the project nor the names of its contributors 21 | # may be used to endorse or promote products derived from this software 22 | # without specific prior written permission. 23 | # 24 | # THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 25 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 | # ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 28 | # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 | # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 | # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 | # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 | # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 | # SUCH DAMAGE. 35 | # 36 | # $Id: gen-ula.cgi,v 1.11 2013/05/20 22:43:57 suz Exp $ 37 | # 38 | 39 | 40 | # 41 | #site-specific parameters 42 | # 43 | 44 | #NTP server name 45 | ntpserv="clk.notemachi.wide.ad.jp" 46 | 47 | #ntpdate program 48 | ntpdate=/usr/sbin/ntpdate 49 | 50 | #the caller of this CGI script 51 | url="http://www.kame.net/~suz/gen-ula.html" 52 | 53 | #list of typical bogus lower 24-bits in MAC address 54 | typical_mac_list="010203 000000 000001 000102 123456" 55 | 56 | #SHA hash calculator 57 | sha=/usr/local/bin/sha 58 | 59 | #IEEE OUI Database (available at http::/standards.ieee.org/regauth/oui/oui.txt) 60 | ieeeoui=oui.txt 61 | 62 | # 63 | # main routine 64 | # 65 | #print-out header 66 | echo Content-type: text/html 67 | echo 68 | 69 | cat << EOH 70 | 71 | 72 | 73 | Generated ULA 74 | 75 | 76 | 77 | EOH 78 | 79 | #main routine 80 | 81 | #1. NTP-date 82 | date=`$ntpdate -dq $ntpserv 2> /dev/null | 83 | sed -n 's/^transmit timestamp: *\([^ ]*\) .*/\1/p' | 84 | tr -d "."` 85 | 86 | #2. EUI64 87 | # obtains a MAC address 88 | # sed 's/\(.*\)=\(..:..:..:..:..:..\).*$/\2/' | 89 | mac=`echo $QUERY_STRING | sed 's/%3A/:/g' | 90 | tr '[:lower:]' '[:upper:]' | 91 | sed 's/\(.*\)=\(..:..:..:..:..:..\).*$/\2/'`; 92 | machex=`echo $mac | tr -d ':'` 93 | #length check 94 | len1=`echo $machex | wc -m` 95 | #character check 96 | len2=`echo $machex | tr -d [:xdigit:] | wc -m` 97 | if [ $len1 != 13 -o $len2 != 1 ]; then 98 | echo "

Error

" 99 | echo "

MAC-address $mac is invalid" 100 | echo "

Please take care of the following points: 101 |

    102 |
  • each octet must be separeted by colon (e.g. 00-01-02-03-04-05 is not permitted) 103 |
  • leading 0 of each octet cannot be omitted (e.g. 3:4:5:4:5:9 is not permitted) 104 |
  • each octet consists of 0-9 and A-F. 105 |

" 106 | echo "go back to the previous page" 107 | exit 108 | fi 109 | 110 | # MAC Vendor check 111 | machexvendor=`echo $machex | cut -c1-6` 112 | macvendor=`grep "^ $machexvendor" $ieeeoui | cut -c23-` 113 | if [ -z "$macvendor" ]; then 114 | echo "

Error

" 115 | echo "

MAC-address $mac" 116 | echo "is not registered to IEEE

" 117 | echo "

Please use the REAL MAC address

" 118 | echo "go back to the previous page" 119 | exit 120 | fi 121 | 122 | # booby trap:-) 123 | machexid=`echo $machex | cut -c7-12` 124 | for i in $typical_mac_list; do 125 | if [ $machexid = $i ]; then 126 | echo "

Error

" 127 | echo "

MAC-address $mac" 128 | echo "is a typical non-existing MAC address that is frequently used when a user is reluctant to find his/her own MAC address:-)

" 129 | echo "

Please use the REAL MAC address

" 130 | echo "go back to the previous page" 131 | exit 132 | fi 133 | done 134 | 135 | # generates EUI64 from the MAC address 136 | first=`echo $machex | cut -c1-1` 137 | second=`echo $machex | cut -c2-2` 138 | macu=`echo $machex | cut -c3-6` 139 | macl=`echo $machex | cut -c7-12` 140 | 141 | # reversing u/l bit 142 | case $second in 143 | [13579BDF]) 144 | echo "

Error

" 145 | echo "

MAC-address = $mac is a group MAC address

" 146 | echo "go back to the previous page" 147 | exit 148 | ;; 149 | 0) 150 | second_rev=2 151 | ;; 152 | 2) 153 | second_rev=0 154 | ;; 155 | 4) 156 | second_rev=6; 157 | ;; 158 | 6) 159 | second_rev=4; 160 | ;; 161 | 8) 162 | second_rev=a; 163 | ;; 164 | A) 165 | second_rev=8; 166 | ;; 167 | C) 168 | second_rev=e; 169 | ;; 170 | E) 171 | second_rev=c; 172 | ;; 173 | *) 174 | #impossible 175 | echo "

Error

" 176 | echo "

MAC-address = $mac" 177 | echo "is registered to the IEEE database, but the first octet is regarded as invalid. (probably a bug in this script...) ($first$second)

" 178 | echo "go back to the previous page" 179 | exit 180 | esac 181 | eui64="${first}${second_rev}${macu}fffe${macl}" 182 | 183 | globalid=`echo $date$eui64 | ${sha} -1 | cut -c23-32` 184 | echo "
" 185 | echo "

" 186 | echo "Generated ULA=" 187 | echo fd${globalid} | sed "s|\(....\)\(....\)\(....\)|\1:\2:\3::/48|" 188 | echo "

" 189 | echo "" 190 | 191 | cat << TAIL 192 |
    193 |
  • MAC address=$mac ($macvendor) 194 |
  • EUI64 address=$eui64 195 |
  • NTP date=$date 196 |
197 | 198 | go back to the previous page 199 | 200 | TAIL 201 | exit 202 | --------------------------------------------------------------------------------