编写 java 程序,为家用电脑 ipv6 自动更新 goddy dns 记录(ddns)


【对话专家,HMS Core 6创新能力解读】11月25日19:00 直播报名>>>

家里放了一台旧 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()) {
			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");
			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.生成一个get请求
			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.执行get请求并返回结果
			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_dev_db 1800 1 1 xxx yyy

命令行参数的含义,见 UpdateDdns.java 中的 main 函数。

 

--------------欢迎转载,转载请注明出处: https://my.oschina.net/jacklondon

 

来源:https://my.oschina.net/jacklondon/blog/5325056


码神部落- 版权声明 1、本主题所有言论和图片纯属会员个人意见,与码神部落立场无关。
2、本站所有主题由该帖子作者发表,该帖子作者对牛谈情码神部落享有帖子相关版权。
3、码神部落管理员和版主有权不事先通知发贴者而删除本文。
4、其他单位或个人使用、转载或引用本文时必须同时征得该帖子作者对牛谈情码神部落的同意。
5、帖子作者须承担一切因本文发表而直接或间接导致的民事或刑事法律责任。
6、本帖部分内容转载自其它媒体,但并不代表本站赞同其观点和对其真实性负责。
7、如本帖侵犯到任何版权问题,请立即告知本站,本站将及时予与删除并致以最深的歉意。

最新回复 (0)
    • 码神部落
      2
        立即登录 立即注册 GitHub登录
返回
发新帖
作者最近主题: