12

We know that we can use the MAC address to create an interface identifier, e.g. for a link-local IPv6 address which should be unique in the Network.

The image shows the way to do this:

Create interface identifier from MAC address

My questions are:

  • How can I create an IPv6 address from a MAC using awk or sed?
  • OR is there any command that gives me the link-local IPv6 address for a specific MAC (something like that createIPv6 myMAC)?
Nidal
  • 8,856
  • 11
  • 55
  • 74
  • I rephrased your question a bit (pending review). IPv6 addresses are not *extracted* from MAC addresses, but created. And here you deal only with the interface identifier part (the last 64 bit) of an IPv6 address. But I'm not sure: Do you only want the interface identifier or a whole IPv6 address? Please re-edit, if I did not understand you correctly. – Dubu Jun 12 '14 at 07:34
  • @Dubu, Thanks for editing, I want the whole IPv6 address. – Nidal Jun 12 '14 at 11:13

5 Answers5

12

If you want to create a whole IPv6 address from a MAC (and a given prefix), you could use the excellent ipv6calc tool by Peter Bieringer.

The following command creates a link-local IPv6 address (fe80:: prefix) from a MAC address:

$ ipv6calc --action prefixmac2ipv6 --in prefix+mac --out ipv6addr fe80:: 00:21:5b:f7:25:1b
fe80::221:5bff:fef7:251b

You can leave most of the options away and let the command guess what to do:

$ ipv6calc --in prefix+mac fe80:: 00:21:5b:f7:25:1b
No action type specified, try autodetection...found type: prefixmac2ipv6
fe80::221:5bff:fef7:251b

For Debian distros, ipv6calc is in the main repository.

Dubu
  • 3,654
  • 18
  • 27
4

From the IPv6 Wikipedia entry a more textual description:

A 64-bit interface identifier is most commonly derived from its 48-bit MAC address.

A MAC address 00:0C:29:0C:47:D5 is turned into a 64-bit EUI-64 by inserting FF:FE in the middle: 00:0C:29:FF:FE:0C:47:D5.

So replacing the third : with :FF:FE: should do the trick:

echo  00:0C:29:0C:47:D5 | sed s/:/:FF:FE:/3
00:0C:29:FF:FE:0C:47:D5

No idea if that syntax is specific to GNU sed.


Work in progress:

Convert that to bits:

for HEX in $(tr ":" " " <<< 00:0C:29:FF:FE:0C:47:D5) 
  do 
    printf "%08d " $(bc <<< "ibase=16;obase=2;$HEX") 
  done

should result in the bits 00000000 00001100 00101001 11111111 11111110 00001100 01000111 11010101 leaving only the flipping of bit number 7.

HBruijn
  • 7,233
  • 23
  • 32
3
#! /usr/bin/env python
import sys
n=[int(x, 16) for x in sys.argv[1].split(":")]
print "fe80::%02x%02x:%02xff:fe%02x:%02x%02x" % tuple([n[0]^2]+n[1:])
Martin Wilck
  • 166
  • 4
1

You can create a bash function (and place it in your ~/.bashrc) that uses IFS to split the MAC address into 6 colon-separated groups and assembles them. You'll also need to flip the 7th most significant bit, i.e. bit 1 of the first byte:

mac_to_ipv6_ll() {
    IFS=':'; set $1; unset IFS
    echo "fe80::$(printf %02x $((0x$1 ^ 2)))$2:${3}ff:fe$4:$5$6"
}

Usage example:

$ mac_to_ipv6_ll 12:34:56:78:90:12
fe80::1034:56ff:fe78:9012
rubo77
  • 27,777
  • 43
  • 130
  • 199
0

I must give kudos to @rubo77 above for a pure-shell (unless you count printf) answer above, which I was seeking.

This adds a bit of sed to:

(a) elide any leading zeroes in each 16-bit chunk; and

(b) elide any further all-zero chunks at the start of the IID

...as per common conventions for address brevity.

mac_to_eui64() {
 IFS=':'; set $1; unset IFS
 echo "fe80::$(printf %x $((0x$1 ^ 2)))$2:${3}ff:fe$4:$5$6" |
  sed -E 's/:0+/:/g; s/:{3,}/::/; s/:$/:0/'
}

Note that if you wished to repurpose this for other (arbitrary) prefixes, which you might since EUI-64 can be used in any scope (although it's advised not to use it for global addresses for privacy reasons), you'd need a slightly more convoluted sed script. That's because the fe80:: prefix already contains three zero-chunks (elided to the double-colon) adjacent to the start of the IID. Thus even if the IID's first chunk is all-zeroes (that is, if the MAC started with 02:00), it would be elided too. The EUI-64 format only leaves one further chunk that could be all-zero -- the last one -- which the script above adds back in as a single zero. Other prefixes might require one to leave a single zero between two colons.

Headbank
  • 111
  • 3
  • You're right, thanks - I went back and left @rubo77's fine `printf` alone and did the additional stuff in sed instead. – Headbank Dec 15 '19 at 01:29