After installing Arch on my Raspberry Pi, internet worked out of the box: I could plug it into the router, turn it on, ssh in and start downloading things. But the router is in my housemate's bedroom, which isn't ideal. If I want the Pi to be connected to the internet in my room, I need it to be connected to my laptop. (Another option would be a USB wifi dongle, of course.) This is how I did it. Much credit goes to the Ubuntu wiki's Connection sharing page.
I should disclaim that I don't fully understand networking stuff, and some of what I say might be wrong. I also didn't write this as I was going; so while I've consulted my browser and shell histories, it's possible I've forgotten some steps.
My laptop is running Gentoo, and this is where most of the work has to be done. It connects to the internet through wifi, on interface wlan0
. The ethernet port is eth0
, and eth0
is also the name of the ethernet port on the Pi.
Step zero: plug everything in.
Step one, on the laptop:
sudo ip addr add 192.168.1.1/24 dev eth0
(there seems to be a typo on the Ubuntu wiki, where this should be eth1
but is written eth0
.)
This gives the laptop IP address 192.168.1.1
, which is what the Pi will use to talk to it. The /24 is a mask meaning "fix the first 24 bits of this address", i.e. matching 192.168.1.*
. I'm not sure exactly what significance it has, but I think the Pi's IP address will have to match this mask. (For that matter, I don't really know what it means to give an IP address to a laptop.) I chose 192.168.1.*
because the router uses IPs in the range 192.168.0.*
and I don't know what would happen if they were to conflict.
Step two, again on the laptop:
sudo iptables -A FORWARD -o wlan0 -i eth0 -s 192.168.1.0/24 -m conntrack --ctstate NEW -j ACCEPT
sudo iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A POSTROUTING -t nat -j MASQUERADE
These tell the packet filtering mechanism what to do with certain types of packets. The first one says to accept packets which are starting a new connection and coming from 192.168.1.*
over eth0
, and forward them over wlan0
. The second says to also forward packets coming from an established connection or at least a connection related to an established one. I think the third rule says that when we're forwarding packets, we pretend to the computer at the other end (e.g. a web server) that we're the original source, and when it replies we forward that reply to whoever really sent the original packet (in this case, the Pi).
Step one point five: Actually, I had trouble with the second step.
phil $ sudo iptables -A FORWARD -o wlan0 -i eth0 -s 192.168.1.0/24 -m conntrack --ctstate NEW -j ACCEPT
WARNING: Deprecated config file /etc/modprobe.conf, all config files belong into /etc/modprobe.d/.
FATAL: Module ip_tables not found.
iptables v1.4.13: can't initialize iptables table `filter': Table does not exist (do you need to insmod?)
Perhaps iptables or your kernel needs to be upgraded.
This was a hint that I needed to recompile my kernel. It took a bit of hunting, but it seems that the relevant config options (in kernel 3.2.12) are
[*] Networking support --->
Networking options --->
[*] Network packet filtering framework (Netfilter) --->
[*] Advanced netfilter configuration
Core Netfilter Configuration --->
-*- Netfilter LOG over NFNETLINK interface
<*> Netfilter connection tracking support
-*- Netfilter Xtables support (required for ip_tables)
<*> "NFLOG" target support
<*> "conntrack" connection tracking match support
<*> "state" match support
IP: Netfilter Configuration --->
<*> IPv4 connection tracking support (required for NAT)
[*] proc/sysctl compatibility with old connection tracking
<*> IP tables support (required for filtering/masq/NAT)
<*> Packet filtering
<*> REJECT target support
<*> Full NAT
<*> MASQUERADE target support
<*> NETMAP target support
<*> REDIRECT target support
<*> Packet mangling
IPv6: Netfilter Configuration --->
<*> IPv6 connection tracking support
<*> IP6 tables support (required for filtering)
<*> Packet filtering
<*> REJECT target support
<*> Packet mangling
I suspect some of these are unnecessary, but I don't think I've missed out anything particularly relevant. You might be able to just build everything here as modules to avoid rebuilding the whole kernel; I didn't try. If the "netfilter" option builds anything into the kernel itself, that probably won't work, but it might just be there to allow you to skip a lot of boring config options. If you don't care about IPv6, you're a bad person and can probably leave out all the stuff under "IPv6".
(Another error which I got while hunting for the correct config is iptables: Protocol wrong type for socket
. This also seems to have been a kernel config issue, although it's less obviously one.)
After step two, my IP tables look like this:
phil $ sudo iptables -L
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain FORWARD (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere anywhere ctstate RELATED,ESTABLISHED
ACCEPT all -- 192.168.1.0/24 anywhere ctstate NEW
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Step three: enable IP forwarding, again on the laptop.
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
(/proc
is a virtual filesystem used for communicating with the kernel. Writing 1
to that file is like pressing a button labelled "IP forwarding".)
Here the Ubuntu wiki tells you to edit /etc/sysctl.conf
. I haven't done that myself, but it looks like that's to enable IP forwarding on future boots.
Step four: sudo ifconfig eth0 up
on the laptop makes sure it's listening for packets.
Step five: on the Pi, get an IP address.
sudo ip addr add 192.168.1.2/24 dev eth0
This presumably needs to be in the range 192.168.1.*
established earlier, and not 192.168.1.1
conflicting with the laptop. I'm not sure what difference the /24
would make here.
Step six: again on the Pi, tell it where to find the internet
sudo ip route add default via 192.168.1.1
At this point, the internet should work. DNS not so much, so ping google.com
won't work; but ping 173.194.34.134
(which is a Google server) should. You should also be able to ssh 192.168.1.2
from the laptop to the Pi (which runs sshd
on boot). (I don't know if I actually tested ssh
at this point, but it worked after step seven and I can't think of a reason it wouldn't work after six.)
Step seven: to get DNS working, I ignored what the Ubuntu wiki was saying about dhcp. Just edit /etc/resolv.conf
and add the line
nameserver 208.67.222.222 208.67.220.220
It looks like resolv.conf
will be rewritten if I ever run dhcpcd
, so this isn't a satisfactory permanent solution; but after this step, everything seems to work fine.
My goal for tomorrow is to make this permanent; I want to be able to turn the Pi on, plug in the ethernet, and ssh in without having to connect a keyboard and monitor in the meantime.
Thanks to sudo find /etc -type f | sudo xargs grep eth0
, I can SSH in directly from boot. Edit /etc/rc.conf
, find the lines
interface=eth0
address=
netmask=
broadcast=
gateway=
(at least, I think this is what they were originally), and edit so they read:
interface=eth0
address=192.168.1.2
netmask=255.255.255.0
broadcast=
gateway=192.168.1.1
This doesn't provide DNS. resolv.conf
seems to have been overwritten at some point, but I don't know when, and it doesn't happen during a normal shutdown/boot cycle. Possibly I ran dhcpcd
at some point and forgot. Just in case, I've created resolv.conf.head
including the line nameserver 208.67.222.222 208.67.220.220
. If dhcpcd
does get run, it will include this file at the top. (But if dhcpcd
gets run, it will break other aspects of routing until the next boot.)
At this point, if I restart the Pi with the ethernet cable inserted, I can immediately (that is, after waiting a minute or so for the boot process) ssh in and use the internet. It also works if I plug in the ethernet cable after boot. The next order of business is to save the configuration on my laptop.
/etc/sysctl.conf
is the config file which initialises things found in /proc/sys
. We need it to have the line net.ipv4.ip_forward = 1
; in my case, that setting was originally zero, but it might simply not be present.
Gentoo has an iptables
service which can be used to persist those settings when you shutdown. Assuming it's not already started (check by running /etc/init.d/iptables status
) we enable it like so:
sudo /etc/init.d/iptables save
sudo /etc/init.d/iptables start
sudo rc-update add iptables boot
The first line dumps the configuration to a specific file; the second line restores it, and ensures that on shutdown the configuration will be dumped again; and the third line makes sure we start the service on future boots.
Finally we need to cause the lines
ip addr add 192.168.1.1/24 dev eth0
ifconfig eth0 up
to be executed on boot. There's probably a more suitable place for these, but I simply created a file /etc/local.d/eth0-ip.start
to put them in. Gentoo's local
service executes all .start
files in that directory. (The file needs to be executable, so chmod 755 /etc/local.d/eth0-ip.start
.)
If your distro doesn't have an iptables
service, you can simply put the iptables -A ...
commands in the same file. If your distro also doesn't have an equivalent of the local
service, you'll just have to figure out its boot process and place that file somewhere where the init scripts will execute it.
At this point I can reboot either my laptop or my Pi and not have to do anything else to ssh in and get full internet access, so I think I'm done with this post.