diff --git a/CHANGELOG.md b/CHANGELOG.md index dfbc51a..367f87b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ + +## [v0.2.0] - 2023-03-03 +### Features +- now has the option to use a custom [extip server](https://github.com/hrbrmstr/extip-svr) + + ## [v0.1.0] - 2023-02-28 ### Features diff --git a/README.md b/README.md index c467e06..437e376 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,9 @@ Small Golang package/cli that uses special DNS resolvers to return your external IP address. -Presently it uses Google, OpenDNS, and Akamai. If there is a conflict between the resolver answers a message will be delivered on stderr with the conflicting values. +By default it uses Google, OpenDNS, and Akamai. If there is a conflict between the resolver answers a message will be delivered on stderr with the conflicting values. + +Alternatively, you can specify an [extip server](https://github.com/hrbrmstr/extip-svr) to use. See below for how to do that. ## References @@ -21,7 +23,40 @@ just build # requires https://github.com/casey/just go install -ldflags "-s -w" github.com/hrbrmstr/extip@latest ``` -## TODO +## Options + +``` +Lookup external IP address via DNS. + +Defaults to using Akamai, OpenDNS, and Google services. +You can specify an extip server via the following command line options. +NOTE: Both server and domain should be specified to override default behavior. +More info about running an extip server can be found at . + +extip 0.2.0 +Usage: extip [--server EXTIP_SERVER] [--domain DOMAIN] [--record-type RECORD_TYPE] [--port PORT] + +Options: + --server EXTIP_SERVER, -s EXTIP_SERVER + extip-svr IP/FQDN. e.g., ip.rudis.net [env: EXTIP_SERVER] + --domain DOMAIN, -d DOMAIN + Domain to use for IP Lookup. e.g., myip.is [env: EXTIP_DOMAIN] + --record-type RECORD_TYPE, -r RECORD_TYPE + DNS record type to lookup. One of TXT or A. [default: TXT, env: EXTIP_RECORD_TYPE] + --port PORT, -p PORT Port extip resolver is listening on. [default: 53, env: EXTIP_PORT] + --help, -h display this help and exit +``` + +## Usage + +Default: -- [ ] Spruce up the CLI to allow folks to choose from the existing list vs use all of them -- [ ] Allow folks to specify an endpoint and record type so it can be used with the companion server +``` +extipsvr +``` + +Use an extip server: + +``` +extip -s ip.rudis.net -d ip.is +``` \ No newline at end of file diff --git a/go.mod b/go.mod index f405b10..3806e82 100644 --- a/go.mod +++ b/go.mod @@ -3,4 +3,6 @@ module github.com/hrbrmstr/extip go 1.19 require ( + github.com/alexflint/go-arg v1.4.3 // indirect + github.com/alexflint/go-scalar v1.1.0 // indirect ) diff --git a/go.sum b/go.sum index e69de29..5dd0ea8 100644 --- a/go.sum +++ b/go.sum @@ -0,0 +1,12 @@ +github.com/alexflint/go-arg v1.4.3 h1:9rwwEBpMXfKQKceuZfYcwuc/7YY7tWJbFsgG5cAU/uo= +github.com/alexflint/go-arg v1.4.3/go.mod h1:3PZ/wp/8HuqRZMUUgu7I+e1qcpUbvmS258mRXkFH4IA= +github.com/alexflint/go-scalar v1.1.0 h1:aaAouLLzI9TChcPXotr6gUhq+Scr8rl0P9P4PnltbhM= +github.com/alexflint/go-scalar v1.1.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/justfile b/justfile index f45bb2c..9413790 100755 --- a/justfile +++ b/justfile @@ -11,7 +11,7 @@ set shell := ["zsh", "-cu"] go build -ldflags "-s -w" -o bin/extip @run: build - ./extip + ./bin/extip # Be a good citizen @fmt: @@ -25,12 +25,9 @@ set shell := ["zsh", "-cu"] GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w" -o bin/extip-darwin-amd64 main.go && cd bin && gzip extip-darwin-amd64 GOOS=darwin GOARCH=arm64 go build -ldflags "-s -w" -o bin/extip-darwin-arm64 main.go && cd bin && gzip extip-darwin-arm64 -# release binaries -@release: - gh workflow run release-binaries.yml - # Check results against dig. Requires dig. @test: build [ "$(dig myip.opendns.com @resolver1.opendns.com +short)" = "$(./bin/extip)" ] && echo "Passed OpenDNS test" [ "$(dig o-o.myaddr.1.google.com @ns1.google.com TXT +short | tr -d '"')" = "$(./bin/extip)" ] && echo "Passed Google test" - [ "$(dig +short TXT whoami.ds.akahelp.net @$(dig +short +answer NS akamai.com | head -1) | grep ns | sed -e 's/[^0-9\.\:]//g')" = "$(./bin/extip)" ] && echo "Passed Akamai test" \ No newline at end of file + [ "$(dig +short TXT whoami.ds.akahelp.net @$(dig +short +answer NS akamai.com | head -1) | grep ns | sed -e 's/[^0-9\.\:]//g')" = "$(./bin/extip)" ] && echo "Passed Akamai test" + [ "$(dig +short TXT myip.is @ip.rudis.net | tr -d '"')" = "$(./bin/extip)" ] && echo "Passed custom extip server test" \ No newline at end of file diff --git a/main.go b/main.go index 7aa0554..29903ec 100644 --- a/main.go +++ b/main.go @@ -7,13 +7,17 @@ import ( "net" "os" "regexp" + "strconv" "strings" "time" + + "github.com/alexflint/go-arg" ) const( + version = "0.2.0" resolverTimeout = 10000 - defaultPort = "53" + defaultPort = 53 googleResolver = "ns1.google.com" openDNSResolver = "resolver1.opendns.com" @@ -44,13 +48,13 @@ func TrimSuffix(s, suffix string) string { } // Setup a specific resovler to use for DNS lookups -func UseResolver(resolver string) *net.Resolver { +func UseResolver(resolver string, port int) *net.Resolver { return &net.Resolver{ PreferGo: true, Dial: func(ctx context.Context, network, address string) (net.Conn, error) { d := net.Dialer{Timeout: time.Millisecond * time.Duration(resolverTimeout)} - return d.DialContext(ctx, network, resolver + ":" + defaultPort) + return d.DialContext(ctx, network, resolver + ":" + strconv.Itoa(port)) }, } @@ -82,7 +86,7 @@ func AkamaiExtIP() ([]string, error) { return []string{""}, err } - r := UseResolver(akamaiResolver) + r := UseResolver(akamaiResolver, defaultPort) txts, err := r.LookupTXT(context.Background(), akamaiHost) if (err != nil) { @@ -98,7 +102,7 @@ func AkamaiExtIP() ([]string, error) { // Get our local, external IP via Google's hack func GoogleExtIP() ([]string, error) { - r := UseResolver(googleResolver) + r := UseResolver(googleResolver, defaultPort) txts, err := r.LookupTXT(context.Background(), googleHost) if (err != nil) { @@ -112,7 +116,7 @@ func GoogleExtIP() ([]string, error) { // Get our local, external IP via OpenDNS's hack func OpenDNSExtIP() ([]string, error) { - r := UseResolver(openDNSResolver) + r := UseResolver(openDNSResolver, defaultPort) ips, err := r.LookupHost(context.Background(), openDNSHost) if (err != nil) { @@ -123,10 +127,63 @@ func OpenDNSExtIP() ([]string, error) { } +// Get our local, external IP via custom extip resolver +func CustomExtIP(resolver string, host string, rectype string, port int) ([]string, error) { + + r := UseResolver(resolver, port) + + var res [](string) + var err error + + if (rectype == "A") { + res, err = r.LookupHost(context.Background(), host) + } else { + res, err = r.LookupTXT(context.Background(), host) + } + + if (err != nil) { + res = []string{""} + } + + return res, err + +} + +type args struct { + Server string `arg:"-s,--server,env:EXTIP_SERVER" help:"extip-svr IP/FQDN. e.g., ip.rudis.net" placeholder:"EXTIP_SERVER"` + Domain string `arg:"-d,--domain,env:EXTIP_DOMAIN" help:"Domain to use for IP Lookup. e.g., myip.is" placeholder:"DOMAIN"` + RecordType string `arg:"-r,--record-type,env:EXTIP_RECORD_TYPE" help:"DNS record type to lookup. One of TXT or A." placeholder:"RECORD_TYPE" default:"TXT"` + Port int `arg:"-p,--port,env:EXTIP_PORT" help:"Port extip resolver is listening on." placeholder:"PORT" default:"53"` +} + +func (args) Description() string { + return "Lookup external IP address via DNS.\n\nDefaults to using Akamai, OpenDNS, and Google services.\nYou can specify an extip server via the following command line options.\nNOTE: Both server and domain should be specified to override default behavior.\nMore info about running an extip server can be found at .\n" +} + +func (args) Version() string { + return "extip " + version +} + // TODO: Make this a proper CLI with cmdline options since we have 3 services func main() { - + l := log.New(os.Stderr, "", 1) + + var args args + + arg.MustParse(&args) + + if args.Server != "" && args.Domain != "" { + custom, cerr := CustomExtIP(args.Server, args.Domain, args.RecordType, args.Port) + if (cerr != nil) { + l.Println("No DNS resolutions worked.") + os.Exit(3) + } else { + fmt.Println(custom[0]) + os.Exit(0) + } + + } opendns, oerr := OpenDNSExtIP() google, gerr := GoogleExtIP()