web-dev-qa-db-ja.com

VethがLinuxネットワーキングブリッジで送信パケットを送信できない

Ubuntu 18.04で作成したLinuxネットワークブリッジがインターネットにアクセスできないという問題が発生しています。 Linuxにアプリケーションを実行したいネットワーク名前空間があります。このアプリケーションでアウトバウンドパケットをインターネットに送信できるようにしたいと考えています。そのため、vethペアをセットアップし、ピアをネットワーク名前空間内に配置します。 Veth1はホストマシン/デフォルトネットワーク名前空間上のvethであり、veth2はカスタムネットワーク名前空間内のveth(テスト)です。次に、ホストにLinuxブリッジをセットアップし、veth1を追加しました。これを実現するために実行したコマンドは次のとおりです。

# Create namespace.
ip netns add test

# Put up loopback interface.
ip netns exec test ip link set lo up

# Create veth pair.
ip link add veth1 type veth peer name veth2

# Put veth2 inside namespace.
ip link set veth2 netns test

# Add IP address to veth2 inside namespace.
ip netns exec test ip addr add 172.20.0.2/16 dev veth2

# Put veth2 up.
ip netns exec test ip link set veth2 up

# Delete default route in namespace.
ip netns exec test ip route delete default

# Add veth2 to default route in namespace.
ip netns exec test ip route add default dev veth2

# Create bridge br0.
ip link add br0 type bridge

# Add veth1 to bridge (I've also tried 'brctl addif br0 veth1').
ip link set veth1 master br0

# Add IP to br0.
ip addr add 172.20.0.1/16 dev br0

# Put br0 up.
ip link set br0 up

最初は、私が作成していないアプリケーションでこれを動作させるようにしようとしていました。アプリケーションは、ネットワークネームスペース内のveth2インターフェースを介してアウトバウンドパケットを送信していました。これがデフォルトルートであるためです。ただし、送信したのはARP要求(誰が持っているか)だけであり、いかなる種類の応答も受信していません。したがって、AF_PACKETソケットを使用する独自のCプログラムを作成することにしました。 ここ は、不思議に思う人のためのコードです。それが行うのは、特定のインターフェースにバインドすることと、コマンドラインで指定された宛先に空のUDPパケットを送信することだけです。また、コマンドラインでソースIPを設定できるようにしました。もう1つ注意したいのは、プログラムがゲートウェイのMACアドレスを取得し、それをイーサネットヘッダーの宛先MACとして使用することです(宛先MACを何に設定し、それをゲートウェイに設定するかを確認できませんでした) ARPリクエストはネットワーク外のIPに送信されるべきではないため、MACアドレスは機能するはずです。

このようなネットワーク名前空間内でプログラムを実行すると:

ip netns exec test ./test_veth veth2 10.50.0.11 10.50.0.3

トラフィックが10.50.0.3に到達することはありません。 tcpdump経由でveth1br0のトラフィックを確認できます。 br0の例を次に示します。

root@netvm02:/home/roy# tcpdump -i br0 -nne
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on br0, link-type EN10MB (Ethernet), capture size 262144 bytes
14:29:13.928570 42:7d:2a:5e:8c:78 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 42: 10.50.0.11.15000 > 10.50.0.3.25000: UDP, length 0
14:29:14.928741 42:7d:2a:5e:8c:78 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 42: 10.50.0.11.15000 > 10.50.0.3.25000: UDP, length 0
14:29:15.928957 42:7d:2a:5e:8c:78 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 42: 10.50.0.11.15000 > 10.50.0.3.25000: UDP, length 0
14:29:16.929181 42:7d:2a:5e:8c:78 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 42: 10.50.0.11.15000 > 10.50.0.3.25000: UDP, length 0
14:29:17.929412 42:7d:2a:5e:8c:78 > 00:00:00:00:00:00, ethertype IPv4 (0x0800), length 42: 10.50.0.11.15000 > 10.50.0.3.25000: UDP, length 0

デフォルトのネットワーク名前空間内でプログラムを実行し、vethに接続すると、br0のトラフィックが表示されることはありません。これは、私のプログラムが宛先MACをゲートウェイに設定していることが原因である可能性があります。

root@netvm02:/home/roy# tcpdump -i veth1 -nne
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on veth1, link-type EN10MB (Ethernet), capture size 262144 bytes
14:30:58.397476 02:a2:0f:2a:7b:bf > 78:8a:20:ba:e1:f9, ethertype IPv4 (0x0800), length 42: 10.50.0.11.15000 > 10.50.0.3.25000: UDP, length 0
14:30:59.397707 02:a2:0f:2a:7b:bf > 78:8a:20:ba:e1:f9, ethertype IPv4 (0x0800), length 42: 10.50.0.11.15000 > 10.50.0.3.25000: UDP, length 0
14:31:00.398022 02:a2:0f:2a:7b:bf > 78:8a:20:ba:e1:f9, ethertype IPv4 (0x0800), length 42: 10.50.0.11.15000 > 10.50.0.3.25000: UDP, length 0
14:31:01.398295 02:a2:0f:2a:7b:bf > 78:8a:20:ba:e1:f9, ethertype IPv4 (0x0800), length 42: 10.50.0.11.15000 > 10.50.0.3.25000: UDP, length 0
14:31:02.398544 02:a2:0f:2a:7b:bf > 78:8a:20:ba:e1:f9, ethertype IPv4 (0x0800), length 42: 10.50.0.11.15000 > 10.50.0.3.25000: UDP, length 0

