有关使用Debian制作的路由器的调整

由于之前提及的文章中包含了MAC地址,为了谨慎起见,我将重新提及它。

前提 – 在中文中只需一种选项:

以前我用这样的方式,在迷你电脑上安装了Debian并制作了路由器。现在仍然在电脑上运行着路由器。

因为Minisforum的小型PC偶尔会出现存储错误或其他问题而重新挂载,变成只读模式,导致路由器无法正常工作,所以最终选择了之前仍在候选名单中的另一个Skynew IN-1购买。可惜在选择期间,它的价格上涨了?。

由于为必要的步骤和配置编写了脚本,所以迁移工作没有太多麻烦,能够轻松完成,这真是太好了。

問題出現了

或许以前就有了

    LAN側からIPv4が通らないことがある
    LAN側からpingするとIPv4が優先される

观察到了这个现象。

如果解决了IPv4在LAN方面无法传输的问题,即使LAN端优先选择IPv4也不会有困扰。但是既然已经支持IPv6,最好是通过IPv6进行通信。

总结来说

有时LAN侧无法通过IPv4连接。

【解决?】调整MTU值后,感觉问题解决了。

还需要再观察一下的话,虽然没法确定,但至少在调整之后尝试了几次 ping,问题都得到了解决。
以前经常会遇到尝试了几次 ping 之后无法收到回应的情况。

【问题】当从局域网一侧ping时,会优先选择IPv4版本。

通过修改gai.conf来解决了这个问题。

通过修改/etc/gai.conf文件,使IPv6在默认情况下具有优先权。

諳熟的内容稍后会提及。

查询的事情

首先设置了MAP-E之后,使用脚本在IPv4和IPv6上进行ping来确认连通性,但是在这过程中有时IPv4会失败。
尽管这个问题之前已经相当稳定了,但由于那次经历,如果有什么不对劲的感觉,就会习惯性地尝试ping来确认。

在这种情况下,我们观察到从局域网一侧ping打不回来,并且在这种情况下是由IPv4进行名称解析。

这是什么意思?

确认DNS相关内容。

在路由器上使用systemd-resolved作为DNS服务器。LAN侧基本上将DNS服务器设置为路由器的IP地址。在我的主要PC上的Ubuntu系统中,systemd-resolved作为存根解析器运行,并在那里指定了路由器的IP地址。

所以,/etc/resolv.conf文件本身被设置为127.0.0.53,但实际上是用于向路由器进行名称解析。

可以尝试输入以下命令验证其行为。

nslookup google.com
nslookup google.com 192.168.0.1
nslookup google.com fd00:0:dead:beef::1
dig A google.com
dig A google.com @192.168.0.1
dig A google.com @fd00:0:dead:beef::1
dig AAAA google.com
dig AAAA google.com @192.168.0.1
dig AAAA google.com @fd00:0:dead:beef::1
sudo resolvectl -p dns query google.com

无论是连接到 DNS 的 IPv4 还是 IPv6,这是关于 A 记录或 AAAA 记录的讨论,我确认在这里都顺利地返回了预期的 IPv4 和 IPv6。

敲击ping命令

ping google.com
ping -4 google.com
ping -6 google.com

虽然默认情况下是IPv4,但是在IPv4情况下,如果没有遇到问题,可以进行ping连接,而选择IPv6则可以顺利进行名称解析和ping连接。

当在路由器的电脑上进行这个操作时,即使默认设置下也能通过IPv6进行名称解析。

我试一试使用wget命令。

wget --no-proxy -O /dev/null https://www.google.com/

当名字解析时,显示了IPv4和IPv6,但实际上只使用了IPv4…… 当遇到无法通过IPv4连接的情况时,会超时,并成功通过IPv6进行通信。

拉齐不变红。

当以IPv6作为首选进行调查时,会发现已经有很多关于如何将优先选择设置为IPv6以及如何禁用IPv6的文章。
不对,不是那样的。

在中国本地,如果对localhost进行ping测试,会被解析成::1,所以并不意味着IPv6被优先选择。
虽然/etc/hosts中有记录,但并没有向DNS服务器查询。

有一个问题,感觉像是在某个地方丢失了数据包,因此ping请求无法返回。虽然尚不清楚是否是造成这个问题的原因,但似乎存在着所谓的Path MTU Discovery黑洞问题。

用wireshark或者其他工具来分析数据包,可以了解到这种情况吗?虽然我有读过HTTP等明文数据包的经验……

我在网上搜索了很多,尝试了很多方法,但是完全没有解决问题。

结果 (jié guǒ)

首先,从IPv6优先的方面开始考虑

