My apartment does not have hardwired ethernet, and the physical location of our incoming cable is such that it's very difficult to position wired ethernet anywhere. I've considered using a powerline adapter to run ethernet over the apartment's electric, but those adapter kits are a bit expensive. When I got my Raspberry Pi though, it occurred to me that I could use it to create an island of wired ethernet that feeds to the wifi connection we've got set up.

This is a depiction of the setup I was going for to turn wireless internet into wired.

Raspberry Pi network diagram

I find iptables (and networking in Linux) extremely obtuse and hate having to figure this stuff out, so now that I've got it working I will leave the necessary configuration details below.

A much more comprehensive writeup on this concept has been developed by Robin Newman, so if this guide is unclear, I highly recommend checking out Robin's guide.

Ben Low also pointed out a handy tutorial that gives a much more sophisticated treatment of this approach using Proxy ARP that is a good thing to check out if this configuration is not good enough.

/etc/network/interfaces should look something like this. If you couldn't tell, this is Raspbian (a Debian-derived distribution)

# The loopback network interface
auto lo
iface lo inet loopback

# the internal (wired) network interface
allow-hotplug eth0
iface eth0 inet static
  address 192.168.2.1
  network 192.168.2.0
  netmask 255.255.255.0
  broadcast 192.168.2.255
  gateway 192.168.2.1

# the external (wifi) interface
allow-hotplug wlan0
iface wlan0 inet static
  address 192.168.1.98
  network 192.168.1.0
  netmask 255.255.255.0
  broadcast 192.168.1.255
  gateway 192.168.1.1
  wpa-ssid "homewifi"
  wpa-psk ...

pre-up iptables-restore < /etc/network/iptables

The contents of /etc/network/iptables are:

&ast;filter
:INPUT ACCEPT &#91;73:5085&#93;
:FORWARD ACCEPT &#91;0:0&#93;
:OUTPUT ACCEPT &#91;72:6792&#93;
-A FORWARD -i eth0 -j ACCEPT
-A FORWARD -i wlan0 -m state --state RELATED,ESTABLISHED -j ACCEPT
COMMIT
&ast;nat
:PREROUTING ACCEPT &#91;43:2584&#93;
:INPUT ACCEPT &#91;2:278&#93;
:OUTPUT ACCEPT &#91;0:0&#93;
:POSTROUTING ACCEPT &#91;0:0&#93;
-A POSTROUTING -o eth0 -j MASQUERADE
-A POSTROUTING -o eth0 -j MASQUERADE
-A POSTROUTING -o wlan0 -j SNAT --to-source 192.168.1.98
COMMIT

which was generated by this script:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/sh
IPT=/sbin/iptables
LOCAL_IFACE=eth0
INET_IFACE=wlan0
INET_ADDRESS=192.168.1.98

# Flush the tables
$IPT -F INPUT
$IPT -F OUTPUT
$IPT -F FORWARD

$IPT -t nat -P PREROUTING ACCEPT
$IPT -t nat -P POSTROUTING ACCEPT
$IPT -t nat -P OUTPUT ACCEPT

# Allow forwarding packets:
$IPT -A FORWARD -p ALL -i $LOCAL_IFACE -j ACCEPT
$IPT -A FORWARD -i $INET_IFACE -m state --state ESTABLISHED,RELATED -j ACCEPT

# Packet masquerading
$IPT -t nat -A POSTROUTING -o $INET_IFACE -j SNAT --to-source $INET_ADDRESS

Of course, ip forwarding has to be enabled in the kernel by editing /etc/sysctl.conf and uncommenting a line:

# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward=1

and then doing sysctl --system.