Skip to content

Commit

Permalink
Add ip update mechanism
Browse files Browse the repository at this point in the history
- check if external IP has been changed by ISP using miniupnpc
- remember new IP and send it to DNS provider
- add some description
  • Loading branch information
mirkosrc committed Sep 21, 2023
1 parent 98d24ad commit 956cafc
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 3 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,9 @@

Using an external configuration file:

`java -jar dnsupdater.jar --spring.config.additional-location=my.properties`
`java -jar dnsupdater.jar --spring.config.additional-location=my.properties`


Since you don't have an OpenWrt Router, there are limited ways to retrieve the external IP
The way is to install https://github.com/transmission/miniupnpc on your server and call `external-ip`, which returns
the external ip of your plastic router.
2 changes: 2 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ dependencies {
implementation("org.springframework.boot:spring-boot-starter")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("io.github.microutils:kotlin-logging:3.0.5")

testImplementation("org.springframework.boot:spring-boot-starter-test")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ internal class GandiClientTest {
wireMockServer.start()
WireMockConfiguration.options().notifier(ConsoleNotifier(true))
configureFor("localhost", 8080)
stubFor(put(urlEqualTo("/api/v5/domains/foo.net/records/bar/A"))
stubFor(put(urlEqualTo("/api/v5/domains/foo.net/records/fqdn/A"))
.willReturn(okJson("{\"keks\":\"dose\"}")))

val ipAddress= "1.1.1.1"
val responseCode = gandiClient.doUpdateIpWithfqdn(ipAddress, "bar")
val responseCode = gandiClient.doUpdateIpWithfqdn(ipAddress, "fqdn")
assertThat(responseCode.statusCode.value()).isEqualTo(200)
wireMockServer.stop()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package net.flyingelectrons.dnsupdater.service

import org.springframework.stereotype.Service

@Service
class ExternalIpRetrieverService(private val processExecutorService: ProcessExecutorService) {

fun getExternalIp(): String {
val execute = processExecutorService.execute("external-ip")
if (execute.isEmpty()) {
throw java.lang.IllegalArgumentException("external IP is empty")
}
return execute
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package net.flyingelectrons.dnsupdater.service

import org.springframework.stereotype.Service
import java.io.BufferedReader
import java.io.InputStream
import java.io.InputStreamReader
import java.util.concurrent.Executors
import java.util.function.Consumer

@Service
class ProcessExecutorService {

fun execute(unixCommand: String): String {
var out = ""
val process: Process = Runtime.getRuntime()
.exec(unixCommand)
val streamGobbler = StreamGobbler(
process.inputStream, fun(x: String?) {
println(x)
out = x.orEmpty()
}
)
Executors.newSingleThreadExecutor().submit(streamGobbler)
val exitCode = process.waitFor()
assert(exitCode == 0)
return out
}
}

private class StreamGobbler(private val inputStream: InputStream, consumer: Consumer<String>) :
Runnable {
private val consumer: Consumer<String>
override fun run() {
BufferedReader(InputStreamReader(inputStream)).lines()
.forEach(consumer)
}

init {
this.consumer = consumer
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package net.flyingelectrons.dnsupdater.service

import mu.KotlinLogging
import net.flyingelectrons.dnsupdater.gateway.GandiClient
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.stereotype.Service

@Service
class UpdateDnsSchedulingService @Autowired constructor(
private val externalIpRetrieverService: ExternalIpRetrieverService,
private val gandiClient: GandiClient,
) {

private var savedIp = "noIpKnownYet"

@Scheduled(cron = "*/3 * * * * *")
fun updateDns() {
val externalIp: String = externalIpRetrieverService.getExternalIp()
LOGGER.info("running scheduler. get external ip: $externalIp")
if (externalIp != savedIp) {
val ipWithfqdn = gandiClient.doUpdateIpWithfqdn(externalIp, "myfqdn")
LOGGER.info("Updating myfqdn")
LOGGER.info(ipWithfqdn.body)
savedIp = externalIp
}
}

companion object {
private val LOGGER = KotlinLogging.logger { }
}
}

0 comments on commit 956cafc

Please sign in to comment.