Padavan 路由器开启 IPv6,使外网通过 IPv6 访问子网树莓派上的网站 | 陶熔鼓铸

步骤:
一、获取公网 IPv6 地址并在树莓派上构建 Web 服务器
二、设置阿里 DNS 域名解析
三、更改树莓派获取 IPv6 地址的方式

四、更改 Padavan 防火墙的设置

一、获取公网 IPv6 地址并在树莓派上构建 Web 服务器

首先需要确定的是,您的运营商支持 IPv6。您可以通过以下配置尝试是否可以获取到 IPv6。

在 IPv6 的设置页面,按上图进行设置。如果运营商已经支持 IPv6 网络,那么设置完成后,在网络地图中的 “ IPv6 地址:WAN ”和“ IPv6 地址:LAN ”中,都会获取到 IPv6 地址,如下图所标示位置:

将树莓派连入网络中,使用 ifconfig 命令检查是否获取到 IPv6 地址。一般接口为 eth0,如果您打开了 wlan,同时查看相应接口是否也获取到 IPv6 地址。
注意:
1、即便 eth0 和 wlan0 连接到了不同路由器,两个接口也都会获取到 IPv6。
2、以 fe80 开头的 IPv6 地址为链路本地连接地址,并不是公网 IPv6 地址。
您可以简单地把它理解为 IPv4 中类似 192.168.x.x 这类私有地址。

使用 ping6 命令可以检查网络的连通性,如下图:

网络连通了以后,您可以在树莓派上安装 Web 服务器,例如 Apache 或 Nginx。具体方法本文不再赘述,请查阅相关资料。安装完成后,请保持默认配置即可,即,所有 IP 地址(IPv4 和 IPv6)都可以通过浏览器访问。您也可以根据自己的需要进行设置。
当您做好了以上准备,就可以进行下一步了。

二、设置阿里 DNS 域名解析

通过以上操作,树莓派已经可以连接到 IPv6 网络,并实现外部访问了。
现在的问题是:
我们是以 PPPoE 方式上网,所获取的 IPv6 地址是动态的,即,每次路由器重启,IPv6 地址就会改变,树莓派重启,它的 IPv6 地址也会改变。这样一来,我们在树莓派上搭建 Web 服务器的话,就需要频繁的更改 IPv6 地址来访问。
为了便于记忆,我们使用域名解析到它的 IPv6 地址。在此只介绍使用阿里 DNS 来进行解析的办法。在设置之前,您需要在阿里云购买了一个域名并进行了实名认证。

1、登录阿里云网站并进入控制台,在右上角个人资料中,选择 AccessKey 管理。

2、出现以下提示时,选择“开始使用子用户 AccessKey”。

3、依次填写用户信息、显示名称,并将访问方式设置为“编程访问”。

4、验证手机后,会显示 AccessKeyID 和 AccessKey Secret,该信息页面关闭后无法再次显示,请妥善保存该信息。

5、在左侧的菜单中,点击“用户”,对刚才添加的用户进行添加授权。在搜索栏输入“dns”,点击下部筛选结果中的“AliyunDNSFullAccess”以将其添加到右侧列表中。点击确定以完成。

6、切换至阿里云域名管理设置界面,对您使用的域名进行解析操作,以初始化记录。在此,您需要解析一个记录类型为“AAAA”的主机,将其 IPv6 地址手动的设置为你树莓派上 eth0 口的 IPv6 地址,主机名称任选,如下图,保存并等待其生效。
至此,阿里云端的操作结束。

7、下面转到树莓派的本地设置。
由于路由器或树莓派本身的重启都会导致树莓派IPv6 地址的变化,我们就需要在树莓派的 IPv6 地址发生变化时,将新的 IPv6 地址信息传递给阿里云,进行 DNS 记录的更改。为便于操作,我们使用 Python 脚本实现这一功能,同时,为了尽量保证中断的时间尽可能短,我们使用计划任务每 10 分钟执行一次这个脚本。

该脚本来源于网络搜集,由 BG3MDO、BH4DQX 进行了编辑改写,对源脚本的问题进行了修正和处理。

请在树莓派的用户目录中,建立一个名称为 xxx.py 的文件,并将以下脚本内容复制过去:

#coding:utf-8
from __future__ import print_function
from aliyunsdkcore import client
from aliyunsdkalidns.request.v20150109 import DescribeDomainsRequest,DescribeDomainRecordsRequest,UpdateDomainRecordRequest
import json,urllib,re
import subprocess

