Initial commit
This commit is contained in:
commit
1ffcd90796
93
.gitignore
vendored
Normal file
93
.gitignore
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/goland+all
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=goland+all
|
||||
|
||||
### GoLand+all ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# AWS User-specific
|
||||
.idea/**/aws.xml
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
# .idea/compiler.xml
|
||||
# .idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# SonarLint plugin
|
||||
.idea/sonarlint/
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
### GoLand+all Patch ###
|
||||
# Ignore everything but code style settings and run configurations
|
||||
# that are supposed to be shared within teams.
|
||||
|
||||
.idea/*
|
||||
|
||||
!.idea/codeStyles
|
||||
!.idea/runConfigurations
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/goland+all
|
||||
|
15
go.mod
Normal file
15
go.mod
Normal file
@ -0,0 +1,15 @@
|
||||
module dyndns-inwx-go
|
||||
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/libdns/inwx v0.2.0
|
||||
github.com/libdns/libdns v0.2.1
|
||||
github.com/sethvargo/go-envconfig v1.0.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/boombuler/barcode v1.0.1 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/pquerna/otp v1.4.0 // indirect
|
||||
)
|
22
go.sum
Normal file
22
go.sum
Normal file
@ -0,0 +1,22 @@
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
|
||||
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/libdns/inwx v0.2.0 h1:yCP5EiVqmmp71dFhCD34PkUxLQixJTEZNOlO6itdNeA=
|
||||
github.com/libdns/inwx v0.2.0/go.mod h1:QNKQqPp5wVvbuMMmGFZz0UL9tZ6FaWlKTMPeUqPsJ+g=
|
||||
github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis=
|
||||
github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
|
||||
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||
github.com/sethvargo/go-envconfig v1.0.0 h1:1C66wzy4QrROf5ew4KdVw942CQDa55qmlYmw9FZxZdU=
|
||||
github.com/sethvargo/go-envconfig v1.0.0/go.mod h1:Lzc75ghUn5ucmcRGIdGQ33DKJrcjk4kihFYgSTBmjIc=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
117
main.go
Normal file
117
main.go
Normal file
@ -0,0 +1,117 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/libdns/libdns"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/libdns/inwx"
|
||||
"github.com/sethvargo/go-envconfig"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Username string `env:"DYNDNS_USERNAME, required"`
|
||||
Password string `env:"DYNDNS_PASSWORD, required"`
|
||||
Zone string `env:"DYNDNS_ZONE, required"`
|
||||
Record string `env:"DYNDNS_RECORD, required"`
|
||||
Nameservers string `env:"DYNDNS_NAMESERVERS, required"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
var cfg Config
|
||||
if err := envconfig.Process(ctx, &cfg); err != nil {
|
||||
log.Fatal("Error reading config: ", err)
|
||||
}
|
||||
|
||||
ifaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
log.Fatal("Error getting interfaces: ", err)
|
||||
}
|
||||
var ownIp string
|
||||
for _, iface := range ifaces {
|
||||
addrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
log.Fatalf("Error getting addresses for %v: %s", iface, err)
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
if ipnet, ok := addr.(*net.IPNet); ok &&
|
||||
ipnet.IP.To4() == nil &&
|
||||
!ipnet.IP.IsPrivate() &&
|
||||
!ipnet.IP.IsLinkLocalUnicast() &&
|
||||
!ipnet.IP.IsLoopback() &&
|
||||
ipnet.IP.IsGlobalUnicast() {
|
||||
ownIp = ipnet.IP.String()
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Print("Detected own IP: ", ownIp)
|
||||
|
||||
resolv := &net.Resolver{
|
||||
PreferGo: true,
|
||||
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
d := net.Dialer{
|
||||
Timeout: time.Duration(10) * time.Second,
|
||||
}
|
||||
var conn net.Conn
|
||||
var err error
|
||||
for _, server := range strings.Split(cfg.Nameservers, ",") {
|
||||
conn, err = d.DialContext(ctx, network, fmt.Sprintf("%s:53", server))
|
||||
if err == nil {
|
||||
return conn, err
|
||||
} else {
|
||||
log.Printf("Error resolving with NS \"%s\"", server)
|
||||
}
|
||||
}
|
||||
return conn, err
|
||||
},
|
||||
}
|
||||
|
||||
target := fmt.Sprintf("%s.%s", cfg.Record, cfg.Zone)
|
||||
resolvIps, err := resolv.LookupHost(ctx, target)
|
||||
if err != nil {
|
||||
log.Fatalf("Error resolving %s: %v", target, err)
|
||||
}
|
||||
if len(resolvIps) != 1 {
|
||||
log.Fatalf("Detected %d IPs for \"%s\". Don't know what to do", len(resolvIps), target)
|
||||
}
|
||||
resolvIp := resolvIps[0]
|
||||
log.Printf("Resolved IP: %s", resolvIp)
|
||||
|
||||
forceUpdate := len(os.Args) == 2 && os.Args[1] == "--force"
|
||||
if forceUpdate {
|
||||
log.Println("Detected force update")
|
||||
}
|
||||
|
||||
if ownIp == resolvIp && !forceUpdate {
|
||||
log.Println("Resolved IP is equal to own IP. Nothing to do.")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
provider := &inwx.Provider{
|
||||
Username: cfg.Username,
|
||||
Password: cfg.Password,
|
||||
}
|
||||
|
||||
records, err := provider.SetRecords(context.Background(), cfg.Zone, []libdns.Record{
|
||||
{
|
||||
Type: "AAAA",
|
||||
Name: cfg.Record,
|
||||
Value: ownIp,
|
||||
TTL: time.Duration(15) * time.Minute,
|
||||
},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Error updating DNS record \"%s\": %s", target, err)
|
||||
}
|
||||
|
||||
for _, record := range records {
|
||||
log.Printf("Set record: %v", record)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user