プログラムをbr0にも接続しようとしましたが、10.50.0.3はまだトラフィックを認識しません。したがって、ブリッジに問題があると想定しています。

メインインターフェース(この場合はens18)に接続すると、10.50.0.3でトラフィックを確認できます。

root@test02:/home/roy# tcpdump -i any Host 10.50.0.11 and udp -nne
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
22:17:59.964569  In 78:8a:20:ba:e1:f9 ethertype IPv4 (0x0800), length 58: 10.50.0.11.15000 > 10.50.0.3.25000: UDP, length 0
22:18:00.964726  In 78:8a:20:ba:e1:f9 ethertype IPv4 (0x0800), length 58: 10.50.0.11.15000 > 10.50.0.3.25000: UDP, length 0
22:18:01.965059  In 78:8a:20:ba:e1:f9 ethertype IPv4 (0x0800), length 58: 10.50.0.11.15000 > 10.50.0.3.25000: UDP, length 0
22:18:02.965271  In 78:8a:20:ba:e1:f9 ethertype IPv4 (0x0800), length 58: 10.50.0.11.15000 > 10.50.0.3.25000: UDP, length 0
22:18:03.965544  In 78:8a:20:ba:e1:f9 ethertype IPv4 (0x0800), length 58: 10.50.0.11.15000 > 10.50.0.3.25000: UDP, length 0

また、物理インターフェイス(ens18)をbrctl(bridge-utils)を介してブリッジに追加してみました。

brctl addif br0 ens18

これにより、VMはパケットを送信できず、VMへの接続が失われます。

私は172.20.0.0/16br0の両方のインターフェースをマスカレードしてみました:

iptables -t nat -A POSTROUTING -s 172.20.0.0/16 -j MASQUERADE
iptables -t nat -A POSTROUTING -o br0 -j MASQUERADE

残念ながら、どちらも機能しませんでした。奇妙なのはプログラムを実行しているときです。iptables -t nat -L -n -vを実行しているときに、これらのルールによって処理されているパケットが表示されません。