#替换以下参数
ID="这里填写你从阿里云获取的AccessKeyID"
Secret="这里填写你从阿里云获取的AccessKeySecret"
RegionId="cn-hangzhou"
DomainName="这里填写你的域名,不带主机名,如:abc.com"
#想要自动修改的主机名和域名类型
HostNameList = ['这里填写你的主机名']
Types = "AAAA"

clt = client.AcsClient(ID,Secret,RegionId)

#获取公网ip
def GetLocalIP():
    ips = subprocess.check_output(["hostname", "-I"])
    #ip = subprocess.check_output(["curl", "-s", "https://api-ipv6.ip.sb/ip"])
    ip = ips.split()[-1]
    print(ip)
    return ip

#获取域名列表
def GetDomainList():
    DomainList = DescribeDomainsRequest.DescribeDomainsRequest()
    DomainList.set_accept_format('json')
    DNSListJson = json.loads(clt.do_action(DomainList))
    print(DNSListJson)

#更新域名ip
def EditDomainRecord(HostName, RecordId, Types, IP):
    UpdateDomainRecord = UpdateDomainRecordRequest.UpdateDomainRecordRequest()
    UpdateDomainRecord.set_accept_format('json')
    UpdateDomainRecord.set_RecordId(RecordId)
    UpdateDomainRecord.set_RR(HostName)
    UpdateDomainRecord.set_Type(Types)
    UpdateDomainRecord.set_TTL('600')
    UpdateDomainRecord.set_Value(IP)
    UpdateDomainRecordJson = json.loads(clt.do_action(UpdateDomainRecord))
    print("Edit Domain Record returns:")
    print(UpdateDomainRecordJson)

#获取域名信息
def GetAllDomainRecords(DomainName, Types, IP):
    DomainRecords = DescribeDomainRecordsRequest.DescribeDomainRecordsRequest()
    DomainRecords.set_accept_format('json')
    DomainRecords.set_DomainName(DomainName)
    DomainRecordsJson = json.loads(clt.do_action(DomainRecords))
    for HostName in HostNameList:
        for x in DomainRecordsJson['DomainRecords']['Record']:
            RR = x['RR']
            Type = x['Type']
            if RR == HostName and Type == Types:
                RecordId = x['RecordId']
                print("Record ID is: " + RecordId)
                print("Hostname: " + HostName)
                print("Types: " + Types)
                print("IP: " + str(IP))
                print("-"*32)
                EditDomainRecord(HostName, RecordId, Types, IP)

IP = GetLocalIP()
print("-"*32)
GetDomainList()
print("-"*32)
GetAllDomainRecords(DomainName, Types, IP)

8、需要树莓派中的 Python 版本为 2.7 以上,使用 pip 安装 SDK:

sudo pip install aliyun-python-sdk-alidns

通过 install 完成升级:

sudo pip install aliyun-python-sdk-alidns --upgrade

9、建立定时任务:

crontab -e

在打开的文件最后一行添加:

* /10 * * * * /usr/bin/python2 /home/xxx.py

至此,阿里 DNS 功能设置完毕。该脚本每 10 分钟向阿里云提交一次更改请求,以保障服务的连续性。

三、更改树莓派获取 IPv6 地址的方式

我们先讨论一下从运营商网络获取 IPv6 地址(Global Address)的方式,然后再说为什么要更改树莓派获取 IPv6 地址的方式。

生成“全球单播地址”,有两种方式:即手动配置和自动配置,我们只讨论自动配置。

自动配置根据获取方式,分为:无状态(Stateless)有状态(Stateful)。
无状态:根据路由通告报文 RA(Router Advertisement)包含的 Prefix 前缀信息自动配置 IPv6 地址,组成方式是:Prefix + (EUI64 或者 随机)。Stateless 也可称为 SLAAC(Stateless address autoconfiguration)。
有状态:通过 DHCPv6 方式获取 IPv6 地址。

其中,“有状态”又分为两种情况:有状态 DHCPv6(Stateful DHCPv6)无状态 DHCPv6(Stateless DHCPv6)
有状态 DHCPv6:IPv6 地址、其它参数(如DNS)均通过 DHCPv6 获取。
无状态 DHCPv6:IPv6 地址依然通过路由通告 RA 方式生成,其它参数(如DNS)通过 DHCPv6获取。

