1
0
mirror of https://github.com/taigrr/go-fastping synced 2025-01-18 05:03:15 -08:00

Option to specify source ip for ping

This commit is contained in:
Anton Skorokhod 2015-08-17 10:31:27 +02:00 committed by Tatsushi Demachi
parent 5bf6f7ec59
commit a06009512e
2 changed files with 39 additions and 5 deletions

View File

@ -23,7 +23,7 @@ func main() {
flag.BoolVar(&useUDP, "udp", false, "use non-privileged datagram-oriented UDP as ICMP endpoints") flag.BoolVar(&useUDP, "udp", false, "use non-privileged datagram-oriented UDP as ICMP endpoints")
flag.BoolVar(&useUDP, "u", false, "use non-privileged datagram-oriented UDP as ICMP endpoints (shorthand)") flag.BoolVar(&useUDP, "u", false, "use non-privileged datagram-oriented UDP as ICMP endpoints (shorthand)")
flag.Usage = func() { flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage:\n %s [options] hostname\n\nOptions:\n", os.Args[0]) fmt.Fprintf(os.Stderr, "Usage:\n %s [options] hostname [source]\n\nOptions:\n", os.Args[0])
flag.PrintDefaults() flag.PrintDefaults()
} }
flag.Parse() flag.Parse()
@ -34,6 +34,11 @@ func main() {
os.Exit(1) os.Exit(1)
} }
source := ""
if flag.NArg() > 1 {
source = flag.Arg(1)
}
p := fastping.NewPinger() p := fastping.NewPinger()
if useUDP { if useUDP {
p.Network("udp") p.Network("udp")
@ -49,6 +54,10 @@ func main() {
os.Exit(1) os.Exit(1)
} }
if source != "" {
p.Source(source)
}
results := make(map[string]*response) results := make(map[string]*response)
results[ra.String()] = nil results[ra.String()] = nil
p.AddIPAddr(ra) p.AddIPAddr(ra)

View File

@ -130,6 +130,7 @@ type Pinger struct {
// key string is IPAddr.String() // key string is IPAddr.String()
addrs map[string]*net.IPAddr addrs map[string]*net.IPAddr
network string network string
source string
hasIPv4 bool hasIPv4 bool
hasIPv6 bool hasIPv6 bool
ctx *context ctx *context
@ -158,6 +159,7 @@ func NewPinger() *Pinger {
seq: rand.Intn(0xffff), seq: rand.Intn(0xffff),
addrs: make(map[string]*net.IPAddr), addrs: make(map[string]*net.IPAddr),
network: "ip", network: "ip",
source: "",
hasIPv4: false, hasIPv4: false,
hasIPv6: false, hasIPv6: false,
Size: TimeSliceLength, Size: TimeSliceLength,
@ -185,6 +187,29 @@ func (p *Pinger) Network(network string) (string, error) {
return origNet, nil return origNet, nil
} }
// Source sets source IP for sending ICMP packets and returns the previous
// setting. Empty value indicates to use system default one.
func (p *Pinger) Source(source string) (string, error) {
origSource := p.source
if "" == source {
p.mu.Lock()
p.source = source
p.mu.Unlock()
return origSource, nil
}
addr := net.ParseIP(source)
if addr == nil {
return origSource, errors.New(source + " is not a valid textual representation of an IP address")
}
p.mu.Lock()
p.source = source
p.mu.Unlock()
return origSource, nil
}
// AddIP adds an IP address to Pinger. ipaddr arg should be a string like // AddIP adds an IP address to Pinger. ipaddr arg should be a string like
// "192.0.2.1". // "192.0.2.1".
func (p *Pinger) AddIP(ipaddr string) error { func (p *Pinger) AddIP(ipaddr string) error {
@ -347,8 +372,8 @@ func (p *Pinger) Err() error {
return p.ctx.err return p.ctx.err
} }
func (p *Pinger) listen(netProto string) *icmp.PacketConn { func (p *Pinger) listen(netProto string, source string) *icmp.PacketConn {
conn, err := icmp.ListenPacket(netProto, "") conn, err := icmp.ListenPacket(netProto, source)
if err != nil { if err != nil {
p.mu.Lock() p.mu.Lock()
p.ctx.err = err p.ctx.err = err
@ -364,14 +389,14 @@ func (p *Pinger) run(once bool) {
p.debugln("Run(): Start") p.debugln("Run(): Start")
var conn, conn6 *icmp.PacketConn var conn, conn6 *icmp.PacketConn
if p.hasIPv4 { if p.hasIPv4 {
if conn = p.listen(ipv4Proto[p.network]); conn == nil { if conn = p.listen(ipv4Proto[p.network], p.source); conn == nil {
return return
} }
defer conn.Close() defer conn.Close()
} }
if p.hasIPv6 { if p.hasIPv6 {
if conn6 = p.listen(ipv6Proto[p.network]); conn6 == nil { if conn6 = p.listen(ipv6Proto[p.network], p.source); conn6 == nil {
return return
} }
defer conn6.Close() defer conn6.Close()