ipipou: không chỉ là một đường hầm không được mã hóa

Chúng ta đang nói gì với Chúa của IPv6?

ipipou: không chỉ là một đường hầm không được mã hóa
Đúng vậy, ngày nay chúng ta cũng sẽ nói như vậy với vị thần mã hóa.

Ở đây chúng ta sẽ nói về một đường hầm IPv4 không được mã hóa, nhưng không phải về một “đèn ấm” mà là về một “đèn LED” hiện đại. Và cũng có các ổ cắm thô nhấp nháy ở đây và công việc đang được tiến hành với các gói trong không gian người dùng.

Có N giao thức đào hầm cho mọi sở thích và màu sắc:

  • phong cách, thời trang, trẻ trung Dây bảo vệ
  • đa chức năng, như dao Thụy Sĩ, OpenVPN và SSH
  • GRE già và không ác
  • IPIP đơn giản nhất, nhanh chóng, hoàn toàn không được mã hóa
  • tích cực phát triển GENEVA
  • nhiều người khác.

Nhưng tôi là một lập trình viên, vì vậy tôi sẽ chỉ tăng N lên một phần nhỏ và giao việc phát triển các giao thức thực sự cho các nhà phát triển Kommersant.

Trong một đứa trẻ chưa sinh dự ánNhững gì tôi đang làm bây giờ là tiếp cận các máy chủ đằng sau NAT từ bên ngoài. Sử dụng các giao thức với mật mã dành cho người lớn cho việc này, tôi không thể tránh khỏi cảm giác giống như bắn chim sẻ ra khỏi súng đại bác. Bởi vì đường hầm phần lớn chỉ được sử dụng để chọc thủng các lỗ hổng trong NAT-e, lưu lượng truy cập nội bộ thường cũng được mã hóa, nhưng chúng vẫn chìm trong HTTPS.

Trong khi nghiên cứu các giao thức đào hầm khác nhau, người theo chủ nghĩa hoàn hảo bên trong của tôi đã nhiều lần chú ý đến IPIP do chi phí tối thiểu của nó. Nhưng nó có một nhược điểm rưỡi đáng kể đối với nhiệm vụ của tôi:

  • nó yêu cầu IP công cộng ở cả hai bên,
  • và không có xác thực cho bạn.

Vì vậy, người cầu toàn bị đẩy lùi vào góc tối của hộp sọ, hoặc bất cứ nơi nào anh ta ngồi ở đó.

Và rồi một ngày, khi đang đọc bài viết trên đường hầm được hỗ trợ nguyên bản trong Linux, tôi đã gặp FOU (Foo-over-UDP), tức là. sao cũng được, được gói trong UDP. Cho đến nay, chỉ hỗ trợ IPIP và GUE (Đóng gói UDP chung).

“Đây là viên đạn bạc! Đối với tôi, một IPIP đơn giản là đủ.” - Tôi đã nghĩ.

Trên thực tế, viên đạn hóa ra không hoàn toàn bằng bạc. Đóng gói trong UDP giải quyết vấn đề đầu tiên - bạn có thể kết nối với các máy khách phía sau NAT từ bên ngoài bằng kết nối được thiết lập trước, nhưng ở đây một nửa nhược điểm tiếp theo của IPIP lại bộc lộ dưới ánh sáng mới - bất kỳ ai từ mạng riêng đều có thể ẩn đằng sau những gì có thể nhìn thấy được IP công cộng và cổng máy khách (trong IPIP thuần túy, vấn đề này không tồn tại).

Để giải quyết vấn đề nan giải này, tiện ích đã ra đời ipipou. Nó thực hiện một cơ chế tự tạo để xác thực một máy chủ từ xa mà không làm gián đoạn hoạt động của FOU kernel, cơ chế này sẽ xử lý các gói trong không gian kernel một cách nhanh chóng và hiệu quả.

Chúng tôi không cần kịch bản của bạn!

Ok, nếu bạn biết cổng công cộng và IP của máy khách (ví dụ: mọi người đằng sau nó không đi đâu cả, NAT cố gắng ánh xạ các cổng 1 trong 1), bạn có thể tạo đường hầm IPIP-over-FOU với theo các lệnh mà không có bất kỳ tập lệnh nào.

trên máy chủ:

# Подгрузить модуль ядра FOU
modprobe fou

# Создать IPIP туннель с инкапсуляцией в FOU.
# Модуль ipip подгрузится автоматически.
ip link add name ipipou0 type ipip 
    remote 198.51.100.2 local 203.0.113.1 
    encap fou encap-sport 10000 encap-dport 20001 
    mode ipip dev eth0

# Добавить порт на котором будет слушать FOU для этого туннеля
ip fou add port 10000 ipproto 4 local 203.0.113.1 dev eth0

# Назначить IP адрес туннелю
ip address add 172.28.0.0 peer 172.28.0.1 dev ipipou0

# Поднять туннель
ip link set ipipou0 up

trên máy khách:

modprobe fou

ip link add name ipipou1 type ipip 
    remote 203.0.113.1 local 192.168.0.2 
    encap fou encap-sport 10001 encap-dport 10000 encap-csum 
    mode ipip dev eth0

# Опции local, peer, peer_port, dev могут не поддерживаться старыми ядрами, можно их опустить.
# peer и peer_port используются для создания соединения сразу при создании FOU-listener-а.
ip fou add port 10001 ipproto 4 local 192.168.0.2 peer 203.0.113.1 peer_port 10000 dev eth0

ip address add 172.28.0.1 peer 172.28.0.0 dev ipipou1

ip link set ipipou1 up

đâu

  • ipipou* - tên của giao diện mạng đường hầm cục bộ
  • 203.0.113.1 - máy chủ IP công cộng
  • 198.51.100.2 - IP công khai của khách hàng
  • 192.168.0.2 - IP khách hàng được gán cho giao diện eth0
  • 10001 - cổng khách hàng cục bộ cho FOU
  • 20001 - cổng khách công cộng cho FOU
  • 10000 - cổng máy chủ công cộng cho FOU
  • encap-csum - tùy chọn thêm tổng kiểm tra UDP vào các gói UDP được đóng gói; có thể được thay thế bởi noencap-csum, chưa kể, tính toàn vẹn đã được kiểm soát bởi lớp đóng gói bên ngoài (trong khi gói ở bên trong đường hầm)
  • eth0 - giao diện cục bộ mà đường hầm ipip sẽ bị ràng buộc
  • 172.28.0.1 — IP của giao diện đường hầm máy khách (riêng tư)
  • 172.28.0.0 - Giao diện máy chủ đường hầm IP (riêng tư)

Miễn là kết nối UDP còn hoạt động, đường hầm sẽ hoạt động bình thường, nhưng nếu nó bị hỏng, bạn sẽ gặp may - nếu cổng IP: của khách hàng vẫn giữ nguyên - nó sẽ hoạt động, nếu họ thay đổi - nó sẽ bị hỏng.

Cách dễ nhất để khôi phục mọi thứ là dỡ bỏ các mô-đun hạt nhân: modprobe -r fou ipip

Ngay cả khi không cần xác thực, IP và cổng công cộng của máy khách không phải lúc nào cũng được biết và thường không thể đoán trước hoặc có thể thay đổi (tùy thuộc vào loại NAT). Nếu bạn bỏ qua encap-dport về phía máy chủ, đường hầm sẽ không hoạt động, không đủ thông minh để lấy cổng kết nối từ xa. Trong trường hợp này, ipipou cũng có thể trợ giúp hoặc WireGuard và những người khác tương tự có thể giúp bạn.

Nó hoạt động như thế nào?

Máy khách (thường nằm sau NAT) mở một đường hầm (như trong ví dụ trên) và gửi gói xác thực đến máy chủ để nó định cấu hình đường hầm ở phía bên của nó. Tùy thuộc vào cài đặt, đây có thể là một gói trống (chỉ để máy chủ có thể nhìn thấy IP công cộng: cổng kết nối) hoặc với dữ liệu mà máy chủ có thể nhận dạng máy khách. Dữ liệu có thể là một cụm mật khẩu đơn giản ở dạng văn bản rõ ràng (tương tự như HTTP Basic Auth) hoặc dữ liệu được thiết kế đặc biệt được ký bằng khóa riêng (tương tự như HTTP Digest Auth chỉ mạnh hơn, xem chức năng client_auth trong mã).

