터미널 서버(서버 B)의 존재를 숨기기 위해 서로 다른 DC에 있는 두 서버 간의 보안 통신 채널로 WireGuard를 사용하고 있습니다. 저는 nftables를 방화벽 관리 도구로 사용합니다.
공용 서버 A에서 트래픽을 전달하고 IP 주소를 예약합니다(애플리케이션에 필요).
대상 서버 B가 패킷을 수신하고 애플리케이션이 이를 처리하지만 결국 서버는 원래 IP(원래 패킷의 보낸 사람 IP)로 패킷을 반환하려고 시도하므로 문제가 됩니다.
원래 IP를 가장하는 것은 간단한 해결책처럼 보이지만 이러한 패킷을 다시 WireGuard 터널로 라우팅하려면 서버 B에 이미 있는 원래 IP를 보존해야 합니다.
서버 B의 tcpdump:
1:02:36.675958 wg0 In IP 1.2.3.4.54617 > 10.0.0.2.21: Flags [S], seq 1265491449, win 64240, options [mss 1452,nop,wscale 8,nop,nop,sackOK], length 0
1:02:36.675980 docker0 Out IP 1.2.3.4.54617 > 172.16.0.2.21: Flags [S], seq 1265491449, win 64240, options [mss 1452,nop,wscale 8,nop,nop,sackOK], length 0
1:02:36.676030 docker0 In IP 172.16.0.2.21 > 1.2.3.4.54617: Flags [S.], seq 1815055360, ack 1265491450, win 64240, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
1:02:36.676033 enp41s0 Out IP 10.0.0.2.21 > 1.2.3.4.54617: Flags [S.], seq 1815055360, ack 1265491450, win 64240, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
- 1.2.3.4 - 원래 IP
- 10.0.0.2 - 서버 B의 IP 라인배커
- 172.16.0.2 - docker 네트워크, 이것이 애플리케이션이라고 가정합시다(모든 것이 잘 작동합니다)
안타깝게도 이 문제에 대한 해결책을 찾지 못해서 여러분의 도움을 요청합니다. 괜찮나요? 그렇다면 무엇을 의미합니까?
고쳐 쓰다
HAProxy를 사용하기로 결정했지만 성능이 뛰어난 솔루션은 아니라고 생각합니다. 그래서 나는 여전히 이 문제에 대한 가능한 해결책이 필요합니다.
systemd-networkd
WireGuard 터널 구성 :
# sudo cat /etc/systemd/network/99-wg0.netdev
[NetDev]
Name=wg0
Kind=wireguard
Description=WireGuard tunnel wg0
[WireGuard]
ListenPort=51820
PrivateKey=[key]
[WireGuardPeer]
PublicKey=[key]
PresharedKey=[key]
AllowedIPs=0.0.0.0/0
Endpoint=[server A]:51820
# sudo cat /etc/systemd/network/99-wg0.network
[Match]
Name=wg0
[Network]
Address=10.0.0.2/24
Address=fdc9:281f:04d7:9ee9::2/64
# sudo ip rule
:
0: from all lookup local
32766: from all lookup main
32767: from all lookup default
nftables 구성:
# sudo nft list ruleset
[0]
table inet filter {
chain allow {
ct state invalid drop comment "early drop of invalid connections"
ct state { established, related } accept comment "allow tracked connections"
ip protocol icmp accept comment "allow icmp"
meta l4proto ipv6-icmp accept comment "allow icmp v6"
icmp type echo-request limit rate over 10/second burst 4 packets drop comment "No ping floods"
icmpv6 type echo-request limit rate over 10/second burst 4 packets drop comment "No ping floods"
}
chain wireguard {
tcp dport 21 accept
}
chain input {
type filter hook input priority filter; policy drop;
iif "lo" accept comment "allow from loopback"
tcp dport 22 ct state new limit rate 15/minute accept comment "Avoid brute force on SSH"
tcp dport 22 accept comment "allow sshd"
ip6 saddr [server A] udp dport 51820 accept comment "Accept wireguard connection from proxy1.vps-da4c9ada.ovh.zolotomc.ru"
jump allow comment "allowed traffic for input"
meta pkttype host limit rate 5/second counter packets 1047 bytes 43403 reject with icmpx admin-prohibited
reject with icmpx host-unreachable
}
chain forward {
type filter hook forward priority filter; policy drop;
iif "docker0" accept comment "allow outgoing traffic from docker"
jump allow comment "allowed traffic for forward"
iif "wg0" jump wireguard comment "Wireguard chain"
reject with icmpx host-unreachable
}
chain output {
type filter hook output priority filter; policy accept;
}
}
table inet nat {
chain prerouting {
type nat hook prerouting priority dstnat; policy accept;
iif "wg0" jump wireguard comment "Wireguard chain"
}
chain wireguard {
tcp dport 21 dnat ip to 172.16.0.2
tcp dport 21 dnat ip6 to fe80::a8d7:f6ff:fe0b:4774
}
chain input {
type nat hook input priority 100; policy accept;
}
chain output {
type nat hook output priority -100; policy accept;
}
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
iif "docker0" oif != "docker0" masquerade
}
}
나는 사용하려고패킷 메타 정보 설정, 그러나 포트를 새로운 임의 포트에 재할당합니다. 하지만 불가능하거나 너무 복잡하다는 생각이 들기 시작했습니다.nftables규칙.
답변1
올바르게 응답하는 데 필요한 정보: "초기 패킷은 어떤 인터페이스에서 왔습니까?" 네트워크 인터페이스의 응답에 다른 패킷이 표시되면 손실됩니다. 이를 기억하고 응답에 재사용할 수 있는 방법이 필요합니다. 여기있어:연결하다현재 추적되는 모든 연결 목록을 기억합니다. 보관도 가능하고,스트림당마크, 그런 다음 호출코맥. 사람들은 가치에 의미를 부여할 수 있습니다.
이를 통해 응용 프로그램을 사용할 수 있습니다.정책 라우팅개별 패킷이 아닌 전체 스트림에 적용됩니다.
블로그리눅스 이상!거기에 설명되어 있습니다 :넷필터 코맥.
아이디어는 흐름이 WireGuard 인터페이스를 사용할 때 정보를 기억하여 응답 패킷이 동일한 흐름과 연결되고 일반적인 경로 대신 WireGuard 인터페이스를 통해 다시 라우팅되도록 하는 것입니다. 이는 독립 기관을 통해 처리될 수 있습니다.nftables테이블 및 관련 라우팅 테이블/규칙을 사용하여 패킷의 정상적인 운명을 변경합니다. 응답을 선택하려면 0xf00
"이 흐름의 출처"를 의미하는 태그 값 wg0
과 라우팅 테이블 1000을 사용하세요 .wg0
응답 패킷의 일반적인 라우팅을 처리할 수 있도록 충분한 라우팅 테이블과 라우팅 규칙을 준비합니다.
ip route add default dev wg0 table 1000
ip rule add fwmark 0xf00 lookup 1000
IPv6도 사용되는 경우(그러나 OP의 구성에서 AllowedIPs에 IPv6가 누락된 경우) 다음도 수행합니다.
ip -6 route add default dev wg0 table 1000
ip -6 rule add fwmark 0xf00 lookup 1000
사용 예 systemd-networkd
:
[Match]
Name=wg0
[Network]
Address=10.0.0.2/24
Address=fdc9:281f:04d7:9ee9::2/64
[Route]
Gateway=0.0.0.0
Table=1000
[RoutingPolicyRule]
Table=1000
FirewallMark=0xf00
그리고 다음 테이블을 추가하세요.
replywg0.nft
:
table inet replywg0 # for idempotency
delete table inet replywg0 # for idempotency
table inet replywg0 {
chain prerouting {
type filter hook prerouting priority -150; policy accept;
iif wg0 ct mark set 0xf00
iif != wg0 ct mark 0xf00 meta mark set 0xf00
}
chain output {
type route hook output priority -150; policy accept;
ct mark 0xf00 meta mark set 0xf00
}
}
짐:
nft -f replywg0.nft
참고 및 경고:
이것가방태그는 라우팅에 영향을 미치는 유일한 태그이며 에서 올 때 설정되지 않고
wg0
설정만 됩니다.코맥설정: 그렇지 않으면 표 1000에 정의된 단일 경로를 선택하고 로컬 시스템이나 Docker 컨테이너로 계속 이동하는 대신 소스에서 패킷을 다시 라우팅합니다. 라우팅 테이블 1000에 내가 모르는 모든 관련 추가 경로가 포함되어 있으면 이 특별한 처리가 필요하지 않습니다.출력 체인이 Docker 트래픽에만 적합한 경우 출력 체인은 완전히 선택 사항입니다. 다음 경우에만 유용합니다.현지의응답 트래픽: 수신된 트래픽작업 그룹 0Docker로 전송되지 않고 로컬 시스템으로 전송됩니다. 대신 여기에서는
type route
대신이 사용되므로type filter
새로운 경로 조회가 여전히 가능합니다. 어쨌든 일부 UDP 서비스는 여기서 올바르게 응답하지 않습니다. IP 소스 주소가 잘못되었을 수 있으며( 에 설정된 주소enp41s0
) 일부 추가적인 불완전한 NAT 반창고가 필요합니다(예: inet nat 출력에서 가장하는 테이블).나중에 플래그에 대한 다른 요구 사항이 있는 경우 주의하십시오(WireGuard 자체에도 플래그를 설정하는 옵션이 있음). 제대로 처리하지 않으면 충돌이 발생할 수 있습니다.
FTP(OP 설정에 표시됨)는 특별합니다. 추가 데이터 연결을 사용하며 필요할 수 있습니다.ALG(보통 서버의 경우 패시브 모드입니다). 암호화되지 않은 한 Linux의 커널 모듈로 처리할 수 있습니다.
nf_conntrack_ftp
+nf_nat_ftp
다음과 같은 설정이 충분합니다.iptables 및 연결 추적 도우미의 안전한 사용그리고 (약간 다른) 등가물이 있습니다nftables설정. RELATED 트래픽(데이터 트래픽)은코맥, 이 블로그에 설명된 설정은 이 답변의 설정에서도 작동합니다. 토글 스위치nf_conntrack_helper
~이다커널 >= 6.0에서 완전히 제거됨이므로 이는 필수 설정이 됩니다.나는 가정한다
rp_filter
값은 1이 아닙니다. 그렇지 않으면wg0
처음에는 아무 일도 일어나지 않을 수 있기 때문입니다. 1로 설정하면 여러 곳에 추가 설정이 필요하다.