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 # Dell和08: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配置选项都可用来诊断。