Skip to content

Add lightweight shell-based macOS client (no Xcode required)#1

Open
sai99claw wants to merge 3 commits into
clyang:masterfrom
sai99claw:add-shell-mac-client
Open

Add lightweight shell-based macOS client (no Xcode required)#1
sai99claw wants to merge 3 commits into
clyang:masterfrom
sai99claw:add-shell-mac-client

Conversation

@sai99claw

Copy link
Copy Markdown

Summary

The existing Swift Mac client (CsieDnsUpdater/) was written for Swift 1.x/2.x in 2015 and no longer compiles on modern Xcode toolchains. This PR adds a small, zero-dependency alternative at CsieDnsUpdater-Mac-Shell/ that does exactly the same job using only bash, curl, and launchd — all of which ship with macOS.

Nothing existing is removed or modified — purely additive.

What it does

  • Reads hostname and token from ~/.csie-ddns.conf (chmod 600, never committed)
  • Fetches the host's current public IP (with fallback echo endpoints)
  • Sends the standard https://csie.io/update?hn=...&token=...&ip=... request
  • Caches the last successful IP locally to avoid unnecessary API calls, but forces a re-send hourly as a safety net
  • Logs every run to ~/Library/Logs/csie-ddns.log
  • Distinguishes the current server response codes (OK, KO2, KO4, KO6) with friendly log messages — the original client only knew OK / KO
  • Installs as a launchd LaunchAgent that runs every 5 minutes and survives reboots

Layout

CsieDnsUpdater-Mac-Shell/
├── csie-ddns.sh                         core updater (safe to run standalone)
├── config.example.sh                    config template
├── io.csie.ddns-updater.plist.template  LaunchAgent template
├── install.sh                           materialises plist, launchctl load
├── uninstall.sh                         unload + remove
└── README.md                            usage

Why

  • The Swift 1.x app no longer builds on current Xcode without a full rewrite.
  • A shell + launchd approach has fewer moving parts than a GUI app and doesn't need to stay running in the menu bar.
  • All settings live in a single shell-snippet config file; no GUI to maintain.

Test plan

  • Verified end-to-end against franksai.csie.io: script run → server returns OK → DNS resolves to the host's new public IP
  • LaunchAgent loads, runs at install, and re-fires every 5 minutes
  • Error paths exercised — confirmed KO2/KO4/KO6 produce distinct log lines

🤖 Generated with Claude Code

sai99claw added 3 commits May 12, 2026 19:20
The original Swift Mac client (CsieDnsUpdater/) was written for Swift
1.x/2.x in 2015 and no longer compiles on modern Xcode toolchains. This
adds a zero-dependency alternative using only bash, curl, and launchd —
all of which ship with macOS.

Layout: CsieDnsUpdater-Mac-Shell/
- csie-ddns.sh                          core updater
- config.example.sh                     config template
- io.csie.ddns-updater.plist.template   LaunchAgent template
- install.sh / uninstall.sh             one-shot setup
- README.md                             usage

Behavioural notes:
- Recognises current server response codes (OK, KO2, KO4, KO6) with
  distinct log messages.
- Caches last-seen IP locally to avoid unnecessary API hits, but forces
  a re-send hourly as a safety net.
- Falls back across multiple public-IP echo endpoints.
- Token is read from ~/.csie-ddns.conf (chmod 600), never committed.

The existing Swift and Java clients are untouched.
When the csie.io server rejects updates (e.g. KO5/KO6/KO7), the
LaunchAgent was still firing every 5 min — which over a day adds up to
~290 useless requests and is an unfriendly client.

Now: after 3 consecutive KO* responses the script writes a "next
attempt" timestamp into ~/.csie-ddns.fail. Subsequent runs no-op until
that timestamp elapses (default 6h). A single OK clears the state and
the normal 5-min cadence resumes.

Tunable via CSIE_BACKOFF_AFTER_FAILS (default 3) and CSIE_BACKOFF_SECONDS
(default 21600 = 6h). Network errors (e.g. transient curl failures) do
not count toward the backoff counter — only server-side rejections.

Also added: explicit log messages for KO5 (token does not authorize this
hostname — newer counterpart of KO6) and KO7 (server refused the IP
change). These weren't recognised before.
Adds DDNS_PROVIDER=duckdns (default remains csie) so a single install
and LaunchAgent can target either csie.io or DuckDNS by editing one
config line. Motivation: when csie.io's update endpoint is unavailable
or restricted for a hostname, users can repoint to DuckDNS without
touching the LaunchAgent.

Implementation: provider-specific block selects the update URL, host
parameter name, and the human-readable record label used in logs. Rest
of the script (IP fetch, state caching, backoff, response decoding) is
shared. csie.io's KO2/KO4/KO5/KO6/KO7 and DuckDNS's plain KO are all
recognised with distinct log messages. Response is trimmed for
providers that append a trailing newline.

Config keys for csie.io users are unchanged (CSIE_HOSTNAME, CSIE_TOKEN);
DuckDNS users set DUCKDNS_DOMAIN and DUCKDNS_TOKEN. All operational
knobs (log path, cache files, force-update interval, backoff) keep the
CSIE_ prefix to preserve compatibility with any existing config files.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant