v0.0.1
Add pre-commit config Update default consensus with more sources Move IP version spec to Source so that dual-stack sites can be used Add tests for HTTPSource and consensus
This commit is contained in:
parent
d8b5497932
commit
9363450cdc
2
.github/ISSUE_TEMPLATE.md
vendored
2
.github/ISSUE_TEMPLATE.md
vendored
@ -6,6 +6,6 @@ Please remove the sections that don't apply
|
||||
|
||||
## Environment
|
||||
|
||||
go-external-ip commit:
|
||||
go-external-ip commit:
|
||||
go version:
|
||||
OS:
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -14,4 +14,3 @@
|
||||
|
||||
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
|
||||
.glide/
|
||||
|
||||
|
18
.pre-commit-config.yaml
Normal file
18
.pre-commit-config.yaml
Normal file
@ -0,0 +1,18 @@
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.2.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
args: [--markdown-linebreak-ext=.gitignore]
|
||||
- id: end-of-file-fixer
|
||||
- id: check-yaml
|
||||
- repo: https://github.com/tekwizely/pre-commit-golang
|
||||
rev: v1.0.0-beta.5
|
||||
hooks:
|
||||
- id: go-mod-tidy
|
||||
- id: go-imports
|
||||
args: [-w]
|
||||
- repo: https://github.com/golangci/golangci-lint
|
||||
rev: v1.46.2
|
||||
hooks:
|
||||
- id: golangci-lint
|
@ -16,4 +16,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
THE SOFTWARE.
|
||||
|
@ -34,7 +34,7 @@ func main() {
|
||||
consensus := externalip.DefaultConsensus(cfg, logger)
|
||||
|
||||
// retrieve the external ip
|
||||
ip4, err := consensus.ExternalIP(4)
|
||||
ip4, _ := consensus.ExternalIP(4)
|
||||
ip6, err := consensus.ExternalIP(6)
|
||||
|
||||
// simple error handling
|
||||
|
42
consensus.go
42
consensus.go
@ -27,17 +27,35 @@ func DefaultConsensus(cfg *ConsensusConfig, logger *log.Logger) *Consensus {
|
||||
consensus := NewConsensus(cfg, logger)
|
||||
|
||||
// TLS-protected providers
|
||||
consensus.AddVoter(NewHTTPSource("https://icanhazip.com/"), 3, IPv6)
|
||||
consensus.AddVoter(NewHTTPSource("https://myexternalip.com/raw"), 3, IPv4)
|
||||
_ = consensus.AddVoter(NewHTTPSource("https://myip-mnpz5ateaq-uw.a.run.app", IPv4), 3)
|
||||
_ = consensus.AddVoter(NewHTTPSource("https://myip-mnpz5ateaq-uw.a.run.app", IPv6), 3)
|
||||
|
||||
_ = consensus.AddVoter(NewHTTPSource("https://api.my-ip.io/ip", IPv4), 1)
|
||||
_ = consensus.AddVoter(NewHTTPSource("https://api.my-ip.io/ip", IPv6), 1)
|
||||
_ = consensus.AddVoter(NewHTTPSource("https://wtfismyip.com/text", IPv4), 1)
|
||||
_ = consensus.AddVoter(NewHTTPSource("https://wtfismyip.com/text", IPv6), 1)
|
||||
_ = consensus.AddVoter(NewHTTPSource("https://icanhazip.com", IPv4), 1)
|
||||
_ = consensus.AddVoter(NewHTTPSource("https://icanhazip.com", IPv6), 1)
|
||||
_ = consensus.AddVoter(NewHTTPSource("https://api.ip.sb/ip", IPv4), 1)
|
||||
_ = consensus.AddVoter(NewHTTPSource("https://api.ip.sb/ip", IPv6), 1)
|
||||
_ = consensus.AddVoter(NewHTTPSource("https://api.myip.la", IPv4), 1)
|
||||
_ = consensus.AddVoter(NewHTTPSource("https://api.myip.la", IPv6), 1)
|
||||
_ = consensus.AddVoter(NewHTTPSource("https://ident.me", IPv4), 1)
|
||||
_ = consensus.AddVoter(NewHTTPSource("https://ident.me", IPv6), 1)
|
||||
|
||||
_ = consensus.AddVoter(NewHTTPSource("https://api.ipify.org/?format=plain", IPv4), 1)
|
||||
_ = consensus.AddVoter(NewHTTPSource("http://api.ipaddress.com/myip", IPv4), 1)
|
||||
_ = consensus.AddVoter(NewHTTPSource("https://ipecho.net/plain", IPv4), 1)
|
||||
|
||||
// Plain-text providers
|
||||
consensus.AddVoter(NewHTTPSource("http://ifconfig.io/ip"), 1, IPv6)
|
||||
consensus.AddVoter(NewHTTPSource("http://checkip.amazonaws.com/"), 1, IPv4)
|
||||
consensus.AddVoter(NewHTTPSource("http://ident.me/"), 1, IPv6)
|
||||
consensus.AddVoter(NewHTTPSource("http://whatismyip.akamai.com/"), 1, IPv4)
|
||||
consensus.AddVoter(NewHTTPSource("http://tnx.nl/ip"), 1, IPv6)
|
||||
consensus.AddVoter(NewHTTPSource("http://myip.dnsomatic.com/"), 1, IPv4)
|
||||
consensus.AddVoter(NewHTTPSource("http://diagnostic.opendns.com/myip"), 1, IPv6)
|
||||
_ = consensus.AddVoter(NewHTTPSource("https://ifconfig.io/ip", IPv6), 1)
|
||||
_ = consensus.AddVoter(NewHTTPSource("https://ifconfig.io/ip", IPv4), 1)
|
||||
_ = consensus.AddVoter(NewHTTPSource("https://checkip.amazonaws.com/", IPv4), 1)
|
||||
_ = consensus.AddVoter(NewHTTPSource("http://whatismyip.akamai.com/", IPv4), 1)
|
||||
_ = consensus.AddVoter(NewHTTPSource("https://tnx.nl/", IPv6), 1)
|
||||
_ = consensus.AddVoter(NewHTTPSource("https://tnx.nl/", IPv4), 1)
|
||||
_ = consensus.AddVoter(NewHTTPSource("http://myip.dnsomatic.com/", IPv4), 1)
|
||||
_ = consensus.AddVoter(NewHTTPSource("https://diagnostic.opendns.com/myip", IPv6), 1)
|
||||
|
||||
return consensus
|
||||
}
|
||||
@ -83,7 +101,7 @@ type Consensus struct {
|
||||
// AddVoter adds a voter to this consensus.
|
||||
// The source cannot be <nil> and
|
||||
// the weight has to be of a value of 1 or above.
|
||||
func (c *Consensus) AddVoter(source Source, weight, ipversion uint) error {
|
||||
func (c *Consensus) AddVoter(source Source, weight uint) error {
|
||||
if source == nil {
|
||||
c.logger.Println("[ERROR] could not add voter: no source given")
|
||||
return ErrNoSource
|
||||
@ -92,13 +110,13 @@ func (c *Consensus) AddVoter(source Source, weight, ipversion uint) error {
|
||||
c.logger.Println("[ERROR] could not add voter: weight cannot be 0")
|
||||
return ErrInsufficientWeight
|
||||
}
|
||||
if ipversion == 4 {
|
||||
if source.IPVersion() == 4 {
|
||||
c.voters4 = append(c.voters4, voter{
|
||||
source: source,
|
||||
weight: weight,
|
||||
})
|
||||
}
|
||||
if ipversion == 6 {
|
||||
if source.IPVersion() == 6 {
|
||||
c.voters6 = append(c.voters6, voter{
|
||||
source: source,
|
||||
weight: weight,
|
||||
|
@ -1,30 +1,91 @@
|
||||
package externalip
|
||||
package externalip_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.narnian.us/lordwelch/externalip"
|
||||
)
|
||||
|
||||
func TestDefaultConsensus(t *testing.T) {
|
||||
consensus := DefaultConsensus(nil)
|
||||
func newConcensus(url string) *externalip.Consensus {
|
||||
consensus := externalip.NewConsensus(&externalip.ConsensusConfig{
|
||||
Timeout: time.Second * 30,
|
||||
}, nil)
|
||||
|
||||
// TLS-protected providers
|
||||
_ = consensus.AddVoter(externalip.NewHTTPSource(url, externalip.IPv4), 1)
|
||||
_ = consensus.AddVoter(externalip.NewHTTPSource(url, externalip.IPv4), 1)
|
||||
_ = consensus.AddVoter(externalip.NewHTTPSource(url, externalip.IPv4), 1)
|
||||
|
||||
return consensus
|
||||
}
|
||||
|
||||
func newServer(ip1, ip2, ip3 string) *httptest.Server {
|
||||
var try = 1
|
||||
return httptest.NewServer(http.HandlerFunc(
|
||||
func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(200)
|
||||
switch try {
|
||||
case 1:
|
||||
fmt.Fprintln(w, ip1)
|
||||
case 2:
|
||||
fmt.Fprintln(w, ip2)
|
||||
case 3:
|
||||
fmt.Fprintln(w, ip3)
|
||||
try = 1
|
||||
}
|
||||
try++
|
||||
}))
|
||||
}
|
||||
|
||||
func TestConsensus(t *testing.T) {
|
||||
server := newServer("127.0.0.1", "127.0.0.1", "127.0.0.2")
|
||||
consensus := newConcensus(server.URL)
|
||||
if consensus == nil {
|
||||
t.Fatal("default consensus should never be nil")
|
||||
}
|
||||
|
||||
ip, err := consensus.ExternalIP()
|
||||
ip, err := consensus.ExternalIP(4)
|
||||
if err != nil {
|
||||
t.Fatal("couldn't get external IP", err)
|
||||
}
|
||||
|
||||
fmt.Println(ip)
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
ipAgain, err := consensus.ExternalIP()
|
||||
if err != nil {
|
||||
t.Fatal("couldn't get external IP", err)
|
||||
}
|
||||
if !ip.Equal(ipAgain) {
|
||||
t.Fatalf("expected %q, while received %q", ip, ipAgain)
|
||||
}
|
||||
if !ip.Equal(net.IPv4(127, 0, 0, 1)) {
|
||||
t.Errorf("invalid ip found: expected %s recieved %s", "127.0.0.1", ip)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConsensus2(t *testing.T) {
|
||||
server := newServer("127.0.0.1", "127.0.0.2", "127.0.0.2")
|
||||
consensus := newConcensus(server.URL)
|
||||
if consensus == nil {
|
||||
t.Fatal("default consensus should never be nil")
|
||||
}
|
||||
|
||||
ip, err := consensus.ExternalIP(4)
|
||||
if err != nil {
|
||||
t.Fatal("couldn't get external IP", err)
|
||||
}
|
||||
if !ip.Equal(net.IPv4(127, 0, 0, 2)) {
|
||||
t.Errorf("invalid ip found: expected %s recieved %s", "127.0.0.2", ip)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConsensus3(t *testing.T) {
|
||||
server := newServer("127.0.0.1", "127.0.0.2", "127.0.0.3")
|
||||
consensus := newConcensus(server.URL)
|
||||
if consensus == nil {
|
||||
t.Fatal("default consensus should never be nil")
|
||||
}
|
||||
|
||||
ip, err := consensus.ExternalIP(4)
|
||||
if err != nil {
|
||||
t.Fatal("couldn't get external IP", err)
|
||||
}
|
||||
if !ip.Equal(net.IPv4(127, 0, 0, 1)) {
|
||||
t.Errorf("invalid ip found: expected %s recieved %s; This will fail on multiple runs it takes whichever request returns first", "127.0.0.1", ip)
|
||||
}
|
||||
}
|
||||
|
11
go.mod
11
go.mod
@ -1,12 +1,3 @@
|
||||
module git.narnian.us/lordwelch/externalip
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
github.com/google/pprof v0.0.0-20190908185732-236ed259b199 // indirect
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 // indirect
|
||||
golang.org/x/arch v0.0.0-20190919213554-7fe50f7625bd // indirect
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7 // indirect
|
||||
golang.org/x/sys v0.0.0-20190919044723-0c1ff786ef13 // indirect
|
||||
golang.org/x/tools v0.0.0-20190919223014-db1d4edb4685 // indirect
|
||||
)
|
||||
go 1.18
|
||||
|
21
go.sum
21
go.sum
@ -1,21 +0,0 @@
|
||||
github.com/google/pprof v0.0.0-20190908185732-236ed259b199 h1:sEyCq3pOT7tNC+3gcLI7sZkBDgntZ6wQJNmr9lmIjIc=
|
||||
github.com/google/pprof v0.0.0-20190908185732-236ed259b199/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 h1:UDMh68UUwekSh5iP2OMhRRZJiiBccgV7axzUG8vi56c=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
golang.org/x/arch v0.0.0-20190919213554-7fe50f7625bd h1:IbZRdF+nCjC31g8APRj0sBwNe35VSPHNThzJKA0idTs=
|
||||
golang.org/x/arch v0.0.0-20190919213554-7fe50f7625bd/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7 h1:0hQKqeLdqlt5iIwVOBErRisrHJAN57yOiPRQItI20fU=
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190919044723-0c1ff786ef13 h1:/zi0zzlPHWXYXrO1LjNRByFu8sdGgCkj2JLDdBIB84k=
|
||||
golang.org/x/sys v0.0.0-20190919044723-0c1ff786ef13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190919223014-db1d4edb4685 h1:/6Ol4IqB+r3aIk191dJQFcnPHMW+pj8RzXAz3ddkmk4=
|
||||
golang.org/x/tools v0.0.0-20190919223014-db1d4edb4685/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
61
sources.go
61
sources.go
@ -1,6 +1,7 @@
|
||||
package externalip
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
@ -12,17 +13,19 @@ import (
|
||||
// NewHTTPSource creates a HTTP Source object,
|
||||
// which can be used to request the (external) IP from.
|
||||
// The Default HTTP Client will be used if no client is given.
|
||||
func NewHTTPSource(url string) *HTTPSource {
|
||||
func NewHTTPSource(url string, ipversion uint) *HTTPSource {
|
||||
return &HTTPSource{
|
||||
url: url,
|
||||
url: url,
|
||||
ipversion: ipversion,
|
||||
}
|
||||
}
|
||||
|
||||
// HTTPSource is the default source, to get the external IP from.
|
||||
// It does so by requesting the IP from a URL, via an HTTP GET Request.
|
||||
type HTTPSource struct {
|
||||
url string
|
||||
parser ContentParser
|
||||
url string
|
||||
parser ContentParser
|
||||
ipversion uint
|
||||
}
|
||||
|
||||
// ContentParser can be used to add a parser to an HTTPSource
|
||||
@ -39,27 +42,57 @@ func (s *HTTPSource) WithParser(parser ContentParser) *HTTPSource {
|
||||
|
||||
// IP implements Source.IP
|
||||
func (s *HTTPSource) IP(timeout time.Duration, logger *log.Logger) (net.IP, error) {
|
||||
var (
|
||||
dialer = &net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
DualStack: false,
|
||||
FallbackDelay: -1,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}
|
||||
n = "tcp4"
|
||||
)
|
||||
if s.ipversion == 6 {
|
||||
n = "tcp6"
|
||||
}
|
||||
// Define the GET method with the correct url,
|
||||
// setting the User-Agent to our library
|
||||
req, err := http.NewRequest("GET", s.url, nil)
|
||||
if err != nil {
|
||||
logger.Printf("[ERROR] could not create a GET Request for %q: %v\n", s.url, err)
|
||||
if logger != nil {
|
||||
logger.Printf("[ERROR] could not create a GET Request for %q: %v\n", s.url, err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("User-Agent", "go-external-ip (github.com/glendc/go-external-ip)")
|
||||
|
||||
client := &http.Client{Timeout: timeout}
|
||||
client := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
DialContext: func(ctx context.Context, network string, addr string) (net.Conn, error) {
|
||||
return dialer.DialContext(ctx, n, addr)
|
||||
},
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
MaxIdleConns: 100,
|
||||
IdleConnTimeout: 30 * time.Second,
|
||||
ResponseHeaderTimeout: timeout,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
},
|
||||
Timeout: timeout,
|
||||
}
|
||||
// Do the request and read the body for non-error results.
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
logger.Printf("[ERROR] could not GET %q: %v\n", s.url, err)
|
||||
if logger != nil {
|
||||
logger.Printf("[ERROR] could not GET %q: %v\n", s.url, err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
bytes, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
logger.Printf("[ERROR] could not read response from %q: %v\n", s.url, err)
|
||||
if logger != nil {
|
||||
logger.Printf("[ERROR] could not read response from %q: %v\n", s.url, err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -68,7 +101,9 @@ func (s *HTTPSource) IP(timeout time.Duration, logger *log.Logger) (net.IP, erro
|
||||
if s.parser != nil {
|
||||
raw, err = s.parser(raw)
|
||||
if err != nil {
|
||||
logger.Printf("[ERROR] could not parse response from %q: %v\n", s.url, err)
|
||||
if logger != nil {
|
||||
logger.Printf("[ERROR] could not parse response from %q: %v\n", s.url, err)
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@ -76,10 +111,16 @@ func (s *HTTPSource) IP(timeout time.Duration, logger *log.Logger) (net.IP, erro
|
||||
// validate the IP
|
||||
externalIP := net.ParseIP(strings.TrimSpace(raw))
|
||||
if externalIP == nil {
|
||||
logger.Printf("[ERROR] %q returned an invalid IP: %v\n", s.url, err)
|
||||
if logger != nil {
|
||||
logger.Printf("[ERROR] %q returned an invalid IP: %v\n", s.url, err)
|
||||
}
|
||||
return nil, InvalidIPError(raw)
|
||||
}
|
||||
|
||||
// returned the parsed IP
|
||||
return externalIP, nil
|
||||
}
|
||||
|
||||
func (s *HTTPSource) IPVersion() uint {
|
||||
return s.ipversion
|
||||
}
|
||||
|
81
sources_test.go
Normal file
81
sources_test.go
Normal file
@ -0,0 +1,81 @@
|
||||
package externalip_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.narnian.us/lordwelch/externalip"
|
||||
)
|
||||
|
||||
func TestHTTPSource(t *testing.T) {
|
||||
server := httptest.NewUnstartedServer(
|
||||
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(200)
|
||||
fmt.Fprintln(w, r.RemoteAddr[1:len(r.RemoteAddr)-7])
|
||||
}))
|
||||
server.Listener.Close()
|
||||
server.Listener, _ = net.Listen("tcp6", "[::1]:0")
|
||||
server.Start()
|
||||
defer server.Close()
|
||||
|
||||
source := externalip.NewHTTPSource("http://"+server.Listener.Addr().String(), 6)
|
||||
ip, _ := source.IP(time.Second*10, nil)
|
||||
if ip.String() != "::1" {
|
||||
t.Errorf("invalid ip found: expected %s recieved %s", "::1", ip)
|
||||
}
|
||||
}
|
||||
func TestHTTPSource2(t *testing.T) {
|
||||
server := httptest.NewUnstartedServer(
|
||||
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(200)
|
||||
fmt.Fprintln(w, r.RemoteAddr[1:len(r.RemoteAddr)-7])
|
||||
}))
|
||||
server.Listener.Close()
|
||||
server.Listener, _ = net.Listen("tcp6", "[::1]:0")
|
||||
server.Start()
|
||||
defer server.Close()
|
||||
|
||||
source := externalip.NewHTTPSource("http://"+server.Listener.Addr().String(), 4)
|
||||
ip, _ := source.IP(time.Second*10, nil)
|
||||
if ip != nil {
|
||||
t.Errorf("invalid ip found: expected %s recieved %s", "nil", ip)
|
||||
}
|
||||
}
|
||||
func TestHTTPSource3(t *testing.T) {
|
||||
server := httptest.NewUnstartedServer(
|
||||
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(200)
|
||||
fmt.Fprintln(w, r.RemoteAddr[:len(r.RemoteAddr)-6])
|
||||
}))
|
||||
server.Listener.Close()
|
||||
server.Listener, _ = net.Listen("tcp4", "127.0.0.1:0")
|
||||
server.Start()
|
||||
defer server.Close()
|
||||
|
||||
source := externalip.NewHTTPSource("http://"+server.Listener.Addr().String(), 4)
|
||||
ip, _ := source.IP(time.Second*10, nil)
|
||||
if ip.String() != "127.0.0.1" {
|
||||
t.Errorf("invalid ip found: expected %s recieved %s", "127.0.0.1", ip)
|
||||
}
|
||||
}
|
||||
func TestHTTPSource4(t *testing.T) {
|
||||
server := httptest.NewUnstartedServer(
|
||||
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(200)
|
||||
fmt.Fprintln(w, r.RemoteAddr[:len(r.RemoteAddr)-6])
|
||||
}))
|
||||
server.Listener.Close()
|
||||
server.Listener, _ = net.Listen("tcp4", "127.0.0.1:0")
|
||||
server.Start()
|
||||
defer server.Close()
|
||||
|
||||
source := externalip.NewHTTPSource("http://"+server.Listener.Addr().String(), 6)
|
||||
ip, _ := source.IP(time.Second*10, nil)
|
||||
if ip != nil {
|
||||
t.Errorf("invalid ip found: expected %s recieved %s", "nil", ip)
|
||||
}
|
||||
}
|
1
types.go
1
types.go
@ -13,6 +13,7 @@ type Source interface {
|
||||
// It is recommended that the IP function times out,
|
||||
// if no result could be found, after the given timeout duration.
|
||||
IP(timeout time.Duration, logger *log.Logger) (net.IP, error)
|
||||
IPVersion() uint
|
||||
}
|
||||
|
||||
// voter adds weight to the IP given by a source.
|
||||
|
Loading…
x
Reference in New Issue
Block a user