参考方案
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