Skip to content

Commit

Permalink
Upload project
Browse files Browse the repository at this point in the history
  • Loading branch information
TobiasGrether committed Aug 6, 2021
0 parents commit 2424ed8
Show file tree
Hide file tree
Showing 12 changed files with 512 additions and 0 deletions.
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Cloudflare & DynDNS

Good for everyone who wants to use Cloudflare with their local ip but has a changing ip address.


## Config
```yaml
# Your cloudflare api token
apiToken: ""
# Your cloudflare email (required for auth)
cfEmail: ""
# The zoneId of the zone you want to update (Can be seen on the right of the domain dashboard)
zoneId: ""
dnsRecords:
- name: "myendpoint.example.com"
type: "A"
```
This project uses Cloudflare APIs only. It uses cloudflares cgi tracing endpoint to resolve the current public address and then handles changes accordingly.
## How to run
- Build with maven (java 11)
- Run on a machine like a server or a Raspberry Pi
- start once, edit configuration
- start again
## Motivation
This is a simple project used by f.e. our smart home endpoints, nginx web server etc.
Mental support provided by @iTzFreeHD
103 changes: 103 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>de.tobiasgrether</groupId>
<artifactId>CF-DynDNS</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<log4j2.version>2.14.0</log4j2.version>
</properties>
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>

<dependencies>
<dependency>
<groupId>org.ini4j</groupId>
<artifactId>ini4j</artifactId>
<version>0.5.4</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.29</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.konghq</groupId>
<artifactId>unirest-java</artifactId>
<version>3.11.09</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.13.3</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j2.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j2.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.2</version>
<configuration>
<archive>
<manifestEntries>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<Main-Class>de.tobiasgrether.dyndns.Bootstrap</Main-Class>
</manifestEntries>
</archive>
<finalName>DynDNS-Exporter</finalName>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
13 changes: 13 additions & 0 deletions src/main/java/de/tobiasgrether/dyndns/Bootstrap.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package de.tobiasgrether.dyndns;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Bootstrap {
private static final Logger logger = LoggerFactory.getLogger("Main");

public static void main(String[] args){
logger.info("Starting up DynDNS..");
DynDNS dnsManager = new DynDNS();
}
}
95 changes: 95 additions & 0 deletions src/main/java/de/tobiasgrether/dyndns/DynDNS.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package de.tobiasgrether.dyndns;

import de.tobiasgrether.dyndns.model.DNSListResult;
import de.tobiasgrether.dyndns.model.DNSRecord;
import de.tobiasgrether.dyndns.model.config.ConfigModel;
import de.tobiasgrether.dyndns.model.config.RecordEntry;
import de.tobiasgrether.dyndns.util.ConfigParser;
import kong.unirest.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.StringReader;
import java.util.Properties;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class DynDNS {

private final Logger logger = LoggerFactory.getLogger("DynDNS");

private ConfigModel model;
private String lastKnownAddress;
private final ObjectMapper mapper = new JsonObjectMapper();

public DynDNS() {
try {
this.model = ConfigParser.parseConfig(this);
} catch (IOException e) {
this.logger.error("Error while parsing configuration file, exiting...", e);
return;
}

ScheduledExecutorService requestRoundExecutor = Executors.newSingleThreadScheduledExecutor();
requestRoundExecutor.scheduleAtFixedRate(this::checkCurrentPublicIP, 0, 30, TimeUnit.SECONDS);
}

private void checkCurrentPublicIP() {
HttpResponse<String> response = Unirest.get("https://cloudflare.com/cdn-cgi/trace")
.asString();

if (response.getStatus() == 200) {
try {
Properties p = new Properties();
p.load(new StringReader(response.getBody()));
String currentIp = p.getProperty("ip");
if (!currentIp.equals(this.lastKnownAddress)) {
this.triggerDNSRewrite(currentIp);
this.lastKnownAddress = currentIp;
}
} catch (Throwable t) {
this.logger.error("Error while handling ini file", t);
}

} else {
this.logger.warn("Could not parse current public ip from Cloudflare. Error " + response.getStatus() + ": " + response.getStatusText());
}
}

private void triggerDNSRewrite(String currentIp) {
this.logger.warn("Detected new public ip, rewriting dns records..");

HttpResponse<JsonNode> result = Unirest.get("https://api.cloudflare.com/client/v4/zones/" + this.model.getZoneId() + "/dns_records")
.header("X-Auth-Key", this.model.getApiToken())
.header("X-Auth-Email", this.model.getCfEmail())
.asJson();

DNSListResult parsedResult = this.mapper.readValue(result.getBody().toString(), DNSListResult.class);
if (parsedResult.isSuccess()) {
for (DNSRecord record : parsedResult.getResult()) {
if (this.model.getDnsRecords().contains(new RecordEntry(record.getName(), "")) && !record.getContent().equals(currentIp)) {
record.setContent(currentIp);
HttpResponse<JsonNode> update = Unirest.put("https://api.cloudflare.com/client/v4/zones/" + this.model.getZoneId() + "/dns_records/" + record.getId())
.body(this.mapper.writeValue(record))
.header("X-Auth-Key", this.model.getApiToken())
.header("X-Auth-Email", this.model.getCfEmail())
.asJson();
if (update.getStatus() == 200) {
this.logger.info("DNS Record updated: {} (Record type {}) now has IP {}", record.getName(), record.getType(), currentIp);
}
}
}
}
this.logger.info("Record rewrite complete, new public ip is " + currentIp);
}

public Logger getLogger() {
return logger;
}

public ConfigModel getModel() {
return model;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package de.tobiasgrether.dyndns.model;

import lombok.Getter;
import lombok.ToString;

@Getter
@ToString
public class CloudflareTraceResult {

public Object fl;
private String h;
private String ip;
private String ts;
private String visit_scheme;
private String uag;
private String colo;
private String http;
private String loc;
private String tls;
private String sni;
private boolean warp;
private boolean gateway;
}
11 changes: 11 additions & 0 deletions src/main/java/de/tobiasgrether/dyndns/model/DNSListResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package de.tobiasgrether.dyndns.model;

import lombok.Getter;
import lombok.ToString;

@Getter
@ToString
public class DNSListResult {
private boolean success;
private DNSRecord[] result;
}
Loading

0 comments on commit 2424ed8

Please sign in to comment.