起因
(此处废话,建议直接跳下一主题)
家里买了一台NAS之后一直想通过公网访问自己的内网。。。但是。。。
自从报装了联通宽带就因为无法得到公网IP而一直和联通客户周旋,打了好多客服电话,又迁了线路。。。最后终于也只是争取到一条 IP一直在公网与内网波动的动态IP线路。客服曰:公网IP不够,根据总公司规定能否获得公网IP只能是靠程(运)序(气)自动分配。
虽然万般无奈,可是虽让我已经交钱了而且也心力交瘁不想再和客服周旋了。所以只能勉强接受这个折中的方案。
然而问题来了,运气好获得公网IP的话我自然能够通过DDNS来在外网访问我的内网。但是如果我运气不好得到内网IP呢?
既然问题来了,那就解决问题,总共有以下这么多问题需要解决:
- 了解联通宽带获取IP的情况是怎样的?如何可以获取公网IP?
- 如何一直获取公网IP?
通过不断的折腾我的路由器终于发现了,联通获取IP的机制就是每次路由器重启或者端口重启都会随机获取一个公网或者内网IP。而是否公网全靠运气,而且获得内网IP的情况远多于获取公网IP的情况。
然而最要命的事你获得一个公网IP之后并不是一直就能持有该IP,而已会每个一段时间刷新IP,间隔大概是一天。
那现在知道了宽带获取IP的机制了,那么如何保证路由器一直获取公网IP呢?
最笨的方法就是一直重启路由器或者端口知道你获得一个公网IP。
或者写个脚本自动判断IP并获取公网IP。
作为能躺着绝对不会坐着的IT工(死)程(肥)师(宅)当然是选择让程序自己来做这个粗活啦。。。
说干就干。。。
处理思路
读取端口IP → 读取本地宽带公网IP → 端口IP≠公网IP 则重启端口,直到端口IP=公网IP
读取端口IP
因为我的路由器是openwrt系统的,所以可以通过命令ifstatus wan来查看我设备端口IP。
查看IP信息
ifstatus wan
root@NETGEAR:/mnt# ifstatus wan
{
"up": true,
"pending": false,
"available": true,
"autostart": true,
"dynamic": false,
"uptime": 21255,
"l3_device": "pppoe-wan",
"proto": "pppoe",
"device": "eth0.2",
"updated": [
"addresses",
"routes"
],
"metric": 0,
"dns_metric": 0,
"delegation": true,
"ipv4-address": [
{
"address": "120.85.165.134",
"mask": 32,
"ptpaddress": "120.85.164.1"
}
],
(。。。中间去掉好多无用文本。。。)
}
}
提取IP所在的行
因为IP的字符串在第20行
ifstatus wan | awk '{if (NR==20) print}'
root@NETGEAR:/mnt# ifstatus wan | awk '{if (NR==20) print}'
"address": "120.85.165.134",
去掉多余字符
因为我只有单独的IP字段,双引号也不要。所以我们可以用双引号来分割字符,分割之后读取第4端字符串。
ifstatus wan | awk -F '"' '{if (NR==20) print $4}'
root@NETGEAR:/mnt# ifstatus wan | awk -F '"' '{if (NR==20) print $4}'
120.85.165.134
读取公网IP
网上可以收到很多查询本地公网IP的URL,我网上查到了好几个
获取外网ip信息的:
curl icanhazip.com
curl trackip.net/ip
curl iiip.co
curl ifconfig.me
最后发现在我的环境ifconfig.me这个网址最快,所以就使用他了。
curl ifconfig.me
开关端口IP
打开WAN端口
ifup wan
关闭WAM端口
ifdown wan
脚本源码
#!/bin/bash
#Restart the interface wan until get the global address
#by Huangxiaosong
while true
do
globalAdd=$(curl icanhazip.com) #读取公网IP,赋值给变量globalAdd
echo "globalAdd:" $globalAdd
wanAdd=$(ifstatus wan | awk -F '"' '{if (NR==19) print $4}') #读取端口IP,赋值给变量wanAdd
if [ -z "$wanAdd" ] #判断 $wanAdd 是否为空,因为读取IP的时候有时候读出来的文本,IP在19行,有时候在20行,因此这里做一个判断,如果19行读不到IP就读20行。
then
wanAdd=$(ifstatus wan | awk -F '"' '{if (NR==20) print $4}')
echo $wanAdd
fi
echo "wanAdd:" $wanAdd
if [ $globalAdd != $wanAdd ] #如果查询到的公网IP不等于WAN口IP,说明路由器获取的IP是联通内网IP。那么就重启WAN口。
then
ifdown wan
echo "ifdown wan"
sleep 1
ifup wan
echo "ifup wan ..."
sleep 7
else
echo "Well done! you get the global address!"
echo "wait 15 min !"
sleep 900 #这里等等15分钟后继续循环执行程序。
fi
done
后记
开源路由器的确不错,本身具备了和linux一样的脚本控制能力。所以可以方便的实现路由器的控制,包括脚本自动化。如果是一般的家用路由器的话。那么估计就要费一番心思去让python来去web端操作了。那不知道要复杂多少倍。