FreeBSD搭建IPv6 Mostly网络

FreeBSD搭建IPv6 Mostly网络

· json · rss
Subscribe:

About

2026.6.14 UPDATE 主要实现完整NAT64路由,以及完善的RA通告,可管理的DNS,提升性能

需要配置的组件,IPFW (NAT64)、Unbound (DNS64)、dhcpcd (获取上游IPv6-PD前缀)、Radvd (IPv6 ND),AdGuardHome(配置缓存上游DNS)

注意!!!!,本片教程仅适用于内网,不要在公网使用,在公网使用配置防火墙之前务必知道自己在做什么。

效果展示:


1、需要配置下本地的配置,为了防止失联,建议使用tty串口连接控制台,FreeBSD配置tty串口

编辑/etc/loader.conf

kern.geom.label.disk_ident.enable="0"
kern.geom.label.gptid.enable="0"
zfs_load="YES"
boot_multicons="YES"
boot_serial="YES"
comconsole_speed="115200"
console="comconsole,vidconsole"

编辑/etc/ttys

ttyu0	"/usr/libexec/getty 3wire.115200"	vt100	on secure

开启SSH

sysrc sshd_enable="YES"
service sshd restart

2、启用组件配置接口默认IP,编辑/etc/rc.conf,这里看着改,需要启用WAN口这里是net0的ND,不然不会生成默认路由

首先需要额外安装组件,这两个组件在Freebsd中默认不提供

pkg install adguardhome unbound radvd

编辑/etc/rc.conf

hostname="Home0-NAT64-Router"
ifconfig_vtnet0="inet 10.10.0.64/24 netmask 255.255.255.0"
defaultrouter="10.10.0.13"
ifconfig_vtnet0_ipv6="inet6 accept_rtadv"
dhcpcd_enable="YES"
sshd_enable="YES"
moused_nondefault_enable="NO"
dumpdev="AUTO"
zfs_enable="YES"
gateway_enable="YES"
ipv6_gateway_enable="YES"
pf_enable="NO"
radvd_enable="YES"
adguardhome_enable="YES"
unbound_enable="YES"
firewall_enable="YES"
firewall_script="/etc/ipfw.rules"

3、编辑IPFW,/etc/ipfw.rules,看不懂的话丢给AI就知道是啥了,AI太好用了知道吗,这个配置的安全性非常低,建议在非公网使用

#!/bin/sh
fwcmd="/sbin/ipfw"
${fwcmd} -f flush
${fwcmd} nat64lsn NAT64 destroy 2>/dev/null

kldstat -q -m ipfw_nat64 || kldload ipfw_nat64 #启用内核组件
ipfw add 105 allow tcp from any to 10.10.0.64 22 in recv vtnet0 setup keep-state #放行SSH
ipfw add 106 allow tcp from any to 10.10.0.64 3000 in recv vtnet0 setup keep-state #放行ADG 端口

${fwcmd} add 50 tcp-setmss 1432 tcp from any to any tcpflags syn setup  #计算你的出口MTU
${fwcmd} nat64lsn NAT64 create prefix4 10.10.0.64/32 allow_private
${fwcmd} add 100 nat64lsn NAT64 ip6 from any to 64:ff9b::/96
${fwcmd} add 110 nat64lsn NAT64 ip4 from any to 10.10.0.64 in recv vtnet0
${fwcmd} add 115 allow ip6 from any to any in recv vtnet1 keep-state
${fwcmd} add 116 allow ip from any to 10.10.0.64 in recv vtnet0 keep-state
${fwcmd} add 65000 allow ip from any to any

4、配置Unbound,编辑/usr/local/etc/unbound/unbound.conf,依旧看不懂的话就丢给AI

sserver:
	chroot: ""
    username: "unbound"
	directory: "/usr/local/etc/unbound"
	interface: 2600:e641::64:64
    interface: ::1
	interface: fe80::be24:11ff:fe75:1760%vtnet1
	port: 53
	access-control: 2600:e641::/64 allow
    access-control: ::1 allow
	access-control: fe80::/10 allow
	access-control: ::/0 allow
	module-config: "dns64 iterator"
	dns64-prefix: 64:ff9b::/96
