参考方案

1 dnspod 动态域名解析 详细:dnspod开放了api 接口 可以修改ip ,于是 我们可以在本地服务器上 做一个程序 脚本检查 本地的公网ip 是否和dnspod的绑定ip 是否一致,如果不一致 则本地脚本 根据API修改 dnspod的ip ,本地检查更新dnspod的脚本

2 有两个问题:1:电信封闭80 端口 需要解决方案 2:路由器需要配置开放80端口 默认关闭状态, 如果菜鸟用户 麻烦。 如此思路的 脚本 县城的有很多 针对window 和服务 linux ssh 等等的 

1 <?php
  2 /**
  3  * @category ${NAME}
  4  * @author   gouki <gouki.xiao@gmail.com>, xin.qin@qinx.cn
  5  * @created 13-4-7 下午9:17
  6  * @updated 13-5-18 22:25
  7  * @since
  8  */
  9 error_reporting(7);
 10 date_default_timezone_set('Asia/Chongqing');
 11 /**
 12  * 
 13  * 
 14  */
 15 define('DNSPOD_APIURL', 'https://dnsapi.cn/Record.Modify');
 16 //define('DNSPOD_APIURL', 'https://dnsapi.cn/Record.Ddns');
 17 define('LAST_IP_TMP_FILE', 'dnspod_ip');
 18 class Dnspod
 19 {
 20     protected $username = 'admin@ff-gzs.cn'; //dnspod username
 21     protected $password = 'fdsdssi'; //dnspod user password
 22     /*
 23     protected $domainId = '对应的domainId';
 24     protected $updated = array(
 25         'subDomain对应的ID' => '域名',
 26     );
 27     */
 28      
 29     protected $domains = array(
 30         //format: domain_id, record_id, sub_domain
 31         array(domain_id,record_id,'sub_domain'), //这个id可以通过dnspod的官方客户端查看
 32         array(domain_id,record_id,'sub_domain')
 33     );
 34      
 35     public function getLastIp()
 36     {
 37         if (!file_exists(LAST_IP_TMP_FILE)) {
 38             touch(LAST_IP_TMP_FILE);
 39         }
 40         return file_get_contents(LAST_IP_TMP_FILE);
 41     }
 42      
 43     public function getCurrentIp()
 44     {
 45         $ip138 = 'http://iframe.ip138.com/ic.asp';
 46         $ip138Content = @file_get_contents($ip138);
 47         preg_match('/\[(.*?)\]/', $ip138Content, $output);
 48         if (isset($output[1])) {
 49             return trim($output[1]);
 50         }
 51         return '';
 52     }
 53      
 54     public function saveCurrentIp($ip)
 55     {
 56         file_put_contents(LAST_IP_TMP_FILE, trim($ip));
 57     }
 58      
 59     public function run()
 60     {
 61         $currentIp = $this->getCurrentIp();
 62         $lastIp = $this->getLastIp();
 63         if ($currentIp == $lastIp || !$currentIp) {
 64             $data = 'the ip address is same as before, or cannot get ip this time.';
 65             $this->log($data); 
 66             return;
 67         }
 68          
 69         /*
 70         foreach ($this->updated as $recordId => $subDomain) {
 71             $result = $this->saveRecord($recordId, $subDomain, $currentIp);
 72             echo $result;
 73         }
 74         */
 75         foreach($this->domains as $value){
 76             $result = $this->saveRecord($value[0], $value[1], $value[2], $currentIp);
 77             $this->log($result);
 78         }
 79          
 80         $this->saveCurrentIp($currentIp);
 81     }
 82      
 83     protected function saveRecord($domainId, $recordId, $subDomain, $ip = '')
 84     {
 85         //"format=json&login_email=$email&login_password=$password&domain_id=$domain_id&record_id=$record_id&sub_domain=$sub_domain&record_line=默认"
 86         $recordData = array(
 87             'format'         => 'json',
 88             'login_email'    => $this->username,
 89             'login_password' => $this->password,
 90             'domain_id'      => $domainId,
 91             'record_id'      => $recordId,
 92             'sub_domain'     => $subDomain,
 93             'record_line'    => '默认' ,
 94             /**
 95              * if you use Record.Ddns interface, no need to specify following 4 paramters.
 96              */
 97              
 98             'record_type'    => 'A',
 99             'value'          => $ip,
100             'mx'             => 1,
101             'ttl'            => 10
102              
103         );
104         return $this->postData(DNSPOD_APIURL, $recordData);
105     }
106      
107     protected function postData($url, $post = null)
108     {
109         $context = array();
110         if (is_array($post)) {
111             ksort($post);
112             $context['http'] = array(
113                 'method'  => 'POST',
114                 'content' => http_build_query($post, '', '&'),
115             );
116         }
117         return file_get_contents($url, false, stream_context_create($context));
118     }
119      
120     protected function log($data){
121         file_put_contents(date('Y-m-d').'', date('Y-m-d H:m:s').': '.$data."\r\n", FILE_APPEND);    
122     }
123 }
124  
125 $ddns = new Dnspod();
126 $ddns->run();

 

 

 

