Thursday, August 22, 2013

ssh to ipv6 link-local host

What I wanted to be able to do was run my Raspberry Pi as a headless server, and just plug an ethernet cable into it from my laptop and ssh in. Is that so much to ask? I expected it to be automatic with ipv6, since it has automatic host discovery built in. No so much.
  1. ipv6 is not enabled on a Raspberry Pi by default. Edit /etc/modules.conf and add a line for "ipv6". Reboot.
  2. You need to know what address to connect to. ip neigh will show you your neighboring IPs, but it doesn't know about the link-local hosts; you need to ping them first. But you need their addresses to ping them, don't you? The secret is to ping the magic link-local address, ff02::1. Then ip neigh will tell you what you need to know.
    $ ping6 -c 1 -I eth0 ff02::1
    PING ff02::1(ff02::1) from fe80::226:2dff:fef9:3f85 eth0: 56 data bytes
    64 bytes from fe80::226:2dff:fef9:3f85: icmp_seq=1 ttl=64 time=0.050 ms
    
    --- ff02::1 ping statistics ---
    1 packets transmitted, 1 received, 0% packet loss, time 0ms
    rtt min/avg/max/mdev = 0.050/0.050/0.050/0.000 ms
    $ ip -6 neigh
    fe80::ba27:ebff:feb6:6647 dev eth0 lladdr b8:27:eb:b6:66:47 DELAY
    
  3. Ok, I've got the address, but ssh fails with a cryptic "Invalid argument" message.
    $ ssh -6 pi@fe80::ba27:ebff:feb6:6647
    ssh: connect to host fe80::ba27:ebff:feb6:6647 port 22: Invalid argument
    
    This is because ssh (actually, the kernel) doesn't know which interface to talk to. Adding a route for the link-local host doesn't seem to work:
    $ sudo route -A inet6 add fe80::ba27:ebff:feb6:6647/128 dev eth0
    $ route -A inet6 | grep eth0
    fe80::ba27:ebff:feb6:6647/128  ::                         UH   1   0     0 eth0
    fe80::/64                      ::                         U    256 0     0 eth0
    ff00::/8                       ::                         U    256 0     0 eth0
    $ ssh -6 pi@fe80::ba27:ebff:feb6:6647 
    ssh: connect to host fe80::ba27:ebff:feb6:6647 port 22: Invalid argument
    
    So instead, I specified the interface in the ssh hostname (by adding it after a '%'). Here's what that looks like:
    $ ssh -6 pi@fe80::ba27:ebff:feb6:6647%eth0
    pi@fe80::ba27:ebff:feb6:6647%eth0's password: 
    
    scp has a similar problem, and it also uses colons to separate hostname and filename, so you have to put the colon-laden ipv6 address inside square brackets
    $ scp -6 my_file.txt pi@fe80::ba27:ebff:feb6:6647%eth0:
    ssh: Could not resolve hostname fe80: Success
    lost connection
    $ scp -6 my_file.txt pi@'[fe80::ba27:ebff:feb6:6647%eth0]':
    pi@fe80::ba27:ebff:feb6:6647%eth0's password: 
    
I ended up writing a shell script to do all that setup for me:
#!/bin/bash

user=$1
test -n "$user" || user=pi

iface=eth0

# Find the ipv6 address for our link-local host
linkhost=`ip -6 neigh | cut -d ' ' -f 1`
if test -z "$linkhost" ; then
    ping6 -c 1 -I $iface ff02::1 >& /dev/null
    linkhost=`ip -6 neigh | cut -d ' ' -f 1`
fi
echo "Found link local host $linkhost"

echo "ssh -6 -X $user@$linkhost%$iface"
ssh -6 -X $user@$linkhost%$iface

Friday, May 10, 2013

Wireshark Config

Wireshark is a GUI tool, so it runs as your normal user, but it needs to be able to capture packets, which is normally a superuser thing. There is a facility for giving a normal user limited permissions to capture packets, but that's not something you want enabled by default. All good and reasonable, but it has the unfortunate consequence that you can't actually do anything with Wireshark out of the box. Fortunately, they make it pretty easy to enable your permissions. You can just run this, and it brings up an ncurses UI to let you enable non-root packet capture.
$ sudo dpkg-reconfigure wireshark-common
It sets up a wireshark group and gives it permission to capture packets (using the dumpcap utility). Then you need to add yourself to the wireshark group.
sudo usermod -a -G wireshark myuser
You'll have to log out and back in for your user session to have the right permissions.