Linux设置为路由器

本文介绍如何将一台Linux系统设置为一个路由器。

这样做的目的:

  • 学习研究相关知识和技术

准备

Linux机器要有两块网卡,还需要一个交换机。

概况

一般家庭网络的布局:

用Linux主机做路由器后,可以不需要SOHO路由器。如果需要多个设备上网,用一个交换机即可。网络布局如下:

配置完成后的地址分配情况:

配置Linux

配置网络接口

这种有多个网络接口的情况下,就不要用NetworkManager了,用interfaces(5)文件来配置。把NetworkManager服务停止掉,这样进入图形界面后网络接口还是由net-tools工具管理。ADSL连接用pppoe搞定。

interfaces(5)文件配置:

auto lo

iface lo inet loopback

auto eth0

iface eth0 inet dhcp

auto eth2

iface eth2 inet static

address 192.168.0.1

netmask 255.255.255.0

post-up iptables -t nat -I POSTROUTING -s 192.168.0.0/24 -j MASQUERADE

pre-down iptables -t nat -D POSTROUTING -s 192.168.0.0/24 -j MASQUERADE

auto dsl-provider

iface dsl-provider inet ppp

pre-up /sbin/ifconfig eth0 up # line maintained by pppoeconf

provider dsl-provider

DHCP服务

在Linux上安装DNSmasq,设置dhcp-range选项。dhcp-range要和eth2的IP地址在一个网段。

dnsmasq.conf文件配置:

interface=eth2

dhcp-range=192.168.0.2,192.168.0.254,255.255.255.0,1h

dhcp-host=f0:4d:a2:7c:a0:46,192.168.0.2 # Dell

log-dhcp

DNS服务

DNSmasq默认安装就是一个DNS转发器。

路由配置

对来自内网的IP包进行SNAT,目标是Internet出口。由于Linux通过ADSL连接得到的是动态IP,所以用iptables的MASQUERADE来做SNAT。我们在interfaces(5)文件里面用up和down来设置自动设置iptables。还要打开/etc/sysctl.conf中的net.ipv4.ip_forward=1选项。

多子网的情况

现在情况更加复杂,在Linux路由器上安装VirtualBox虚拟化软件,增加了一个虚拟网卡vnet0。VirtualBox中安装了3个虚拟机:Fedora、Debian和Windows XP。

vnet0的配置如下:

auto vnet0

iface vnet0 inet static

address 192.168.1.10

netmask 255.255.255.0

bridge_ports none

bridge_maxwait 0

bridge_fd 1

post-up iptables -t nat -I POSTROUTING -s 192.168.1.0/24 -j MASQUERADE

pre-down iptables -t nat -D POSTROUTING -s 192.168.1.0/24 -j MASQUERADE

vnet0是VirtualBox的虚拟网卡,该网卡从DNSmasq获取地址192.168.1.10。Fedora、Debian和Windows虚拟机都要设置为Bridge网络模式。现在vnet0和eth2不在同一个子网中,虚拟机从vnet0获得的IP地址在192.168.1.0/24网络里。DNSmasq支持不同的网络,我们加入多个interface和dhcp-range选项。配置文件如下:

interface=eth2

dhcp-range=192.168.0.2,192.168.0.254,255.255.255.0,10h

dhcp-host=f0:4d:a2:7c:a0:46,192.168.0.2 # Dell

dhcp-host=E0:05:C5:99:DC:2D,192.168.0.50 # Wireless router

interface=vnet0

dhcp-range=192.168.1.2,192.168.1.254,255.255.255.0,10h

dhcp-host=08:00:27:7B:51:F3,192.168.1.3 # VirtualBox Fedora

dhcp-host=08:00:27:2E:4F:7F,192.168.1.4 # VirtualBox Debian

dhcp-host=08:00:27:2E:86:D5,192.168.1.5 # VirtualBox CentOS

dhcp-host=08:00:27:C8:62:09,192.168.1.6 # VirtualBox Windows XP

log-dhcp

这种情况下,交换机后面的机器和虚拟机都可以上网。由于对192.168.0.1/24和192.168.1.10/24这两个子网都设置了SNAT,所以交换机所在的机器可以和几个虚拟机之间通信。比如f0:4d:a2:7c:a0:46,192.168.0.2 # Dell08:00:27:2E:4F:7F,192.168.1.4 # VirtualBox Debian之间可以互相SSH登录到对方。

更复杂的情况

现在情况变了,把vnet0和eth2配置在了同一个网络192.168.0.0/24内:

auto vnet0

iface vnet0 inet static

address 192.168.0.10

netmask 255.255.255.0

bridge_ports none

bridge_maxwait 0

bridge_fd 1

post-up iptables -t nat -I POSTROUTING -s 192.168.0.0/24 -j MASQUERADE

pre-down iptables -t nat -D POSTROUTING -s 192.168.0.0/24 -j MASQUERADE

DNSmasq在eth0和vnet0都监听,也给几个虚拟机配置了固定IP:

dhcp-host=08:00:27:7B:51:F3,192.168.0.3 # VirtualBox Fedora

dhcp-host=08:00:27:2E:4F:7F,192.168.0.4 # VirtualBox Debian

dhcp-host=08:00:27:C8:62:09,192.168.0.6 # VirtualBox Windows XP

布局没变,但是几个IP地址变了:

这样的情况下,连接交换机的计算机可以上网,但是几个虚拟机连IP地址都得不到。DNSmasq的log显示处理了DHCP请求,但是虚拟机收不到回复。

