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 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
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
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.
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 22.214.171.124 (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 126.96.36.199 188.8.131.52
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.
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 184.108.40.206 220.127.116.11. 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.