家里放了一台旧 acer 笔记本电脑,外挂几个硬盘盒,插上几个硬盘,组成硬盘盒。
因笔记本电脑的耗电较小,硬盘盒有自动休眠省电模式,所以长期开机。此笔记本电脑,使用家庭的移动宽带,会自动分配 IPv6 , 可远程连接。
之前,自动分配 IPv6,很长时间不变。当然,我不可能去记这个 IPv6,所以找个 DNS 服务器,记在 AAAA 记录里。
最近好像不停地变化,这就麻烦了。用 cn.bing.com 网上搜索一番, 找到有脚本可自动更新 goddy dns 记录(ddns)。恰好我购买了一个goddy 的域名,附送 DNS 管理,也有免费的 DDNS 编程接口。脚本语言我不太熟悉,于是就改成用 java 重写了一次。
程序分两部分:
a. 主控 main 类 UpdateDdns,负责反复循环,每间隔 5 秒,检查 IP 地址是否变化。
b. 业务操作类 UpdateSrv, 负责单次循环中的业务。
代码比较简单,直接贴上,以下是 UpdateDdns.java :
1 package update_godaddy_ddns; 2 3 import org.slf4j.Logger; 4 import org.slf4j.LoggerFactory; 5 6 public class UpdateDdns { 7 8 public static void main(String[] args) { 9 Logger log = LoggerFactory.getLogger(UpdateDdns.class); 10 log.info("main begin..."); 11 String domain = args[0]; // "mydomain.com" # your domain 12 String typeMulti = args[1]; // ="A" # Record type A, CNAME, MX, etc. 13 String name = args[2]; // "sip" # name of record to update 14 String ttl = args[3]; // "3600" # Time to Live min value 600 15 String port = args[4]; // "1" # Required port, Min value 1 16 String weight = args[5]; // "1" # Required weight, Min value 1 17 String key = args[6]; // "abc" # key for godaddy developer API 18 String secret = args[7]; // "efg" # secret for godaddy developer API 19 20 String[] typeArrr = typeMulti.split("/"); 21 UpdateSrv srv = new UpdateSrv(); 22 23 log.info("start work loop"); 24 while (true) { 25 try { 26 for (String type : typeArrr) { 27 srv.doUpdate(domain, type, name, ttl, port, weight, key, secret); 28 } 29 30 Thread.sleep(5000); 31 } catch (Exception err) { 32 //err.printStackTrace(); 33 log.error(err.getMessage(),err); 34 } 35 } 36 // log.info("main end"); 37 } 38 39 }
以下是 UpdateSrv.java
1 package update_godaddy_ddns; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.io.InputStreamReader; 7 import java.net.Inet4Address; 8 import java.net.Inet6Address; 9 import java.net.InetAddress; 10 import java.net.NetworkInterface; 11 import java.net.SocketException; 12 import java.util.ArrayList; 13 import java.util.Collection; 14 import java.util.Enumeration; 15 16 import org.apache.commons.lang3.StringUtils; 17 import org.apache.http.StatusLine; 18 import org.apache.http.client.ClientProtocolException; 19 import org.apache.http.client.methods.CloseableHttpResponse; 20 import org.apache.http.client.methods.HttpGet; 21 import org.apache.http.client.methods.HttpPut; 22 import org.apache.http.entity.StringEntity; 23 import org.apache.http.impl.client.CloseableHttpClient; 24 import org.apache.http.impl.client.HttpClients; 25 import org.slf4j.Logger; 26 import org.slf4j.LoggerFactory; 27 28 import net.sf.json.JSONArray; 29 import net.sf.json.JSONObject; 30 31 public class UpdateSrv { 32 private String lastUpdatedIpToDnsServer; 33 34 public void doUpdate(String domain, String type, String name, String ttl, String port, String weight, String key, 35 String secret) throws ClientProtocolException, IOException { 36 Logger log = LoggerFactory.getLogger(UpdateSrv.class); 37 log.info("doUpdate begin..."); 38 39 if (this.lastUpdatedIpToDnsServer == null) { 40 String ipFromDns = getIpFromDnsServer(domain, type, name, ttl, port, weight, key, secret); 41 this.lastUpdatedIpToDnsServer = ipFromDns; 42 } 43 44 ArrayList<InetAddress> ipListForInternet = new ArrayList<InetAddress>(); 45 46 // getFromLocalMachine(ipListForInternet); 47 getInternetIpsFromLocalMachine(ipListForInternet); 48 49 if (ipListForInternet.isEmpty()) { 50 log.warn("cannot find ipv6 for internet"); 51 return; 52 } 53 54 // check if already send ip of local machine public ip(in used) to DDNS server 55 if (StringUtils.isNotEmpty(this.lastUpdatedIpToDnsServer)) { 56 for (InetAddress ia : ipListForInternet) { 57 // String ip = ia.getHostAddress(); 58 String ip = getIp(ia); 59 if (ip.equalsIgnoreCase(this.lastUpdatedIpToDnsServer)) { 60 log.info("local machine ip not changed,no need to update:" + ip); 61 return; 62 } 63 } 64 } 65 66 String newIp = pickUpOneIpV6(ipListForInternet); 67 if (StringUtils.isEmpty(newIp)) { 68 log.warn("cannot find ipv6 for internet,2"); 69 return; 70 } 71 72 log.info("try update for newIp:" + newIp); 73 tryUpdateIpForDns(newIp, domain, type, name, ttl, port, weight, key, secret); 74 log.info("after update for newIp:" + newIp); 75 76 // if no error 77 this.lastUpdatedIpToDnsServer = newIp; 78 79 } 80 81 public void tryUpdateIpForDns(String newIp, String domain, String type, String name, String ttl, String port, 82 String weight, String key, String secret) throws ClientProtocolException, IOException { 83 Logger log = LoggerFactory.getLogger(UpdateSrv.class); 84 log.info("tryUpdateIpForDns begin..." + newIp); 85 86 // 1.获得一个httpclient对象 87 try (CloseableHttpClient httpclient = HttpClients.createDefault()) { 88 89 // 2.生成一个 put 请求 90 String url = "https://api.godaddy.com/v1/domains/" + domain + "/records/" + type + "/" + name; 91 HttpPut httpput = new HttpPut(url); 92 httpput.setHeader("Content-Type", "application/json"); 93 httpput.setHeader("Authorization", "sso-key " + key + ":" + secret); 94 95 String strJson = "[{\"data\":\"" + newIp + "\",\"ttl\":" + ttl + "}]"; 96 StringEntity stringEntity = new StringEntity(strJson, "utf-8"); 97 httpput.setEntity(stringEntity); 98 99 // 3.执行 put 请求并返回结果 100 try (CloseableHttpResponse response = httpclient.execute(httpput)) { 101 log.info("after httpclient.execute"); 102 103 // try { 104 // 4.处理结果 105 StatusLine sl = response.getStatusLine(); 106 log.info("getStatusLine:" + sl); 107 // HTTP/1.1 401 Unauthorized 108 if (sl.getStatusCode() == 200) { 109 log.info("updated success"); 110 StringBuilder sbBuffer = new StringBuilder(); 111 112 try (InputStream is = response.getEntity().getContent()) { 113 try (InputStreamReader isr = new InputStreamReader(is)) { 114 try (BufferedReader reader = new BufferedReader(isr)) { 115 String line; 116 while ((line = reader.readLine()) != null) { 117 log.info("strResponse:" + line); 118 sbBuffer.append(line); 119 } 120 } 121 } 122 } 123 124 String strResponse = sbBuffer.toString(); 125 // should be empty 126 log.info("strResponse:" + strResponse); 127 } else { 128 129 } 130 } 131 } 132 } 133 134 // private void getFromLocalMachine(ArrayList<String> ipListForInternet) throws 135 // SocketException { 136 private void getInternetIpsFromLocalMachine(ArrayList<InetAddress> ipListForInternet) throws SocketException { 137 Logger log = LoggerFactory.getLogger(UpdateSrv.class); 138 log.info("getInternetIpsFromLocalMachine begin..."); 139 140 // get ip-v6 only 141 Enumeration<NetworkInterface> ints = NetworkInterface.getNetworkInterfaces(); 142 while (ints.hasMoreElements()) { 143 // each network card 144 NetworkInterface it = ints.nextElement(); 145 146 Enumeration<InetAddress> adds = it.getInetAddresses(); 147 while (adds.hasMoreElements()) { 148 // each ip 149 InetAddress ia = adds.nextElement(); 150 // String ip = ia.getHostAddress(); 151 String ip = getIp(ia); 152 // if (ia instanceof Inet4Address) { 153 // continue; 154 // } else if (ia instanceof Inet6Address) { 155 if (ia.isAnyLocalAddress()) { 156 continue; 157 } else if (ia.isLoopbackAddress()) { 158 continue; 159 } else if (ia.isLinkLocalAddress()) { 160 continue; 161 } else if (ia.isSiteLocalAddress()) { 162 continue; 163 } 164 165 if (ip.startsWith("fe80:")) { 166 continue; 167 } 168 // ipListForInternet.add(ip); 169 ipListForInternet.add(ia); 170 // } else { 171 // // should not goes here. 172 // } 173 174 } 175 } 176 } 177 178 private String getIpFromDnsServer(String domain, String type, String name, String ttl, String port, String weight, 179 String key, String secret) throws ClientProtocolException, IOException { 180 Logger log = LoggerFactory.getLogger(UpdateSrv.class); 181 log.info("getIpFromDns begin..."); 182 183 // 1.获得一个httpclient对象 184 try (CloseableHttpClient httpclient = HttpClients.createDefault()) { 185 186 // 2.生成一个get请求 187 String url = "https://api.godaddy.com/v1/domains/" + domain + "/records/" + type + "/" + name; 188 HttpGet httpget = new HttpGet(url); 189 httpget.addHeader("Authorization", "sso-key " + key + ":" + secret); 190 // 3.执行get请求并返回结果 191 try (CloseableHttpResponse response = httpclient.execute(httpget)) { 192 log.info("after httpclient.execute"); 193 194 // try { 195 // 4.处理结果 196 StatusLine sl = response.getStatusLine(); 197 log.info("getStatusLine:" + sl); 198 // HTTP/1.1 401 Unauthorized 199 if (sl.getStatusCode() == 200) { 200 StringBuilder sbBuffer = new StringBuilder(); 201 202 try (InputStream is = response.getEntity().getContent()) { 203 try (InputStreamReader isr = new InputStreamReader(is)) { 204 try (BufferedReader reader = new BufferedReader(isr)) { 205 String line; 206 while ((line = reader.readLine()) != null) { 207 log.info("strResponse:" + line); 208 sbBuffer.append(line); 209 } 210 } 211 } 212 } 213 214 String strResponse = sbBuffer.toString(); 215 // [{"data":"2409:8a1e:90ad:a1e0:dd40:8bcd:xxx","name":"abc-ipv6","ttl":1800,"type":"AAAA"}] 216 log.info("strResponse:" + strResponse); 217 218 // parse 219 String ip = parseIpFromGodaddyResponse(strResponse); 220 return ip; 221 } else { 222 223 } 224 } 225 } 226 227 return null; 228 } 229 230 public String parseIpFromGodaddyResponse(String strResponse) { 231 Logger log = LoggerFactory.getLogger(UpdateSrv.class); 232 log.info("parseIpFromGodaddyResponse begin..." + strResponse); 233 234 // [{"data":"2409:8a1e:90ad:a1e0:dd40:8bcd:xxx","name":"abc-ipv6","ttl":1800,"type":"AAAA"}] 235 // JSONObject obj = JSONObject.fromObject(strResponse); 236 JSONArray arr = JSONArray.fromObject(strResponse); 237 238 for (Object object : arr) { 239 JSONObject obj = (JSONObject) object; 240 241 // Set keys = obj.keySet(); 242 String name = (String) obj.get("name"); 243 Number ttl = (Number) obj.get("ttl"); 244 String type = (String) obj.get("type"); 245 String data = (String) obj.get("data"); 246 247 log.info("name:" + name + ",ttl:" + ttl + ",type:" + type + ",data:" + data); 248 249 if (StringUtils.isNotEmpty(data)) { 250 return data; 251 } 252 } 253 // log.info(arr.toString()); 254 255 return null; 256 } 257 258 private String pickUpOneIpV6(Collection<InetAddress> ipListForInternet) { 259 Logger log = LoggerFactory.getLogger(UpdateSrv.class); 260 log.info("pickUpOneIpV6 begin..."); 261 262 for (InetAddress ia : ipListForInternet) { 263 if (ia instanceof Inet4Address) { 264 continue; 265 } else if (ia instanceof Inet6Address) { 266 String ip = getIp(ia); 267 return ip; 268 } else { 269 // should not goes here. 270 } 271 } 272 return null; 273 } 274 275 private String getIp(InetAddress ia) { 276 String ip = ia.getHostAddress(); 277 // 2409:891e:9340:xxx:xxx:xxx:f3c7:xxx%wlp4s0 278 int pos = ip.lastIndexOf("%"); 279 if (pos > 0) { 280 ip = ip.substring(0, pos); 281 } 282 return ip; 283 } 284 }
编译后,在 ubuntu 下,使用命令行运行:
export CLASSPATH=".:../bin:../lib/slf4j-api-1.7.25.jar:../lib/httpclient-4.5.2.jar:../lib/httpcore-4.4.4.jar:../lib/jcl-over-slf4j-1.7.25.jar:../lib/logback-classic-1.2.3.jar:../lib/logback-core-1.2.3.jar:../lib/json-lib-2.4-jdk15.jar:../lib/commons-lang-2.4.jar:../lib/commons-lang3-3.0.1.jar:../lib/ezmorph-1.0.6.jar:../lib/commons-collections-3.2.2.jar:../lib/commons-beanutils-1.9.3.jar" java update_godaddy_ddns.UpdateDdns some.com AAAA zg_xxx 1800 1 1 xxx yyy
命令行参数的含义,见 UpdateDdns.java 中的 main 函数。
--------------欢迎转载,转载请注明出处: https://my.oschina.net/jacklondon