动态IP解析
本文介紹兩種方便獲取主機動態IP的方式(DDNS,IP報告網頁),并給出相應的代碼實現.
shell腳本獲取本機IP,執行上傳操作和更新DNS操作.定期執行通過crontab或者systemd等服務.
應用場景
遠程訪問具有動態IP的公網或內網主機時,如果通過ip進行訪問,由于公網IP總是在變化,我們不得不每次去查看新的ip地址,往往這個重復的過程比較麻煩.
遠程主機聯網的方式有所不同,主要有以下幾種情形:
又可以簡易地分成兩類: 配有公網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
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 securityif($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" ] ;thenecho 'please specify conf file'exit 0 elsesource $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;doip_data=$ipbreak # only use first one done #ip_data=${ip6s}' '${ip4s} #echo $ip_dataAPI_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 Automaticecho "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" ];thenecho 'IP unchanged.'exit 0 fi echo 'IP changed,push to remote.' if [ -z "$REC_ID" ] ; thenRECS=$($CURL "$API_URL/zones/$ZONE_ID/dns_records?name=$DOMAIN_NAME")echo $RECSREC_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" ];thenecho $ip_data > $IP_FILE # update the file elseecho '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地址變更事件通知
得到網絡變化的方式有多種:
如果網絡是使用NetworkManager(Ubuntu等系統默認的網絡管理器)進行DHCP獲取動態IP,比較方便的方式是將我們的腳本添加到事件響應腳本中. 參考man手冊,在/etc/NetworkManager/dispatcher.d中添加腳本.
#!/bin/bash # put this script in /etc/NetworkManager/dispatcher.dIF=$1 STATUS=$2case "$STATUS" indown)#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/sysloglogger "IP6_ADDRESS_0 = $IP6_ADDRESS_0"/path/to/ipv6-dns.sh /path/to/dns.conf 2>&1 > /dev/null*);; esaccron定時執行
執行crontab -e將會編輯用戶的crontab文件,其創建/tmp下的臨時文件進行編輯,保存后將會提交到系統目錄下(/var/spool/cron),這種設計方式類似visudo,目的是先檢查用戶的輸入,防止錯誤的輸入帶來的破壞.系統重啟后/tmp下的文件會刪除,而crontab不會丟失.
也可以使用自定義的crontab文件導入到系統任務中:`crontab /path/to/cronfile
文件內容如下,注意使用絕對路徑:
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
轉載于:https://www.cnblogs.com/makefile/p/ddns.html
總結
- 上一篇: 普通幼儿园投资多少钱 创业者们应该看一看
- 下一篇: 多种缺陷管理软件简介