Trên máy chủ (phía có IP công cộng), khi ipipou khởi động, nó sẽ tạo một trình xử lý hàng đợi nfqueue và định cấu hình bộ lọc mạng để các gói cần thiết được gửi đến nơi cần đến: các gói khởi tạo kết nối đến hàng đợi nfqueue và [gần như] tất cả phần còn lại sẽ chuyển thẳng đến FOU của người nghe.

Đối với những người chưa biết, nfqueue (hoặc NetfilterQueue) là một điều đặc biệt dành cho những người nghiệp dư không biết cách phát triển các mô-đun hạt nhân, việc sử dụng netfilter (nftables/iptables) cho phép bạn chuyển hướng các gói mạng đến không gian người dùng và xử lý chúng ở đó bằng cách sử dụng có sẵn các phương tiện nguyên thủy: sửa đổi (tùy chọn) và đưa nó trở lại kernel hoặc loại bỏ nó.

Đối với một số ngôn ngữ lập trình có các ràng buộc để làm việc với nfqueue, đối với bash thì không có (heh, không có gì đáng ngạc nhiên), tôi phải sử dụng python: ipipou sử dụng Hàng đợi Netfilter.

Nếu hiệu suất không quan trọng, bằng cách sử dụng thứ này, bạn có thể tạo ra logic của riêng mình một cách tương đối nhanh chóng và dễ dàng để làm việc với các gói ở mức khá thấp, chẳng hạn như tạo các giao thức truyền dữ liệu thử nghiệm hoặc kiểm soát các dịch vụ cục bộ và từ xa có hành vi không chuẩn.

Các ổ cắm thô hoạt động song song với nfqueue, ví dụ: khi đường hầm đã được cấu hình và FOU đang lắng nghe trên cổng mong muốn, bạn sẽ không thể gửi gói từ cùng một cổng theo cách thông thường - nó đang bận, nhưng bạn có thể nhận và gửi một gói được tạo ngẫu nhiên trực tiếp đến giao diện mạng bằng cách sử dụng ổ cắm thô, mặc dù việc tạo gói như vậy sẽ cần phải mày mò nhiều hơn một chút. Đây là cách các gói có xác thực được tạo trong ipipou.

Vì ipipou chỉ xử lý các gói đầu tiên từ kết nối (và những gói đã rò rỉ vào hàng đợi trước khi kết nối được thiết lập), nên hiệu suất hầu như không bị ảnh hưởng.

Ngay khi máy chủ ipipou nhận được một gói được xác thực, một đường hầm sẽ được tạo và tất cả các gói tiếp theo trong kết nối đã được xử lý bởi kernel bỏ qua nfqueue. Nếu kết nối không thành công thì gói đầu tiên của gói tiếp theo sẽ được gửi đến hàng đợi nfqueue, tùy thuộc vào cài đặt, nếu đó không phải là gói có xác thực mà từ IP và cổng máy khách được ghi nhớ cuối cùng, nó có thể được chuyển trên hoặc bị loại bỏ. Nếu gói được xác thực đến từ IP và cổng mới, đường hầm sẽ được cấu hình lại để sử dụng chúng.

IPIP-over-FOU thông thường còn có một vấn đề nữa khi làm việc với NAT - không thể tạo hai đường hầm IPIP được gói gọn trong UDP có cùng IP, vì các mô-đun FOU và IPIP khá tách biệt với nhau. Những thứ kia. một cặp máy khách có cùng IP công cộng sẽ không thể kết nối đồng thời với cùng một máy chủ theo cách này. Trong tương lai, có lẽ, nó sẽ được giải quyết ở cấp độ kernel, nhưng điều này không chắc chắn. Trong khi chờ đợi, các vấn đề về NAT có thể được giải quyết bằng NAT - nếu xảy ra trường hợp một cặp địa chỉ IP đã bị chiếm bởi một đường hầm khác, ipipou sẽ thực hiện NAT từ IP công khai sang một IP riêng thay thế, thì đấy! - bạn có thể tạo đường hầm cho đến khi hết cổng.

Bởi vì Không phải tất cả các gói trong kết nối đều được ký, khi đó biện pháp bảo vệ đơn giản này dễ bị tấn công bởi MITM, vì vậy nếu có kẻ xấu ẩn nấp trên đường dẫn giữa máy khách và máy chủ, kẻ có thể nghe lưu lượng và thao túng nó, hắn có thể chuyển hướng các gói đã được xác thực. thông qua một địa chỉ khác và tạo một đường hầm từ một máy chủ không đáng tin cậy.