#	dns64-synthall: yes #启用这个选项会过滤所有IPv6的地址强制使用NAT64 
	prefetch: yes
	prefetch-key: yes
	msg-cache-size: 16m
	rrset-cache-size: 32m
	do-not-query-localhost: no

#	log-queries: no
#	verbosity: 2
#	logfile: "/var/log/unbound.log"	

forward-zone:
	name: "."
	forward-addr: 127.0.0.1@5353

5、配置dhcpcd,从我的RouterOS上划了一段电信的/64,通过DHCP分配过来,但是注意,如果不想给局域网其他设备分配PD前缀,需要使用DUID Bouding,这样默认其他设备申请dhcpv6,RouterOS就会忽略请求,配置例子

/ipv6 dhcp-server
add comment=nat64-bsd-publicprefix interface=vlan10-general name=\
  nat64-bsd-publicprefix
/ipv6 dhcp-server binding
add address=::/0 duid=0x0001000131bc22f1bc2411324e57 iaid=1 \
  life-time=10m prefix-pool=ipv6-wan server=nat64-bsd-publicprefix

注意RouterOS上游更新之后并不会更新Bindings里面的地址,需要在dhcpv6-client里面添加一个脚本,这样就会重新下发新前缀了

:if ($"pd-valid" = 1) do={
    :log info "IPv6 Prefix changed. Updating FreeBSD router binding..."
:local bindId [/ipv6 dhcp-server binding find where comment="freebsd-rt-prefix"]
:if ($bindId != "") do={
        /ipv6 dhcp-server binding set $bindId address=::/64
        :log info "FreeBSD router binding address has been reset to ::/64"
    } else={
        :log warning "DHCPv6 binding with comment 'freebsd-rt-prefix' not found."
    }
}

DUID FreeBSD安装dhcpcd后使用cat /var/db/dhcpcd/duid获取,删掉冒号写成0x 16进制就行

接下来编辑/usr/local/etc/dhcpcd.conf,从vtnet0获取地址,分配前缀到vtnet1

ipv6only
noipv4
duid
persistent
option rapid_commit
require dhcp_server_identifier
allowinterfaces vtnet0
interface vtnet0
	ipv6rs
	ia_na 1
	ia_pd 2 vtnet1/0

配置一个触发器/usr/local/etc/dhcpcd.exit-hook,如果前缀发生变化会重新发起BOUND6,只要检测到BOUND6重启radvd,使旧的Prefix的lifetime 为 0, 不然客户端不会知道目前的前缀过期了

#!/bin/sh

echo "[$(date)] Kernel Single -> interface: $interface | Reason: $reason" >> /var/log/dhcpcd_test.log

INT_IFACE="vtnet1"
case "$reason" in
    BOUND6)
            if [ "$interface" = "$INT_IFACE" ]; then
            sleep 1
            echo "[$(date)] detecting prefix change, reloading...">> /var/log/dhcpcd_test.log
            /usr/sbin/service radvd restart >/dev/null 2>&1
        fi
        ;;
esac

6、最后配置Radvd,这是Freebsd默认的IPv6 NDP,编辑cat /etc/radvd.conf,注意需要有pref64和rdnss参数,IOS和Android客户端才会开启464XLAT模式,使用IPv6传输IPv4

interface vtnet1 {
    AdvSendAdvert on;
    MinRtrAdvInterval 3;
    MaxRtrAdvInterval 10;
    AdvLinkMTU 1492;  #让客户端使用1492 MTU如果你的出口是PPPOE拨号会有这个问题
    AdvManagedFlag off;
    AdvOtherConfigFlag on;

    prefix ::/64 {
        AdvOnLink on;
        AdvAutonomous on;
        AdvValidLifetime 7200;
        AdvPreferredLifetime 1800;
	    DeprecatePrefix on;  #当接口地址更新之后将过期地址进行Deprecate
    };

    RDNSS 2600:e641::64:64 { #设置一个内网的DNS,建议找一个不用打公网前缀,虽然也可以使用link-local,但是部分操作系统不兼容
        AdvRDNSSLifetime 1800;
    };
    nat64prefix 64:ff9b::/96 {
        AdvValidLifetime 1800;
    };
};

7、最后一步直接reboot重启大法就行了,理论重启玩所有的都OK了,但是注意,ipv6上游前缀更新会导致临时断网,因为ipv4 over ipv6 clat转换,会导致ipv4也会临时瘫痪