lione95678 发表于 2024-3-27 12:41:31

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

小白教小白-当ipv6地址发生变更后,自动更新openwrt软路由的防火墙规则

起因:我是移动宽带,只能获取ipv6公网,软路由使用istoreos系统,是根据openwrt修改而来的。Homeassistant是通过docker方式安装在unraid系统中的。因为需要公网访问hass,又不希望通过关闭软路由的防火墙来实现访问hass,因为这样会公开unraid系统的全部端口。所以只在istoreos系统中的网络-防火墙-通信规则,开放了unraid的8123端口。但是因为软路由重启等行为,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-red的1880端口和hass的8123端口。否则一切免谈。 先放流程图:流程解释:就是每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个输出,其中如果对比结果2个ip地址一致,就有第一个输出,结果不一致,就有后面第2、3、4个输出。其中第一个输出我实际上后面没有流程了;第二个输出是将新的ipv6地址保存到“本机ipv6地址.txt”文件中,用于后续的再比较;第三个输出就是通过ssh节点来运行一个修改路由器防火墙文件的命令;第4个输出,后面接了一个延迟节点,延迟5秒后运行一个重启路由器防火墙的命令。这个函数节点,我再内容里添加了备注,具体可以看一下节点函数。7、新建一个ssh节点,这个节点你需要自行安装。可以在node-red的节点管理中,搜索并安装“node-red-contrib-ssh-v3”这个节点。安装后,节点的设置,按照你软路由的ip地址、用户名、密码等填写。注意:这个流程,sed命令和/etc/init.d/firewall restart这个防火墙重启命令,可能要看你的软路由的情况,需要你自行查询测试。 放上一个istoreos的防火墙配置图片名称:随意填写目标地址:你主机的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 ;\n}\nelse {\n    return ;\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"
    }
]






lione95678 发表于 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,不会出现端口被占用的情况

隔壁的王叔叔 发表于 2024-3-27 15:25:18

用lucky反代是不是更方便一些啊

lione95678 发表于 2024-3-28 09:46:29

隔壁的王叔叔 发表于 2024-3-27 15:25
用lucky反代是不是更方便一些啊

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

隔壁的王叔叔 发表于 2024-3-28 10:07:49

lione95678 发表于 2024-3-28 09:46
lucky和NginxProxyManager一样,看你安装在什么地方,如果安装在软路由系统,那都没问题。如果安装在内网 ...

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

[email protected] 发表于 2024-3-31 08:54:31

谢谢分享。。。。。。。。

[email protected] 发表于 2024-3-31 08:55:34

隔壁的王叔叔 发表于 2024-3-28 10:07
我是lucky装在内网主机上,ipv6转发ipv4访问其他的内网机器。

我也是这样做的

inevitab 发表于 2024-3-31 10:09:02

隔壁的王叔叔 发表于 2024-3-28 10:07
我是lucky装在内网主机上,ipv6转发ipv4访问其他的内网机器。

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

隔壁的王叔叔 发表于 2024-3-31 22:31:38

inevitab 发表于 2024-3-31 10:09
不太建议搞ipv6转发,全世界花了这么多努力让每一粒沙子都有一个ipv6地址,直接用内网设备的ipv6地址访问 ...

你说的对。。。。
页: [1]
查看完整版本: 小白教小白-ipv6变化后自动更新openwrt软路由的防火墙规则