Nếu bất kỳ ai có ý tưởng về cách khắc phục vấn đề này trong khi vẫn giữ lại phần lớn lưu lượng truy cập trong lõi, đừng ngần ngại lên tiếng.

Nhân tiện, tính năng đóng gói trong UDP đã được chứng minh rất tốt. So với việc đóng gói qua IP, nó ổn định hơn nhiều và thường nhanh hơn mặc dù có thêm chi phí của tiêu đề UDP. Điều này là do hầu hết các máy chủ trên Internet chỉ hoạt động tốt với ba giao thức phổ biến nhất: TCP, UDP, ICMP. Phần hữu hình có thể loại bỏ hoàn toàn mọi thứ khác hoặc xử lý nó chậm hơn vì nó chỉ được tối ưu hóa cho ba phần này.

Ví dụ: đây là lý do tại sao QUICK, dựa trên HTTP/3, được tạo trên UDP chứ không phải trên IP.

Chà, nói đủ rồi, đã đến lúc xem nó hoạt động như thế nào trong “thế giới thực”.

Trận đánh

Được sử dụng để mô phỏng thế giới thực iperf3. Xét về mức độ gần với thực tế, điều này gần giống như mô phỏng thế giới thực trong Minecraft, nhưng hiện tại thì nó sẽ làm được.

Đối tượng tham gia cuộc thi:

  • kênh chính tham khảo
  • người hùng của bài viết này là ipipou
  • OpenVPN có xác thực nhưng không mã hóa
  • OpenVPN ở chế độ trọn gói
  • WireGuard không có PresharedKey, với MTU=1440 (vì chỉ có IPv4)

Dữ liệu kỹ thuật dành cho người đam mê công nghệ
Số liệu được thực hiện bằng các lệnh sau:

trên máy khách:

UDP

CPULOG=NAME.udp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -c SERVER_IP -4 -t 60 -f m -i 10 -B LOCAL_IP -P 2 -u -b 12M; tail -1 "$CPULOG"
# Где "-b 12M" это пропускная способность основного канала, делённая на число потоков "-P", чтобы лишние пакеты не плодить и не портить производительность.

TCP

CPULOG=NAME.tcp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -c SERVER_IP -4 -t 60 -f m -i 10 -B LOCAL_IP -P 2; tail -1 "$CPULOG"

Độ trễ ICMP

ping -c 10 SERVER_IP | tail -1

trên máy chủ (chạy đồng thời với máy khách):

UDP

CPULOG=NAME.udp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -s -i 10 -f m -1; tail -1 "$CPULOG"

TCP

CPULOG=NAME.tcp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -s -i 10 -f m -1; tail -1 "$CPULOG"

Cấu hình đường hầm

ipipou
máy chủ
/etc/ipipou/server.conf:

server
number 0
fou-dev eth0
fou-local-port 10000
tunl-ip 172.28.0.0
auth-remote-pubkey-b64 eQYNhD/Xwl6Zaq+z3QXDzNI77x8CEKqY1n5kt9bKeEI=
auth-secret topsecret
auth-lifetime 3600
reply-on-auth-ok
verb 3

systemctl start ipipou@server

khách hàng
/etc/ipipou/client.conf:

client
number 0
fou-local @eth0
fou-remote SERVER_IP:10000
tunl-ip 172.28.0.1
# pubkey of auth-key-b64: eQYNhD/Xwl6Zaq+z3QXDzNI77x8CEKqY1n5kt9bKeEI=
auth-key-b64 RuBZkT23na2Q4QH1xfmZCfRgSgPt5s362UPAFbecTso=
auth-secret topsecret
keepalive 27
verb 3

systemctl start ipipou@client

openvpn (không mã hóa, có xác thực)
máy chủ

openvpn --genkey --secret ovpn.key  # Затем надо передать ovpn.key клиенту
openvpn --dev tun1 --local SERVER_IP --port 2000 --ifconfig 172.16.17.1 172.16.17.2 --cipher none --auth SHA1 --ncp-disable --secret ovpn.key

khách hàng

openvpn --dev tun1 --local LOCAL_IP --remote SERVER_IP --port 2000 --ifconfig 172.16.17.2 172.16.17.1 --cipher none --auth SHA1 --ncp-disable --secret ovpn.key

