Туннелирование и частные сети

Туннелирование: использование некоторого потока данных для инкапсуляции (в общем случае — произвольного) сетевого трафика.

Простейший туннель: IP over IP

Замечание в сторону: SRv6 в действительности тоже решает похожую задачу: можно прицельно доставлять пакеты до определённого узла, а вторым узлом в заголовке (SRH) указать актуального адресата. Однако для собственно туннелирования SRv6 обычно не используется (можно поэкспериментировать самому).

TODO Заменить «поверх» (в значении «over») в тексте на «внутри» (хотя это и почти антонимы, но ассоциация с «поверхность» сильно сбивает с толку).

Использование

IP6 over IP6 — это как-то скучно! Ради большей наглядности пустим IP4 поверх IP6.

Обычная схема:

[root@router ~]# sysctl net.ipv{6,4}.conf.all.forwarding
net.ipv6.conf.all.forwarding = 1
net.ipv4.conf.all.forwarding = 0

Настроим передачу IPv4 в тоннеле:

[root@client ~]# ip -6 -br a show scope global
eth1             UP             2a00:f480:8:cc5:a00:27ff:fe1a:ffa/64 
[root@client ~]# ip link add name over0 type ip6tnl mode ipip6 local 2a00:f480:8:cc5:a00:27ff:fe1a:ffa remote 2a00:f480:8:cde:a00:27ff:fee3:f50e
[root@client ~]# ip link set over0 up
[root@client ~]# ip a add 10.50.0.1/24 dev over0
# это IPv4; здесь весь префикс on-link, и назначился маршрут на over0
[root@client ~]# ip -d link show over0
<...>

[root@srv ~]# ip -6 -br a
lo               UNKNOWN        ::1/128 
eth1             UP             2a00:f480:8:cde:a00:27ff:fee3:f50e/64 fe80::a00:27ff:fee3:f50e/64 
[root@srv ~]# ip tunnel add over0 mode ipip6 local 2a00:f480:8:cde:a00:27ff:fee3:f50e remote 2a00:f480:8:cc5:a00:27ff:fe1a:ffa
[root@srv ~]# ip link set over0 up
[root@srv ~]# ip a add 10.50.0.2/24 dev over0 
# это IPv4; здесь весь префикс on-link, и назначился маршрут на over0
[root@srv ~]# ip -d link show over0
<...>

Ядро Linux приписывает к внешнему заголовку destination option "Tunnel Encap Limit" rfc2473, равный 4.

TODO Даже tshark тянет over 120 Мб собственной библиотеки. Предложить скачать результат запуска tcpdump -w и посмотреть на хосте с помощью хостового wireshark?

Паста из wireshark:

Frame 1: Packet, 146 bytes on wire (1168 bits), 146 bytes captured (1168 bits)
Ethernet II, Src: PCSSystemtec_1a:0f:fa (08:00:27:1a:0f:fa), Dst: PCSSystemtec_d7:92:2a (08:00:27:d7:92:2a)
    Destination: PCSSystemtec_d7:92:2a (08:00:27:d7:92:2a)
    Source: PCSSystemtec_1a:0f:fa (08:00:27:1a:0f:fa)
    Type: IPv6 (0x86dd)
Internet Protocol Version 6, Src: 2a00:f480:8:cc5:a00:27ff:fe1a:ffa, Dst: 2a00:f480:8:cde:a00:27ff:fee3:f50e
    0110 .... = Version: 6
    .... 0000 0000 .... .... .... .... .... = Traffic Class: 0x00 (DSCP: CS0, ECN: Not-ECT)
    .... 0001 1011 0001 1000 1110 = Flow Label: 0x1b18e
    Payload Length: 92
    Next Header: Destination Options for IPv6 (60)
    Hop Limit: 64
    Source Address: 2a00:f480:8:cc5:a00:27ff:fe1a:ffa
    Destination Address: 2a00:f480:8:cde:a00:27ff:fee3:f50e
    [Source SLAAC MAC: PCSSystemtec_1a:0f:fa (08:00:27:1a:0f:fa)]
    [Destination SLAAC MAC: PCSSystemtec_e3:f5:0e (08:00:27:e3:f5:0e)]
    Destination Options for IPv6
        Next Header: IPIP (4)
        Length: 0
        [Length: 8 bytes]
        Tunnel Encapsulation Limit
            Type: Tunnel Encapsulation Limit (0x04)
            Length: 1
            Tunnel Encapsulation Limit: 4
        PadN
            Type: PadN (0x01)
            Length: 1
            PadN: 00