bash解决方案    感谢 参考:http://zengrong.net/post/1524.htm

 

域名配置

domainList[0]='domain1.com \* @'
domainList[1]='domain2.com www subdomain1 subdomain2'

 

守护进程启动

在 etc/rc.local中添加

/usr/bin/dnspodsh dnspod_name dnspod_passwaord &>/dev/null   #参数 分别为 你懂得

 

 

1 #!/bin/bash
  2 
  3 ##############################
  4 # dnspodsh v0.3
  5 # 基于dnspod api构架的bash ddns客户端
  6 # 作者:zrong(zengrong.net)
  7 # 详细介绍:http://zengrong.net/post/1524.htm
  8 # 创建日期:2012-02-13
  9 # 更新日期:2012-03-11
 10 ##############################
 11 
 12 login_email=${1:?'必须提供登录名'}
 13 login_password=${2:?'必须提供密码'}
 14 format="json"
 15 lang="en"
 16 userAgent="dnspodsh/0.3()"
 17 commonPost="login_email=$login_email&login_password=$login_password&format=$format&lang=$lang"
 18 
 19 apiUrl='https://dnsapi.cn/'
 20 ipUrl='http://members.3322.org/dyndns/getip'
 21 
 22 # 要处理的域名数组,每个元素代表一个域名的一组记录
 23 # 在数组的一个元素中,以空格分隔域名和子域名
 24 # 第一个空格前为主域名,后面用空格分离多个子域名
 25 # 如果使用泛域名,必须用\*转义
 26 domainList[0]='domain1.com \* @ www'
 27 domainList[1]='domain2.com subdomain subdomain2'
 28 
 29 # 多长时间比较一次ip地址
 30 delay=300
 31 
 32 # logfile
 33 logDir='/var/log'
 34 logFile=$logDir'/dnspodsh.log'
 35 traceFile=$logDir'/dnspodshtrace.log'
 36 
 37 # 检测ip地址是否符合要求
 38 checkip()
 39 {
 40     # ipv4地址
 41     if [[ "$1" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]];then
 42         return 0
 43     # ipv6地址
 44     elif [[ "$1" =~ ^([\da-fA-F]{1,4}:){7}[\da-fA-F]{1,4}$|^:((:[\da-fA-F]{1,4}){1,6}|:)$|^[\da-fA-F]{1,4}:((:[\da-fA-F]{1,4}){1,5}|:)$|^([\da-fA-F]{1,4}:){2}((:[\da-fA-F]{1,4}){1,4}|:)$|^([\da-fA-F]{1,4}:){3}((:[\da-fA-F]{1,4}){1,3}|:)$|^([\da-fA-F]{1,4}:){4}((:[\da-fA-F]{1,4}){1,2}|:)$|^([\da-fA-F]{1,4}:){5}:([\da-fA-F]{1,4})?$|^([\da-fA-F]{1,4}:){6}:$ ]];then
 45         return 0
 46     fi
 47     return 1
 48 }
 49 
 50 getUrl()
 51 {
 52     #curl -s -A $userAgent -d $commonPost$2 --trace $traceFile $apiUrl$1
 53     curl -s -A $userAgent -d $commonPost$2 $apiUrl$1
 54 }
 55 
 56 getVersion()
 57 {
 58     getUrl "Info.Version"
 59 }
 60 
 61 getUserDetail()
 62 {
 63     getUrl "User.Detail"
 64 }
 65 
 66 writeLog()
 67 {
 68     if [ -w $logDir ];then
 69         local pre=`date`
 70         for arg in $@;do
 71             pre=$pre'\t'$arg
 72         done
 73         echo -e $pre>>$logFile
 74     fi
 75     echo -e $1
 76 }
 77 
 78 getDomainList()
 79 {
 80     getUrl "Domain.List" "&type=all&offset=0&length=10"
 81 }
 82 
 83 # 根据域名id获取记录列表
 84 # $1 域名id
 85 getRecordList()
 86 {
 87     getUrl "Record.List" "&domain_id=$1&offset=0&length=20"
 88 }
 89 
 90 # 设置记录
 91 setRecord()
 92 {
 93     writeLog "set domain $3.$8 to new ip:$7"
 94     local subDomain=$3
 95     # 由于*会被扩展,在最后一步将转义的\*替换成*
 96     if [ "$subDomain" = '\*' ];then
 97         subDomain='*'
 98     fi
 99     local request="&domain_id=$1&record_id=$2&sub_domain=$subDomain&record_type=$4&record_line=$5&ttl=$6&value=$7"
100     #echo $request
101     local saveResult=$(getUrl 'Record.Modify' "$request")
102     # 检测返回是否正常,但即使不正常也不退出程序
103     if checkStatusCode "$saveResult" 0;then
104         writeLog "set record $3.$8 success."
105     fi
106     #getUrl 'Record.Modify' "&domain_id=$domainid&record_id=$recordid&sub_domain=$recordName&record_type=$recordtype&record_line=$recordline&ttl=$recordttl&value=$newip"
107 }
108 
109 # 设置一批记录
110 setRecords()
111 {
112     numRecord=${#changedRecords[@]}
113     for (( i=0; i < $numRecord; i++ ));do
114         setRecord ${changedRecords[$i]}
115     done
116     # 删除待处理的变量
117     unset changeRecords
118 }
119 
120 # 通过key得到找到一个JSON对象字符串中的值
121 getDataByKey()
122 {
123     local s='s/{[^}]*"'$2'":["]*\('$(getRegexp $2)'\)["]*[^}]*}/\1/'
124     #echo '拼合成的regexp:'$s
125     echo $1|sed $s
126 }
127 
128 # 根据key返回要获取的正则表达式
129 getRegexp()
130 {
131     case $1 in
132         'value') echo '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}';;
133         'type') echo '[A-Z]\+';;
134         'name') echo '[-_.A-Za-z*]\+';;
135         'ttl'|'id') echo '[0-9]\+';;
136         'line') echo '[^"]\+';;
137     esac
138 }
139 
140 # 通过一个JSON key名称,获取一个{}包围的JSON对象字符串
141 # $1 要搜索的key名称
142 # $2 要搜索的对应值
143 getJSONObjByKey()
144 {
145     grep -o '{[^}{]*"'$1'":"'$2'"[^}]*}'
146 }
147 
148 # 获取A记录类型的域名信息
149 # 对于其它记录,同样的名称可以对应多条记录,因此使用getJSONObjByKey可能获取不到需要的数据
150 getJSONObjByARecord()
151 {
152     grep -o '{[^}{]*"name":"'$1'"[^}]*"type":"A"[^}]*}'
153 }
154 
155 # 获取返回代码是否正确
156 # $1 要检测的字符串,该字符串包含{status:{code:1}}形式,代表DNSPodAPI返回正确
157 # $2 是否要停止程序,因为dnspod在代码错误过多的情况下会封禁账号
158 checkStatusCode()
159 {
160     if [[ "$1" =~ \{\"status\":\{[^}{]*\"code\":\"1\"[^}]*\} ]];then
161         return 0
162     fi
163     writeLog "DNSPOD return error:$1"
164     # 根据参数需求退出程序
165     if [ -n "$2" ] && [ "$2" -eq 1 ];then
166         writeLog 'exit dnspodsh'
167         exit 1
168     fi
169 }
170 
171 # 获取与当前ip不同的,要更新的记录的数组
172 getChangedRecords()
173 {
174     # 从DNSPod获取最新的域名列表
175     local domainListInfo=$(getDomainList)
176     if [ -z "$domainListInfo" ];then
177         writeLog 'DNSPOD tell me domain list is null,waiting...'
178         return 1
179     fi
180     checkStatusCode "$domainListInfo" 1
181 
182     # 主域名的id
183     local domainid
184     local domainName
185     # 主域名的JSON信息
186     local domainInfo
187     # 主域名的所有记录列表
188     local recordList
189     # 一条记录的JSON信息
190     local recordInfo
191     # 记录的id
192     local recordid
193     local recordName
194     # 记录的TTL
195     local recordTtl
196     # 记录的类型
197     local recordType
198     # 记录的线路
199     local recordLine
200     local j
201 
202     # 用于记录被改变的记录
203     unset changedRecords
204 
205     local numDomain=${#domainList[@]}
206     local domainGroup
207 
208     for ((i=0;i<$numDomain;i++));do
209         domainGroup=${domainList[$i]}
210         j=0
211         for domain in ${domainGroup[@]};do
212             # 列表的第一个项目,是主域名
213             if ((j==0));then
214                 domainName=$domain
215                 domainInfo=$(echo $domainListInfo|getJSONObjByKey 'name' $domainName) 
216                 domainid=$(getDataByKey "$domainInfo" 'id')
217                 recordList=$(getRecordList $domainid)
218                 if [ -z "$recordList" ];then
219                     writeLog 'DNSPOD tell me record list null,waiting...'
220                     return 1
221                 fi
222                 checkStatusCode "$recordList" 1
223             else
224                 # 从dnspod获取要设置的子域名记录的信息
225                 recordInfo=$(echo $recordList|getJSONObjByARecord $domain)
226                 # 如果取不到记录,则不处理
227                 if [ -z "$recordInfo" ];then
228                     continue
229                 fi
230 
231                 # 从dnspod获取要设置的子域名的ip
232                 oldip=$(getDataByKey "$recordInfo" 'value')
233 
234                 # 检测获取到的旧ip地址是否符合ip规则
235                 if ! checkip "$oldip";then
236                     writeLog 'get old ip error!it is "$oldid".waiting...'
237                     continue
238                 fi
239 
240                 if [ "$newip" != "$oldip" ];then
241                     recordid=$(getDataByKey "$recordInfo" 'id')
242                     recordName=$(getDataByKey "$recordInfo" 'name')
243                     recordTtl=$(getDataByKey "$recordInfo" 'ttl')
244                     recordType=$(getDataByKey "$recordInfo" 'type')
245                     # 由于从服务器获取的线路是utf编码,目前无法知道如何转换成中文,因此在这里写死。dnspod中免费用户的默认线路的名称就是“默认”
246                     #recordLine=$(getDataByKey "$recordInfo" 'line')
247                     recordLine='默认'
248                     # 判断取值是否正常,如果值为空就不处理
249                     if [ -n "$recordid" ] && [ -n "$recordTtl" ] && [ -n "$recordType" ]; then
250                         # 使用数组记录需要修改的子域名的所有值
251                         # 这里一共有8个参数,与setRecord中的参数对应
252                         changedRecords[${#changedRecords[@]}]="$domainid $recordid $domain $recordType $recordLine $recordTtl $newip $domainName"
253                     fi
254                 fi
255             fi
256             j=$((j+1))
257         done
258     done
259 }
260 
261 # 执行检测工作
262 go()
263 {
264     # 由于获取到的数据多了一些多余的字符,所以提取ip地址的部分
265     # 从api中获取当前的外网ip
266     newip=$(curl -s $ipUrl|grep -o $(getRegexp 'value'))
267     # 如果获取最新ip错误,就继续等待下一次取值
268     if ! checkip "$newip";then
269         writeLog 'can not get new ip,waiting...'
270         sleep $delay
271         continue
272     fi
273     # 获取需要修改的记录
274     getChangedRecords
275     if (( ${#changedRecords[@]} > 0 ));then
276         writeLog "ip is changed,new ip is:$newip"
277         setRecords
278     fi
279 }
280 
281 while [ 1 ];do
282     go
283     sleep $delay
284 done