openvpn (có mã hóa, xác thực, qua UDP, mọi thứ như mong đợi)
Được cấu hình bằng cách sử dụng quản lý openvpn

dây bảo vệ
máy chủ
/etc/wireguard/server.conf:

[Interface]
Address=172.31.192.1/18
ListenPort=51820
PrivateKey=aMAG31yjt85zsVC5hn5jMskuFdF8C/LFSRYnhRGSKUQ=
MTU=1440

[Peer]
PublicKey=LyhhEIjVQPVmr/sJNdSRqTjxibsfDZ15sDuhvAQ3hVM=
AllowedIPs=172.31.192.2/32

systemctl start wg-quick@server

khách hàng
/etc/wireguard/client.conf:

[Interface]
Address=172.31.192.2/18
PrivateKey=uCluH7q2Hip5lLRSsVHc38nGKUGpZIUwGO/7k+6Ye3I=
MTU=1440

[Peer]
PublicKey=DjJRmGvhl6DWuSf1fldxNRBvqa701c0Sc7OpRr4gPXk=
AllowedIPs=172.31.192.1/32
Endpoint=SERVER_IP:51820

systemctl start wg-quick@client

Những phát hiện

Dấu hiệu xấu xí ẩm ướt
Tải CPU của máy chủ không mang tính biểu thị nhiều, bởi vì... Có nhiều dịch vụ khác đang chạy ở đó, đôi khi chúng ngốn tài nguyên:

proto bandwidth[Mbps] CPU_idle_client[%] CPU_idle_server[%]
# 20 Mbps канал с микрокомпьютера (4 core) до VPS (1 core) через Атлантику
# pure
UDP 20.4      99.80 93.34
TCP 19.2      99.67 96.68
ICMP latency min/avg/max/mdev = 198.838/198.997/199.360/0.372 ms
# ipipou
UDP 19.8      98.45 99.47
TCP 18.8      99.56 96.75
ICMP latency min/avg/max/mdev = 199.562/208.919/220.222/7.905 ms
# openvpn0 (auth only, no encryption)
UDP 19.3      99.89 72.90
TCP 16.1      95.95 88.46
ICMP latency min/avg/max/mdev = 191.631/193.538/198.724/2.520 ms
# openvpn (full encryption, auth, etc)
UDP 19.6      99.75 72.35
TCP 17.0      94.47 87.99
ICMP latency min/avg/max/mdev = 202.168/202.377/202.900/0.451 ms
# wireguard
UDP 19.3      91.60 94.78
TCP 17.2      96.76 92.87
ICMP latency min/avg/max/mdev = 217.925/223.601/230.696/3.266 ms

## около-1Gbps канал между VPS Европы и США (1 core)
# pure
UDP 729      73.40 39.93
TCP 363      96.95 90.40
ICMP latency min/avg/max/mdev = 106.867/106.994/107.126/0.066 ms
# ipipou
UDP 714      63.10 23.53
TCP 431      95.65 64.56
ICMP latency min/avg/max/mdev = 107.444/107.523/107.648/0.058 ms
# openvpn0 (auth only, no encryption)
UDP 193      17.51  1.62
TCP  12      95.45 92.80
ICMP latency min/avg/max/mdev = 107.191/107.334/107.559/0.116 ms
# wireguard
UDP 629      22.26  2.62
TCP 198      77.40 55.98
ICMP latency min/avg/max/mdev = 107.616/107.788/108.038/0.128 ms

kênh 20 Mb/giây

ipipou: không chỉ là một đường hầm không được mã hóa

ipipou: không chỉ là một đường hầm không được mã hóa

kênh trên 1 Gbps lạc quan

ipipou: không chỉ là một đường hầm không được mã hóa

ipipou: không chỉ là một đường hầm không được mã hóa

Trong mọi trường hợp, ipipou có hiệu suất khá gần với kênh cơ sở, điều này thật tuyệt!

Đường hầm openvpn không được mã hóa hoạt động khá kỳ lạ trong cả hai trường hợp.

Nếu có ai định thử nghiệm nó, sẽ rất thú vị khi nghe phản hồi.

Cầu mong IPv6 và NetPrickle đồng hành cùng chúng tôi!

Nguồn: www.habr.com

Thêm một lời nhận xét