Internet Protocol Version 4, Src: 10.50.0.1, Dst: 10.50.0.2
Internet Control Message Protocol

Среди опций для узла назначения:

Проверим, что туннель работает

зарежем TCP на router:

Какой-нибудь date | netcat 10.50.0.242 80 должен продолжать работать (потому что через router проходит не TCP, а IP)

Недостатки

TODO разъяснить: over0 — «не совсем настоящий» интерфейс (только p2p, без MAC и т. п.)

IP6 over TCP «на скорую руку» с socat

В socat есть работа с tun/tap устройствами. Буквально в одну строку из них делается полноценный тоннель:

[root@srv ~]# socat TCP6-LISTEN:1337,fork,reuseaddr TUN,tun-name=cli0,up </dev/null &

и

[root@client ~]# socat TCP:сервер:1337 TUN,tun-name=srv0,up </dev/null &

Результат:

[root@srv ~]# ip -6 -br a show dev cli0
cli0             UNKNOWN        fe80::e89a:f475:389f:48cd/64 

[root@client ~]# ip -6 r show dev srv0
fe80::/64 proto kernel metric 256 pref medium

[root@client ~]# ping -c2 fe80::e89a:f475:389f:48cd%srv0
PING fe80::e89a:f475:389f:48cd%srv0 (fe80::e89a:f475:389f:48cd%srv0) 56 data bytes
64 bytes from fe80::e89a:f475:389f:48cd%srv0: icmp_seq=1 ttl=64 time=0.338 ms
64 bytes from fe80::e89a:f475:389f:48cd%srv0: icmp_seq=2 ttl=64 time=0.339 ms

--- fe80::e89a:f475:389f:48cd%srv0 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 0.338/0.338/0.339/0.000 ms

* посмотреть tcpdump на router

l2tp — фреймы в IP или UDP

TODO В идеале — вообще не использовать IP-адреса, а прокинуть что-то, чему нужен непосредственно L2. Если не получится — всё-таки заменить IP4 на IP6.

Можно туннелировать не IP-пакеты, а фреймы — например, при помощи L2TP.

Всё по документации — скажем, с инкапсуляцией не в IP, а в UDP; и для простоты — без bridge

Особенности:

Виртуальный интерфейс l2tpeth можно добавить в bridge c локальным интерфейсом — тогда абоненты из туннелей окажутся в одном сегменте с абонентами локальной сети

WireGuard

Сайт, и конечно Arch-вики

Начальная настройка:

[root@srv ~]# cat /etc/systemd/network/50-intnet.network
[Match]
Name=eth1

[IPv6AcceptRA]
Token=::918

[root@router ~]# cat /etc/systemd/network/50-intnet.network
[Match]
Name=eth1

[Network]
IPv6SendRA=yes
Address=2a00:f480:8:e50::919/64

[IPv6Prefix]
Prefix=2a00:f480:8:e50::/64

[root@router ~]# cat /etc/systemd/network/60-deepnet.network
[Match]
Name=eth2

[Network]
IPv6SendRA=yes
Address=2a00:f480:8:e60::919/64

[IPv6Prefix]
Prefix=2a00:f480:8:e60::/64

[root@router ~]# cat /etc/systemd/networkd.conf
[Network]
IPv6Forwarding=yes

[root@client ~]# cat /etc/systemd/network/60-deepnet.network
[Match]
Name=eth1