Chain POSTROUTING (policy ACCEPT 5 packets, 355 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 MASQUERADE  all  --  *      *       172.20.0.0/16        0.0.0.0/0
    0     0 MASQUERADE  all  --  *      br0     0.0.0.0/0            0.0.0.0/0

また、プログラムのソースIPを172.20.0.2に設定して、最初のルールがパケットを処理するかどうかを確認しました。残念ながらそうではありませんでした。

net.ipv4.ip_forward1経由でsysctl net.ipv4.ip_forward=1に設定することも試みました。私もこれで運がありませんでした。

IPTablesで試した転送ルールは次のとおりです。

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
    0     0 ACCEPT     all  --  A      A       0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  br0    br0     0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  br0    !br0    0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED
    0     0 ACCEPT     all  --  A      br0     0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  br0    A       0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  ens18  br0     0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  br0    ens18   0.0.0.0/0            0.0.0.0/0

これらの多くはおそらく役に立たないことは知っていますが、それらが何らかの違いを生むかどうかを確認するためだけに試みていました。

以下は、完全なifconfigなどを含む追加情報です。

root@netvm02:/home/roy# ifconfig
veth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        ether 02:a2:0f:2a:7b:bf  txqueuelen 1000  (Ethernet)
        RX packets 3655  bytes 154906 (154.9 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 2380  bytes 101548 (101.5 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.20.0.1  netmask 255.255.0.0  broadcast 0.0.0.0
        inet6 fe80::185a:96ff:fe62:d174  prefixlen 64  scopeid 0x20<link>
        ether 02:a2:0f:2a:7b:bf  txqueuelen 1000  (Ethernet)
        RX packets 726  bytes 55088 (55.0 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 276  bytes 12624 (12.6 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

ens18: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.50.0.11  netmask 255.255.255.0  broadcast 10.50.0.255
        inet6 fe80::e087:deff:fe1f:d504  prefixlen 64  scopeid 0x20<link>
        ether e2:87:de:1f:d5:04  txqueuelen 1000  (Ethernet)
        RX packets 1423812  bytes 306465717 (306.4 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1694988587  bytes 2103526747383 (2.1 TB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<Host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 2436  bytes 223919 (223.9 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 2436  bytes 223919 (223.9 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

root@netvm02:/home/roy# ip netns exec test ifconfig
veth2: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.20.0.2  netmask 255.255.0.0  broadcast 0.0.0.0
        inet6 fe80::407d:2aff:fe5e:8c78  prefixlen 64  scopeid 0x20<link>
        ether 42:7d:2a:5e:8c:78  txqueuelen 1000  (Ethernet)
        RX packets 2380  bytes 101548 (101.5 KB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 3677  bytes 155830 (155.8 KB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<Host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

root@netvm02:/home/roy# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope Host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope Host
       valid_lft forever preferred_lft forever
2: ens18: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether e2:87:de:1f:d5:04 brd ff:ff:ff:ff:ff:ff
    inet 10.50.0.11/24 brd 10.50.0.255 scope global dynamic ens18
       valid_lft 80490sec preferred_lft 80490sec
    inet6 fe80::e087:deff:fe1f:d504/64 scope link
       valid_lft forever preferred_lft forever
4: veth1@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br0 state UP group default qlen 1000
    link/ether 02:a2:0f:2a:7b:bf brd ff:ff:ff:ff:ff:ff link-netnsid 0
5: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 02:a2:0f:2a:7b:bf brd ff:ff:ff:ff:ff:ff
    inet 172.20.0.1/16 scope global br0
       valid_lft forever preferred_lft forever
    inet6 fe80::185a:96ff:fe62:d174/64 scope link
       valid_lft forever preferred_lft forever

root@netvm02:/home/roy# ip netns exec test ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope Host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope Host
       valid_lft forever preferred_lft forever
3: veth2@if4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 42:7d:2a:5e:8c:78 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.20.0.2/16 scope global veth2
       valid_lft forever preferred_lft forever
    inet6 fe80::407d:2aff:fe5e:8c78/64 scope link
       valid_lft forever preferred_lft forever


root@netvm02:/home/roy# ip route
default via 10.50.0.1 dev ens18 proto dhcp src 10.50.0.11 metric 100
10.50.0.0/24 dev ens18 proto kernel scope link src 10.50.0.11
10.50.0.1 dev ens18 proto dhcp scope link src 10.50.0.11 metric 100
172.20.0.0/16 dev br0 proto kernel scope link src 172.20.0.1

root@netvm02:/home/roy# ip netns exec test ip route
default dev veth2 scope link
172.20.0.0/16 dev veth2 proto kernel scope link src 172.20.0.2

root@netvm02:/home/roy# brctl show
bridge name     bridge id               STP enabled     interfaces
br0             8000.02a20f2a7bbf       no              veth1

さらに、10.50.0.1110.50.0.3は、ProxMoxを実行しているホームサーバー上のVMです。メインインターフェイス(ens18)でDHCPを使用していますが、エッジルーターからの静的IPマッピングがあります。

これまでブリッジやベスをいじっていなかったので、おそらく何か足りないことがあるでしょう。

br0からのトラフィックがインターネットに到達できるようにしたいだけです。上記では、ローカルネットワークの接続をテストしていますが、実行する予定のアプリケーションは、ネットワーク外のIPにパケットを送信します。

追加情報が必要な場合はお知らせください。

どんな助けも高く評価され、あなたの時間をありがとう!

2

別個のネットワーク名前空間を別のホストであるかのように扱う必要があり、vethペア間の接続を外部パケットが着信するラインとして扱う必要があるため、ルーティングをアクティブにする必要があります。メイン名前空間のiptablesは、PREROUTINGとPOSTROUTING、およびINPUTとOUTPUTのパケットを参照します。

したがって、送信関数をセットアップするには(eth0を外部インターフェースに置き換えます):

# Activate router functions
# Has side effects: e.g. net.ipv4.conf.all.accept_redirects=0,secure_redirects=1
# Resets ipv4 kernel interface 'all' config values to default for Host or ROUTER
# https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt
echo 1 > /proc/sys/net/ipv4/ip_forward
# Set a gateway for the 'inside' namespace
# You have to specify an ip which will be the next hop
# This ip must be on the network segment of the main namespace veth
ip netns exec test ip route add default via 172.20.0.1
# Masquerade outgoing connections (you can limit to tcp with `-p tcp`)
iptables -t nat -A POSTROUTING -s 172.20.0.1 -o eth0 -j MASQUERADE
# If default FORWARD policy is DROP
# Let packets move from the outward interface
# to the virtual ethernet pair and vice versa
iptables -A FORWARD -i eth0 -o br0 -j ACCEPT
iptables -A FORWARD -o eth0 -i br0 -j ACCEPT
# Setup a resolver (replace with your own DNS, does not work with a loopback resolver)
mkdir -p /etc/netns/test
echo nameserver dns-ip > /etc/netns/test/resolv.conf
# Maybe give it its own hosts file, to do edits
cp /etc/hosts /etc/netns/test/hosts

これでip netns exec test ping example.comでテストできます

1
Gerrit