编写 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 :

 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

上一篇:面试编程题


下一篇:Java ASM系列:(041)InstructionAdapter介绍