动态IP解析
本文介绍两种方便获取主机动态IP的方式(DDNS,IP报告网页),并给出相应的代码实现.
shell脚本获取本机IP,执行上传操作和更新DNS操作.定期执行通过crontab或者systemd等服务.
应用场景
远程访问具有动态IP的公网或内网主机时,如果通过ip进行访问,由于公网IP总是在变化,我们不得不每次去查看新的ip地址,往往这个重复的过程比较麻烦.
远程主机联网的方式有所不同,主要有以下几种情形:
- 远程主机是通过PPPoE拨号上网,通常获取到动态的私有网络(内网)地址
- 远程主机直接获取到的是动态公网ipv4地址.
- 在教育网中通常还能获得动态的公网ipv6地址.
又可以简易地分成两类: 配有公网ip的主机与仅配置内网ip的主机.
内网主机访问方式
反向隧道
对于躲在NAT之后的内网主机,比较方便的方式是在内网主机建立到公网主机的反向隧道
,命令行建立反向隧道工具有:ssh,ngrok,tmate等,参考我之前的反向隧道的文章. 这些工具往往都能在ip发生改变后自动重建连接.
缺点是我们需要一台拥有公网ip的主机,并且时刻保持隧道长连接,另外由于远程访问内网主机需要经过这个公网主机中转,速度变慢.内网穿透
通过公网服务器得到内网主机在NAT设备的转码地址,然后可以建立p2p的连接.QQ,TeamViewer即是类似原理.前提是内网容易穿透.
路由器端口映射
外网IP和端口映射到内网:在路由器的「转发规则」页面添加外网的端口到内网某主机端口的映射.
本着只要有不断重复的麻烦事就用脚本实现的原则,我们通过一些脚本来方便我们的工作.
DDNS (动态域名IP解析)
IP报告/收集脚本
IP报告脚本
通过linux的ip命令获取到本机的公网ip以及通过网站获取本机的外网ip,然后上传到自建的php服务器上.
脚本使用了本地文件记录前一次变更的ip地址,当ip发生变化才执行网络操作.文件保存在内存文件系统或临时文件中.
reportIP.sh
#!/bin/bash
# __author__ = fyk
# get global ipv6 & ipv4 address,
# note that both ipv6 & ipv4 addr may have more than 1.
# grep -v to exclude temporary ipv6 privacy addr.
ip6s=$(ip -6 addr |grep 'global'|grep -v 'tmpaddr'|awk '{print $2}'|sed 's/\/.*//' | uniq)
ip4s_local=$(ip -4 a | grep global |awk '{print $2}' | uniq) # local v4 ips ,public or prive ips that behind NAT
ips_pub=$(curl -s ifconfig.me) # there are lots of websites supplying IP echo services
ip_data=$ips_pub' '${ip6s}' '${ip4s_local}
#echo $ip_data
IP_FILE='/dev/shm/lastip97451' # or in /tmp .etc
ip_data_old=$(cat $IP_FILE 2> /dev/null) # for non-exist file,content is null
if [ "$ip_data" != "$ip_data_old" ];then
echo 'IP changed,push to remote.'
#echo $ip_data > $IP_FILE # update the file
params='k=fyk'
cnt=0
for ip in $ip_data;do
echo $ip
params=$params"&ip$cnt=$ip" # shell will handle & specially,so we first trans & to %26
((cnt=cnt+1))
done
params="n=$cnt&$params"
sever_addr="http://x.makefile.tk/"
#echo ${sever_addr}
curl -G -d "$params" "$sever_addr"
else echo 'IP unchanged.'
fi
# TODO:增加断网重连
php收集脚本
提供的服务地址形式是:http://x.makefile.tk/?k=password&n=2&p0=x.x.x.x&p1=x.x.x.x
,其中n是ip地址个数,p0,p1,...分别是单独的ip,参数k为了简单地防止一些人捣乱.直接访问http://x.makefile.tk/
将能看到上一次保存的ip地址.
下面是index.php代码,通过文件来记录ip地址,不能够并发写入.同shell报告脚本一样可以使用内存文件来加快读写速度.
<html>
<body>
<?php
if ( !function_exists('sys_get_temp_dir')) {
function sys_get_temp_dir() {
if (!empty($_ENV['TMP'])) { return realpath($_ENV['TMP']); }
if (!empty($_ENV['TMPDIR'])) { return realpath( $_ENV['TMPDIR']); }
if (!empty($_ENV['TEMP'])) { return realpath( $_ENV['TEMP']); }
$tempfile=tempnam(uniqid(rand(),TRUE),'');
if (file_exists($tempfile)) {
unlink($tempfile);
return realpath(dirname($tempfile));
}
}
}
?>
<?php
//echo "QUERY_STRING: " . $_SERVER['QUERY_STRING'];
//echo "<br>";
//$temp_file = tempnam(sys_get_temp_dir(), 'Tux');
//$temp_file = sys_get_temp_dir() . 'ip97845';
//$temp_file = '/dev/shm/ip97845';//seems to be frequently erased by cloud host.
$temp_file = 'ip97845';
//if has param of n,then save ip to file
if(isset($_GET['n'])){
$n = $_GET['n'];
if(isset($_GET['k'])){
$key = $_GET['k'];//for simple security
if($key == 'password'){
$myfile = fopen($temp_file, "w") or die("Unable to open file!");
for ($x=0; $x<$n; $x++) {
$ip_idx = 'ip' . $x;
$line = $ip_idx . "=$_GET[$ip_idx]<br>";
echo $line;
fwrite($myfile, $line);
}
fclose($myfile);
echo 'save ip ok!<br>' ;
}else echo 'key error';
}else echo 'no key error';
}else{ // read from file
$myfile = fopen($temp_file, "r") or die("Unable to open file!");
echo fread($myfile,filesize($temp_file));
fclose($myfile);
}
echo "<br><br>";
echo "Your INFO:<br>";
echo "IP: " . $_SERVER['REMOTE_ADDR'];
echo "<br>";
echo "UA: " . $_SERVER['HTTP_USER_AGENT'];
echo "<br>";
?>
</body>
</html>
对于这种web应用,使用网络上各种php建站即可.
公用DNS服务
准备:购买公网域名,域名设置DNS解析服务为Dnspod或CloudFlare.本文的代码使用CloudFlare的API动态修改DNS记录.
思路是修改IP报告脚本,将更新的IP更新的公共的DNS服务上.
ipv6-dns.sh 代码:
#!/bin/bash
# __author__ = fyk
# get global ipv6 & ipv4 address,
# note that both ipv6 & ipv4 addr may have more than 1.
# get variables in dns.conf which includes cloudflare info
# source dns.conf
if [ -z "$1" ] ;then
echo 'please specify conf file'
exit 0
else
source $1
fi
# grep -v to exclude temporary ipv6 privacy addr.
ip6s=$(ip -6 addr |grep 'global'|grep -v 'tmpaddr'|awk '{print $2}'|sed 's/\/.*//')
#for my own needs,i only use ipv6
#ip4s=$(ip -4 a | grep global |awk '{print $2}')
for ip in $ip6s;do
ip_data=$ip
break # only use first one
done
#ip_data=${ip6s}' '${ip4s}
#echo $ip_data
API_URL="https://api.cloudflare.com/client/v4"
CURL="curl -s \
-H Content-Type:application/json \
-H X-Auth-Key:$AUTH_KEY \
-H X-Auth-Email:$AUTH_EMAIL "
update_dns(){
UPDATE_DATA=$(cat << EOF
{ "type": "AAAA",
"name": "$DOMAIN_NAME",
"content": "$2",
"proxied": false }
EOF
)
#"ttl": 1, # let it be Automatic
echo "update dns: $DOMAIN_NAME -> $2"
$CURL -X PUT "$API_URL/zones/$ZONE_ID/dns_records/$1" -d "$UPDATE_DATA" > /tmp/cloudflare-ddns.json
}
# get current IP
get_dns_ip(){
RECS=$($CURL "$API_URL/zones/$ZONE_ID/dns_records?name=$DOMAIN_NAME")
IP=$(echo "$RECS" | sed -e 's/[{}]/\n/g' | sed -e 's/,/\n/g' | grep '"content":"' | cut -d'"' -f4)
echo $IP
}
IP_FILE='/dev/shm/lastip9745' # or in /tmp .etc
ip_data_old=$(cat $IP_FILE 2> /dev/null) # for non-exist file,content is null
if [ "$ip_data" == "$ip_data_old" ];then
echo 'IP unchanged.'
exit 0
fi
echo 'IP changed,push to remote.'
if [ -z "$REC_ID" ] ; then
RECS=$($CURL "$API_URL/zones/$ZONE_ID/dns_records?name=$DOMAIN_NAME")
echo $RECS
REC_ID=$(echo "$RECS" | sed -e 's/[{}]/\n/g' | sed -e 's/,/\n/g' | grep '"id":"' | cut -d'"' -f4)
echo "REC_ID=$REC_ID"
fi
update_dns "$REC_ID" "$ip_data"
cur_ip=$(get_dns_ip)
if [ "$cur_ip"=="$ip_data" ];then
echo $ip_data > $IP_FILE # update the file
else
echo 'update dns failed.'
fi
脚本中通过source dns.conf读取了配置信息:
# this is Cloudflare api info for DDNS
# !!do not leave space around =
AUTH_EMAIL=<cloudflare-auth-email>
#This is your *Global API Key* under Cloudflare account settings
AUTH_KEY=<cloudflare-auth-key>
#Zone ID:can be find out there: <https://www.cloudflare.com/a/overview/>
ZONE_ID=<DNS Zone>
#your sub domain name
DOMAIN_NAME="ip.example.com"
具体API使用方法查阅https://api.cloudflare.com
自建DNS服务
准备:外网服务器B,搭建bind9服务用来提供DNS服务
借助于IP报告/收集脚本,在服务器B上不断更新域名解析.
客户端机器C,手动设置DNS服务地址为B的IP.这种方式的优点是域名想怎么写就怎么写.
示意图:
通过DNS服务可以实现与著名的花生壳
相类似的服务,而且成本低,“自主、可控”:) 。
关于域名解析ttl
TTL是英语Time-To-Live的简称,意思为一条域名解析记录在DNS服务器中的存留时间。当各地的DNS服务器接受到解析请求时,就会向域名指定的NS服务器发出解析请求从而获得解析记录;在获得这个记录之后,记录会在DNS服务器中保存一段时间,这段时间内如果再接到这个域名的解析请求,DNS服务器将不再向NS服务器发出请求,而是直接返回刚才获得的记录;而这个记录在DNS服务器上保留的时间,就是TTL值。
如果域名的IP经常变更,那么减小TTL的值,如果很少改变,调大成几个小时都行.
将TTL设为1,表示'Automatic',如Cloudflare的DNS会在约5分钟内push出去.
IP地址变更事件通知
得到网络变化的方式有多种:
- C语言使用linux下的rtnetlink的NETLINK_ROUTE socket,监听之后会收到消息.要求写的程序一直在运行.参考.
- 如果网络管理器使用的Gnome的NetworkManager,那么会通过D-Bus广播事件(浏览器等常通过这种方式切换在线/离线模式).
- Debian系统中网络接口up或down时会执行/etc/network下的相关脚本.
- ifplugd 当网线被拔掉或接入时会执行相应脚本.
如果网络是使用NetworkManager(Ubuntu等系统默认的网络管理器)进行DHCP获取动态IP,比较方便的方式是将我们的脚本添加到事件响应脚本中. 参考man手册,在/etc/NetworkManager/dispatcher.d中添加脚本.
#!/bin/bash
# put this script in /etc/NetworkManager/dispatcher.d
IF=$1
STATUS=$2
case "$STATUS" in
down)
#logger -s "NM Script down $IF triggered"
;;
dhcp6-change|up) #
#if [ $IP6_NUM_ADDRESSES > 0 ];then
# echo $IP6_ADDRESS_0 //0,1,2,...
#fi
# msg logged to /va/log/syslog
logger "IP6_ADDRESS_0 = $IP6_ADDRESS_0"
/path/to/ipv6-dns.sh /path/to/dns.conf 2>&1 > /dev/null
*)
;;
esac
cron定时执行
执行crontab -e
将会编辑用户的crontab文件,其创建/tmp下的临时文件进行编辑,保存后将会提交到系统目录下(/var/spool/cron),这种设计方式类似visudo,目的是先检查用户的输入,防止错误的输入带来的破坏.系统重启后/tmp下的文件会删除,而crontab不会丢失.
也可以使用自定义的crontab文件导入到系统任务中:`crontab /path/to/cronfile
文件内容如下,注意使用绝对路径:
0 */1 * * * /home/s05/fyk/ip/ipv6-dns.sh /home/s05/fyk/ip/dns.conf
cron job的执行命令情况可以在/var/log/syslog中看到.
使用logger 'msg'可以将msg记录到syslog文件中.
crontab无需重启会立即生效.
邮件通知
发送邮件.适合于ip更新不太频繁的情形,通过代码发送邮件的代码很简便,Python,Java等语言均有方便的实现.
More
本文代码地址: https://github.com/makefile/CharmScript/tree/master/DDNS
其它资源:
- shell版1 https://www.rohanjain.in/cloudflare-ddns/
- shell版2 https://gist.github.com/lyoshenka/6257440
- php版 https://github.com/lyoshenka/cloudflare-ddns
动态IP解析的更多相关文章
- 更新TP-LINK路由器的外网IP到花生壳动态IP解析
------------------------------------------------------------------------------- 以下内容可能还是存在问题,等之后有时间再 ...
- 域名动态解析到动态IP
一般宽带用户的IP都是动态IP,重连之后IP可能会发生变化. 如果想在其他地方连接家里的设备,或者在家中搭建服务器,就会受到影响. 现在提供一种动态解析域名的方式,只要检测到IP的变化,那么就调用阿里 ...
- Linux 静态IP动态IP设置
1.设置动态IP ifconfig eth0 192.168.1.12 设置后立即生效,重启机器后就无效了 2.设置静态IP 编辑文件 /etc/sysconfig/network-scripts/i ...
- 动态IP或无公网IP时外网訪问内网ORACLE数据库
ORACLE数据库是应用最多的一个数据库.一般项目应用.将ORACLE部署在内网,内网调用,及运维都仅仅能是内网完毕. 假设ORACLE主机或所在局域网没有固定公网IP,又想在外网对ORACLE进行訪 ...
- 动态IP下群晖搭建DDNS服务
转载地址:https://www.zimrilink.com/share/dsm_aliddns_server.html 通过阿里云API(php)搭建出DDNS动态域名解析服务器;不同的是本文的方法 ...
- nodejs爬虫如何设置动态ip以及userAgent
nodejs爬虫如何设置动态ip以及userAgent 转https://blog.csdn.net/u014374031/article/details/78833765 前言 在写nodejs爬虫 ...
- 2014-10-2 bug更新5 ecshop和ectouch解决动态ip登录超时和购物车清空问题
有客户说登陆网站后台操作的时候,会时不时的掉一下,要重新登陆才能继续操作,自动登出的频率快和时间短,针对这个问题是因为: 购物车问题原因的产生是因为动态IP的SESSEION机制导致很多在公司或者其他 ...
- 实体ip 虚拟ip 固定ip 动态ip
实体 IP:在网络的世界里,为了要辨识每一部计算机的位置,因此有了计算机 IP 位址的定义.一个 IP 就好似一个门牌!例如,你要去微软的网站的话,就要去『 207.46.197.101 』这个 IP ...
- IP工具类-自己动手做个ip解析器
IP工具类-自己动手做个ip解析器 一.资料准备 导入依赖包:
随机推荐
- 如何将ASP.NET-WebApi发布到IIS6.0上(转)
关于"如何将ASP.NET-WebApi发布到IIS6.0上"的这方面的学习,一开始项目组长让我们接触的时候,我的心情是这样的 哇呜.jpg 当时真的是一脸懵逼啊,对于刚接触asp ...
- 201521123051《Java程序设计》第六周学习总结
1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 注1:关键词与内容不求多,但概念之间的联系要清晰,内容覆盖 ...
- 201521044091 《Java学习笔记》 第六周学习总结
1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结.注1:关键词与内容不求多,但概念之间的联系要清晰,内容覆盖面 ...
- 201521123013 《Java程序设计》第2周学习总结
1. 本章学习总结 1.final声明,一旦赋值不能被改变.移位运算符的应用,负数右移高位补"1",正数右移高位补"1".利用移位运算,按位与运算可以方便得出整 ...
- 201521123004 《Java程序设计》第2周学习总结
本周学习总结 ① String类的对象是不可变(immutable)的 String对象创建之后不能再进行修改 -->StringBuilder ② 字符串的拼接(使用"+" ...
- 201521123080《Java程序设计》第12周学习总结
1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多流与文件相关内容. 流(Stream): Stream是从起源(source)到接收(sink)的有序数据 按照流向分可以分为输入 ...
- java程序设计----学生基本信息管理系统
1. 团队课程设计博客链接 http://www.cnblogs.com/hyy786030686/p/7063890.html 2. 个人负责模块或任务说明 --登录界面的设计 --用户名和密码验证 ...
- idea使用转载【别人的专栏】
维C果糖
- 从JS和jQuery浅谈DOM操作,当我们在获取时,究竟获取了什么
0.写在前面的话 自己对前端的东西一直不是很熟,现在开始要想办法从前端各个地方去获取想要的属性值的时候,也基本是在网上现炒现卖,几周下来,发现自己还是迷迷糊糊,可以算是一无所获. 所以就抽时间,把这一 ...
- activiti07- Task
任务 用户任务: 用户任务,用来对那些需要人参与完成的工作进行建模.当流程执行到这样的用户任务时,会在被分配到该任务的用户或用户组的任务列表中创建新的任务. 用户任务中可以包含描述.事实上,任何BPM ...