『瀚思彼岸』» 智能家居技术论坛

 找回密码
 立即注册
查看: 324|回复: 8

[教程系列] 小白教小白-ipv6变化后自动更新openwrt软路由的防火墙规则

[复制链接]

32

主题

302

帖子

1734

积分

金牌会员

Rank: 6Rank: 6

积分
1734
金钱
1427
HASS币
40
发表于 2024-3-27 12:41:31 | 显示全部楼层 |阅读模式
小白教小白-当ipv6地址发生变更后,自动更新openwrt软路由的防火墙规则

起因:我是移动宽带,只能获取ipv6公网,软路由使用istoreos系统,是根据openwrt修改而来的。Homeassistant是通过docker方式安装在unraid系统中的。因为需要公网访问hass,又不希望通过关闭软路由的防火墙来实现访问hass,因为这样会公开unraid系统的全部端口。所以只在istoreos系统中的网络-防火墙-通信规则,开放了unraid8123端口。但是因为软路由重启等行为,unraid获取的ipv6地址会放生变化,又不希望每次手动更改,所以使用了node-red来进行自动化操作。
备注:ipv6地址的获取,可以通过openwrt来设置,这里也不说了,我也是小白,自己也不懂,说也说不来,而且获取分为有状态、无状态什么的,看网上,有状态好像可以固定ipv6后面的地址段,这样可以通过防火墙规则,匹配固定的地址段来达到开放端口的目的,但我实在看不懂,也不会设置,就想着干脆点,你的ip地址变了,那我防火墙规则自动变。所以有了下文。
注意,按下面的操作,你需要
1、除了你的路由器,你的主机必须获取ipv6,且外网可以正常通过ipv6访问到你的主机。
2、如果通过docker方式安装的node-red,那么网路模式必须是host,否则docker安装的node-red无法获取宿主机的ipv6地址。
3、如果你要公开的端口是docker的应用,那么同上,必须是host,理由同上。
比如我是在unraid系统安装的hass,你要通过外网ipv6访问到hass,那么首先,在路由器关闭网络防火墙的前提下,必须外网能通过ipv6访问到unraid系统node-red1880端口和hass8123端口。否则一切免谈。
先放流程图:
1.png
流程解释:
就是每10分钟运行一次流程,让node-red来获取一下宿主机的公网ipv6地址,然后对比原先的ipv6地址,如果一致,则不操作,如果不一致,就通过ssh的方式,对openwrt使用sed命令和/etc/init.d/firewall restart这个防火墙重启命令来,达到修改防火墙通信规则的目的。
1、新建一个时间戳的节点,让他每10分钟运行一下;
2、新建一个exec节点,让他运行curl -s ipv6.icanhazip.com命令,获取宿主机的ipv6地址;
3、新建一个函数节点,因为通过上面exec节点获取的ipv6地址,最后有一个回车符号,需要把这个回车符号去除掉。
4、新建一个read file节点,读取原来储存在名为“本机ipv6地址.txt”文件中的ipv6地址。注意,这个节点中,文件名称和路径要视你的实际情况来写。(你可以先新建一个文件,然后手动把宿主机的ipv6地址写进去,比如2409:aaaa:bbbb:cccc:1111:2222:3333:4444)。
5、实际上你也可以不要这个文件,可以通过设置node-red的全局变量(可持久化存储变量)来达到这个目的,详见https://bbs.hassbian.com/thread-5842-1-1.html但是我还是偷懒了。反正也无所谓。但node-red普通的全局变量不合适,因为万一node-red重启了,变量值就没有了。
6、新建一个函数节点,对新获得的ipv6地址和原来储存在文件中ipv6地址进行对比,并根据对比结果是否相同来触发后续流程。在本例中,我设置了4个输出,其中如果对比结果2ip地址一致,就有第一个输出,结果不一致,就有后面第234个输出。其中第一个输出我实际上后面没有流程了;第二个输出是将新的ipv6地址保存到“本机ipv6地址.txt”文件中,用于后续的再比较;第三个输出就是通过ssh节点来运行一个修改路由器防火墙文件的命令;第4个输出,后面接了一个延迟节点,延迟5秒后运行一个重启路由器防火墙的命令。这个函数节点,我再内容里添加了备注,具体可以看一下节点函数。
7、新建一个ssh节点,这个节点你需要自行安装。可以在node-red的节点管理中,搜索并安装“node-red-contrib-ssh-v3”这个节点。安装后,节点的设置,按照你软路由的ip地址、用户名、密码等填写。
注意:这个流程,sed命令和/etc/init.d/firewall restart这个防火墙重启命令,可能要看你的软路由的情况,需要你自行查询测试。
放上一个istoreos的防火墙配置图片
2.png
3.png
名称:随意填写
目标地址:你主机的ipv6地址,比如我的unraid系统主机的ipv6地址
目标端口:你要公开的端口,比如hass的端口。
其他的都不需要更改。
保存后,不要忘了在通信规则的主界面,点击“保存并应用”按键。
最后放上流程和json文件。