因为只有ULA,所以我认为IPv4被优先使用,我试着在ip命令中分配适合全局地址前缀的IPv6地址,结果ping时开始使用IPv6。
一旦这样,问题就很简单了,只需查找如何使ULA优先于IPv4的方法即可。

参考这个方向,在/etc/gai.conf中写下以下内容。

label fc00::/7 1
precedence fc00::/7 40
precedence ::ffff:0:0/96 1

使用该选项,IPv6将成为首选,并且IPv6环境确认网站的情况也很好。

image.png

接下来我们来讨论IPv4通信失败的情况。

由于IPv6的最小传输单元(MTU)为1280,因此将WAN侧设备的MTU和IPv4隧道设备的MTU设置为1280。目前还没有观察到设置后ping无法返回的情况,但是否可行作为解决方法尚不明确。如果可以增加MTU的值,较大的数值更好……

因为使用MAP-E进行IPv4通信,我认为实际物理网卡通过IPv6进行通信,所以将那部分的MTU设置为1280,以解决IPv4引起的问题不会感到特别不自然。

不过,我对这方面不太了解,如果有巧妙的设置,我很想知道……
(然而,我对于这方面不是很了解,如果有一些巧妙的设置,我很想知道……)

顺便提一下,原本是100Mbps的公寓VDSL网络,即使将MTU设置为1280,速度测试仍然保持在80至90Mbps左右,没有明显差异。

付録- Chinese translation options:

