diff options
| author | Franck Cuny <franck@fcuny.net> | 2023-03-12 18:23:05 -0700 |
|---|---|---|
| committer | Franck Cuny <franck@fcuny.net> | 2023-03-12 18:23:05 -0700 |
| commit | c06d0f4e79edfe0a5ec650b2d2a8c1a441ed3226 (patch) | |
| tree | 906d8eed426a82ae80f9644e4d5857d4b41cd11f /ts.go | |
| download | dns-updater-main.tar.gz | |
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 'ts.go')
| -rw-r--r-- | ts.go | 82 |
1 files changed, 82 insertions, 0 deletions
@@ -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 +} |