[
    {
        "id": "44fdaba6710cfcac",
        "type": "comment",
        "z": "cbe57fd6f44c0398",
        "name": "替换文件中的内容可以使用以下命令",
        "info": "sed -i 's/原内容/现内容/g' /etc/config/firewall\n",
        "x": 920,
        "y": 180,
        "wires": []
    },
    {
        "id": "a8168fe07ed0533a",
        "type": "comment",
        "z": "cbe57fd6f44c0398",
        "name": "每10分钟查询宿主机的公网ip地址,如果与原来的ip地址不一致,则更改openwrt的防火墙规则",
        "info": "注意,要查询到宿主机的ipv6,必须在node-red的docker安装时,使用host网路。",
        "x": 420,
        "y": 180,
        "wires": []
    },
    {
        "id": "d97fad1588a88f22",
        "type": "exec",
        "z": "cbe57fd6f44c0398",
        "command": "curl -s ipv6.icanhazip.com",
        "addpay": "",
        "append": "",
        "useSpawn": "false",
        "timer": "",
        "winHide": false,
        "oldrc": false,
        "name": "",
        "x": 370,
        "y": 260,
        "wires": [
            [
                "14707bd83ffd63c5"
            ],
            [],
            []
        ]
    },
    {
        "id": "84f29c9208408ba1",
        "type": "inject",
        "z": "cbe57fd6f44c0398",
        "name": "",
        "props": [
            {
                "p": "payload"
            },
            {
                "p": "topic",
                "vt": "str"
            }
        ],
        "repeat": "600",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 160,
        "y": 260,
        "wires": [
            [
                "d97fad1588a88f22"
            ]
        ]
    },
    {
        "id": "8c1e7ebc76b47860",
        "type": "file in",
        "z": "cbe57fd6f44c0398",
        "name": "",
        "filename": "/mnt/cache/appdata/logs/本机ipv6地址.txt",
        "filenameType": "str",
        "format": "utf8",
        "chunk": false,
        "sendError": false,
        "encoding": "none",
        "allProps": false,
        "x": 860,
        "y": 260,
        "wires": [
            [
                "e5e1d84306606703"
            ]
        ]
    },
    {
        "id": "e5e1d84306606703",
        "type": "function",
        "z": "cbe57fd6f44c0398",
        "name": "判断ip地址是否一致",
        "func": "var old_ip = msg.payload;\n//新建一个变量,变量名称是old_ip,他的值是前面传下来的msg.payload的值\nvar new_ip = msg.new_ip;\n//新建一个变量,变量名称是new_ip,他的值是前面传下来的msg.new_ip的值\nvar msg1 = {\n    "payload": old_ip,\n}\n//这实际上就是重新赋予msg.payload新的值,他的值就是变量old_ip的值\nvar msg2 = {\n    "payload": new_ip,\n}\n//这实际上就是重新赋予msg.payload新的值,他的值就是变量new_ip的值\nvar msg3 = {\n    "payload": "sed -i 's/" + old_ip + "/" + new_ip + "/g' /etc/config/firewall",\n}\n//这实际上就是重新赋予msg.payload新的值,他的值就是sed -i 's/" + old_ip + "/" + new_ip + "/g' /etc/config/firewall。\n//如果你原来的ip是192.168.0.1,新的ip是192.1.1.1,那么这个msg.payloa的值就是sed -i 's/192.168.0.1/192.1.1.1/g' /etc/config/firewall\n//这实际上是一个sed命令,用来搜索并替换文件内容,他搜索了/etc/config/firewall文件,并将文件中192.168.0.1替换为192.1.1.1\n//这个命令的用法可以自行百度搜索一下用法。配后后面ssh的节点,就可用ssh的方式登录路由器并修改防火墙规则的文件。\n\nvar msg4 = {\n    "payload": '/etc/init.d/firewall restart',\n}\n//这实际上就是重新赋予msg.payload新的值,他的值就是/etc/init.d/firewall restart\n//这是一个重启openwrt路由防火墙的命令,因为openwrt系统的不一样,可能命令也不一样,请自修搜索并测试\n\nif (new_ip == old_ip) {\n    return [msg1, null, null, null];\n}\nelse {\n    return [null, msg2,msg3,msg4];\n}\n//用if进行判断,如果新的ip地址和旧的ip地址一样,就在第一个输出中,输出msg1,而后面3个输出中不予输出任何内容\n//如果新的ip地址和旧的ip地址不一样,那么第一个输出中不予输出任何内容,后面3个输出中,分别输出不同内容。\n//这个就可以进行判断ip地址是否更新,并触发后续不同的流程。\n",
        "outputs": 4,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 210,
        "y": 400,
        "wires": [
            [
                "13b9aa9acd9c766e"
            ],
            [
                "3732bd003b93dbd1"
            ],
            [
                "9d4685449276e70c"
            ],
            [
                "a9ecd801ae2d9de2"
            ]
        ]
    },
    {
        "id": "13b9aa9acd9c766e",
        "type": "debug",
        "z": "cbe57fd6f44c0398",
        "name": "输出ip信息",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 430,
        "y": 360,
        "wires": []
    },
    {
        "id": "14707bd83ffd63c5",
        "type": "function",
        "z": "cbe57fd6f44c0398",
        "name": "去除回车符",
        "func": "msg.new_ip = msg.payload.replace(/\\n/g, '');\nreturn msg;\n",
        "outputs": 1,
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 590,
        "y": 260,
        "wires": [
            [
                "8c1e7ebc76b47860"
            ]
        ]
    },
    {
        "id": "a32c6a90cea1c25c",
        "type": "ssh-v3",
        "z": "cbe57fd6f44c0398",
        "name": "istoreos",
        "conf": "a0d90d0d10c5af01",
        "debug": false,
        "x": 260,
        "y": 600,
        "wires": [
            [
                "bfd64169598baa27"
            ]
        ]
    },
    {
        "id": "bfd64169598baa27",
        "type": "debug",
        "z": "cbe57fd6f44c0398",
        "name": "输出ip信息",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 550,
        "y": 600,
        "wires": []
    },
    {
        "id": "3732bd003b93dbd1",
        "type": "file",
        "z": "cbe57fd6f44c0398",
        "name": "",
        "filename": "/mnt/cache/appdata/logs/本机ipv6地址.txt",
        "filenameType": "str",
        "appendNewline": false,
        "createDir": true,
        "overwriteFile": "true",
        "encoding": "none",
        "x": 520,
        "y": 400,
        "wires": [
            [
                "bd019ed074eefa95"
            ]
        ]
    },
    {
        "id": "bd019ed074eefa95",
        "type": "debug",
        "z": "cbe57fd6f44c0398",
        "name": "输出ip信息",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 790,
        "y": 400,
        "wires": []
    },
    {
        "id": "410692bda45b51c6",
        "type": "link in",
        "z": "cbe57fd6f44c0398",
        "name": "ssh istoreos",
        "links": [
            "9d4685449276e70c",
            "fb5aa5e12f07e062",
            "4fd7d10edec1121f"
        ],
        "x": 125,
        "y": 600,
        "wires": [
            [
                "a32c6a90cea1c25c"
            ]
        ]
    },
    {
        "id": "9d4685449276e70c",
        "type": "link out",
        "z": "cbe57fd6f44c0398",
        "name": "call ssh istoreos",
        "mode": "link",
        "links": [
            "410692bda45b51c6"
        ],
        "x": 405,
        "y": 440,
        "wires": []
    },
    {
        "id": "a9ecd801ae2d9de2",
        "type": "delay",
        "z": "cbe57fd6f44c0398",
        "name": "",
        "pauseType": "delay",
        "timeout": "5",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "allowrate": false,
        "outputs": 1,
        "x": 420,
        "y": 480,
        "wires": [
            [
                "4fd7d10edec1121f"
            ]
        ]
    },
    {
        "id": "4fd7d10edec1121f",
        "type": "link out",
        "z": "cbe57fd6f44c0398",
        "name": "call ssh istoreos",
        "mode": "link",
        "links": [
            "410692bda45b51c6"
        ],
        "x": 525,
        "y": 480,
        "wires": []
    },
    {
        "id": "a0d90d0d10c5af01",
        "type": "ssh-conf",
        "ssh": "",
        "name": "isoreos",
        "userlabel": "isoreos"
    }
]


