Я столкнулся с проблемой, из-за которой сетевой мост Linux, созданный мной в Ubuntu 18.04, не может получить доступ к Интернету. У меня есть сетевое пространство имен в Linux, в котором я хочу запустить приложение. Я хочу, чтобы это приложение могло отправлять исходящие пакеты в Интернет. Поэтому я настраиваю veth-пару и помещаю однорангового узла в сетевое пространство имен. Veth1
является veth на хост-машине / сетевом пространстве имен по умолчанию и veth2
это veth внутри пользовательского сетевого пространства имён (test). Затем я установил мост 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-запросы (у кого есть), и он так и не получил никакого ответа. Поэтому я решил создать свою собственную программу на C, которая использует AF_PACKET
Розетки. Вот это код для всех, кому интересно. Все, что он делает, это привязывается к определенному интерфейсу и отправляет пустой пакет UDP в пункт назначения, указанный в командной строке. Я также сделал так, чтобы вы могли установить исходный IP-адрес в командной строке. Еще одна вещь, которую я хотел бы отметить, это программа извлекает MAC-адрес шлюза и использует его в качестве MAC-адреса назначения для заголовка Ethernet (я не был уверен, что установить MAC-адрес назначения и прочитать, установив его для шлюза. MAC-адрес должен работать, поскольку запросы ARP не должны идти на IP-адреса за пределами сети).
При выполнении программы внутри сетевого пространства имен следующим образом:
ip netns exec test ./test_veth veth2 10.50.0.11 10.50.0.3
Трафик никогда не достигает 10.50.0.3
. Я вижу движение на veth1
и br0
через tcpdump
. Вот пример 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
(мост-утилиты):
brctl addif br0 ens18
Это приводит к тому, что виртуальная машина не может отправлять исходящие пакеты, и соединение с виртуальной машиной теряется.
Я пытался замаскировать оба 172.20.0.0/16
и br0
интерфейс через:
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_forward
к 1
через 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.11
и 10.50.0.3
- это виртуальные машины на моем домашнем сервере, на которых работает ProxMox. Они используют DHCP на основных интерфейсах (ens18), но имеют статические сопоставления IP от моего пограничного маршрутизатора.
До этого я особо не возился с мостами или ветровиками, так что, вероятно, что-то мне не хватает.
Я просто хочу трафик от br0
чтобы иметь доступ к Интернету. Выше я тестирую соединения в своей локальной сети, но приложение, которое я планирую запустить, будет отправлять пакеты на IP-адреса за пределами сети.
Если вам нужна дополнительная информация, дайте мне знать!
Любая помощь приветствуется и спасибо за ваше время!
Вы должны рассматривать отдельное сетевое пространство имен, как если бы это был другой хост, а соединение между парой 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