赞
踩
光猫:ZXHN F650(GPON ONU)
硬件环境:openwrt x86
openwrt固件版本:21.02.0 r16279-5cc0535800
由光猫拨号,openwrt直接使用DHCP客户端连接。光猫具体配置如下图:
防火墙讲道理应该是不用设置的。因为看说明好像只是ipv4的设置。
而openwrt的应设置3个接口。分别为与光猫连接的WAN口,这个口只是用于ip4协议使用DHCP4客户端,然后再在这个接口上添加WAN6,协议使用DHCP6客户端用于获取光猫下发的ipv6。而LAN口除了正常的ip4的配置外,还应该添加ipv6 DHCP6服务。如下图
WAN
WAN6
LAN
PC侧的防火墙我就不演示了,实在不行可以直接关掉试试。
openwrt的防火墙可以在网络->防火墙->常规设置。将forward设置为accept。然后再讲区域中的都改成accept。这样就可以连接到你ipv6上的每一个端口。但是这样设置几乎就完全暴露自己了。但是可以先这样试试看是否能连接常用的一些端口。
正常做法是自定义规则来,避免完全暴露。如下
在Firewall - Traffic Rules中添加规则
这里的目标地址可以不填。当然你也可以指定IP,避免lan口上所有的设备都暴露下面的端口。
我这里是直接用的阿里云,因为官方固件对阿里的ddns不是很友好,用阿里云的DDNS API来做。具体做法
1、在openwrt中安装python环境
2、python pip 安装阿里云Python API
3、编写脚本,查询本机IP,如有更改就调用阿里云API更新DNS
4、使用openwrt的定时脚本,定时执行
使用openwrt opkg安装python3,当然也可以用web管理界面安装。其中需要安装 python3、python3-pip、python3-dev、python3-cffi、python3-cff3-src。黑体字这3个会影响到阿里云SDK的正确安装。
按照阿里云的说明,先安装pip install alibabacloud_tea_openapi,然后安装pip install alibabacloud_alidns20150109==2.0.2。到这里阿里云API的环境搭建完成。
脚本可以按照说明书下面的示例写,需要用到AccessKey,这个直接在阿里云的网站上面设置。下面给出一个我自己写的脚本。
Openwrt路由的IP可以通过连接2400:da00:2::29获得,而我个人PC的IP是直接通过ping我PC的计算机名称来获取,我的计算机名为HomeComputer,所以有一行代码是
val = os.popen('ping -6 -c 1 HomeComputer').read()
以下是完整的python刷新openwrt IP的脚本
- from socket import AddressFamily
- from socket import SocketKind
- from socket import socket
- from typing import List
- import os
- import time
- import traceback
- from alibabacloud_alidns20150109 import client
- from alibabacloud_alidns20150109.client import Client as Client
- from alibabacloud_alidns20150109 import models as alidns_20150109_models
- from alibabacloud_tea_openapi import models as open_api_models
- def CalculateComputerIP(ipv6):
- newIP = ''
- val = os.popen('ping -6 -c 1 HomeComputer').read() #此处使用自己的计算机名称
- if 'bad address' in val: #电脑关机休眠的情况
- newIP = ipv6
- else:
- newIP = val[val.rfind('(') + 1:val.rfind(')')]
- return newIP
- def UpdateRecord():
- localtime = time.asctime( time.localtime(time.time()))
- print(localtime)
- s = socket(AddressFamily.AF_INET6,SocketKind.SOCK_DGRAM)
- s.connect(('2400:da00:2::29',80))
- ip = s.getsockname()[0]
- print('current openwrt ip6->' + ip)
- config = open_api_models.Config(
- # 您的AccessKey ID,
- access_key_id='-----------------',
- # 您的AccessKey Secret,
- access_key_secret='----------------'
- )
- config.endpoint='alidns.cn-hangzhou.aliyuncs.com'
- client = Client(config)
- request = alidns_20150109_models.DescribeDomainRecordsRequest()
- request.domain_name = '*******.cn'
- request.lang = 'en'
- response = client.describe_domain_records(request)
- #for record in response.body.domain_records.record:
- #print(record.value)
- results = [r for r in response.body.domain_records.record if r.type == 'AAAA']
- computerResult = results[0]
- openwrtResult = results[1]
- computerIP = CalculateComputerIP(computerResult.value)
- print('current computer ip->' + computerIP)
- print('ali computer ip->' + computerResult.value + '\t' + "ali openwrt id->" + openwrtResult.value)
- print('ali computer id->' + computerResult.record_id + '\t' + "ali openwrt id->" + openwrtResult.record_id)
- isUpdateOpenwrt = False
- isUpdateComputer = False
- if(openwrtResult.value!=ip):
- print('current openwrt ip != ali ip,will be update ddns.')
- # 更新AAAA纪录
- update_openwrt_request = alidns_20150109_models.UpdateDomainRecordRequest(
- rr='openwrt',
- type='AAAA',
- record_id=openwrtResult.record_id,
- value=ip
- )
- print('update openwrt AAAA record.')
- try:
- #print('update_openwrt_request:' + update_openwrt_request.__str__)
- updateOpenwrtIPReponse = client.update_domain_record(update_openwrt_request)
- isUpdateOpenwrt = True
- print('update openwrtIP is ok.')
- except Exception as e:
- print('update openwrtIP record except:' + e.args)
- UpdateRecord()

