내가 한 일은 매우 간단했습니다. 포트 전달을 사용하고 POSTROUTING 체인에서 가장을 활성화했습니다.
table inet nat {
chain prerouting {
type nat hook prerouting priority -100; policy accept;
ip daddr 198.51.100.105 counter dnat to 10.8.0.105 comment "host.example.com"
}
chain postrouting {
type nat hook postrouting priority 100; policy accept;
counter masquerade
}
}
내 컴퓨터에는 다음과 같은 인터페이스가 있습니다.
1: lo
2: ens18
3: ens19
4: wg0
경로는 다음과 같습니다:
default via 203.0.113.1 dev ens18 onlink
10.8.0.0/24 dev wg0 proto kernel scope link src 10.8.0.1
198.51.100.0/24 dev ens19 proto kernel scope link src 198.51.100.3
203.0.113.0/24 dev ens18 proto kernel scope link src 203.0.113.134
규칙은 다음과 같습니다:
0: from all lookup local
32764: from all to 198.51.100.0/24 lookup subnets
32765: from 198.51.100.0/24 lookup subnets
32766: from all lookup main
32767: from all lookup default
출력은 ip route get 198.51.100.105
다음과 같습니다
local 198.51.100.105 dev lo table local src 198.51.100.3 uid 0
cache <local>
출력 ip route show table subnets
:
default via 198.51.100.1 dev ens19
198.51.100.0/24 dev ens19 scope link src 198.51.100.3
지금 핑할 때사람들외부 VPS 또는 내 집 DSL 주소에서 198.51.100.105
ICMP 패킷이 수신되었을 뿐만 아니라 다음 주소에도 응답되었는지 확인할 수 있습니다.
ICMP 요청
root@debian:~# tcpdump -i ens19 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens19, link-type EN10MB (Ethernet), snapshot length 262144 bytes
21:35:51.686208 IP 192.0.2.2 > 198.51.100.105: ICMP echo request, id 14855, seq 1, length 64
ICMP 응답
root@debian:~# tcpdump -i ens18 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens18, link-type EN10MB (Ethernet), snapshot length 262144 bytes
21:35:38.797502 IP 198.51.100.105 > 192.0.2.2: ICMP echo reply, id 5107, seq 1, length 64
하지만 보시다시피 응답은 잘못된 인터페이스에서 나옵니다. 이어야 하는데 ens19
이미 사용 중인데 ens18
그 이유를 모르겠습니다.
경로/규칙을 따르지 않는 이유는 무엇입니까? 서브넷은
198.51.100.0/24
아무 관련이 없으며ens18
다른 VLAN도 마찬가지입니다.nftables는 위장된 패킷에 대해 다른 아웃바운드 인터페이스를 강제할 수 없습니까?
도움을 주셔서 감사합니다.
편집하다: 출력은 다음과 ip -br link; ip -4 -br addr; ip -4 route; ip rule; ip rule show table subnets
같습니다.
ip -br link; ip -4 -br addr; ip -4 route; ip rule; ip rule show table subnets
lo UNKNOWN 00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
ens18 UP a6:ea:02:1c:XX:XX <BROADCAST,MULTICAST,UP,LOWER_UP>
ens19 UP ac:71:fe:18:XX:XX <BROADCAST,MULTICAST,UP,LOWER_UP>
wg0 UNKNOWN <POINTOPOINT,NOARP,UP,LOWER_UP>
lo UNKNOWN 127.0.0.1/8
ens18 UP 203.0.113.134/24
ens19 UP 198.51.100.3/24 198.51.100.100/24 198.51.100.101/24 198.51.100.102/24 198.51.100.103/24 198.51.100.104/24 198.51.100.105/24
wg0 UNKNOWN 10.8.0.1/24
default via 203.0.113.1 dev ens18 onlink
10.8.0.0/24 dev wg0 proto kernel scope link src 10.8.0.1
198.51.100.0/24 dev ens19 proto kernel scope link src 198.51.100.3
203.0.113.0/24 dev ens18 proto kernel scope link src 203.0.113.134
0: from all lookup local
32764: from all to 198.51.100.0/24 lookup subnets
32765: from 198.51.100.0/24 lookup subnets
32766: from all lookup main
32767: from all lookup default
32764: from all to 198.51.100.0/24 lookup subnets
32765: from 198.51.100.0/24 lookup subnets
라인배커
명령 출력 wg
:
interface: wg0
public key: XrSd2TftIpiL3zhXXX=
private key: (hidden)
listening port: 51820
peer: gZ89rFX6DvBtdeuYXXX=
endpoint: 233.252.0.0:39126
allowed ips: 10.8.0.0/24
latest handshake: 20 seconds ago
transfer: 3.42 MiB received, 4.08 MiB sent
명령 출력:systemctl status [email protected]
● [email protected] - WireGuard via wg-quick(8) for wg0
Loaded: loaded (/lib/systemd/system/[email protected]; enabled; preset: enabled)
Active: active (exited) since Sat 2023-08-05 23:42:48 CEST; 14h ago
Docs: man:wg-quick(8)
man:wg(8)
https://www.wireguard.com/
https://www.wireguard.com/quickstart/
https://git.zx2c4.com/wireguard-tools/about/src/man/wg-quick.8
https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8
Process: 690 ExecStart=/usr/bin/wg-quick up wg0 (code=exited, status=0/SUCCESS)
Main PID: 690 (code=exited, status=0/SUCCESS)
CPU: 27ms
Aug 05 23:42:48 debian systemd[1]: Starting [email protected] - WireGuard via wg-quick(8) for wg0...
Aug 05 23:42:48 debian wg-quick[690]: [#] ip link add wg0 type wireguard
Aug 05 23:42:48 debian wg-quick[690]: [#] wg setconf wg0 /dev/fd/63
Aug 05 23:42:48 debian wg-quick[690]: [#] ip -4 address add 10.8.0.1/24 dev wg0
Aug 05 23:42:48 debian wg-quick[690]: [#] ip link set mtu 1420 up dev wg0
Aug 05 23:42:48 debian systemd[1]: Finished [email protected] - WireGuard via wg-quick(8) for wg0.
서버:/etc/wireguard/wg0.conf
[Interface]
Address = 10.8.0.1/24
SaveConfig = true
ListenPort = 51820
PrivateKey = 8BspU4XXX=
[Peer]
PublicKey = gZ89rFX6DvBtdeuYXXX=
AllowedIPs = 10.8.0.0/24
Endpoint = 233.252.0.0:58642
피어: /etc/wireguard/wg0.conf
[Interface]
# Client Private Key
PrivateKey = iO00+qQDXXX=
Address = 10.8.0.107/24
[Peer]
# Server Public Key
PublicKey = XrSd2TftIpiL3zhXXX=
AllowedIPs = 10.8.0.0/24
PersistentKeepalive = 25
Endpoint = 198.51.100.3:51820
답변1
참고 및 조정 사항(혼란으로 인한 것일 수 있음):
- WireGuard 피어가 일치하기 위해 10.8.0.107 대신 10.8.0.105를 사용한다고 가정합니다.nftables규칙 세트.
- 233.252.0.0은 시뮬레이션에서 문제를 일으킬 수 있습니다(특히 다음과 같은 경우).동료) 멀티캐스트 주소이기 때문입니다. 아래에서는 192.0.2.233을 사용하겠습니다(192.0.2.2와 네트워크 관계가 없음).
이 질문은 로컬 트래픽뿐만 아니라 전달을 위해 dnat 규칙을 사용하는 문제를 해결하기 위한 것입니다. 마지막에 수정된 WireGuard 터널 엔벨로프에도 숨겨진 문제가 있습니다.
ping 테스트(사전 라우팅에서 발생하는 실제 dnat 및 응답에서 발생하는 마스킹 해제 포함)를 통한 라우팅 스택의 동작은 커널에 어떤 경로를 쿼리할지 쿼리하는 다음 두 명령으로 요약할 수 있습니다. 사용:
# ip route get from 192.0.2.2 iif ens19 to 10.8.0.105
10.8.0.105 from 192.0.2.2 dev wg0
cache iif ens19
# ip route get from 10.8.0.105 iif wg0 to 192.0.2.2
192.0.2.2 from 10.8.0.105 via 203.0.113.1 dev ens18
cache iif wg0
여기에서 응답이 잘못된 인터페이스를 사용하고 있음을 알 수 있습니다. 주소가 다시 작성됩니다.연결하다항목 내용: 위에 표시되지 않더라도 여전히 198.51.100.105입니다.
이는 누락된 규칙으로 인해 발생합니다: any from (returns)작업 그룹 0테이블을 사용해야 한다서브넷. 다음으로 수정됨:
ip rule add iif wg0 lookup subnets
이것은 또한 문제를 해결했습니다.rp_filter=1
RTNETLINK answers: Invalid cross-device link
위의 첫 번째 경로 테스트는 일반적으로 추가되어야 함에도 불구하고 실패합니다.작업 그룹 0경로도 이 표에 있습니다.
이제 주어진:
# ip route get from 10.8.0.105 iif wg0 to 192.0.2.2
192.0.2.2 from 10.8.0.105 via 198.51.100.1 dev ens19 table subnets
cache iif wg0
이제 핑 테스트가 제대로 작동합니다.
추가적인 숨겨진 WireGuard 봉투 라우팅 문제가 있습니다.
콤비네이션:
- 활성화되지 않음엄격한 역방향 경로 전달(RFC 3704)
- 피어가 먼저 서버에 접속하도록 합니다(마지막에 있는 추가 질문 참조).
- (적어도) 커널 구현은 원래 접촉했던 것과 동일한 소스를 사용하여 응답해야 한다고 결정합니다.
WireGuard가 작동하도록 허용합니다 ping 10.8.0.1
.동료응답이 수신되고 이후의 WireGuard 트래픽은 동일한 봉투 주소를 계속 사용하도록 허용됩니다.
로컬(라우팅되지 않은) 흐름의 소스 주소가 선언되지 않은 경우 라우팅 스택은 지정된 경로에 어떤 주소를 사용해야 하는지 파악해야 합니다. 이는 소켓이 일반적으로 바인딩되지 않은 상태로 유지되는 UDP의 경우 특히 중요합니다(즉, 소스가 0.0.0.0, 즉 INADDR_ANY임). TCP 서버의 경우 나중에 생성된 중복 소켓이 accept(2)
더 이상 0.0.0.0에 바인딩되지 않고 올바른 주소에 바인딩되므로 이는 문제가 되지 않습니다. 그런 다음 이 주소를 라우팅 스택에 제공합니다. 여기서 WireGuard는 UDP 및 INADDR_ANY를 사용합니다. 특히 198.51.100.3에 바인딩되지 않습니다. 이는 소스 0.0.0.0으로 나타나고 나가는 소스 IP 주소의 확인을 커널의 라우팅 스택에 남겨둔다는 의미입니다.
만약에섬기는 사람WireGuard는 항상 첫 번째 패킷을 시작합니다(대신동료이렇게 하면 198.51.100.3 대신 203.0.113.134가 사용됩니다. 라우팅 스택에는 특정 항목이 없습니다.IP 규칙0.0.0.0의 경우:IP 규칙 32765: from 198.51.100.0/24 lookup subnets
일치하는 항목이 없으며 특수 정책 라우팅이 적용되지 않습니다. 마지막으로 UDP 패킷은 ens18을 사용하여 203.0.113.134로 나갑니다.
커널 구현은 적어도 쿼리된 것과 동일한 주소를 계속 사용하는 것 같습니다. 이는 신뢰할 수 없으며 UDP 서비스를 사용한 멀티호밍에는 특별한 지원이 필요합니다(예:IP_PKTINFO
) 따라서 응용 프로그램에서.
WireGuard가 추구하는 결과:
# ip route get from 198.51.100.105 to 192.0.2.233
192.0.2.233 from 198.51.100.105 via 198.51.100.1 dev ens19 table subnets uid 0
cache
적어도 트래픽을 가장 먼저 시작한 실제 결과라면 다음과 같습니다.
# ip route get from 0.0.0.0 to 192.0.2.233
192.0.2.233 via 203.0.113.1 dev ens18 src 203.0.113.134 uid 0
cache
WireGuard 터널 멀티호밍 라우팅 자체를 실제로 수정하려면 L4별 프로토콜 라우팅 규칙을 사용할 수 있습니다.
ip rule add iif lo ipproto udp sport 51820 lookup subnets
( iif lo
로컬에서 시작된(전달되지 않은) 트래픽을 나타내는 특수 구문이며 인터페이스 독립적입니다 lo
.)
주다:
# ip route get from 0.0.0.0 ipproto udp sport 51820 to 192.0.2.233
192.0.2.233 via 198.51.100.1 dev ens19 table subnets src 198.51.100.3 uid 0
cache
INADDR_ANY를 소스로 사용함에도 불구하고 이제 UDP 소스 포트 51820이 선택됩니다.서브넷라우팅 테이블.