SSH Using Link-Local IPv6 Addresses
Because every interface on your system, physical or virtual, has a link local IPv6 address your system needs a little guidance as to which one to use when sending packets to link-local IPv6 addresses. From an IPv4 perspective this type of addressing is an alien concept. But to IPv6, it’s everyday life.
Imagine for a moment that a network prefix is a color. Link-local prefixes (fe80::/10), for the sake of my example, are the color green. Now imagine you are standing in a room with three doors. Each door is painted green. To you, each door looks identical. This means that each door is configured with the same link-local prefix (again, fe80::/10). Now imagine that you need to strap an IPv6 packet on your back, leave the room, and deliver it to some remote location. The packet is addressed to fe80::223:6cff:fe96:788b. You pull out your map of networks (e.g. your routing table) and it says that in order to get to fe80::<something> you need to go out the green door. Uh-oh …all the doors that leave the room are green. Which one do you take? And there’s the rub.
Because the link-local prefix is used on every interface without any subnetting (64-bits of prefix, 64-bits of node, 128-bits of address) your system is unable to tell out which interface a packet destined to a link-local IPv6 address is supposed to be sent. The solution to the problem is you. When using link-locals, you will need to tell the device out which interface the packet should go.
Every interface (physical or virtual) has an identifier. This is true for all of the OS’ (Windows, Linux, OSX). They call them different things but the idea is consistent. Windows OS’ use number to identify their interfaces. Linux uses identifiers like eth0, eth1, wlan0, sit0 (some of the distros have moved away from this syntax). OSX systems use identifiers like en0 and en1.
When using link-local prefixes in each of the OS you need to use this simple syntax:
ipv6-address + percent sign (%) + interface-id.
The interface ID is the identifier of the interface you want the packet to go out (e.g. leave your device). A common mistake I see made by people new to IPv6 is to want to use the interface ID of the interface you want the packet to go into on the receiving node. Not only is this incorrect, it’s impractical to think that you could ever know what that ID even is. You don’t, you won’t and it doesn’t matter. All you need to know is your own interface ID’s.
Here’s the syntax for each OS.
Linux (Ubuntu, in this case)
If necessary, use the ifconfig command to determine the interface identifier (wlan0, eth1).
ssh to a remote host (fe80::216:eaff:fe5f:4cad):
ssh colin@fe80::216:eaff:fe5f:4cad%eth1
Mac/OSX
If necessary, use the ifconfig command to determine the interface identifier (en0, en1)
ssh to a remote host (fe80::216:eaff:fe5f:4cad):
ssh colin@fe80::216:eaff:fe5f:4cad%en0
Windows
You can use the ipconfig command to determine the interface ID (look for the number after the percent sign in each interface’s link-local IPv6 address) or use the netsh interface ipv6 show addresscommand.
Using your third party tool like putty (because Microsoft continues to NOT include a native ssh client) ssh to a remote host (fe80::216:eaff:fe5f:4cad):
fe80::216:eaff:fe5f:4cad%10
Now, if you are using global unicast prefixes or unique local prefixes the addition of the interface identifier is not necessary (and not supported in the syntax).
Happy secure shelling!