OpenVPN 터널을 통해 일부 LAN 호스트의 트래픽과 DNS를 전달하도록 Linux 라우터를 구성하시겠습니까?

OpenVPN 터널을 통해 일부 LAN 호스트의 트래픽과 DNS를 전달하도록 Linux 라우터를 구성하시겠습니까?

내 홈 네트워크용 라우터로 설정한 GNU/Linux 상자가 있습니다. 세 개의 네트워크 인터페이스가 있습니다.

  • ppp0은 업스트림 연결입니다.
  • lan은 로컬 네트워크 입니다
  • nordvpn은 VPN 터널입니다

저는 방화벽으로 nftables를 사용하고 있으며 캐싱 DNS 서버(dnsmasq)를 실행하고 있습니다. LAN의 DNS 요청은 가로채서 대신 라우터의 DNS 서버로 전송됩니다. 지금까지는 너무 좋았지만...

기본적으로 NordVPN 경로모두VPN 터널을 통해 업스트림 트래픽을 전송하고, 이렇게 구성하면 작동하지만 저는 이것을 원하지 않습니다. 나는 대부분의 인터넷 트래픽이 ppp0 인터페이스를 통과하고 특정 LAN 호스트의 트래픽이 대신 VPN을 통해 전송되기를 원합니다. VPN을 사용하는 호스트에 대한 DNS 요청은 로컬 서버가 아닌 VPN 공급자의 DNS 서버로 전달되어야 합니다.

유사한(그러나 동일하지는 않은) 작업을 수행하는 방법에 대해 설명하는 다양한 기사를 읽었지만 지금까지는 이를 작동시킬 수 없었습니다. 나는 분명히 적어도 한 가지 잘못을 하고 있습니다. 내가 이해하는 바에 따르면 방화벽에서 패킷을 표시한 다음 사용자 지정 라우팅 테이블을 사용하여 nordvpn 인터페이스를 통해 해당 패킷을 보낼 수 있어야 합니다. 내가 지금까지 가지고 있는 것은 다음과 같습니다.

에 다음 줄을 추가했습니다 /etc/iproute2/rt_tables.

5     nordvpn

openvpn이 자체 경로를 설정하는 것을 방지하기 위해 다음 줄을 /etc/openvpn/client/nordvpn.conf.

route-noexec
script-security 2
route-up /etc/openvpn/client/mkroute.sh

작동하려면 nordvpn 인터페이스에서 역방향 경로 필터링을 비활성화해야 한다고 생각합니까? 이것은 openvpn이 라우팅을 설정하는 데 사용하는 스크립트입니다.

#!/bin/bash

TABLE="nordvpn"
MARK="0x5"

die() {
  echo "Error: $1"
  exit 1
}

[ $(id -u) -eq 0 ] || die "Not running as root"

ip route flush cache || echo "error 1"
ip route flush table "$TABLE" || echo "error 2"

ip route add 192.168.2.0/24 dev lan src 192.168.2.1 table "$TABLE" || echo "error 3"
ip route add $route_vpn_gateway dev lan src $ifconfig_local table "$TABLE" || echo "error 4"
ip route add default via $route_vpn_gateway dev "$dev" table "$TABLE" || echo "error 5"
ip rule delete fwmark "$MARK" || :
ip rule add fwmark "$MARK" lookup "$TABLE" || echo "error 6"
sysctl -w net.ipv4.conf.nordvpn.rp_filter=0 || echo "error 7"

마지막으로 이것은 내 nftables 스크립트입니다.

flush ruleset

define i_wan = ppp0
define i_nordvpn = nordvpn
define i_lan = lan

define p_dns = 53

define a4_nordvpn_dns_1 = 103.86.96.100
define m_nordvpn = 5

define h4_nimrod = 192.168.2.21

