Skip to content

Instantly share code, notes, and snippets.

@manikmagar
Last active May 30, 2020 14:22
Show Gist options
  • Save manikmagar/f5a21d216ac6a5ccc7ff7e329cae382a to your computer and use it in GitHub Desktop.
Save manikmagar/f5a21d216ac6a5ccc7ff7e329cae382a to your computer and use it in GitHub Desktop.
CloudflareDDNSUpdate Java and Jbang based script. See https://javastreets.com/blog/java-jbang-cloudflare-ddns.html
zoneId=
fqdn=
cfApiToken=
//usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS com.konghq:unirest-java:3.4.00:standalone
//DEPS info.picocli:picocli:4.1.4
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.Callable;
import kong.unirest.Unirest;
import kong.unirest.json.JSONObject;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Parameters;
/**
* This class updates the DNS in Cloudflare with public IP address for current network.
*
* cfConfigPath must point to a properties file containing three property values -
* zoneId: Cloudflare DNS Zone Id
* fqdn: Fully qualified domain name to update with public IP. eg. test.example.com
* cfApiToken: An API Token for interacting with Cloudflare apis.
*
* @author manikmagar
*/
@Command(name = "CloudflareDDNSUpdate", mixinStandardHelpOptions = true, version = "CloudflareDDNSUpdate 1.0",
description = "Dynamic DNS update for Cloudflare")
class CloudflareDDNSUpdate implements Callable<Integer> {
@Parameters(index = "0", description = "Cloudflare configuration properties file path")
private File cfConfigPath;
public static void main(String[] args) {
Integer exit = new CommandLine(new CloudflareDDNSUpdate()).execute(args);
System.exit(exit);
}
public Integer call() throws Exception {
System.out.println("Initiating DNS update for cloudflare ...");
final String zoneId, fqdn, cfApiToken;
// Load properties file
Properties props = new Properties();
try {
props.load(new FileInputStream(cfConfigPath));
} catch (IOException e) {
System.err.println("Unable to load configuration file - " + e.getMessage());
return 1;
}
zoneId = props.getProperty("zoneId");
fqdn = props.getProperty("fqdn");
cfApiToken = props.getProperty("cfApiToken");
String publicIP = Unirest.post("https://beta.ipinfo.in").asString().getBody();
System.out.println("Public IP is - " + publicIP);
JSONObject dnsRecord = Unirest.get("https://api.cloudflare.com/client/v4/zones/{zone_id}/dns_records")
.routeParam("zone_id", zoneId).queryString("type", "A").queryString("name", fqdn)
.header("Authorization", "Bearer " + cfApiToken).asJson().getBody().getObject().getJSONArray("result")
.optJSONObject(0);
if (dnsRecord == null) {
System.err.println("DNS Record " + fqdn + " does not exist in zone id " + zoneId);
return 1;
}
if (dnsRecord.getString("content").equals(publicIP)) {
System.out.println("Public IP has not changed. Skipping DNS update.");
return 0;
}
final String dnsRecordId = dnsRecord.getString("id");
System.out.println("DNS Record Id - " + dnsRecordId);
Map<String, Object> dnsData = new HashMap<>();
dnsData.put("type", "A");
dnsData.put("name", fqdn);
dnsData.put("content", publicIP);
dnsData.put("ttl",1);
JSONObject dns = new JSONObject(dnsData);
JSONObject putResponse = Unirest
.put("https://api.cloudflare.com/client/v4/zones/" + zoneId + "/dns_records/" + dnsRecordId).body(dns)
.header("Authorization", "Bearer " + cfApiToken).header("Content-Type", "application/json").asJson()
.getBody().getObject();
if (!putResponse.getBoolean("success")) {
System.err.println("DNS Update failed with error - " + putResponse.getJSONArray("errors").join(","));
return 1;
} else {
System.out.println("DNS Updated successfully with new ip address - " + publicIP);
return 0;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment