网络配置

来自 Arch Linux 中文维基

这篇文章或章节的翻译不反映原文。

原因:本文久未同步,内容与英语原文相比,已有较大差异。(在 Talk:网络配置# 中讨论)

本页解释了如何在 OSI 第三层及之上配置网络连接。有部分内容在网络配置/以太网网络配置/无线网络配置两个页面中。

提示:建议参阅systemd-networkd

检查连接[编辑 | 编辑源代码]

若要排查网络连接问题,请先确保你满足了以下要求。

  1. 你的网络接口可见并已启用。否则请检查设备驱动-请查阅 Network configuration/Ethernet#Device driverWireless network configuration#设备驱动[损坏的链接:无效的章节] 页面。
  2. 你已连接到网络。网线已接好或者已经连接到无线局域网
  3. 你的网络接口拥有一个IP 地址
  4. 你的路由表设置正确。
  5. 你可以 ping 通一个本地 IP 地址(例如你的默认网关)。
  6. 你可以 ping 通一个公网 IP 地址(例如 9.9.9.9 ,即 Quad9 的 DNS 服务器)。
  7. 检查是否能解析域名(例如 archlinux.org)。

Ping[编辑 | 编辑源代码]

ping 用于测试你是否可连接到某个主机, 用 Ctrl+c 停止测试。

$ ping www.example.com
PING www.example.com (93.184.216.34): 56(84) data bytes
64 bytes from 93.184.216.34: icmp_seq=0 ttl=56 time=11.632 ms
64 bytes from 93.184.216.34: icmp_seq=1 ttl=56 time=11.726 ms
64 bytes from 93.184.216.34: icmp_seq=2 ttl=56 time=10.683 ms
...

如上所示,Ping 命令对每个收到的回应都会显示一行信息。详细的解释请阅读 ping(8) 手册。注意,计算机可以配置为不响应 ICMP 回应请求。[1]

如果没有收到回应,原因可能与默认网关配置或者网络接入服务商(ISP)有关。可以运行 traceroute 以进一步诊断到对端主机的路由。

网络管理[编辑 | 编辑源代码]

通过以下步骤来设置网络链接:

  1. 确保网络接口已连接并已开启。
  2. 连接到网络。网线已接好或者已经连接到无线局域网
  3. 配置网络连接:
注意: 安装镜像使用 systemd-resolvedsystemd-networkd[2], WLANWWAN网络配置 DHCP 客户端。

网络工具[编辑 | 编辑源代码]

Arch Linux 已经弃用了 net-tools 转而使用 iproute2[3]

已弃用的命令 替换命令
arp ip neighbor
ifconfig ip address, ip link
netstat ss
route ip route

想要更多更完整的总结,请参阅这篇文章

iproute2[编辑 | 编辑源代码]

iproute2base 元包的依赖,提供 ip(8) 命令行接口,用于管理网络接口IP 地址路由表。注意使用 ip 进行的配置会在重启后丢失。要进行永久配置,可以使用网络管理器或通过脚本和 systemd 单元使 ip 命令自动化。同时需要注意的是 ip 命令通常能够缩写,为了清楚起见,本文对其进行了详细说明。

网络接口[编辑 | 编辑源代码]

默认情况下, udev 使用可预测的网络接口名称分配给你的网络接口,该名称以 en (有线/以太网) ,wl (无线/WLAN) 或 ww (WWAN)开头 。参见 systemd.net-naming-scheme(7)

提示:要改变接口名称,请参阅 #更改接口名称#改回传统接口名称

列出网络接口[编辑 | 编辑源代码]

有线和无线接口名称都可以通过 ls /sys/class/netip link 找到。要注意的是 loLoop 设备,不被用于建立网络连接。

同样,也可以用 iw dev 来检索无线设备的名称。可以参阅无线网#获取有用信息[损坏的链接:无效的章节]

如果未列出您的网络接口,请确保已成功加载设备驱动。参阅以太网#设备驱动无线网#设备驱动[损坏的链接:无效的章节]

启用和禁用网络接口[编辑 | 编辑源代码]

可以使用 ip link set interface up|down 来启用/禁用网络接口,参阅 ip-link(8)

要想检查接口 enp2s0 的状态:

$ ip link show dev enp2s0
2: enp2s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master br0 state DOWN mode DEFAULT qlen 1000
...

<BROADCAST,MULTICAST,UP,LOWER_UP> 中的 UP 表示接口已经启动,而非表示稍后的 state DOWN

注意: 如果您的默认路由是通过接口 enp2s0 进行的,则将其删除也会删除该路由,而恢复备份将不会自动重新建立默认路由。参阅 #路由表 以重新建立它。

静态还是动态 IP 地址?[编辑 | 编辑源代码]

如果你在使用 WiFi 或路由器,你很可能会使用动态 IP 地址。你的计算机应该被配置为使用由 WiFi 或路由器分配的 IP 地址。如果你处于家庭环境且电脑连接到网络接入服务商提供的调制解调器,比如一个线缆调制解调器,那也会使用一个动态 IP 地址。动态 IP 地址会在每次开机时改变。在工作环境中,你可能具有静态 IP 地址或动态 IP 地址。在家里,你可以将路由器配置为始终为计算机分配相同的 IP 地址,在这种情况下,你将使用静态 IP 地址。使用动态 IP 地址时,需要使用 DHCP 以便用正确的 IP 地址设置网络接口。除了配置 IP 地址外,DHCP 还可以配置路由(如何从你的位置到达任意网络中你要访问的的位置)以及域名服务器,域名服务器会转换主机名(例如 google.com)到 IP 地址(带点号的数字)。

静态 IP 地址[编辑 | 编辑源代码]

可以通过绝大多数的网络管理器dhcpcd 来配置静态 IP 地址。

要手动配置静态 IP 地址,请按照 #IP 地址中的说明添加 IP 地址,设置路由表配置 DNS 服务器

IP 地址[编辑 | 编辑源代码]

通过 ip-address(8) 来管理 IP 地址

列出 IP 地址:

$ ip address show

将 IP 地址添加到接口:

# ip address add address/prefix_len broadcast + dev interface
注意:
注意: 要确保手动分配的 IP 地址与 DHCP 分配的 IP 地址不冲突。

将 IP 地址从接口中删除:

# ip address del address/prefix_len dev interface

删除所有符合条件的地址,例如某个特定接口的地址:

# ip address flush dev interface
提示:可通过 ipcalc (ipcalc) 计算 IP 地址。

路由表[编辑 | 编辑源代码]

路由表被用于确定是否可以直接访问某个 IP 地址或该使用哪个网关(路由器)。如果别的路由与这个 IP 地址匹配,将使用默认网关

通过 ip-route(8) 来管理路由表。

应在 PREFIX 处使用 CIDR 表示法,或填入 default 表示默认网关。

列出 IPv4 路由:

$ ip route show

列出 IPv6 路由:

$ ip -6 route

添加路由:

# ip route add PREFIX via address dev interface

删除路由:

# ip route del PREFIX via address dev interface

DHCP[编辑 | 编辑源代码]

动态主机配置协议(DHCP) 服务器为客户端提供动态 IP 地址,子网掩码,默认网关 IP 地址,有时还可以提供域名服务器。

要使用 DHCP ,需要网络中有 DHCP 服务器和 DHCP 客户端:

客户端 软件包 Archiso 备注 Systemd 单元
dhcpcd dhcpcd DHCP, DHCPv6, ZeroConf, static IP dhcpcd.service, dhcpcd@interface.service
ISC dhclient dhclient DHCP, DHCPv6, BOOTP, static IP dhclient@interface.service
注意:
  • ISC 从 2022 年初开始已经停止 ISC DHCP 客户端开发,程序已经不再维护,请不要在生产系统中使用。
  • 不能同时运行两个 DHCP 客户端。
  • 除了直接使用独立的 DHCP 客户端,还可以使用具有内置 DHCP 客户端的网络管理器
  • 另外,iwd 提供了内置的 DHCP 客户端,可以通过某些配置来使用它:iwd#启用内置网络配置
提示:
  • 可以通过 dhcping 检查一个 DHCP 服务器是否在运行。
  • 在等待分配 IP 时,可以运行 watch -n 1 ping -c 1 archlinux.org 之类的命令来自动确认网络是否配置好。

服务器[编辑 | 编辑源代码]

服务器 软件包 IPv4 IPv6 GUI 接口 后端存储 备注
dhcpd dhcp Glass-ISC-DHCP ? 文件
dnsmasq dnsmasq ? 文件 还可运行 DNS,PXE 和 TFTP 服务
Kea kea Stork REST,RADIUS 和 NETCONF 文件,MySQL,PostgreSQL 和 Cassandra 还可运行 DNS 服务

网络管理器[编辑 | 编辑源代码]

网络管理器可以在网络配置文件中管理网络连接设置,以便切换网络。

注意: 有许多可选的方案,但他们都相互排斥,因此不要同时运行两个守护程序
网络管理器 GUI Archiso [4] CLI 工具 点对点协议 支持
(例如 3G 调制解调器)
DHCP 客户端 Systemd 单元
ConnMan 8 种,非官方 connmanctl(1) 是(通过 ofonoAUR 内置 connman.service
netctl 2 种,非官方 netctl(1), wifi-menu dhcpcddhclient netctl-ifplugd@interface.service, netctl-auto@interface.service
NetworkManager nmcli(1), nmtui(1) 内置或 dhclient NetworkManager.service
systemd-networkd 是 (base) networkctl(1) 内置 systemd-networkd.service, systemd-resolved.service

设置计算机名[编辑 | 编辑源代码]

主机名是一个网络中唯一标识一台机器的名称。主机名通过文件 /etc/hostname 进行配置,参阅 hostname(5)hostname(7) 获取详细介绍。/etc/hostname 可以包含系统使用的域名(如果有)。要设置主机名,请编辑 /etc/hostname 使之包含单独一行 myhostname

/etc/hostname
myhostname
提示:有关选取一个主机名的建议,参阅 RFC 1178

也可以使用 hostnamectl(1)

# hostnamectl set-hostname myhostname

要临时设置主机名(直到下次重启为止),使用 inetutils 中的 hostname(1) 命令:

# hostname myhostname

要设置“美观”的主机名和其它机器元数据,请参考 machine-info(5)

局域网主机名解析[编辑 | 编辑源代码]

要想使用主机名在你的局域网上访问你的机器,你可以使用下列方法:

  • 编辑你局域网上所有设备的 /etc/hosts,参见 hosts(5)
  • 设立一个 DNS 服务器来解析你的主机名,并让局域网中的设备都使用这个 DNS 服务器(比如,通过 #DHCP
  • 或者最简单的方式:使用 Zero-configuration networking 服务:
    • 通过微软的 NetBIOS 进行主机名解析。在 Linux 上由 Samba 提供。它只需要启用 nmb.service 模块。运行 Windows,macOS 或运行 nmb 的 Linux 的计算机都能够发现你的设备。
    • 通过 mDNS 进行主机名解析。 由带有 Avahinss_mdns(阅读 Avahi#Hostname resolution 获取详细配置)或 systemd-resolved 提供。 运行 macOS,或者带有 Avahi 的 Linux 或者运行 systemd-resolved 的 Linux 的计算机能够发现你的设备。老版本的 Win32 API 不支持 mDNS,一些老的 Windows 应用可能无法访问你的设备。

更多设置[编辑 | 编辑源代码]

更改接口名称[编辑 | 编辑源代码]

注意: 当你改变接口命名规则时,不要忘记更新所有与网络相关的配置文件和自定义的 systemd 单元文件以反映更改。

你可以通过编辑 udev 规则来手动更改设备名称。例如:

/etc/udev/rules.d/10-network.rules
SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="aa:bb:cc:dd:ee:ff", NAME="net1"
SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="ff:ee:dd:cc:bb:aa", NAME="net0"

这些规则将在启动时自动应用。

值得注意的两点:

  • 使用这条命令来获得每张网卡的 MAC 地址:

cat /sys/class/net/设备名/address

  • 确保你的 udev 规则中使用小写的十六进制值,而不是大写。

如果网卡的 MAC 地址是会动态变化的,你可以使用 DEVPATH,例如:

/etc/udev/rules.d/10-network.rules
SUBSYSTEM=="net", DEVPATH=="/devices/platform/wemac.*", NAME="int"
SUBSYSTEM=="net", DEVPATH=="/devices/pci*/*1c.0/*/net/*", NAME="en"

要得到所有当前已连接设备的 DEVPATH,请查看 /sys/class/net/ 中符号链接指向的位置。例如:

file /sys/class/net/*
/sys/class/net/enp0s20f0u4u1: symbolic link to ../../devices/pci0000:00/0000:00:14.0/usb2/2-4/2-4.1/2-4.1:1.0/net/enp0s20f0u4u1
/sys/class/net/enp0s31f6:     symbolic link to ../../devices/pci0000:00/0000:00:1f.6/net/enp0s31f6
/sys/class/net/lo:            symbolic link to ../../devices/virtual/net/lo
/sys/class/net/wlp4s0:        symbolic link to ../../devices/pci0000:00/0000:00:1c.6/0000:04:00.0/net/wlp4s0

设备路径应与新设备名称和旧设备名称均匹配,因为该规则可能在启动时执行多次。例如,在第二条规则中若写 "/devices/pci*/*1c.0/*/net/enp*" 是错误的,因为一旦设备名称更改为 en,它将停止匹配。 只有系统默认规则会第二次触发,从而使设备名称改回例如 enp1s0

如果你正在使用具有动态 MAC 地址的 USB 网络设备(如 Android 手机网络共享),并且你希望能够使用不同的 USB 端口,你可以使用匹配供应商和产品 ID 的规则:

/etc/udev/rules.d/10-network.rules
SUBSYSTEM=="net", ACTION=="add", ATTRS{idVendor}=="12ab", ATTRS{idProduct}=="3cd4", NAME="net2"

测试[损坏的链接:无效的章节]自定义规则,可以直接从用户空间触发这些规则,例如使用 udevadm --debug test /sys/class/net/*。切记先关闭您要重命名的接口(例如,ip link set enp1s0 down)。

注意: 选择静态名称时,应该避免使用形如“ethX”或“wlanX”的名称,因为这可能在引导时导致内核与 udev 之间的竞争状态。相反,最好用内核默认不会使用的接口名称,例如:net0net1wifi0wifi1。更多细节请查看 systemd 文档。

改回传统接口名称[编辑 | 编辑源代码]

如果希望使用像 eth0 这样的传统接口命名,可以通过下面方法禁用可预测网络接口名:

# ln -s /dev/null /etc/udev/rules.d/80-net-setup-link.rules

设定设备的 MTU 和队列长度[编辑 | 编辑源代码]

你可以手动定义一条 udev 规则来改变设备的 MTU 和队列长度。举例来说:

/etc/udev/rules.d/10-network.rules
ACTION=="add", SUBSYSTEM=="net", KERNEL=="wl*", ATTR{mtu}="1500", ATTR{tx_queue_len}="2000"

mtu:使用大于 1500 的值(所谓的巨型帧)可以大大加快网络传输速度。请注意,所有网络接口(包括本地网络中的交换机)都必须支持相同的 MTU 才能使用巨型帧。对于 PPPoE,MTU 不应大于 1492。您还可以通过 systemd.netdev(5) 设置MTU。

tx_queue_len:对于具有高延迟的速度较慢的设备(如调制解调器链路和 ISDN),使用较小的值。对于通过高速 Internet 连接进行大型数据传输的服务器,建议使用较大的值。

绑定和链路聚合[编辑 | 编辑源代码]

参阅 netctl[损坏的链接:无效的章节]systemd-networkd无线网络绑定

IP 别名[编辑 | 编辑源代码]

IP 别名是指给同一个网络接口分配多个 IP 地址。这样一个网络节点可以有多个网络连接,每个实现不同的作用。典型的用处是 Web 服务器和 FTP 服务器的虚拟主机,或者是重组服务器时不需要更新其他任何机器上的 IP (对于名称服务器来说很有用)。

例子[编辑 | 编辑源代码]

要手动设置别名,可以使用 iproute2 执行:

# ip addr add 192.168.2.101/24 dev enp2s0 label eth0:1

删除别名:

# ip addr del 192.168.2.101/24 dev enp2s0:1

默认情况下,发往子网的数据包将使用主 IP。如果目标 IP 子别名,原始 IP 也会被相应设置。如果有多个网卡,可以通过 ip route 查看默认路由。

混杂模式[编辑 | 编辑源代码]

切换网卡到混杂模式可以让(无线)网卡接收所有数据然后转交给操作系统处理。而正常模式下,网卡会丢掉不是发给自己的数据。这通常用来检查网络问题或进行数据包嗅探

/etc/systemd/system/promiscuous@.service
[Unit]
Description=Set %i interface in promiscuous mode
After=network.target

[Service]
Type=oneshot
ExecStart=/usr/bin/ip link set dev %i promisc on
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

如果要在 enp2s0 上启用全接收模式,只需要启用promiscuous@enp2s0.service.

检测套接字[编辑 | 编辑源代码]

ss 是用来检测网络端口的工具,是 iproute2 软件包的一部分。它与已弃用的 netstat 工具具有相似的功能。

一般的用途包括:

显示所有 TCP 连接及相应的服务名:

$ ss -at

显示所有 TCP 连接及其端口号:

$ ss -atn

显示所有 UDP 连接:

$ ss -au

更多信息请参阅 ss(8)

疑难解答[编辑 | 编辑源代码]

TCP窗口扩缩(window scaling)故障[编辑 | 编辑源代码]

TCP 包头有个“窗口”(window)值表明其它主机可以发送多少数据回来。这个值只有16个bit,也就是说窗口大小最多只有 64KiB。TCP包会被缓存一段时间( 它们要重新排序),如果内存有限(过去经常是)的话,主机会很容易用完内存。

回到 1992 年,内存逐渐增加,RFC 1323 被发布以改善情况:窗口扩缩(Window Scaling)。所有包里的窗口值,可以被初始连接时定义的一个缩放因子(Scale Factor)所改变。8bit 的缩放因子使得窗口可以是初始 64KiB 的 32 倍。

但是 Internet 上有些有故障的路由器和防火墙会将缩放因子重写为 0,这导致主机之间产生误解。Linux内核 2.6.17 引入了新的计算方式生成更高的缩放因子,间接的使得这些有故障的路由器和防火墙引发的后果更明显。

这导致连接缓慢甚至中断。

如何诊断故障[编辑 | 编辑源代码]

首先,我们要明白:这个问题很怪异。在某些案例中,你根本无法使用(HTTP, FTP, ...),而有时候,你可以连接某些主机(很罕见)。

当你碰到这个故障时,dmesg 的输出正确,日志也没问题,ip addr 报告状态正常……实际上一切看起来都很正常。

如果你无法浏览任何网站,不过你能 ping 通某些主机,很可能你是遇到了这个问题:ping 使用 ICMP 协议所以不受 TCP 问题的影响。

你可以尝试使用 Wireshark。你也许会看到 UDP 和 ICMP 通讯成功,但是 TCP 通讯不成功(仅对外部主机)。

如何修复[编辑 | 编辑源代码]

糟糕的方法[编辑 | 编辑源代码]

用比较糟糕的方法修复的话,你可以修改缩放因子计算所基于的 tcp_rmem 值。虽然它对大部分主机有效,但并不担保一定都有效,特别是某些很远的主机。

# echo "4096 87380 174760" > /proc/sys/net/ipv4/tcp_rmem
好点的方法[编辑 | 编辑源代码]

只需要禁止窗口缩放。虽然窗口缩放是个不错的TCP特性,但它也可能令人不安,特别是当你没法修改出了问题的路由器的时候。有几种方法可以禁止窗口缩放,而看来最可靠的(适用于大部分内核)是将下面一行加入到你的 /etc/sysctl.d/99-disable_window_scaling.conf 中 (参见 sysctl):

net.ipv4.tcp_window_scaling = 0
最佳的方法[编辑 | 编辑源代码]

这个故障是由有毛病的路由器/防火墙引起的,所以最好换了它。有些用户报告说那些有故障的路由是他们自己的 DSL 路由。

更多[编辑 | 编辑源代码]

本段内容是基于 LWN文章 TCP window scaling and broken routers 和一篇 Kernel Trap 文章:Window Scaling on the Internet

在 LKML 上也有几篇相关的帖子。

连接第二台电脑后无法进行桥接[编辑 | 编辑源代码]

第一台电脑有两个 LAN 口。第二台电脑有一个 LAN 口并连接到第一台电脑。让第二台电脑桥接网络接口并可以访问 LAN 口:

# sysctl net.bridge.bridge-nf-filter-pppoe-tagged=0
# sysctl net.bridge.bridge-nf-filter-vlan-tagged=0
# sysctl net.bridge.bridge-nf-call-ip6tables=0
# sysctl net.bridge.bridge-nf-call-iptables=0
# sysctl net.bridge.bridge-nf-call-arptables=0

本地主机名解析[编辑 | 编辑源代码]

systemdmyhostname Name Service Switch (NSS) 模块提供localhost 和本地域名到 IP 地址的解析,默认是启用的。

然而一些客户端应用仍然会依赖于 /etc/hosts,相关例子参见 [5] [6]

要阻止程序通过网络非安全的解析 localhost,请将 localhost 加入 hosts(5) 文件:

/etc/hosts
127.0.0.1        localhost
::1              localhost
注意: Report any software affected by this issue in FS#56684. This may help in getting localhost entries added to the default /etc/hosts.

要配置 /etc/hosts,将以下内容加入其中:

127.0.0.1        localhost
::1              localhost
127.0.0.1        myhostname.localdomain        myhostname
注意: /etc/hosts 中在 IP 地址后的主机名或别名的顺序是重要的。第一个字符串会被认为是标准主机名,其后可以加上以点逐级分隔的上级域名(也就是上面的 .localdomain)。所有同一行中其后的字符串都被认为是别名。更多信息请参阅 hosts(5)

这样系统就会解析每条配置:

$ getent hosts
127.0.0.1       localhost
127.0.0.1       localhost
127.0.0.1       myhostname.localdomain myhostname

对于有固定 IP 地址的系统,应该用固定 IP 地址替换 127.0.0.1。For a system with a fully qualified domain name, insert the fully qualified domain name before the hostname (see the following link for the reasoning). For example:

/etc/hosts
127.0.0.1        localhost
::1              localhost
203.0.113.45     host1.fqdomain.example host1
注意: The order of hostnames/aliases that follow the IP address in /etc/hosts is significant. The first string is considered the canonical hostname and may be appended with parent domains, where domain components are separated by a dot. All following strings on the same line are considered aliases. See hosts(5) for more info.

As a result the system resolves to both entries:

$ getent hosts
127.0.0.1       localhost
127.0.0.1       localhost
127.0.0.1       myhostname

扩展阅读[编辑 | 编辑源代码]