1. 附件 (fù lù)
2. 附录 (fù lù)
3. 附属品 (fù shǔ

前面的脚本“add-rules”已根据以下内容进行了修改:

#!/bin/bash

function finish() {
  cd - > /dev/null 2>&1
  exit $1
}

cd $(dirname "$0")

NODE_PATH=$(which node)
if [ $? -ne 0 ]; then
  echo $NODE_PATH
  finish 1
fi

# LAN側のNIC
LAN_DEV=enp3s0
# WAN側のNIC
WAN_DEV=enp4s0
# TUNNELデバイス
TUN_DEV=tun0

# トンネルデバイスは落とす
ip link set $TUN_DEV down

# IPv6
WAN_IPv6=$(ip -6 addr show dev "$WAN_DEV" | grep inet6 | grep -v "inet6 fe" | sed -e 's/^ *inet6 \([^ ]*\).*/\1/')

# pppoeを落としておく
poff -a > /dev/null 2>&1

NODE_RET=$(node ./map-e.js "$WAN_IPv6")
if [ $? -ne 0 ]; then
    echo "$NODE_RET"
    finish 2
fi

echo $NODE_RET
eval "$NODE_RET"
# echo $BR
# echo $CE
# echo $IPv4
# echo $PSID

cat << YAML > /etc/netplan/00-init.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    # LAN
    ${LAN_DEV}:
      dhcp4: false
      dhcp6: true
      accept-ra: true
      mtu: 1500
      addresses:
        - 192.168.0.1/24
        - fd00:0:dead:beef::1/64
      match:
        macaddress: 00:00:00:00:00:00
      set-name: enp3s0
    # WAN
    ${WAN_DEV}:
      dhcp4: false
      dhcp6: true
      accept-ra: true
      optional: true
      mtu: 1280
      addresses:
        - ${CE}/64
      match:
        macaddress: 00:00:00:00:00:00
      set-name: enp4s0
      nameservers:
        addresses:
          - 2001:4860:4860::8888
          - 2001:4860:4860::8844
YAML

# cat /etc/netplan/00-init.yaml

cat << YAML > /etc/netplan/10-ipoe-gw.yaml
network:
  version: 2
  tunnels:
    ${TUN_DEV}:
      mode: ipip6
      accept-ra: true
      local: ${CE}
      remote: ${BR}
      mtu: 1280
      addresses:
        - ${IPv4}/32
      routes:
        - to: 0.0.0.0/0
          scope: link
YAML

# cat /etc/netplan/10-ipoe-gw.yaml

netplan generate

sleep 1

ip addr flush ${TUN_DEV}
ip link set ${TUN_DEV} down && ip link set ${TUN_DEV} up
ip -4 route delete default dev ${TUN_DEV}
ip -4 route add default dev ${TUN_DEV}
ip -6 tunnel change ${TUN_DEV} encaplimit none

iptables -t nat -F

rule=1
while [ $rule -lt 16 ]; do
  mark=$(($rule + 16))
  pn=$(($rule - 1))
  port_l=$(($rule * 4096 + $PSID * 16))
  port_r=$(($port_l + 15))

  iptables -t nat -A PREROUTING -m statistic --mode nth --every 15 --packet $pn -j MARK --set-mark $mark
  iptables -t nat -A OUTPUT -m statistic --mode nth --every 15 --packet $pn -j MARK --set-mark $mark

  iptables -t nat -A POSTROUTING -p icmp -o $TUN_DEV -m mark --mark $mark -j SNAT --to $IPv4:$port_l-$port_r
  iptables -t nat -A POSTROUTING -p tcp -o $TUN_DEV -m mark --mark $mark -j SNAT --to $IPv4:$port_l-$port_r
  iptables -t nat -A POSTROUTING -p udp -o $TUN_DEV -m mark --mark $mark -j SNAT --to $IPv4:$port_l-$port_r

  rule=$(($rule + 1))
done

iptables -t mangle -F
iptables -t mangle -o $TUN_DEV --insert FORWARD 1 -p tcp --tcp-flags SYN,RST SYN -m tcpmss --mss 1400:65495 -j TCPMSS --clamp-mss-to-pmtu

finish 0

呼出此脚本的语法如下所示。

#!/bin/bash

# OSブート時に実行されるスクリプト
# rootユーザーによって実行される想定

function writelog() {
  LOG_PATH=/dev/shm/startup.log
  echo "[$(date "+%Y-%m-%d %H:%M:%S")] $1" >> $LOG_PATH
}

writelog "start-up スクリプトを始します"

cd $(dirname "$0")

TRY=0
RETRY_MAX=5
while [ true ]; do
  writelog "map-e の適用処理を開始します"
  # MAP-E適用
  writelog "$(../map-e/add-rules 2>&1)"
  netplan apply

  writelog "www.iijmio.jp へ IPv4 PING を送信します"
  ping -4 -n -c3 -W1 www.iijmio.jp > /dev/null 2>&1
  IIJMIO_IPv4_PING=$?
  writelog "www.iijmio.jp へ IPv6 PING を送信します"
  ping -6 -n -c3 -W1 www.iijmio.jp > /dev/null 2>&1
  IIJMIO_IPv6_PING=$?

  writelog "google.com へ IPv4 PING を送信します"
  ping -4 -n -c3 -W1 google.com > /dev/null 2>&1
  GOOGLE_IPv4_PING=$?
  writelog "google.com へ IPv6 PING を送信します"
  ping -6 -n -c3 -W1 google.com > /dev/null 2>&1
  GOOGLE_IPv6_PING=$?

  IPv4_OK=0
  IPv6_OK=0

  if [ $IIJMIO_IPv4_PING -eq 0 -o $GOOGLE_IPv4_PING -eq 0 ]; then
    IPv4_OK=1
  fi
  if [ $IIJMIO_IPv6_PING -eq 0 -o $GOOGLE_IPv6_PING -eq 0 ]; then
    IPv6_OK=1
  fi

  if [ $IPv4_OK -eq 1 -a $IPv6_OK -eq 1 ]; then
    writelog "PING 確認が成功しました! ($(($TRY + 1))回試行)"
    writelog "ping result (www.iijmio.jp):        $IIJMIO_IPv4_PING"
    writelog "ping result (www.iijmio.jp [IPv6]): $IIJMIO_IPv6_PING"
    writelog "ping result (google.com):           $GOOGLE_IPv4_PING"
    writelog "ping result (google.com [IPv6]):    $GOOGLE_IPv6_PING"
    break
  else
    if [ $TRY -ge $RETRY_MAX ]; then
      writelog "PING 確認に失敗しました"
      writelog "start-up スクリプトを停止します"
      echo "$(
        echo "ルーター起動スクリプトエラー"
        echo
        echo "map-eの設定に失敗しました"
        echo "ping result (www.iijmio.jp):        $IIJMIO_IPv4_PING"
        echo "ping result (www.iijmio.jp [IPv6]): $IIJMIO_IPv6_PING"
        echo "ping result (google.com):           $GOOGLE_IPv4_PING"
        echo "ping result (google.com [IPv6]):    $GOOGLE_IPv6_PING"
      )" | mail -s "ルーター起動スクリプトエラー" -a "From:alert@example.com" "$STARTUP_MAILTO"
      exit 1
    fi
    writelog "$(($TRY + 1))回目失敗"
    writelog "IPv4_OK: $IPv4_OK"
    writelog "IPv6_OK: $IPv6_OK"
    if [ $TRY -lt $RETRY_MAX ]; then
      sleep $((2 ** $TRY))
    fi
  fi

  TRY=$(($TRY + 1))
done

writelog "start-up スクリプトの全行程が完了いたしました"

我认为在add-rules的一边执行netplan apply会更好,因为之前一直都是在不同方面进行尝试,但最终还是保持了在exec方面的netplay apply操作。

据推测,IPv4的ping失败是由于无法连接到已解决的IPv4案例所引起的,因此应该不需要进行重新尝试处理,但如果一次能成功就结束那就没有问题,所以将其保留不变。


那么,祝您度过愉快的Debian生活。

bannerAds