package dns import ( "context" "fmt" "net" "os" "time" "github.com/AlecAivazis/survey/v2" "github.com/sirupsen/logrus" ) // NewToken constructs a new DNS provider token. func NewToken(provider, providerTokenEnvVar string) (string, error) { if token, present := os.LookupEnv(providerTokenEnvVar); present { return token, nil } logrus.Debugf("no %s in environment, asking via stdin", providerTokenEnvVar) var token string prompt := &survey.Input{ Message: fmt.Sprintf("%s API token?", provider), } if err := survey.AskOne(prompt, &token); err != nil { return "", err } return token, nil } // EnsureIPv4 ensures that an ipv4 address is set for a domain name func EnsureIPv4(domainName string) (string, error) { var ipv4 string // comrade librehosters DNS resolver -> https://www.privacy-handbuch.de/handbuch_93d.htm freifunkDNS := "5.1.66.255:53" resolver := &net.Resolver{ PreferGo: false, Dial: func(ctx context.Context, network, address string) (net.Conn, error) { d := net.Dialer{ Timeout: time.Millisecond * time.Duration(10000), } return d.DialContext(ctx, "udp", freifunkDNS) }, } ctx := context.Background() ips, err := resolver.LookupIPAddr(ctx, domainName) if err != nil { return ipv4, err } if len(ips) == 0 { return ipv4, fmt.Errorf("unable to retrieve ipv4 address for %s", domainName) } ipv4 = ips[0].IP.To4().String() logrus.Debugf("%s points to %s (resolver: %s)", domainName, ipv4, freifunkDNS) return ipv4, nil } // EnsureDomainsResolveSameIPv4 ensures that domains resolve to the same ipv4 address func EnsureDomainsResolveSameIPv4(domainName, server string) (string, error) { var ipv4 string domainIPv4, err := EnsureIPv4(domainName) if err != nil { return ipv4, err } if domainIPv4 == "" { return ipv4, fmt.Errorf("cannot resolve ipv4 for %s?", domainName) } serverIPv4, err := EnsureIPv4(server) if err != nil { return ipv4, err } if serverIPv4 == "" { return ipv4, fmt.Errorf("cannot resolve ipv4 for %s?", server) } if domainIPv4 != serverIPv4 { err := "app domain %s (%s) does not appear to resolve to app server %s (%s)?" return ipv4, fmt.Errorf(err, domainName, domainIPv4, server, serverIPv4) } return ipv4, nil } // GetTTL parses a ttl string into a duration func GetTTL(ttl string) (time.Duration, error) { val, err := time.ParseDuration(ttl) if err != nil { return val, err } return val, nil }