小白教小白-当ipv6地址发生变更后,自动更新openwrt软路由的防火墙规则.rar (282.12 KB, 下载次数: 3)





回复

使用道具 举报

32

主题

302

帖子

1734

积分

金牌会员

Rank: 6Rank: 6

积分
1734
金钱
1427
HASS币
40
 楼主| 发表于 2024-3-27 13:05:54 | 显示全部楼层
本帖最后由 lione95678 于 2024-3-27 13:10 编辑

老规矩,自己先顶一下。实际上我使用了NginxProxyManager进行反向代理,只公开了宿主机的443这一个端口。这样只要用域名的前缀就可以访问不同的内网界面。如果只需要通过不同端口访问不同应用,建议直接使用openwrt的socat。这样软路由的ipv6端口计算如何变化都无所谓。
istoreos安装socat,可以直接将软路由的ipv6端口转发给内网机器的ipv4端口,且可以自动在防火墙开放相应端口,不需要后续再有什么操作。而且后续docker安装的程序也不要用host方式。
我是希望用域名访问,所以安装了NginxProxyManager,没有办法。如果你也需要用NginxProxyManager进行反向代理hass等,那么通过docker方式安装的NginxProxyManager,必须使用host网络,但是docker安装的hass什么的就不需要用host网络。
另外,我使用的是jlesage/nginx-proxy-manager,因为他的使用的默认端口不是80和443,这样使用host网络安装NginxProxyManager,不会出现端口被占用的情况
回复