为什么不在同一个子网没有问题,放在同一个子网反而不能互通了呢?因为不在同一个子网的时候,Linux的路由功能完全负责了两个网络间的通信。在同一个子网的时候,比如连接交换机的Dell电脑192.168.0.2想和IP地址为192.168.0.4的虚拟机Debian通信,它要广播ARP请求,试图让Debian收到ARP请求并将其MAC地址告知Dell。但是Linux不能转发广播包,所以Debian收不到Dell的ARP请求,它们之间也就不能通信了。

Proxy ARP

解决上面的问题,要在路由器的两个网卡上启用proxy ARP(Linux 2.6.38-8):

echo 1 > /proc/sys/net/ipv4/conf/eth2/proxy_arp

echo 1 > /proc/sys/net/ipv4/conf/vnet0/proxy_arp

本来的路由是:

221.223.120.1 dev ppp0 proto kernel scope link src 221.223.127.207

192.168.0.0/24 dev eth2 proto kernel scope link src 192.168.0.1

192.168.0.0/24 dev vnet0 proto kernel scope link src 192.168.0.1

169.254.0.0/16 dev eth0 proto kernel scope link src 169.254.10.222

169.254.0.0/16 dev eth2 scope link metric 1000

default dev ppp0 scope link

default dev eth0 scope link metric 1002

我们把两个到192.168.0.0/24的路由删除,而是分别指定路由:

ip r del 192.168.0.0/24 dev eth2

ip r del 192.168.0.0/24 dev vnet0

ip r add 192.168.0.4 dev vnet0

ip r add 192.168.0.2 dev eth2

路由变成了如下(路由表的显示顺序和优先级是无关的):

221.223.120.1 dev ppp0 proto kernel scope link src 221.223.127.207

192.168.0.2 dev eth2 scope link

192.168.0.4 dev vnet0 scope link

169.254.0.0/16 dev eth0 proto kernel scope link src 169.254.10.222

169.254.0.0/16 dev eth2 scope link metric 1000

default dev ppp0 scope link

default dev eth0 scope link metric 1002

这样内核就可以Proxy ARP和转发IP包了。这个路由表中都没有192.168.0.1和192.168.0.10的路由,不过这并不影响三台机器的任意一台到这两个地址的通达性。

在路由器上列出两个网卡的MAC地址:

$ ip l

......

3: eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 1000

link/ether c8:3a:35:dc:1c:95 brd ff:ff:ff:ff:ff:ff

4: vnet0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN

link/ether 32:c5:45:bd:6e:e2 brd ff:ff:ff:ff:ff:ff

......

在Debian VM (192.168.0.4)上我们查看其ARP表:

$ ip n

192.168.0.2 dev eth0 lladdr 32:c5:45:bd:6e:e2 REACHABLE

192.168.0.1 dev eth0 lladdr 32:c5:45:bd:6e:e2 REACHABLE

位于eth2那边的192.168.0.2的MAC地址是vnet0的,说明vnet0代理了192.168.0.4对192.168.0.2的ARP。

同样,在Dell (192.168.0.2)上我们看到:

$ ip n

192.168.0.4 dev eth1 lladdr c8:3a:35:dc:1c:95 REACHABLE

192.168.0.1 dev eth1 lladdr c8:3a:35:dc:1c:95 REACHABLE

位于vnet0那边的192.168.0.4的MAC地址是eth2的,说明eth2代理了192.168.0.2对192.168.0.4的ARP。

为了方便,把对/proc/sys/net的修改写到sysctl.conf里面:

net.ipv4.conf.eth2.proxy_arp = 1

net.ipv4.conf.vnet0.proxy_arp = 1

把对路由的修改写到interfaces文件里面。最终的完整的interfaces配置:

auto lo

iface lo inet loopback

auto eth0

iface eth0 inet dhcp

auto eth2

iface eth2 inet static

address 192.168.0.1

netmask 255.255.255.0

post-up iptables -t nat -I POSTROUTING -s 192.168.0.0/24 -j MASQUERADE

post-up ip route del 192.168.0.0/24 dev eth2

post-up ip route add 192.168.0.2 dev eth2

pre-down iptables -t nat -D POSTROUTING -s 192.168.0.0/24 -j MASQUERADE

auto vnet0

iface vnet0 inet static

address 192.168.0.10

netmask 255.255.255.0

bridge_ports none

bridge_maxwait 0

bridge_fd 1

post-up iptables -t nat -I POSTROUTING -s 192.168.0.0/24 -j MASQUERADE

post-up ip route del 192.168.0.0/24 dev vnet0

post-up ip route add 192.168.0.3 dev vnet0

post-up ip route add 192.168.0.4 dev vnet0

post-up ip route add 192.168.0.5 dev vnet0

post-up ip route add 192.168.0.6 dev vnet0

pre-down iptables -t nat -D POSTROUTING -s 192.168.0.0/24 -j MASQUERADE

auto dsl-provider

iface dsl-provider inet ppp

pre-up /sbin/ifconfig eth0 up # line maintained by pppoeconf

provider dsl-provider

最后要补充的是,eth2和vnet0甚至可以用一样的IP地址,见[4]。对于被路由器隔开,但是又划分到一个子网的主机,都可以在路由器上设置Proxy ARP来解决,见[5]。

诊断

如果出现问题,dmesg, /var/log/syslog, tcpdump, DNSmasq的-d启动选项和dhcp-log配置选项都可用来诊断。

参考

  1. RFC 1027 - Using ARP to implement transparent subnet gateways