table ip ip4_firewall {

  set s_inet_nordvpn { type ipv4_addr; elements = { $h4_nimrod }; }

  chain c_here_to_wan { tcp flags syn tcp option maxseg size set rt mtu; accept; }
  chain c_here_to_nordvpn { tcp flags syn tcp option maxseg size set rt mtu; accept; }
  chain c_here_to_lan { accept; }
  chain c_wan_to_here { ip protocol icmp accept; drop; }
  chain c_wan_to_lan { ip protocol icmp accept; drop; }
  chain c_nordvpn_to_here { ip protocol icmp accept; drop; }
  chain c_nordvpn_to_lan { ip protocol icmp accept; drop; }
  chain c_lan_to_here { accept; }
  chain c_lan_to_wan { tcp flags syn tcp option maxseg size set rt mtu; accept; }
  chain c_lan_to_nordvpn { tcp flags syn tcp option maxseg size set rt mtu; accept; }

  chain preroute_nordvpn {
    udp dport $p_dns mark set $m_nordvpn dnat $a4_nordvpn_dns_1
    tcp dport $p_dns mark set $m_nordvpn dnat $a4_nordvpn_dns_1
    oif $i_wan mark set $m_nordvpn
  }

  chain prerouting { type nat hook prerouting priority -100
    ip saddr @s_inet_nordvpn goto preroute_nordvpn
    iif $i_lan oif $i_wan udp dport $p_dns redirect
    iif $i_lan oif $i_wan tcp dport $p_dns redirect
  }

  chain postrouting { type nat hook postrouting priority 100
    oif $i_nordvpn masquerade
    oif $i_wan snat <my public IP address>
  }

  chain input { type filter hook input priority 0; policy drop
    ct state established,related accept
    ct state invalid drop
    iif vmap {
      lo: accept,
      $i_wan : jump c_wan_to_here,
      $i_nordvpn : jump c_nordvpn_to_here,
      $i_lan : jump c_lan_to_here
    }
    log prefix "Unhandled input: " drop
  }

  chain output { type filter hook output priority 0; policy drop
    ct state established,related accept
    ct state invalid drop
    oif vmap {
      lo: accept,
      $i_wan : jump c_here_to_wan,
      $i_nordvpn : jump c_here_to_nordvpn,
      $i_lan : jump c_here_to_lan
    }
    log prefix "Unhandled output: " drop
  }

  chain forward { type filter hook forward priority 0; policy drop
    ct state established,related accept
    ct state invalid drop
    iif . oif vmap {
      $i_lan . $i_wan : jump c_lan_to_wan,
      $i_wan . $i_lan : jump c_wan_to_lan,
      $i_lan . $i_nordvpn : jump c_lan_to_nordvpn,
      $i_nordvpn . $i_lan : jump c_nordvpn_to_lan,
    }
    log prefix "Unhandled forward: " drop
  }
}

일단 구성되면 다음이 있습니다.

[root@cerberus ~]# ip rule ls
0:      from all lookup local
32765:  from all fwmark 0x65 lookup nordvpn
32766:  from all lookup main
32767:  from all lookup default
[root@cerberus ~]# ip route ls
default dev ppp0 scope link 
10.0.0.1 dev ppp0 proto kernel scope link src <my public IP address> 
10.8.0.0/24 dev nordvpn proto kernel scope link src 10.8.0.12 
192.168.2.0/24 dev lan proto kernel scope link src 192.168.2.1 
[root@cerberus ~]# ip route ls table nordvpn
default via 10.8.0.1 dev nordvpn 
10.8.0.1 dev lan scope link src 10.8.0.12 
192.168.2.0/24 dev lan scope link src 192.168.2.1 
[root@cerberus ~]# ip rule ls
0:      from all lookup local
32764:  from all fwmark 0x5 lookup nordvpn
32766:  from all lookup main
32767:  from all lookup default

VPN에 할당된 클라이언트를 활성화하면 DNS 조회가 실패합니다. 요청은 VPN 터널을 통해 전송되는 것 같지만 응답은 전달 체인이 아닌 입력 체인에 도착하여 클라이언트에 전달되지 않습니다. 내가 어디로 잘못 가고 있습니까?

어떤 도움이라도 미리 감사드립니다 :)

답변1

변경해 보세요:

  chain preroute_nordvpn {
    udp dport $p_dns mark set $m_nordvpn dnat $a4_nordvpn_dns_1
    tcp dport $p_dns mark set $m_nordvpn dnat $a4_nordvpn_dns_1
    oif $i_wan mark set $m_nordvpn
  }

  chain prerouting { type nat hook prerouting priority -100
    ip saddr @s_inet_nordvpn goto preroute_nordvpn
    iif $i_lan oif $i_wan udp dport $p_dns redirect
    iif $i_lan oif $i_wan tcp dport $p_dns redirect
  }

에게:

  chain fwmark { type filter hook prerouting priority -150
    ip saddr @s_inet_nordvpn mark set $m_nordvpn
  }

  chain lan_dns {
    ip saddr @s_inet_nordvpn dnat $a4_nordvpn_dns_1
    redirect
  }

  chain lan_dnat {
    udp dport $p_dns goto lan_dns
    tcp dport $p_dns goto lan_dns
  }

  chain prerouting { type nat hook prerouting priority -100
    iif $i_lan goto lan_dnat
  }

관련 정보