编写 java 程序,为家用电脑 ipv6 自动更新 goddy dns 记录(ddns)
Posted Jacklondon Chen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了编写 java 程序,为家用电脑 ipv6 自动更新 goddy dns 记录(ddns)相关的知识,希望对你有一定的参考价值。
家里放了一台旧 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 :
package update_godaddy_ddns; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class UpdateDdns { public static void main(String[] args) { Logger log = LoggerFactory.getLogger(UpdateDdns.class); log.info("main begin..."); String domain = args[0]; // "mydomain.com" # your domain String typeMulti = args[1]; // ="A" # Record type A, CNAME, MX, etc. String name = args[2]; // "sip" # name of record to update String ttl = args[3]; // "3600" # Time to Live min value 600 String port = args[4]; // "1" # Required port, Min value 1 String weight = args[5]; // "1" # Required weight, Min value 1 String key = args[6]; // "abc" # key for godaddy developer API String secret = args[7]; // "efg" # secret for godaddy developer API String[] typeArrr = typeMulti.split("/"); UpdateSrv srv = new UpdateSrv(); log.info("start work loop"); while (true) { try { for (String type : typeArrr) { srv.doUpdate(domain, type, name, ttl, port, weight, key, secret); } Thread.sleep(5000); } catch (Exception err) { //err.printStackTrace(); log.error(err.getMessage(),err); } } // log.info("main end"); } }
以下是 UpdateSrv.java
package update_godaddy_ddns; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import org.apache.commons.lang3.StringUtils; import org.apache.http.StatusLine; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPut; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.sf.json.JSONArray; import net.sf.json.JSONObject; public class UpdateSrv { private String lastUpdatedIpToDnsServer; public void doUpdate(String domain, String type, String name, String ttl, String port, String weight, String key, String secret) throws ClientProtocolException, IOException { Logger log = LoggerFactory.getLogger(UpdateSrv.class); log.info("doUpdate begin..."); if (this.lastUpdatedIpToDnsServer == null) { String ipFromDns = getIpFromDnsServer(domain, type, name, ttl, port, weight, key, secret); this.lastUpdatedIpToDnsServer = ipFromDns; } ArrayList<InetAddress> ipListForInternet = new ArrayList<InetAddress>(); // getFromLocalMachine(ipListForInternet); getInternetIpsFromLocalMachine(ipListForInternet); if (ipListForInternet.isEmpty()) { log.warn("cannot find ipv6 for internet"); return; } // check if already send ip of local machine public ip(in used) to DDNS server if (StringUtils.isNotEmpty(this.lastUpdatedIpToDnsServer)) { for (InetAddress ia : ipListForInternet) { // String ip = ia.getHostAddress(); String ip = getIp(ia); if (ip.equalsIgnoreCase(this.lastUpdatedIpToDnsServer)) { log.info("local machine ip not changed,no need to update:" + ip); return; } } } String newIp = pickUpOneIpV6(ipListForInternet); if (StringUtils.isEmpty(newIp)) { log.warn("cannot find ipv6 for internet,2"); return; } log.info("try update for newIp:" + newIp); tryUpdateIpForDns(newIp, domain, type, name, ttl, port, weight, key, secret); log.info("after update for newIp:" + newIp); // if no error this.lastUpdatedIpToDnsServer = newIp; } public void tryUpdateIpForDns(String newIp, String domain, String type, String name, String ttl, String port, String weight, String key, String secret) throws ClientProtocolException, IOException { Logger log = LoggerFactory.getLogger(UpdateSrv.class); log.info("tryUpdateIpForDns begin..." + newIp); // 1.获得一个httpclient对象 try (CloseableHttpClient httpclient = HttpClients.createDefault()) { // 2.生成一个 put 请求 String url = "https://api.godaddy.com/v1/domains/" + domain + "/records/" + type + "/" + name; HttpPut httpput = new HttpPut(url); httpput.setHeader("Content-Type", "application/json"); httpput.setHeader("Authorization", "sso-key " + key + ":" + secret); String strJson = "[{\\"data\\":\\"" + newIp + "\\",\\"ttl\\":" + ttl + "}]"; StringEntity stringEntity = new StringEntity(strJson, "utf-8"); httpput.setEntity(stringEntity); // 3.执行 put 请求并返回结果 try (CloseableHttpResponse response = httpclient.execute(httpput)) { log.info("after httpclient.execute"); // try { // 4.处理结果 StatusLine sl = response.getStatusLine(); log.info("getStatusLine:" + sl); // HTTP/1.1 401 Unauthorized if (sl.getStatusCode() == 200) { log.info("updated success"); StringBuilder sbBuffer = new StringBuilder(); try (InputStream is = response.getEntity().getContent()) { try (InputStreamReader isr = new InputStreamReader(is)) { try (BufferedReader reader = new BufferedReader(isr)) { String line; while ((line = reader.readLine()) != null) { log.info("strResponse:" + line); sbBuffer.append(line); } } } } String strResponse = sbBuffer.toString(); // should be empty log.info("strResponse:" + strResponse); } else { } } } } // private void getFromLocalMachine(ArrayList<String> ipListForInternet) throws // SocketException { private void getInternetIpsFromLocalMachine(ArrayList<InetAddress> ipListForInternet) throws SocketException { Logger log = LoggerFactory.getLogger(UpdateSrv.class); log.info("getInternetIpsFromLocalMachine begin..."); // get ip-v6 only Enumeration<NetworkInterface> ints = NetworkInterface.getNetworkInterfaces(); while (ints.hasMoreElements()) { // each network card NetworkInterface it = ints.nextElement(); Enumeration<InetAddress> adds = it.getInetAddresses(); while (adds.hasMoreElements()) { // each ip InetAddress ia = adds.nextElement(); // String ip = ia.getHostAddress(); String ip = getIp(ia); // if (ia instanceof Inet4Address) { // continue; // } else if (ia instanceof Inet6Address) { if (ia.isAnyLocalAddress()) { continue; } else if (ia.isLoopbackAddress()) { continue; } else if (ia.isLinkLocalAddress()) { continue; } else if (ia.isSiteLocalAddress()) { continue; } if (ip.startsWith("fe80:")) { continue; } // ipListForInternet.add(ip); ipListForInternet.add(ia); // } else { // // should not goes here. // } } } } private String getIpFromDnsServer(String domain, String type, String name, String ttl, String port, String weight, String key, String secret) throws ClientProtocolException, IOException { Logger log = LoggerFactory.getLogger(UpdateSrv.class); log.info("getIpFromDns begin..."); // 1.获得一个httpclient对象 try (CloseableHttpClient httpclient = HttpClients.createDefault()) { // 2.生成一个get请求 String url = "https://api.godaddy.com/v1/domains/" + domain + "/records/" + type + "/" + name; HttpGet httpget = new HttpGet(url); httpget.addHeader("Authorization", "sso-key " + key + ":" + secret); // 3.执行get请求并返回结果 try (CloseableHttpResponse response = httpclient.execute(httpget)) { log.info("after httpclient.execute"); // try { // 4.处理结果 StatusLine sl = response.getStatusLine(); log.info("getStatusLine:" + sl); // HTTP/1.1 401 Unauthorized if (sl.getStatusCode() == 200) { StringBuilder sbBuffer = new StringBuilder(); try (InputStream is = response.getEntity().getContent()) { try (InputStreamReader isr = new InputStreamReader(is)) { try (BufferedReader reader = new BufferedReader(isr)) { String line; while ((line = reader.readLine()) != null) { log.info("strResponse:" + line); sbBuffer.append(line); } } } } String strResponse = sbBuffer.toString(); // [{"data":"2409:8a1e:90ad:a1e0:dd40:8bcd:xxx","name":"abc-ipv6","ttl":1800,"type":"AAAA"}] log.info("strResponse:" + strResponse); // parse String ip = parseIpFromGodaddyResponse(strResponse); return ip; } else { } } } return null; } public String parseIpFromGodaddyResponse(String strResponse) { Logger log = LoggerFactory.getLogger(UpdateSrv.class); log.info("parseIpFromGodaddyResponse begin..." + strResponse); // [{"data":"2409:8a1e:90ad:a1e0:dd40:8bcd:xxx","name":"abc-ipv6","ttl":1800,"type":"AAAA"}] // JSONObject obj = JSONObject.fromObject(strResponse); JSONArray arr = JSONArray.fromObject(strResponse); for (Object object : arr) { JSONObject obj = (JSONObject) object; // Set keys = obj.keySet(); String name = (String) obj.get("name"); Number ttl = (Number) obj.get("ttl"); String type = (String) obj.get("type"); String data = (String) obj.get("data"); log.info("name:" + name + ",ttl:" + ttl + ",type:" + type + ",data:" + data); if (StringUtils.isNotEmpty(data)) { return data; } } // log.info(arr.toString()); return null; } private String pickUpOneIpV6(Collection<InetAddress> ipListForInternet) { Logger log = LoggerFactory.getLogger(UpdateSrv.class); log.info("pickUpOneIpV6 begin..."); for (InetAddress ia : ipListForInternet) { if (ia instanceof Inet4Address) { continue; } else if (ia instanceof Inet6Address) { String ip = getIp(ia); return ip; } else { // should not goes here. } } return null; } private String getIp(InetAddress ia) { String ip = ia.getHostAddress(); // 2409:891e:9340:xxx:xxx:xxx:f3c7:xxx%wlp4s0 int pos = ip.lastIndexOf("%"); if (pos > 0) { ip = ip.substring(0, pos); } return ip; } }
编译后,在 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://www.cnblogs.com/jacklondon
以上是关于编写 java 程序,为家用电脑 ipv6 自动更新 goddy dns 记录(ddns)的主要内容,如果未能解决你的问题,请参考以下文章
win10电脑连接路由器和光猫后不能连网,IPV4和IPV6无网络访问权限,DNS设为自动显示错误
Window配置网络设定IPv6的固定IP自动被修改为169.254.*.*的问题
使用 Java Swing 编写 IpChat, 基于 IP Messenger 协议,支持 IPv6