aboutsummaryrefslogtreecommitdiff
path: root/ts.go
diff options
context:
space:
mode:
authorFranck Cuny <franck@fcuny.net>2023-03-12 18:23:05 -0700
committerFranck Cuny <franck@fcuny.net>2023-03-12 18:23:05 -0700
commitc06d0f4e79edfe0a5ec650b2d2a8c1a441ed3226 (patch)
tree906d8eed426a82ae80f9644e4d5857d4b41cd11f /ts.go
downloaddns-updater-c06d0f4e79edfe0a5ec650b2d2a8c1a441ed3226.tar.gz
a CLI to update records for fcuny.xyzHEADmain
I want a simple solution to update the records for fcuny.xyz. The host that serves these records is a tailscale node, so I want to also query tailscale to get the IP for that host instead of hard coding the value. Some other information are hard coded, like the name of the project in GCP, etc.
Diffstat (limited to '')
-rw-r--r--ts.go82
1 files changed, 82 insertions, 0 deletions
diff --git a/ts.go b/ts.go
new file mode 100644
index 0000000..94c4b5a
--- /dev/null
+++ b/ts.go
@@ -0,0 +1,82 @@
+package main
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "net/http"
+
+ "inet.af/netaddr"
+)
+
+type device struct {
+ Hostname string `json:"hostname"`
+ ID string `json:"id"`
+ Addresses []string `json:"addresses"`
+}
+
+const (
+ TS_NAME = "franck.cuny@gmail.com"
+ TS_API_DOMAIN = "api.tailscale.com"
+)
+
+func getTsDevice(ctx context.Context, APIKey, deviceName string) (*device, error) {
+ url := fmt.Sprintf("https://%s/api/v2/tailnet/%s/devices", TS_API_DOMAIN, TS_NAME)
+ req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
+ if err != nil {
+ return nil, err
+ }
+
+ req.SetBasicAuth(APIKey, "")
+ resp, err := http.DefaultClient.Do(req)
+ if err != nil {
+ return nil, err
+ }
+
+ defer resp.Body.Close()
+
+ if resp.StatusCode != http.StatusOK {
+ return nil, fmt.Errorf("non-ok status code %d returned from tailscale api: %s", resp.StatusCode, resp.Status)
+ }
+ var buf struct {
+ Devices []device `json:"devices"`
+ }
+ if err := json.NewDecoder(resp.Body).Decode(&buf); err != nil {
+ return nil, err
+ }
+
+ for _, d := range buf.Devices {
+ if d.Hostname == deviceName {
+ return &d, nil
+ }
+ }
+ return nil, fmt.Errorf("could not find the tailscale device named %s", deviceName)
+}
+
+// Get the Tailscale IPv4 and IPv6 addresses associated with the given device.
+func getTsIpsDevice(ctx context.Context, APIKey, device string) ([]string, []string, error) {
+ ts_device, err := getTsDevice(ctx, APIKey, device)
+ if err != nil {
+ return nil, nil, fmt.Errorf("failed to get Tailscale device information: %v", err)
+ }
+
+ var (
+ tsIpV4Addresses = []string{}
+ tsIpV6Addresses = []string{}
+ )
+ for _, ipString := range ts_device.Addresses {
+ // we convert the string to a netaddr.IP so we can check if
+ // it's an IP v4 or v6. We need to know what's the version in
+ // order to use it properly when creating/updating the
+ // record. Then we convert it back as a string, since this is
+ // what the DNS API expect.
+ ip := netaddr.MustParseIP(ipString)
+ if ip.Is4() {
+ tsIpV4Addresses = append(tsIpV4Addresses, ip.String())
+ } else {
+ tsIpV6Addresses = append(tsIpV6Addresses, ip.String())
+ }
+ }
+
+ return tsIpV4Addresses, tsIpV6Addresses, nil
+}