Convert MAC Address to a IPv6 Link Local Address
The IPv6 Link Local Algorithm in Haskell
The OS should take care of this for you, but if you needed the algorithm in Haskell, here is how to make an IPv6 link local address from a MAC address. Requires the relude and ip packages. Although it’s trivial to drop the Relude requirement in favor of Prelude.
References:
- https://ben.akrin.com/?p=1347
- http://www.tcpipguide.com/free/t_IPv6InterfaceIdentifiersandPhysicalAddressMapping-2.htm
- https://tools.ietf.org/html/rfc4291#section-2.5.6
Online Converters:
-- prelude
import Relude
-- base
import Data.Bits
-- Hackage
import Net.IPv6
import Net.Mac
-- | Try and convert a MAC address to an IPv6 link local address
--
-- For example
--
-- @00:1c:a1:40:00:1f@ -> @fe80::21c:a1ff:fe40:1f@
mkIPV6LinkLocalAddress :: Text -> Maybe IPv6
mkIPV6LinkLocalAddress m = do
vm_mac <- Net.Mac.decode m
let (o1, o2, o3, o6, o7, o8) = Net.Mac.toOctets vm_mac
o1_inverted <- invertAt 6 (toBinary o1)
let o1' = toDecimal o1_inverted
s5 = toWord16 (fromIntegral o1') (fromIntegral o2)
s6 = toWord16 (fromIntegral o3) 0xff
s7 = toWord16 0xfe (fromIntegral o6)
s8 = toWord16 (fromIntegral o7) (fromIntegral o8)
Just (Net.IPv6.fromWord16s 0xfe80 0x0 0x0 0x0 s5 s6 s7 s8)
where
toWord16 :: Word16 -> Word16 -> Word16
toWord16 hi lo =
let hi' = Data.Bits.shift hi 8
lo' = (.&.) lo 0xff
in (.|.) hi' lo'
toDecimal :: Foldable t => t Word8 -> Word8
toDecimal n = snd (foldr f (0, 0) n)
where
f :: Word8 -> (Word8, Word8) -> (Word8, Word8)
f a (i, b) = (i + 1, b + (a * (2 ^ i)))
invertAt :: Int -> [Word8] -> Maybe [Word8]
invertAt i n = case n !!? i of
Nothing -> Nothing
Just e -> do
let (start, end) = splitAt i n
case viaNonEmpty tail end of
Nothing -> Nothing
Just end_dropped -> Just (start ++ [invert e] ++ end_dropped)
where
invert 0 = 1
invert 1 = 0
invert i' = i'
toBinary :: Integral a => a -> [a]
toBinary 0 = replicate 8 0
toBinary n = pad (reverse (helper n))
where
pad n' = replicate (8 - length n') 0 ++ n'
helper 0 = []
helper n' = let (q, r) = n' `divMod` 2 in r : helper q