diff --git a/docs/manual.md b/docs/manual.md index 897e5994a..16b3c29c6 100644 --- a/docs/manual.md +++ b/docs/manual.md @@ -425,6 +425,8 @@ addr: tcp://ip-address-or-domain-name:80: reachable: true timeout: 500 + # optional attributes + local-address: 127.0.0.1 ``` diff --git a/integration-tests/goss/alpine3/goss.yaml b/integration-tests/goss/alpine3/goss.yaml index 6c91c7968..61315212b 100644 --- a/integration-tests/goss/alpine3/goss.yaml +++ b/integration-tests/goss/alpine3/goss.yaml @@ -23,5 +23,10 @@ port: listening: true ip: - "::" +addr: + tcp://127.0.0.1:80: + reachable: true + timeout: 500 + local-address: 127.0.0.1 gossfile: "../goss-s*.yaml": {} diff --git a/integration-tests/goss/centos7/goss.yaml b/integration-tests/goss/centos7/goss.yaml index 90744513b..bca8f8bd7 100644 --- a/integration-tests/goss/centos7/goss.yaml +++ b/integration-tests/goss/centos7/goss.yaml @@ -23,5 +23,10 @@ port: listening: true ip: - '0.0.0.0' +addr: + tcp://127.0.0.1:80: + reachable: true + timeout: 500 + local-address: 127.0.0.1 gossfile: "../goss-s*.yaml": {} diff --git a/integration-tests/goss/goss-shared.yaml b/integration-tests/goss/goss-shared.yaml index ac92b72e3..9f61e2855 100644 --- a/integration-tests/goss/goss-shared.yaml +++ b/integration-tests/goss/goss-shared.yaml @@ -68,6 +68,10 @@ addr: tcp://google.com:443: reachable: true timeout: 5000 + tcp://google.com:80: + reachable: false + timeout: 5000 + local-address: 127.0.0.1 port: tcp:9999: listening: false diff --git a/integration-tests/goss/precise/goss.yaml b/integration-tests/goss/precise/goss.yaml index 5c7aba63d..f138b7b9f 100644 --- a/integration-tests/goss/precise/goss.yaml +++ b/integration-tests/goss/precise/goss.yaml @@ -23,5 +23,10 @@ port: listening: true ip: - 0.0.0.0 +addr: + tcp://127.0.0.1:80: + reachable: true + timeout: 500 + local-address: 127.0.0.1 gossfile: "../goss-s*.yaml": {} diff --git a/integration-tests/goss/wheezy/goss.yaml b/integration-tests/goss/wheezy/goss.yaml index 051931471..3d3bcbec1 100644 --- a/integration-tests/goss/wheezy/goss.yaml +++ b/integration-tests/goss/wheezy/goss.yaml @@ -23,5 +23,10 @@ port: listening: true ip: - '0.0.0.0' +addr: + tcp://127.0.0.1:80: + reachable: true + timeout: 500 + local-address: 127.0.0.1 gossfile: "../goss-s*.yaml": {} diff --git a/integration-tests/test.sh b/integration-tests/test.sh index 65f718ae6..cdc0ff8f2 100755 --- a/integration-tests/test.sh +++ b/integration-tests/test.sh @@ -44,9 +44,9 @@ out=$(docker_exec "/goss/$os/goss-linux-$arch" --vars "/goss/vars.yaml" -g "/gos echo "$out" if [[ $os == "arch" ]]; then - egrep -q 'Count: 83, Failed: 0, Skipped: 3' <<<"$out" + egrep -q 'Count: 84, Failed: 0, Skipped: 3' <<<"$out" else - egrep -q 'Count: 99, Failed: 0, Skipped: 5' <<<"$out" + egrep -q 'Count: 101, Failed: 0, Skipped: 5' <<<"$out" fi if [[ ! $os == "arch" ]]; then diff --git a/resource/addr.go b/resource/addr.go index c37bbe2fe..f22b5a601 100644 --- a/resource/addr.go +++ b/resource/addr.go @@ -6,11 +6,12 @@ import ( ) type Addr struct { - Title string `json:"title,omitempty" yaml:"title,omitempty"` - Meta meta `json:"meta,omitempty" yaml:"meta,omitempty"` - Address string `json:"-" yaml:"-"` - Reachable matcher `json:"reachable" yaml:"reachable"` - Timeout int `json:"timeout" yaml:"timeout"` + Title string `json:"title,omitempty" yaml:"title,omitempty"` + Meta meta `json:"meta,omitempty" yaml:"meta,omitempty"` + Address string `json:"-" yaml:"-"` + LocalAddress string `json:"local-address,omitempty" yaml:"local-address,omitempty"` + Reachable matcher `json:"reachable" yaml:"reachable"` + Timeout int `json:"timeout" yaml:"timeout"` } func (a *Addr) ID() string { return a.Address } @@ -25,7 +26,8 @@ func (a *Addr) Validate(sys *system.System) []TestResult { if a.Timeout == 0 { a.Timeout = 500 } - sysAddr := sys.NewAddr(a.Address, sys, util.Config{Timeout: a.Timeout}) + + sysAddr := sys.NewAddr(a.Address, sys, util.Config{Timeout: a.Timeout, LocalAddress: a.LocalAddress}) var results []TestResult results = append(results, ValidateValue(a, "reachable", a.Reachable, sysAddr.Reachable, skip)) @@ -36,9 +38,10 @@ func NewAddr(sysAddr system.Addr, config util.Config) (*Addr, error) { address := sysAddr.Address() reachable, err := sysAddr.Reachable() a := &Addr{ - Address: address, - Reachable: reachable, - Timeout: config.Timeout, + Address: address, + Reachable: reachable, + Timeout: config.Timeout, + LocalAddress: config.LocalAddress, } return a, err } diff --git a/system/addr.go b/system/addr.go index 2d6fd0b2a..0505d9b7d 100644 --- a/system/addr.go +++ b/system/addr.go @@ -15,15 +15,17 @@ type Addr interface { } type DefAddr struct { - address string - Timeout int + address string + LocalAddress string + Timeout int } func NewDefAddr(address string, system *System, config util.Config) Addr { addr := normalizeAddress(address) return &DefAddr{ - address: addr, - Timeout: config.Timeout, + address: addr, + LocalAddress: config.LocalAddress, + Timeout: config.Timeout, } } @@ -38,7 +40,12 @@ func (a *DefAddr) Exists() (bool, error) { return a.Reachable() } func (a *DefAddr) Reachable() (bool, error) { network, address := splitAddress(a.address) - conn, err := net.DialTimeout(network, address, time.Duration(a.Timeout)*time.Millisecond) + localAddr := &net.TCPAddr{ + IP: net.ParseIP(a.LocalAddress), + } + + d := net.Dialer{LocalAddr: localAddr, Timeout: time.Duration(a.Timeout) * time.Millisecond} + conn, err := d.Dial(network, address) if err != nil { return false, nil } @@ -52,7 +59,6 @@ func splitAddress(fulladdress string) (network, address string) { return split[0], split[1] } return "tcp", fulladdress - } func normalizeAddress(fulladdress string) string { diff --git a/util/config.go b/util/config.go index ed28ff8ce..22f41c03f 100644 --- a/util/config.go +++ b/util/config.go @@ -17,6 +17,7 @@ type Config struct { Server string Username string Password string + LocalAddress string } type OutputConfig struct {