现在我们回过头来再说为什么要更改树莓派 IPv6 地址的获取方式。

内网设备(本例中的树莓派)的 IPv6 地址,前半部分是 IPv6 前缀,是运营商分配的,宽带重新连接后会发生变化。
后半部分,有两种情况,一种是随机,这样的话也会有变化。另一种是 EUI64,与 MAC 地址相关,不会变化,除非更换网卡。

如果整个 IPv6 的前后两个部分都会变,那么防火墙规则就没办法写了。除非全网放行(内网目标地址掩码填 ::/0 或 any)。

所以,将树莓派 IPv6 地址的后半部分设置为 EUI64,防火墙的目标地址掩码填写 ::xxxx:xxxx:xxxx:xxxx/::FFFF:FFFF:FFFF:FFFF,这样就比较安全了。因为 IPv6 地址掩码比 IPv4 灵活,IPv6 可以掩前面,也可以掩后面,而 IPv4 就只能掩前面。
需要注意的是,这里的例子,默认的掩码为/64,如果您的网络分配的掩码不是64,则需要调整掩码位数。

目的很简单,更改树莓派的 IPv6 地址后半部分的获取方式为 EUI64,可以让我们有办法在防火墙上做相应设置。

步骤如下:

vi /etc/dhcpcd.conf

在此配置文件中,查找 slaac ,将其默认的 slaac private 注释掉,将默认注释掉的 slaac hwaddr 启用即可。更改后重新获取 IPv6 地址,再用 ifconfig 命令验证,其 IPv6 地址后六位与对应的 MAC 地址后六位相同并且不变。

四、更改 Padavan 防火墙的设置

在路由器设置中,开启防火墙,此时搭建在树莓派上的 IPv6 网站无法从外网访问。
在路由器配置界面中,打开“自定义设置”——“脚本”。在“在防火墙规则启动后执行”一项中,填入以下内容:

ip6tables -A INPUT --ipv6 -p tcp -d ::xxxx:xxxx:xxxx:xxxx/::FFFF:FFFF:FFFF:FFFF -j ACCEPT
ip6tables -A OUTPUT --ipv6 -p tcp -d ::xxxx:xxxx:xxxx:xxxx/::FFFF:FFFF:FFFF:FFFF -j ACCEPT
ip6tables -A FORWARD --ipv6 -p tcp -d ::xxxx:xxxx:xxxx:xxxx/::FFFF:FFFF:FFFF:FFFF -j ACCEPT
ip6tables -A INPUT --ipv6 -p tcp -d ::nnnn:nnnn:nnnn:nnnn/::FFFF:FFFF:FFFF:FFFF -j ACCEPT
ip6tables -A OUTPUT --ipv6 -p tcp -d ::nnnn:nnnn:nnnn:nnnn/::FFFF:FFFF:FFFF:FFFF -j ACCEPT
ip6tables -A FORWARD --ipv6 -p tcp -d ::nnnn:nnnn:nnnn:nnnn/::FFFF:FFFF:FFFF:FFFF -j ACCEPT

上述代码中,::xxxx:xxxx:xxxx:xxxx 是 eth0 端口的 IPv6 地址的后半部分,而 ::nnnn:nnnn:nnnn:nnnn 是 wlan0 端口的 IPv6 地址的后半部分。这样,当树莓派既连接了有线又连接了无线时,不管树莓派使用 eth0 还是 wlan0 端口的 IPv6 地址向阿里 DNS 提交解析数据时,都可以实现从外网到此树莓派的访问。
如果您的内网主机设备有多个网络接口,可以参照上述配置添加所有接口的防火墙规则。由于我们没有固定的 IPv6 地址,所以无法在 Web 服务器中绑定一个地址(或者,通过脚本实现起来非常麻烦)。

至此,树莓派可以实现从使用 IPv6 的外网通过域名访问了。其实,之所以使用 ipv6 来搭建,主要的原因有二,一是,部分运营商没有公网 IPv4,但提供了公网 IPv6;二是,貌似所有运营商早已将 IPv4 的 80 端口封锁,而 IPv6 可能尚未封锁。

我这里搭建好的访问地址是:http://pi.liyajun.top,欢迎测试。如果您接入了 IPv6 网络,打开这个网址,您将会看到一个树莓派 Dashboard 页面。

(0)

相关推荐