OpenWrt로 NAT64/DNS64 환경 구축

2021/05/26 추가: OpenWrt의 현재 stable release (19.07)의 Jool 패키지는 버전 3.5.7이지만 다음 OpenWrt 21.02에서는 4.1.5로 업데이트되는 것 같습니다.
Jool 4.x 용 기사 내용을 변경했지만 3.5를 사용하려면 여기을 참조하십시오.

OpenWrt의 LAN측 네트워크는 기본적으로 IPv4/IPv6 듀얼 스택에서 동작하도록 설정되어 있지만, 이것을 IPv6 싱글 스택으로 변경하기 위해 Jool과 Unbound를 사용하여 NAT64/DNS64 환경을 구축했습니다.

환경


root@OpenWrt:~# cat /etc/openwrt_release
DISTRIB_ID='OpenWrt'
DISTRIB_RELEASE='21.02.0-rc1'
DISTRIB_REVISION='r16046-59980f7aaf'
DISTRIB_TARGET='ath79/generic'
DISTRIB_ARCH='mips_24kc'
DISTRIB_DESCRIPTION='OpenWrt 21.02.0-rc1 r16046-59980f7aaf'
DISTRIB_TAINTS=''
root@OpenWrt:~# jool --version
4.1.5.0
root@OpenWrt:~# unbound -V
Version 1.13.1

기본적으로 다음과 같은 네트워크 구성입니다.
# ifstatus wan
...
        "proto": "dhcp",
        "device": "eth0.2",
        "ipv4-address": [
                {
                        "address": "10.10.10.113",
                        "mask": 24
                }
        ],
        "dns-server": [
                "10.10.10.1"
        ],
...

# ifstatus wan6
...
        "proto": "dhcpv6",
        "device": "eth0.2",
        "ipv6-prefix": [
                {
                        "address": "2001:db8:fc7e:200::",
                        "mask": 56,
                        "class": "wan6",
                        "assigned": {
                                "lan": {
                                        "address": "2001:db8:fc7e:200::",
                                        "mask": 60
                                }
                        }
                }

        ],
        "dns-server": [
                "2001:db8:fc7e::1"
        ],
...

# ifstatus lan
...
        "proto": "static",
        "device": "br-lan",
        "ipv4-address": [
                {
                        "address": "192.168.1.1",
                        "mask": 24
                }
        ],
        "ipv6-prefix-assignment": [
                {
                        "address": "2001:db8:fc7e:200::",
                        "mask": 60,
                        "local-address": {
                                "address": "2001:db8:fc7e:200::1",
                                "mask": 60
                        }
                },
                {
                        "address": "fd92:2bfc:16ee::",
                        "mask": 60,
                        "local-address": {
                                "address": "fd92:2bfc:16ee::1",
                                "mask": 60
                        }
                }
        ],
...

+------+  |
| Host +--+ LAN +---------+ WAN/ +------+
+------+  |     |         | WAN6 |      |
          +-----+ OpenWrt +------+  GW  |
+------+  |     |         |      |      |
| Host +--+     +---------+      +------+
+------+  |

<---------------- v4/v6 ---------------->

이것을 다음과 같이 변경합니다.
+------+  |
| Host +--+ LAN +---------+ WAN/ +------+
+------+  |     |         | WAN6 |      |
          +-----+ OpenWrt +------+  GW  |
+------+  |     |         |      |      |
| Host +--+     +---------+      +------+
+------+  |

<---- v6 ----> NAT64/DNS64 <--- v4/v6 --->

NAT64/DNS64를 이용하여 IPv4에의 접속성을 확보하면서, LAN측의 IPv4를 무효로 합니다.

필요한 패키지 설치


# opkg update
# opkg install unbound-daemon kmod-jool jool-tools

DNS64 (Unbound) 설정


# uci set unbound.@unbound[0].dns64='1'
# uci commit unbound

모든 이름 해석을 다른 DNS 캐시 서버로 forward하고 싶은 경우는 다음과 같이 forward-zone을 설정한다.

/etc/unbound/unbound_ext.conf
forward-zone:
        name: "."
        forward-addr: 10.10.10.1
        forward-addr: 2001:db8:fc7e::1

Dnsmasq의 DNS 서버를 비활성화합니다.
# uci set dhcp.@dnsmasq[0].port='0'
# uci commit dhcp
# service dnsmasq restart
# service unbound restart

이름이 해결되었는지 확인하십시오.
# nslookup ipv4.google.com localhost
Server:         localhost
Address:        ::1#53

Name:      ipv4.google.com
ipv4.google.com canonical name = ipv4.l.google.com
Name:      ipv4.l.google.com
Address 1: 172.217.25.110
ipv4.google.com canonical name = ipv4.l.google.com
Address 2: 64:ff9b::acd9:196e