[IPv6AcceptRA]
Token=::91a

Ручная настройка

Лайфхак для копипасты:

# wg genkey | tee /dev/stderr | wg pubkey

Для настройки вручную на сервере нужно

На клиенте:

[root@athena ~]# ip link add dev wg0 type wireguard
[root@athena ~]# ip a add 2a00:f480:8:b::a/64 dev wg0
[root@athena ~]# ip -br l
wg0              DOWN           <POINTOPOINT,NOARP> 
[root@srv ~]# ip link add dev wg0 type wireguard
[root@srv ~]# ip a add 2a00:f480:8:b::c/64 dev wg0
[root@srv ~]# ip -br l
wg0              DOWN           <POINTOPOINT,NOARP> 

[root@athena ~]# wg genkey | tee /etc/wireguard/secret.key | wg pubkey
FYmBjluPBjLW5YWjAdPGeaVKupiwGpkWepelFNKI5RE=
[root@athena ~]# chmod go-rwx /etc/wireguard/secret.key
[root@srv ~]# wg genkey | tee /etc/wireguard/secret.key | wg pubkey 
Qi5gNRivObZUEUWocQPAct5a7MQxOY6MrUPyyqGeMS8=
[root@srv ~]# chmod go-rwx /etc/wireguard/secret.key 

[root@srv ~]# wg set wg0 listen-port 51820 private-key /etc/wireguard/secret.key
[root@srv ~]# wg set wg0 peer 'FYmBjluPBjLW5YWjAdPGeaVKupiwGpkWepelFNKI5RE=' allowed-ips 2a00:f480:8::/48
[root@athena ~]# wg set wg0 private-key /etc/wireguard/secret.key 
# neither '2001:db8:0:c::91a' nor '[2001:db8:0:c::91a]' are sufficient as endpoint
[root@athena ~]# wg set wg0 peer 'Qi5gNRivObZUEUWocQPAct5a7MQxOY6MrUPyyqGeMS8=' endpoint '[2001:db8:0:c::91a]:51820' allowed-ips 2a00:f480:8::/48
[root@athena ~]# ip link set wg0 up
[root@srv ~]# ip link set wg0 up

Туннель установлен!

[root@athena ~]# ping -c4 -i0.4 2a00:f480:8:b::c 
PING 2a00:f480:8:b::c (2a00:f480:8:b::c) 56 data bytes
64 bytes from 2a00:f480:8:b::c: icmp_seq=1 ttl=64 time=9.39 ms
64 bytes from 2a00:f480:8:b::c: icmp_seq=2 ttl=64 time=2.53 ms
64 bytes from 2a00:f480:8:b::c: icmp_seq=3 ttl=64 time=2.80 ms
64 bytes from 2a00:f480:8:b::c: icmp_seq=4 ttl=64 time=2.84 ms

--- 2a00:f480:8:b::c ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 1204ms
rtt min/avg/max/mdev = 2.526/4.389/9.392/2.890 ms

Настройка средствами networkd

Для systemd-networkd:

Сервер:

Клиент:

Поля PublicKey = клиентасервера) заполняются из вывода wg pubkey < /etc/systemd/network/70-wg-private.key <!> на том хосте, чей ключ!

Д/З

wg — route encap/decap — наблюдатель — route encap/decap — wg

TODO: включить в конфиге ядра ALT MPLS-маршрутизацию

[root@athena ~]# ip route add 0.0.0.0/0 encap mpls 102 via inet6 2001:db8:0:a::919
[root@router ~]# ip -M route add 102 as 203 via inet6 2001:db8:0:c::91a
RTNETLINK answers: Operation not supported
[root@srv ~]# ip -M route add 203 dev lo
RTNETLINK answers: Operation not supported

LecturesCMC/LinuxNetwork2026/Six/11_TunnelingVPN (последним исправлял пользователь FrBrGeorge 2026-06-08 22:18:59)