使用道具 举报

7

主题

1072

帖子

3361

积分

论坛元老

Rank: 8Rank: 8

积分
3361
金钱
2289
HASS币
0
发表于 2024-3-27 15:25:18 | 显示全部楼层
用lucky反代是不是更方便一些啊
回复

使用道具 举报

32

主题

302

帖子

1734

积分

金牌会员

Rank: 6Rank: 6

积分
1734
金钱
1427
HASS币
40
 楼主| 发表于 2024-3-28 09:46:29 | 显示全部楼层
隔壁的王叔叔 发表于 2024-3-27 15:25
用lucky反代是不是更方便一些啊

lucky和NginxProxyManager一样,看你安装在什么地方,如果安装在软路由系统,那都没问题。如果安装在内网的其他主机上,那就绕不开开放软路由防火墙。我的istoreos死活用不了docker,又不想重装。isotroeos安装luky,也没办法ipv6转发局域网内主机端口.所以只能装在局域网的unraid上。
回复

使用道具 举报

7

主题

1072

帖子

3361

积分

论坛元老

Rank: 8Rank: 8

积分
3361
金钱
2289
HASS币
0
发表于 2024-3-28 10:07:49 | 显示全部楼层
lione95678 发表于 2024-3-28 09:46
lucky和NginxProxyManager一样,看你安装在什么地方,如果安装在软路由系统,那都没问题。如果安装在内网 ...

我是lucky装在内网主机上,ipv6转发ipv4访问其他的内网机器。
回复

使用道具 举报

2

主题

411

帖子

2367

积分

金牌会员

Rank: 6Rank: 6

积分
2367
金钱
1956
HASS币
0
QQ
发表于 2024-3-31 08:54:31 | 显示全部楼层
谢谢分享。。。。。。。。
回复

使用道具 举报

2

主题

411

帖子

2367

积分

金牌会员

Rank: 6Rank: 6

积分
2367
金钱
1956
HASS币
0
QQ
发表于 2024-3-31 08:55:34 | 显示全部楼层
隔壁的王叔叔 发表于 2024-3-28 10:07
我是lucky装在内网主机上,ipv6转发ipv4访问其他的内网机器。

我也是这样做的
回复

使用道具 举报

30

主题

107

帖子

477

积分

中级会员

Rank: 3Rank: 3

积分
477
金钱
370
HASS币
0
发表于 2024-3-31 10:09:02 | 显示全部楼层
隔壁的王叔叔 发表于 2024-3-28 10:07
我是lucky装在内网主机上,ipv6转发ipv4访问其他的内网机器。

不太建议搞ipv6转发,全世界花了这么多努力让每一粒沙子都有一个ipv6地址,直接用内网设备的ipv6地址访问是最好的。
回复

使用道具 举报

7

主题

1072

帖子

3361

积分

论坛元老

Rank: 8Rank: 8

积分
3361
金钱
2289
HASS币
0
发表于 2024-3-31 22:31:38 | 显示全部楼层
inevitab 发表于 2024-3-31 10:09
不太建议搞ipv6转发,全世界花了这么多努力让每一粒沙子都有一个ipv6地址,直接用内网设备的ipv6地址访问 ...

你说的对。。。。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|Hassbian

GMT+8, 2024-4-28 15:10 , Processed in 0.061079 second(s), 34 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表