NAT64 (Jool) 설정


# modprobe jool
# jool instance add "example" --iptables --pool6 64:ff9b::/96
# ip6tables -t mangle -A PREROUTING -j JOOL --instance "example"
# iptables -t mangle -A PREROUTING -j JOOL --instance "example"

시작시 Jool이 활성화되도록 init 스크립트와 구성 파일을 만듭니다.
# mkdir /etc/jool
# cat << "EOF" > /etc/jool/jool.conf
{
    "comment": "Configuration for the NAT64 Jool service.",

    "instance": "example",
    "framework": "iptables",

    "global": {
        "pool6": "64:ff9b::/96"
    }
}
EOF
# cat << "EOF" >> /etc/firewall.user
ip6tables -t mangle -A PREROUTING -j JOOL --instance "example"
iptables -t mangle -A PREROUTING -j JOOL --instance "example"
EOF
# cat << "EOF" >> /etc/sysupgrade.conf
/etc/init.d/jool
/etc/jool/
EOF
# wget -O /etc/init.d/jool https://gist.githubusercontent.com/konosukef/d0a3b8fa73458defd4f61c95649dd029/raw/jool
# chmod +x /etc/init.d/jool
# service jool enable
# service jool restart
# service firewall restart

LAN의 IPv4 설정을 삭제합니다.
# uci delete network.lan.ipaddr
# uci delete network.lan.netmask
# uci commit network
# service network restart

연결 테스트


root@OpenWrt:~# jool instance display
+--------------------+-----------------+-----------+
|          Namespace |            Name | Framework |
+--------------------+-----------------+-----------+
|           8064df98 |         example |  iptables |
+--------------------+-----------------+-----------+

root@OpenWrt:~# jool --instance "example" global display
  manually-enabled: true
  pool6: 64:ff9b::/96
  lowest-ipv6-mtu: 1280
  logging-debug: false
  zeroize-traffic-class: false
  override-tos: false
  tos: 0
  mtu-plateaus: 65535,32000,17914,8166,4352,2002,1492,1006,508,296,68
  address-dependent-filtering: false
  drop-externally-initiated-tcp: false
  drop-icmpv6-info: false
  source-icmpv6-errors-better: true
  f-args: 11 (0b1011): SrcAddr:1 SrcPort:0 DstAddr:1 DstPort:1
  handle-rst-during-fin-rcv: false
  tcp-est-timeout: 2:00:00 (HH:MM:SS)
  tcp-trans-timeout: 0:04:00 (HH:MM:SS)
  udp-timeout: 0:05:00 (HH:MM:SS)
  icmp-timeout: 0:01:00 (HH:MM:SS)
  logging-bib: false
  logging-session: false
  maximum-simultaneous-opens: 10
  ss-enabled: false
  ss-flush-asap: true
  ss-flush-deadline: 2000
  ss-capacity: 512
  ss-max-payload: 1452

root@OpenWrt:~# ip6tables -t mangle -L
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
JOOL       all      anywhere             anywhere             instance:example
...

root@OpenWrt:~# iptables -t mangle -L
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination
JOOL       all  --  anywhere             anywhere             instance:example
...

LAN 측 호스트에서 ipv4.google.com으로 ping해보십시오.
user@host:~$ ping6 ipv4.google.com
PING ipv4.google.com(nrt13s51-in-f14.1e100.net (64:ff9b::acd9:196e)) 56 data bytes
64 bytes from nrt13s51-in-f110.1e100.net (64:ff9b::acd9:196e): icmp_seq=1 ttl=116 time=5.18 ms
64 bytes from nrt13s51-in-f110.1e100.net (64:ff9b::acd9:196e): icmp_seq=2 ttl=116 time=5.00 ms
64 bytes from nrt13s51-in-f110.1e100.net (64:ff9b::acd9:196e): icmp_seq=3 ttl=116 time=5.20 ms
64 bytes from nrt13s51-in-f110.1e100.net (64:ff9b::acd9:196e): icmp_seq=4 ttl=116 time=5.36 ms
...

ICMP 세션 테이블을 확인합니다.
root@OpenWrt:~# jool --instance "example" session display --icmp
---------------------------------
Expires in 0:00:49.412
Remote: nrt13s51-in-f110.1e100.net#63022 2001:db8:fc7e:200:8e3:5b48:3ed8:e40#1
Local: 10.10.10.113#63022       64:ff9b::acd9:196e#1
---------------------------------

아래와 같이 Android에서는 clatd이 움직여 192.0.0.4가 자동 설정되어 있으므로 464XLAT도 문제없는 것 같습니다.


참고


  • Stateful NAT64 Run - Jool
  • Userspace Clients General Usage - Jool
  • Persistence - Jool
  • 좋은 웹페이지 즐겨찾기