然后使用crontab来设置定时启动上面这个文件就好了。
而PC端的IP可以直接改上面的Python代码来实现,但是经过测试很不稳定,所以我在PC端写了一个服务定时刷新IP进行DDNS。主要的代码如下
- public partial class AliDDNSService : ServiceBase
- {
- Client _ddnsClient;
- DescribeDomainRecordsRequest _request;
- DescribeDomainRecordsResponse _response;
- bool _running = false;
- Timer _timer;
- public AliDDNSService()
- {
- InitializeComponent();
- _ddnsClient = CreateClient("-------------", "-------------------");
- _request = new DescribeDomainRecordsRequest();
- _response = new DescribeDomainRecordsResponse();
- _timer = new Timer(10 * 60 * 1000);
- _timer.Elapsed += RefreshDNS;
- }
-
- protected override void OnStart(string[] args)
- {
- _timer.Start();
- }
-
- private void RefreshDNS(object sender, ElapsedEventArgs e)
- {
- if (_running) return;
- try
- {
- _running = true;
- _request.DomainName = "*********.cn";
- _request.Lang = "en";
- _response = _ddnsClient.DescribeDomainRecords(_request);
- var results = _response.Body.DomainRecords.Record.Where(w => w.Type == "AAAA");
- var result = results.ElementAt(0); //设计第一个IP为PC的IP
- string recordIP = result.Value;
- string currentIP = GetCurrenIPV6();
- if (recordIP == currentIP) return;
- _ddnsClient.UpdateDomainRecord(new UpdateDomainRecordRequest
- {
- RR = "computer",
- Type = "AAAA",
- RecordId = result.RecordId,
- Value = currentIP
- });
- }
- catch (Exception exp)
- {
-
- }
- finally
- {
- _running = false;
- }
-
- }
-
- protected override void OnStop()
- {
- _timer.Stop();
- }
- protected override void OnPause()
- {
- _timer.Stop();
- }
- protected override void OnContinue()
- {
- _timer.Start();
- }
- protected override void OnShutdown()
- {
- _timer.Stop();
- }
-
- private Client CreateClient(string accessKeyId, string accessKeySecret)
- {
- Config config = new Config
- {
- // 必填,您的 AccessKey ID
- AccessKeyId = accessKeyId,
- // 必填,您的 AccessKey Secret
- AccessKeySecret = accessKeySecret,
- };
- // 访问的域名
- config.Endpoint = "alidns.cn-hangzhou.aliyuncs.com";
- return new Client(config);
- }
- private string GetCurrenIPV6()
- {
- var hostName = Dns.GetHostName();
- var addresses = Dns.GetHostAddresses(hostName);
- var list = addresses.Where(w => w.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6);
- list = list.Where(l => l.ToString().First() == '2');
- return list.OrderBy(l=>l.ToString().Length).First().ToString();
- }
- }

注意:如果要远程连接PC,需要先使用OpenWrt的Wake On Lan唤醒我们的计算机。
当然也可以写一个脚本完成此项操作,我这里用C#写了一个控制台的程序。思路就是OpenWrt打开SSH,然后通过SSH来操作路由器,让路由器上的WakeOnLan工作。我这个引用了nuget包ssh.net
以下就是我的控制台程序
- namespace wakeOnLan
- {
- internal class Program
- {
- static SshClient _client;
- static void Main(string[] args)
- {
- try
- {
- var result = GetOpenwrtIP().Result;
- if (!result.Item1)
- {
- Console.WriteLine("Get openwrt ip failure.");
- return;
- }
- _client = new SshClient($"{result.Item2}", 2222, "root", "root密码");//使用2222作为ssh的端口,这里可以在openwrt中更改
- _client.Connect();
- var command = _client.RunCommand("/usr/bin/etherwake -D -i br-lan -b mac地址");//这里填入自己的设备MAC地址
- Console.WriteLine(command.Result);
- _client.Disconnect();
- _client.Dispose();
- }
- catch (Exception exp)
- {
- Console.WriteLine(exp.Message);
- }
- finally
- {
- Console.WriteLine("Wait a minute.");
- }
- }
- static async Task<(bool, string)> GetOpenwrtIP()
- {
- Process process = new Process();
- process.StartInfo.FileName = "cmd.exe";
- process.StartInfo.UseShellExecute = false;
- process.StartInfo.RedirectStandardInput = true;
- process.StartInfo.RedirectStandardOutput = true;
- process.StartInfo.RedirectStandardError = true;
- process.StartInfo.CreateNoWindow = true;
- process.Start();
- process.StandardInput.WriteLine("ping -6 -n 1 *****.*****.cn");//通过域名来找到IPv6
- process.StandardInput.Flush();
- process.StandardInput.Close();
- Thread.Sleep(1000);
- string content = await process.StandardOutput.ReadToEndAsync();
-
- if (!content.Contains("0% loss")) return (false, "");
- var contents = content.Split("\r\n");
- content = contents[5];
- content = content.Split("]")[0].Split("[")[1];
- return (true, content);
-
- }
- }
- }

编译后,将可执行的文件拷贝至Windows/system32文件夹下,即可在cmd或powershell中运行。
这里因为是这电脑没有ipv6所以失败了
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。