qdm12 / ddns-updater

Container to update DNS records periodically with WebUI for many DNS providers
https://hub.docker.com/r/qmcgaw/ddns-updater/
MIT License
1.77k stars 168 forks source link

Feature request: Run a command on ip update #570

Open brko7 opened 11 months ago

brko7 commented 11 months ago
  1. What's the feature?

Add an environment variable for a command or a path to bash script, which will run on an IP change.

  1. Extra information?

Helpful for wireguard tunnels to run this script.

Wireguard doesn't know that the peer IP changed and maintains the connection on the old DNS IP until it is restarted or reconfigured by running the mentioned script. This feature would enable the server1 that changed IP and updated the DNS to run an additional command to notify the server2 connected to server1 via wg tunnel to run the script on server2 so the new IP would be added.

qdm12 commented 10 months ago

How are you running DDNS updater? In its Docker image? Or as a binary outside a container (not yet pre-built but will be soon). If it's in the Docker image, unfortunately it has no base system so there is no bash or any shell to run scripts (plus you would have to run it on the host (or container as root with NET_ADMIN) eventually, to fiddle with Wireguard.

brko7 commented 10 months ago

Hi, thanks for the reply. I am running as a Docker image. Thanks for clarifying; I will look into triggering a command based on a web push that DDNS-updater is making or some other solution.

I am running site-to-site wireguard between two servers, and on both servers, I do not have a dedicated IP, so I run DNS-updater. So when the IP of one server changes, the other stops connecting to it. I can run scripts on both servers to check the connection every few minutes, but I was hoping as ddns-updater knows when the IP changed to somehow automatically trigger reconnection on the other server.

qdm12 commented 10 months ago

DDNS-updater could definitely either:

You could also have a program/script reading the ddns updater logs and acting on them? 🤔 With docker logs -f ddns-updater and some grep-ing, that could be feasible? Feel free to share such script, I would add it to the readme!

brko7 commented 10 months ago

Thanks for the ideas! Probably the best thing for me would be to have an event-driven trigger as ip-s change once every 5-7 days and I feel it would be a waste of resources to have script checking every minute or so. But yes maybe I can try greping the docker logs that should not be resource intensive at all.

Great I will share up here if I can think of something useful.

qdm12 commented 10 months ago

Here's a quick untested script to do it:

docker logs -f ddns-updater | \
  while IFS= read -r line; do
      if [[ "$line" =~ "your_predefined_regex" ]]; then
          ./your-action-script.sh
      fi
  done

I feel it would be a waste of resources to have script checking every minute or so. But yes maybe I can try greping the docker logs that should not be resource intensive at all.

Ehh more or less the same, doing an HTTP GET every second would likely not affect performance at all, despite the 'feeling' 😄 And having a one second delay would be fine too to be fair. Event driven is always better obviously, but if time driven is a lot easier, it's worth it here 😉

incaseoftrouble commented 9 months ago

A docker-compatible approach would be to touch / write a file. Scripts could easily check the modification time regularly or use filesystem events (inotify) for instant response.

EDIT: Actually, you could just monitor updates.json for changes :D You'd probably want to know which address has changed.

Using inotify should be something like (haven't tried it)

import pathlib
import json
import inotify.adapters

path = pathlib.Path('/path/to/updates.json')
def _main():
    i = inotify.adapters.Inotify()
    i.add_watch(str(path))
    for _ in i.event_gen(yield_nones=False):
      print("Address changed!")
      with path.open("rt") as f:
        data = json.load(f)
      # Do stuff

or simply check path.stat().st_mtime every second or so, that would be without dependencies :)

brko7 commented 9 months ago

Thanks for all the ideas and info, for now I ended up creating a service on both sides of the wireguard VPN tunnel. It runs every 2minutes and runs wireguard reresolvedns script just like in the arch docs under 5.2:

https://wiki.archlinux.org/title/WireGuard

As I am not running any production critical workloads 2minutes is fine. When ddns-updater updates the record reresolve services catches it in under 2minutes which suits me well for now.

But thanks for the ideas and script which I would definitely test somewhere in the future if I will need VPN back up in the matter of seconds.