Linux网络管理
Linux网络管理
在解释Linux网络管理相关的内容时,我觉得有必要先解释数据包转发功能以及因此涉及到的路由决策,这对厘清路由和未来的防火墙有重要帮助。然后再介绍网络配置命令和相关文件。
Linux处理数据包过程
当向外界主机发送数据时,在它从网卡流入后需要对它做路由决策,根据其目标决定是流入本机数据还是转发给其他主机,如果是流入本机的数据,则数据会从内核空间进入用户空间(被应用程序接收、处理)。当用户空间响应(应用程序生成新的数据包)时,响应数据包是本机产生的新数据,在响应包流出之前,需要做路由决策,根据目标决定从哪个网卡流出。如果不是流入本机的,而是要转发给其他主机的,则必然涉及到另一个流出网卡,此时数据包必须从流入网卡完整地转发给流出网卡,这要求Linux主机能够完成这样的转发。但Linux主机默认未开启ip_forward
功能,这使得数据包无法转发而被丢弃。Linux主机和路由器不同,路由器本身就是为了转发数据包,所以路由器内部默认就能在不同网卡间转发数据包,而Linux主机默认则不能转发。
如下图:
另外,IP地址是属于内核的(不仅如此,整个tcp/ip协议栈都属于内核,包括端口号),只要能和其中一个地址通信,就能和另一个地址通信(这么说是不准确的,即使地址属于内核,但还存在一个检查数据包是否丢弃的问题,不过这不是本文内容),而不管是否开启了数据包转发功能。例如某Linux主机有两网卡eth0:172.16.10.5和eth1:192.168.100.20,某192.168.100.22主机网关指向192.168.100.20,若它ping 172.16.10.5,结果将是通的,因为地址属于内核,从eth1进来的数据包被内核分析时,发现目标地址为本机地址,直接就回应192.168.100.22,回应数据包继续从eth1出去。
如果Linux主机有多块网卡,如果不开启数据包转发功能,则这些网卡之间是无法互通的。例如eth0是172.16.10.0/24网段,而eth1是192.168.100.0/24网段,到达该Linux主机的数据包无法从eth0交给eth1或者从eth1交给eth0,除非Linux主机开启了数据包转发功能。
在Linux上开启转发功能有多种方法:
1 | shell> echo 1 > /proc/sys/net/ipv4/ip_forward |
以上两种方法是临时生效的,若要永久生效,则应该写入配置文件。在CentOS 6中,将/etc/sysctl.conf
文件中的net.ipv4.ip\_forward
值改为1即可,但在CentOS 7中,systemd管理了太多的功能,sysctl的配置文件也分化为多个,包括/etc/sysctl.conf、/etc/sysctl.d/\*.conf和/usr/lib/sysctl.d/\*.conf
,并且这些文件中默认都没有net.ipv4.ip\_forward
项。当然,直接将此项写入到这些配置文件中也都是可以的,建议写在/etc/sysctl.d/\*.conf
中,这是systemd提供自定义内核修改项的目录。例如:
1 | shell> echo "net.ipv4.ip_forward=1" > /etc/sysctl.d/ip_forward.conf |
可以使用以下几种方式查看是否开启了转发功能。
1 | [root@xuexi ~]# sysctl net.ipv4.ip_forward |
和网络相关的几个文件说明
网卡配置文件ifcfg-*
在/etc/sysconfig/network-scripts/
目录下有不少文件,绝大部分都是脚本类的文件,但有一类ifcfg开头的文件为网卡配置文件(interface config),所有ifcfg开头的文件在启动网络服务的时候都会被加载读取,但具体的文件名ifcfg-XX的XX可以随意命名。
以下是一个(CentOS 7上)ifcfg-XX文件的内容示例。
1 | [root@xuexi ~]# cat /etc/sysconfig/network-scripts/ifcfg-eth0 |
DNS配置文件/etc/resolv.conf
该文件用于设置DNS指向,以及解析顺序。该文件格式如下:
1 | # 声明本地域名,即解析时自动隐式补齐的域名 |
例如将/etc/resolv.conf
设置为下所示,为了测试,暂且不设置nameserver。
1 | domain malong.com |
当解析不带点.
的主机名时,如www
,认为不是fqdn,将自动加上.malong.com
变成解析www.malong.com
。
1 | [root@xuexi ~]# host -a www |
当解析的名称末尾不带点但中间带了点的,如www.host
,认为是fqdn,将直接解析www.host
,解析完这个后再解析加上malong.com
的名称,即再解析www.host.malong.com
。
1 | [root@xuexi ~]# host -a www.host |
当解析末尾带点的名称时,如www.host.
认为是完整的fqdn,将直接解析www.host
,解析完后直接结束解析,不会再补齐本地域名再解析。
1 | [root@xuexi ~]# host -a www.host. |
search关键字的作用和domain是一样的,只不过search同时还暗含域名搜索的顺序。例如设置search为如下内容:
1 | search malongshuai.com longshuai.com mashuai.com |
此时若解析www.host
,将依次解析www.host
,www.host.malongshuai.com
,www.host.longshuai.com
,www.host.mashuai.com
。
1 | [root@xuexi ~]# host -a www.host |
1 | [root@xuexi ~]# host -a www |
domain部分和search部分不能共存,如果共存了,则后出现的行有效。
/etc/udev/rules.d/70-persistent-net.rules
当插入新的网络设备时,内核首先识别到,随后在sysfs文件系统(一般挂载在/sys下)中生成该设备对应的信息文件。然后内核通知udev的后台守护进程udevd(若不知道它是什么东西,请认为它是Windows系统中的设备管理器,管理和监视硬件设备),udevd将读取sysfs中对应设备的相关信息,并比对或生成udev的规则集,能匹配上的则做对应的操作。对于网卡来说,CentOS 6上它的的规则集文件默认为/etc/udev/rules.d/70-persistent-net.rules
,匹配该规则集成功后,最后还在/sys/class/net
目录中生成对应的设备子目录。
以下为两个网卡的规则集的内容:
1 | [root@xuexi ~]# cat /etc/udev/rules.d/70-persistent-net.rules |
具体的udev规则集语法并非本文内容,所以此处仅简单解释下上面的两个规则集。规则集文件的写法都是key/value格式,但分为匹配key/vaule和行为key/value。上述例子中,从SUBSYSTEM直到KERNEL都是使用==
号,表示匹配key/value,最后一个NAME使用单=
号,表示赋值key/value。所以上述文件的意思是:当/sys中的某设备各信息都能匹配上述某条规则,则赋值该设备名称为eth0或eth1,/sys/class/net目录下也由此名称命名设备信息的目录,ifcfg-*
配置文件中的DEVICE的值必须和它们相同。
注意,网络规则集文件会由内核检测到设备时自动生成或写入,因此清空它不会有任何影响。
克隆虚拟机时,总是会出现MAC地址冲突,这是因为规则集文件和ifcfg配置文件都被克隆了,而新克隆出来的机器中MAC地址又是新的,所以会生成新的规则集,但克隆过来的ifcfg配置文件中的DEVICE值和该规则对应不上,导致克隆主机的网络将启动不了。解决办法是清空该文件,然后重启克隆主机,这样内核将新生成对应新MAC地址的规则集文件。当然,在克隆前清空模板主机的规则集文件,然后再克隆也是可以的。
值得一提的是,在CentOS 7中,systemd已经将udevd的功能整合在了一起,udev的规则集文件几乎都放到了/usr/lib/udev/rules.d/目录下,但却更方便了,克隆CentOS 7主机时,根本就不会出现MAC地址冲突的可能。不过,显式书写在/etc/udev/rules.d/目录下的规则集文件仍然是生效的。
/etc/services
该文件中记录的是端口和服务的对应关系。
1 | [root@xuexi ~]# grep '^ftp\|^ssh' /etc/services |
网络接口配置和主机名
ifconfig
该命令虽然在man文档中被说明已废弃,但大众显然无法忘记它。ifconfig命令是一个接口配置命令,但更多的被用来显示已激活的网络接口信息。
1 | ifconfig [ interface | -a ] |
ifconfig示例:
1 | # 添加IP地址 |
需要注意的是,ifconfig所有的配置都是应用于内核的,所以只会临时生效,重启网络服务后会立即失效。
对于slave地址,即别名地址,若要永久生效,应该建立对应的别名接口配置文件,如/ets/sysconfig/network-scripts/ifcfg-eth0:0
,然后在该文件中的DEVICE关键字上给定eth0:0名称,该DEVICE项必须配置正确。
ifcfg
用法很简单。
1 | ifcfg DEV [[add|del [ADDR[/LEN]] | stop] |
例如:
1 | [root@xuexi ~]# ifcfg eth1:0 add 192.168.100.20/24 # 添加一个地址 |
hostname命令
用于设置主机名,但也有几个其它好用的功能。
1 | hostname [-I] [-f] [-d] [-s] [hostname] |
使用-I选项可以直接获取该主机上的所有IP地址,包括别名地址,这在某些时候太方便了。
1 | [root@xuexi ~]# hostname -I |
hostname修改的主机名为临时生效,它修改的其实是/proc/sys/kernel/hostname文件。
1 | [root@xuexi ~]# cat /proc/sys/kernel/hostname |
虽然在man文档中说有个永久有效的选项(-b),但测试时却毫无效果。要想永久生效,需要修改配置文件/etc/hostname(CentOS 7)或/etc/sysconfig/network(CentOS 6)。例如在CentOS 7上:
1 | [root@xuexi ~]# echo "ma.longshuai.com" >/etc/hostname |
网关/路由
Linux上分为3种路由:
- 主机路由:直接指明到某台具体的主机怎么走,主机路由也就是所谓的静态路由
- 网络路由:指明某类网络怎么走
- 默认路由:不走主机路由的和网络路由的就走默认路由。操作系统上设置的默认路由一般也称为网关。
若Linux上到某主机有多条路由可以选择,这时候会挑选优先级高的路由。在Linux中,路由条目的优先级确定方式是先匹配掩码位长度,再比较管理距离(比如metric)。也就是说,掩码位长的路由条目优先级一定比掩码位短的优先级高,所以主机路由的优先级最高,然后是直连网络(即同网段)的路由(也算是网络路由)次之,再是网络路由,最后才是默认路由。若路由条目的掩码长度相同,则比较节点之间的管理距离,管理距离短的生效。
例如下面的路由表中,若ping 192.168.5.20,则先比对192.168.100.78发现无法匹配,然后比对192.168.100.0,发现也无法匹配,接着再匹配192.168.0.0这条网络路由条目,发现能匹配,所以选择该路由条目。
1 | [root@xuexi ~]# route -n |
再比如下面的路由表。由于两块网卡eth0和eth1都是192.168.100.0/24网段地址,所以它们的路由条目在掩码长度的匹配上是相同的,但是和eth0直连的网段主机通信时,肯定会选择eth0这条路由条目,因为eth1和该网段主机隔了一个eth0,距离增加了1。
1 | [root@xuexi ~]# route -n |
route命令
route命令用于显示和管理路由表。当使用了add或del选项时,route命令将设置路由条目,否则route命令将显示路由表。
要显示路由表信息,只需简单的route -n
即可,其中-n
选项表示不解析主机名。
例如:
1 | [root@xuexi ~]# route -n |
对于CentOS 6以上的系统,请忽略Metric和Ref两列,它们已经不被内核使用,只是有些路由软件可能会用上。
对于Flags列,如果没有安装路由软件,则只可能出现下面的3种值:
1 | U (route is up) |
若要管理路由表,则使用add或del选项。
1 | route [add/del] [-host/-net/default] [address[/mask]] [netmask] [gw] [dev] |
例如:
(1).添加和删除默认路由
1 | shell> route add default gw 192.168.100.10 |
因为默认路由的目的地是0.0.0.0,所以操作默认路由也可以使用0.0.0.0替代default关键字,但这样就麻烦的多了。
(2).添加和删除网络路由
1 | shell> route add -net 172.16.10.0/24 gw 192.168.100.70 |
若实在不知道下一跳给谁,那么指定本机接口也是可以的。
1 | shell> route add -net 172.16.10.0/24 dev eth0 |
删除路由可以直接在增加路由的语句上将add改为del关键字。如
1 | shell> route del -net 172.16.10.0/24 gw 192.168.100.70 |
但大多数时候,可以偷懒,只要能唯一确定删除的是哪条路由即可。如:
1 | shell> route del -net 172.16.10.0/24 |
(3)添加和删除主机路由
1 | shell> route add -host 172.16.10.55 gw 192.168.10.20 |
配置永久路由
根据接口创建路由配置文件/etc/syconfig/network-scripts/route-ethX,要从那个接口出去X就是几。
路由配置文件的配置格式非常简单,每一行一个路由条目,先是要到达的目标,然后是via关键字,最后是下一跳地址。要求下一跳必须能到达,且一般都和ethX同网段。
DEST via nexthop
例如eth0网卡的IP地址是192.168.10.123,要通过网卡eth0出去到达10.0.0.10,那么下一跳的地址要和eth0的地址在同网段,如192.168.10.222。
1 | 10.0.0.0 via 192.168.10.222 |
添加主机路由、默认路由、网段路由示例如下,其中dev是可以省略的,因为没有任何用处,配置在哪个eth文件中就会从哪个接口出去。
1 | #默认路由 |
配置完后,重启network服务即可立即生效。
route-ethX文件的还有另外一种永久路由的配置写法,但上面的方法更简单快捷,所以此处就不多说了。
配置永久路由时,需要注意几点:
(1).route-ethX的对应网卡配置文件ifcfg-ethX必须存在,否则路由无效。(对于虚拟机,通常新添加的网卡都没有对应的ifcfg-ethX文件,但ifconfig却能找到该网卡)
(2).如果在文件中配置永久默认路由,则必须保证所有使用了DHCP服务的网卡配置文件ifcfg-ethX中的DEFROUTE指令设置为”no”,表示DHCP不设置默认路由。
(3).如果在route-ethX文件中配置永久路由,且该网卡使用了DHCP服务分配地址,则必须保证该网卡的ifcfg-ethX文件中的PEERROUTES指令设置为”no”,表示DHCP设置的路由允许被覆盖。
arp和arping命令
维护或查看系统arp缓存,该命令已废弃,使用ip neigh代替。
arp为地址解析协议,将给定的ipv4地址在网络中查找其对应的MAC地址。
一般会使用arp协议获取局域网内的主机MAC,所以局域网主机之间也互称为网络邻居。
arp命令
arp命令语法:
1 | arp -n -v -i # 查看arp缓存 |
hostname:操作该主机的arp条目,除了删除还有其他动作,如手动添加主机的arp条目,此处就不解释该用法了
例如:
1 | [root@xuexi ~]# arp -n |
其实查看的信息是/proc/net/arp文件中的内容。
1 | [root@xuexi ~]# cat /proc/net/arp |
1 | [root@xuexi ~]# arp -d 192.168.100.70 -i eth0 # 删除arp缓存条目 |
arp命令一次只能删除一条arp条目,要批量删除或清空整个arp条目,使用ip neigh flush
命令。如:
1 | [root@xuexi ~]# ip neigh flush all # 清空所有 |
arping命令
arping用于发送arp请求报文,解析并获取目标地址的MAC。默认将先发送广播报文,收到回复后再发送单播报文,局域网内所有主机都能收到广播报文,但只有目标主机才会回复自己的MAC地址。
注意:发送arp请求报文实际上是另类的ping,所以可以探测目标是否存活,也需要和目标通信,通信时目标主机上也会缓存本主机(即源地址)的arp条目。
语法:
1 | arping [-fqbDU] [-c count] [-w timeout] [-I device] [-s source] destination |
例如:
(1).请求解析192.168.100.70主机的MAC地址
1 | [root@xuexi ~]# arping -f 192.168.100.70 |
这将会发送广播报文,直到收到192.168.100.70的回复才退出。
同时,192.168.100.70也会缓存本机的IP和MAC对应条目,由于此处没有指定请求报文的发送接口和源地址,所以发送报文时是根据路由表来选择接口和对应该接口地址的。
(2).指定发送一个请求报文给192.168.100.70就退出,发送报文的接口为eth1,并指定请求报文中的源地址为本机eth0接口上的地址192.168.100.54
1 | [root@xuexi ~]# arping -c 1 -I eth1 -s 192.168.100.54 192.168.100.70 |
发送这样的arp请求包,将会使得目标主机192.168.100.70缓存本机的arp条目为”192.168.100.54 MAC_eth1”,但实际上,192.168.100.54所在接口的MAC地址为MAC_eth0。
arping命令仅能实现这种简单的arp欺骗,更多的arp欺骗方法可以使用专门的工具。
(3).探测对方主机是否存活
例如发送4个探测报文,有回复就说明对方存活
1 | [root@xuexi ~]# arping -c 4 -I eth0 192.168.100.2 |
可见发送了4个探测报文,其中第一个报文是广播报文,并且收到了4个回复。
ip命令
这是一个极其强大的命令,前面所有的网络信息显示和管理的命令,都可以由ip命令来替代完成。它是一个严格模式化的命令。
获取ip命令的帮助
先简单说明下ip命令的基础和获取帮助的方法。
1 | [root@xuexi ~]# ip -h |
可见命令非常复杂,有很多options,还有很多object,每个Object又对应不同的命令。但其实能用到的就几个object:addr/route/neigh/link。
使用ip object help可以获取到该object的语法帮助。例如:
1 | [root@xuexi ~]# ip addr help |
在ip命令行下,任何object都可以写其全名,也可以写其缩写名,例如address这个object,可以简写为addr,也可以简写为一个字母a。
1 | # 等价于ip address help和ip addr help |
尽管还有一个a开头的object为addrlabel。这时因为ip会从上述语法给出的object顺序从前向后匹配,例如”ip m”将匹配到”ip maddr”,如果想匹配别的,如addrlabel,则写长一点即可”ip addrl”。
对于CentOS 6,man ip时会输出整个ip的帮助文档,包括每个object的命令和说明。在CentOS 7中,则要对每个object独立进行man,例如addr这个object。
1 | [root@xuexi ~]# man ip-address |
以下是所有Object的man列表。
1 | [root@xuexi ~]# rpm -ql iproute | grep "man8/ip-" |
ip addr
ip addr用于管理网络设备上的ip地址,也可以查看ip地址的属性信息。在老版本的Linux中,一块网卡上设置多个IP,这些IP称为别名IP,但是从CentOS 6开始,这些IP称为secondary IP或slave IP,因为这些IP自身也可以附带属性。
(1).ip addr add/del
1 | ip address { add | del } IFADDR dev STRING |
例如:
1 | [root192.168.100.45 dev eth0 ~]# ip addr add |
此方式添加的地址不会在ifconfg命令中显示,ifconfg能捕捉到的是别名,所以可以为地址加上label,以让secondary被ifconfig查看到。例如:
1 | [root@xuexi ~]# ip addr add 192.168.100.45 dev eth0 label eth0:0 |
要删除ip,则简单的多,但必须指定dev,且最好也指定cidr的掩码长度。
1 | [root@xuexi ~]# ip addr del 192.168.100.45 dev eth0 |
(2).ip addr show
虽然也有几个选项,但是感觉没什么用,直接ip addr show就够了。因为ip命令可以缩写,所以可以写为
1 | [root@xuexi ~]# ip a show |
(3).ip addr flush
用于批量删除地址,该命令其实非常危险,一个不小心就会误伤无辜,所幸的是flush的时候不给定任何参数或者没有任何条目可以匹配上的时候将不执行flush动作,总之该命令要小心使用。同样也必须给定dev参数。
例如删除eth1上所有地址。
1 | [root@xuexi ~]# ip a flush dev eth1 |
删除eth1上所有的secondary地址。
1 | [root@xuexi ~]# ip a f secondary dev eth1 |
ip route
该命令维护和查看内核中的路由表。
(1).ip route add/del/change/append/replace
语法格式为:
1 | ip route { add | del | change | append | replace } dest[/cidr_mask] [ via ADDRESS ] [ dev STRING ] |
其中dest为目标地址,可以是主机地址、网段地址,一般在地址后都会带上cidr格式的掩码长度,不带时默认为32位长度。如果dest为”0/0”或者写为”default”,则表示默认路由。
例如添加/修改/替换普通路由:
1 | [root@xuexi ~]# ip route add/change/replace 172.16.10.0/24 via 192.168.10.20 |
添加/修改/替换默认路由:
1 | [root@xuexi ~]# ip route add/change/replace default via 192.168.10.20 |
删除某路由:
1 | [root@xuexi ~]# ip route del 172.16.10.0/24 |
(2).ip route show
列出路由表。
语法格式为:
1 | ip route show [to [ root | match | exact ] ADDR_pattern ] [ via ADDR ] |
其中to关键字是默认关键字,用来匹配路由的目标地址。其后可以跟上修饰符root/match/exact,exact为默认修饰符,表示精确匹配掩码位长度,root修饰符表示匹配的掩码位长度大于或等于ADDR_pattern给定的掩码位长度,match修饰符匹配短于或等于ADDR_pattern掩码位长度。例如”to match 16.0/16”将能匹配到”16.0/16”、”16/8”和”0/0”,但却无法匹配”16.1/16”和”16.0/24”以及”16.0.1/24”,而”to root 16.0/16”将能匹配”16.0/24”和”16.0.1/24”。
via是根据下一跳的方式来列出路由条目。
例如:
1 | [root@xuexi ~]# ip route show | column -t |
其实无需那么花哨,简简单单的ip r
多方便。
(3).ip route flush
批量删除路由表条目。参数和ip route show
的参数一样。
例如删除由eth1出去的路由条目。
1 | [root ~]# ip route flush eth1 |
删除下一跳为192.168.100.70的路由条目。
1 | [root192.168.100.70 ~]# ip r flush via |
删除目标为192.168.0.0/16网段的路由
1 | [root192.168/16 ~]# ip route flush |
(4).ip route save/restore
用于保存当前的路由表以及恢复路由表。保存路由表时,路由表将以二进制裸数据的格式输出,也就是看不懂的二进制文件。恢复路由表时,要求设备的设置和保存路由表时是一样的,恢复时已存在于路由表中的路由条目将被忽略。
例如当前路由表信息如下:
1 | [root@xuexi ~]# ip r |
保存当前路由表。
1 | [root@xuexi ~]# ip route save > /tmp/route.txt |
删除几条路由表。
1 | [root@xuexi ~]# ip route flush dev eth0 |
恢复路由表。
1 | [root@xuexi ~]# ip route restore < /tmp/route.txt |
ip link
link表示link layer的意思,即链路层。该命令用于管理和查看网络接口,甚至可以添加虚拟网络接口,将网络接口分组进行管理。
(1).ip link set
1 | ip link set DEVICE { up | down | arp { on | off } | name NEWNAME | address LLADDR } |
例如,禁用eth1网卡。
1 | [root@xuexi ~]# ip link set eth1 down |
其实等价于:
1 | [root@xuexi ~]# ifconfig eth1 down |
修改网卡eth1的MAC地址。
1 | [root@xuexi ~]# ip link set eth1 address 00:0c:29:f3:33:77 |
(2).ip link show
语法格式:
1 | ip [ -s | -h ] link show [dev DEV] |
例如:
1 | [root@xuexi ~]# ip -s -h link show dev eth0 |