Esempio n. 1
0
func (ipad Net) ResolveIPAddr(p string, a string) (*net.IPAddr, error) {
	var i net.IPAddr
	i.Zone = "france"
	i.IP = net.ParseIP("localhost")
	ptr := &i
	return ptr, nil
}
Esempio n. 2
0
func sendPing(conn *net.IPConn, addr *net.IPAddr, id, seq int) {
	bytes, err := (&icmpMessage{
		Type: icmpv4EchoRequest, Code: 0,
		Body: &icmpEcho{
			ID: id, Seq: seq,
			Data: timeToBytes(time.Now()),
		},
	}).Marshal()
	if err != nil {
		panic(err)
	}

	for {
		if _, _, err := conn.WriteMsgIP(bytes, nil, addr); err != nil {
			if neterr, ok := err.(*net.OpError); ok {
				if neterr.Err == syscall.ENOBUFS {
					// creating a busy loop?
					continue
				}
			}
		}
		fmt.Printf("ICMP: Ping sent: %s, id=%d.\n", addr.String(), id)
		break
	}
}
func (cloud *OpenStack) ReturnFloatingIP(addr net.IPAddr) error {
	// grab the address out of the used
	index := indexOfAddress(cloud.usedIPs, addr)
	if index == -1 {
		return errors.New(fmt.Sprintf("'%s' address was not previously allocated", addr.String()))
	}

	// mutex
	cloud.mutex.Lock()

	// remove from usedIPs
	cloud.usedIPs = cloud.usedIPs[:index+copy(cloud.usedIPs[index:], cloud.usedIPs[index+1:])]

	// recreate the availableIPs slice if it was set to nil
	if cloud.availableIps == nil {
		cloud.availableIps = make([]net.IPAddr, 0)
	}

	// add the address to available
	cloud.availableIps = append(cloud.availableIps, addr)

	// mutex
	cloud.mutex.Unlock()

	return nil
}
Esempio n. 4
0
// AddIPAddr adds an IP address to Pinger. ip arg should be a net.IPAddr
// pointer.
func (p *Pinger) AddIPAddr(ip *net.IPAddr) {
	p.addrs[ip.String()] = ip
	if isIPv4(ip.IP) {
		p.hasIPv4 = true
	} else if isIPv6(ip.IP) {
		p.hasIPv6 = true
	}
}
Esempio n. 5
0
func ReverseLookup(ip net.IPAddr) (name string, err error) {
	names, err := net.LookupAddr(ip.String())
	if err == nil && len(names) > 0 {
		name = names[0]
		// names seem to have a . at the end. remove it
		if name[len(name)-1] == '.' {
			name = name[:len(name)-1]
		}
	}
	return
}
Esempio n. 6
0
// SetIPAddr sets the ip address of the target host.
func (p *Pinger) SetIPAddr(ipaddr *net.IPAddr) {
	var ipv4 bool
	if isIPv4(ipaddr.IP) {
		ipv4 = true
	} else if isIPv6(ipaddr.IP) {
		ipv4 = false
	}

	p.ipaddr = ipaddr
	p.addr = ipaddr.String()
	p.ipv4 = ipv4
}
Esempio n. 7
0
func (state *State) onRecv(addr *net.IPAddr, rtt time.Duration) {
	s := state.PingSessions[addr.String()]

	s.Lock()
	s.TotalRTT += rtt
	s.PingCount++
	if s.PingCount > state.PingChecker.PingLimit {
		state.Pinger.RemoveIPAddr(addr)
	}
	s.Unlock()

	return
}
Esempio n. 8
0
File: ping.go Progetto: hizel/pingd
func ping(host string, ra *net.IPAddr, rtt time.Duration, c chan bool, lock *sync.RWMutex, store map[string]*HostStore) {
	p := fastping.NewPinger()

	results := make(map[string]*response)
	results[ra.String()] = nil
	p.AddIPAddr(ra)

	onRecv, onIdle := make(chan *response), make(chan bool)
	p.AddHandler("receive", func(addr *net.IPAddr, t time.Duration) {
		onRecv <- &response{addr: addr, rtt: t}
	})
	p.AddHandler("idle", func() {
		onIdle <- true
	})

	p.MaxRTT = rtt
	quit, errch := p.RunLoop()

	wait := make(chan bool)

loop:
	for {
		select {
		case <-c:
			log.Printf("get interrupted %v", ra)
			quit <- wait
		case res := <-onRecv:
			if _, ok := results[res.addr.String()]; ok {
				results[res.addr.String()] = res
			}
		case <-onIdle:
			for v, r := range results {
				lock.Lock()
				if r == nil {
					store[host].Insert(0)
				} else {
					store[host].Insert(r.rtt)
				}
				lock.Unlock()
				results[v] = nil
			}
		case err := <-errch:
			log.Println("%v failed: %v", ra, err)
			c <- true
		case <-wait:
			break loop
		}
	}
	log.Printf("exit %v", ra)
}
Esempio n. 9
0
// Bootstrap message initiator retrieving possible peer addresses from various
// seed generators and sending bootstrap requests at a given rate.
func (b *Bootstrapper) initiator() {
	b.log.Info("starting initiator")

	// Repeat message initiation until termination is requested
	var errc chan error
	for errc == nil {
		// Retrieve a possible seed address from a random algorithm
		var addr *net.IPAddr
		select {
		// Short circuit termination request
		case errc = <-b.quit:
			continue

		default:
			select {
			case addr = <-b.scanSink:
			case addr = <-b.probeSink:
			case addr = <-b.coreOSSink:
			case errc = <-b.quit:
				continue
			}
		}
		// Discard self addresses
		self := 0
		if b.ipnet.IP.String() == addr.IP.String() {
			self = b.addr.Port
		}
		// Send a bootstrap request on all configured ports
		for _, port := range config.BootPorts {
			if port == self {
				continue
			}
			host := net.JoinHostPort(addr.String(), strconv.Itoa(port))

			addr, err := net.ResolveUDPAddr("udp", host)
			if err != nil {
				panic(fmt.Sprintf("failed to resolve remote bootstrapper (%v): %v.", host, err))
			}
			b.sock.WriteToUDP(b.request, addr)
		}
		time.Sleep(100 * time.Millisecond)
	}
	// Report termination and sync closer
	b.log.Info("terminating initiator")
	errc <- nil
}
Esempio n. 10
0
// Tests that the scanning ad-hoc seeder indeed generates IP addresses in the
// correct order and range for a specific ipnet configuration.
func testScanSeeder(t *testing.T, subnet int, addr *net.IPAddr) {
	// Create the IP net from the configurations
	ipnet := &net.IPNet{
		IP:   addr.IP,
		Mask: net.CIDRMask(subnet, 32),
	}
	// Create the scanning seed generator, address sink and boot it
	seeder := newScanSeeder(ipnet, log15.New("ipnet", ipnet))
	sink, phase := make(chan *net.IPAddr), uint32(0)

	if err := seeder.Start(sink, &phase); err != nil {
		t.Fatalf("failed to start seed generator: %v.", err)
	}
	// Retrieve twice the possible host count, ensuring they are in range
	valid := (1 << uint(32-subnet)) - 2
	addrs := make(map[string]int)
	for i := 0; i < 2*valid; i++ {
		select {
		case addr := <-sink:
			if !ipnet.Contains(addr.IP) {
				t.Fatalf("out of range address generated: %v.", addr)
			}
			addrs[addr.String()]++
		case <-time.After(time.Second):
			t.Fatalf("failed to retrieve next address")
		}
	}
	// Verify that enough hosts were returned and the right multiplier
	if len(addrs) != valid {
		t.Fatalf("address variation mismatch: have %v, want %v.", len(addrs), valid)
	}
	for _, count := range addrs {
		if count != 2 {
			t.Fatalf("address generation count mismatch: have %v, want %v.", count, 2)
		}
	}
	// Terminate the generator
	if err := seeder.Close(); err != nil {
		t.Fatalf("failed to terminate seed generator: %v.", err)
	}
}
Esempio n. 11
0
// Tests that the probing ad-hoc seeder indeed generates IP addresses in the
// correct range for a specific ipnet configuration.
func testProbeSeeder(t *testing.T, subnet int, addr *net.IPAddr) {
	// Create the IP net from the configurations
	ipnet := &net.IPNet{
		IP:   addr.IP,
		Mask: net.CIDRMask(subnet, 32),
	}
	// Create the probing seed generator, address sink and boot it
	seeder := newProbeSeeder(ipnet, log15.New("ipnet", ipnet))
	sink, phase := make(chan *net.IPAddr), uint32(0)

	if err := seeder.Start(sink, &phase); err != nil {
		t.Fatalf("failed to start seed generator: %v.", err)
	}
	// Retrieve a large batch of random addresses, ensuring they are in range
	iters := 100000
	addrs := make(map[string]int)
	for i := 0; i < iters; i++ {
		select {
		case addr := <-sink:
			if !ipnet.Contains(addr.IP) {
				t.Fatalf("out of range address generated: %v.", addr)
			}
			addrs[addr.String()]++
		case <-time.After(time.Second):
			t.Fatalf("failed to retrieve next address")
		}
	}
	// Verify that multipliers are within expected range
	for _, count := range addrs {
		lo := (iters / ((1 << uint(32-subnet)) - 2)) / 10 * 5
		hi := (iters / ((1 << uint(32-subnet)) - 2)) / 10 * 15
		if lo > count || count > hi {
			t.Fatalf("non uniform address count: have %v, want in [%v-%v].", count, lo, hi)
		}
	}
	// Terminate the generator
	if err := seeder.Close(); err != nil {
		t.Fatalf("failed to terminate seed generator: %v.", err)
	}
}
Esempio n. 12
0
func Ping(addr *net.IPAddr, duration time.Duration) *time.Duration {
	reply := make(chan *time.Duration, 3)
	pingChan <- PingJob{
		Reply:    reply,
		Addr:     addr,
		Deadline: time.Now().Add(duration),
	}
	select {
	case rtt := <-reply:
		if rtt == nil {
			fmt.Printf("Ping: %s: got timeout.\n", addr.String())
		} else {
			fmt.Printf("Ping: %s: %s.\n", addr.String(), rtt)
		}
		return rtt
	case <-time.After(duration):
		fmt.Printf("Ping: %s: no reply.\n", addr.String())
		return nil
	}
}
Esempio n. 13
0
func (l *icmpLoop) sendEchoRequest(addr *net.IPAddr) (*requestContext, error) {
	var conn *icmp.PacketConn
	var proto int
	var typ icmp.Type

	if l == nil {
		panic("icmp loop not initialized")
	}

	if isIPv4(addr.IP) {
		conn = l.conn4
		proto = protocolICMP
		typ = ipv4.ICMPTypeEcho
	} else if isIPv6(addr.IP) {
		conn = l.conn6
		proto = protocolIPv6ICMP
		typ = ipv6.ICMPTypeEchoRequest
	} else {
		return nil, fmt.Errorf("%v is unknown ip address", addr)
	}

	id := requestID{
		addr:  addr.String(),
		proto: proto,
		id:    rand.Intn(0xffff),
		seq:   rand.Intn(0xffff),
	}

	ctx := &requestContext{
		l:      l,
		id:     id,
		result: make(chan requestResult, 1),
	}

	l.mutex.Lock()
	l.requests[id] = ctx
	l.mutex.Unlock()

	payloadBuf := make([]byte, 0, 8)
	payload := bytes.NewBuffer(payloadBuf)
	ts := time.Now()
	binary.Write(payload, binary.BigEndian, ts.UnixNano())

	msg := &icmp.Message{
		Type: typ,
		Body: &icmp.Echo{
			ID:   id.id,
			Seq:  id.seq,
			Data: payload.Bytes(),
		},
	}
	encoded, _ := msg.Marshal(nil)

	_, err := conn.WriteTo(encoded, addr)
	if err != nil {
		return nil, err
	}

	ctx.ts = ts
	return ctx, nil
}
Esempio n. 14
0
func ExamplePacketConn_tracingIPPacketRoute() {
	// Tracing an IP packet route to www.google.com.

	const host = "www.google.com"
	ips, err := net.LookupIP(host)
	if err != nil {
		log.Fatal(err)
	}
	var dst net.IPAddr
	for _, ip := range ips {
		if ip.To4() != nil {
			dst.IP = ip
			fmt.Printf("using %v for tracing an IP packet route to %s\n", dst.IP, host)
			break
		}
	}
	if dst.IP == nil {
		log.Fatal("no A record found")
	}

	c, err := net.ListenPacket(fmt.Sprintf("ip4:%d", iana.ProtocolICMP), "0.0.0.0") // ICMP for IPv4
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()
	p := ipv4.NewPacketConn(c)

	if err := p.SetControlMessage(ipv4.FlagTTL|ipv4.FlagSrc|ipv4.FlagDst|ipv4.FlagInterface, true); err != nil {
		log.Fatal(err)
	}
	wm := icmp.Message{
		Type: ipv4.ICMPTypeEcho, Code: 0,
		Body: &icmp.Echo{
			ID:   os.Getpid() & 0xffff,
			Data: []byte("HELLO-R-U-THERE"),
		},
	}

	rb := make([]byte, 1500)
	for i := 1; i <= 64; i++ { // up to 64 hops
		wm.Body.(*icmp.Echo).Seq = i
		wb, err := wm.Marshal(nil)
		if err != nil {
			log.Fatal(err)
		}
		if err := p.SetTTL(i); err != nil {
			log.Fatal(err)
		}

		// In the real world usually there are several
		// multiple traffic-engineered paths for each hop.
		// You may need to probe a few times to each hop.
		begin := time.Now()
		if _, err := p.WriteTo(wb, nil, &dst); err != nil {
			log.Fatal(err)
		}
		if err := p.SetReadDeadline(time.Now().Add(3 * time.Second)); err != nil {
			log.Fatal(err)
		}
		n, cm, peer, err := p.ReadFrom(rb)
		if err != nil {
			if err, ok := err.(net.Error); ok && err.Timeout() {
				fmt.Printf("%v\t*\n", i)
				continue
			}
			log.Fatal(err)
		}
		rm, err := icmp.ParseMessage(iana.ProtocolICMP, rb[:n])
		if err != nil {
			log.Fatal(err)
		}
		rtt := time.Since(begin)

		// In the real world you need to determine whether the
		// received message is yours using ControlMessage.Src,
		// ControlMessage.Dst, icmp.Echo.ID and icmp.Echo.Seq.
		switch rm.Type {
		case ipv4.ICMPTypeTimeExceeded:
			names, _ := net.LookupAddr(peer.String())
			fmt.Printf("%d\t%v %+v %v\n\t%+v\n", i, peer, names, rtt, cm)
		case ipv4.ICMPTypeEchoReply:
			names, _ := net.LookupAddr(peer.String())
			fmt.Printf("%d\t%v %+v %v\n\t%+v\n", i, peer, names, rtt, cm)
			return
		default:
			log.Printf("unknown ICMP message: %+v\n", rm)
		}
	}
}
Esempio n. 15
0
func (p *Pinger) procRecv(recv *packet, queue map[string]*net.IPAddr) {
	var ipaddr *net.IPAddr
	switch adr := recv.addr.(type) {
	case *net.IPAddr:
		ipaddr = adr
	case *net.UDPAddr:
		ipaddr = &net.IPAddr{IP: adr.IP, Zone: adr.Zone}
	default:
		return
	}

	addr := ipaddr.String()
	p.mu.Lock()
	if _, ok := p.addrs[addr]; !ok {
		p.mu.Unlock()
		return
	}
	p.mu.Unlock()

	var bytes []byte
	var proto int
	if isIPv4(ipaddr.IP) {
		if p.network == "ip" {
			bytes = ipv4Payload(recv.bytes)
		} else {
			bytes = recv.bytes
		}
		proto = ProtocolICMP
	} else if isIPv6(ipaddr.IP) {
		bytes = recv.bytes
		proto = ProtocolIPv6ICMP
	} else {
		return
	}

	var m *icmp.Message
	var err error
	if m, err = icmp.ParseMessage(proto, bytes); err != nil {
		return
	}

	if m.Type != ipv4.ICMPTypeEchoReply && m.Type != ipv6.ICMPTypeEchoReply {
		return
	}

	var rtt time.Duration
	switch pkt := m.Body.(type) {
	case *icmp.Echo:
		p.mu.Lock()
		if pkt.ID == p.id && pkt.Seq == p.seq {
			rtt = time.Since(bytesToTime(pkt.Data[:TimeSliceLength]))
		}
		p.mu.Unlock()
	default:
		return
	}

	if _, ok := queue[addr]; ok {
		delete(queue, addr)
		p.mu.Lock()
		handler := p.OnRecv
		p.mu.Unlock()
		if handler != nil {
			handler(ipaddr, rtt)
		}
	}
}
Esempio n. 16
0
// RemoveIPAddr removes an IP address from Pinger. ip arg should be a net.IPAddr
// pointer.
func (p *Pinger) RemoveIPAddr(ip *net.IPAddr) {
	p.mu.Lock()
	delete(p.addrs, ip.String())
	p.mu.Unlock()
}
Esempio n. 17
0
func (p *Pingbeat) Addr2Name(addr *net.IPAddr) (string, string) {
	var name, tag string
	if _, found := p.ipv4targets[addr.String()]; found {
		name = p.ipv4targets[addr.String()][0]
		tag = p.ipv4targets[addr.String()][1]
	} else if _, found := p.ipv6targets[addr.String()]; found {
		name = p.ipv6targets[addr.String()][0]
		tag = p.ipv6targets[addr.String()][1]
	} else {
		logp.Err("Error: %s not found in Pingbeat targets!", addr.String())
		name = "err"
		tag = "err"
	}
	return name, tag
}
Esempio n. 18
0
// RemoveIPAddr removes an IP address from Pinger. ip arg should be a net.IPAddr
// pointer.
func (p *Pinger) RemoveIPAddr(ip *net.IPAddr) {
	delete(p.addrs, ip.String())
}
Esempio n. 19
0
func updateNamespaceNetworkLinks(name string, sourceAddr *net.IPAddr, ports io.Reader) error {

	// Enable routing in the namespace
	output, err := exec.Command("ip", "netns", "exec", name, "sysctl", "-w", "net.ipv4.conf.all.route_localnet=1").Output()
	if err != nil {
		log.Printf("gear: Failed to enable localnet routing: %v", err)
		log.Printf("gear: error output: %v", output)
		return err
	}

	// Enable ip forwarding
	output, err = exec.Command("ip", "netns", "exec", name, "sysctl", "-w", "net.ipv4.ip_forward=1").Output()
	if err != nil {
		log.Printf("gear: Failed to enable ipv4 forwarding: %v", err)
		log.Printf("gear: error output: %v", output)
		return err
	}

	// Restore a set of rules to the table
	cmd := exec.Command("ip", "netns", "exec", name, "iptables-restore")
	stdin, errp := cmd.StdinPipe()
	if errp != nil {
		log.Printf("gear: Could not open pipe to iptables-restore: %v", errp)
		return errp
	}
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	defer stdin.Close()
	if err := cmd.Start(); err != nil {
		log.Printf("gear: Could not start iptables-restore: %v", errp)
		return err
	}

	fmt.Fprintf(stdin, "*nat\n")
	for {
		link := containers.NetworkLink{}
		if _, err := fmt.Fscanf(ports, "%s\t%v\t%v\t%s\n", &link.FromHost, &link.FromPort, &link.ToPort, &link.ToHost); err != nil {
			if err == io.EOF {
				break
			}
			log.Printf("gear: Could not read from network links file: %v", err)
			continue
		}
		if err := link.Check(); err != nil {
			log.Printf("gear: Link in file is not valid: %v", err)
			continue
		}
		if link.Complete() {
			srcIP, err := net.ResolveIPAddr("ip", link.FromHost)
			if err != nil {
				log.Printf("gear: Link source host does not resolve %v", err)
				continue
			}

			destIP, err := resolver.ResolveIP(link.ToHost)
			if err != nil {
				log.Printf("gear: Link destination host does not resolve %v", err)
				continue
			}

			log.Printf("Mapping %s(%s):%d -> %s:%d", sourceAddr.String(), srcIP.String(), link.FromPort, destIP.String(), link.ToPort)

			data := OutboundNetworkIptables{sourceAddr.String(), srcIP.IP.String(), link.FromPort, destIP.String(), link.ToPort}
			if err := OutboundNetworkIptablesTemplate.Execute(stdin, &data); err != nil {
				log.Printf("gear: Unable to write network link rules: %v", err)
				return err
			}
		}
	}
	fmt.Fprintf(stdin, "COMMIT\n")

	stdin.Close()
	if err := cmd.Wait(); err != nil {
		log.Printf("gear: iptables-restore did not successfully complete: %v", err)
		return err
	}
	return nil
}
Esempio n. 20
0
func ServiceRequests() {
	var sockConfig tls.Config

	// resolve the bind address
	bindAddressStr := GetStringOpt("bind address")
	var bindAddr *net.IPAddr
	if bindAddressStr != "" {
		var err error
		bindAddr, err = net.ResolveIPAddr("ip", bindAddressStr)
		if err != nil {
			o.Warn("Ignoring bind address.  Couldn't resolve \"%s\": %s", bindAddressStr, err)
		} else {
			bindAddr = nil
		}
	}
	// load the x509 certificate and key, then attach it to the tls config.
	x509CertFilename := GetStringOpt("x509 certificate")
	x509PrivateKeyFilename := GetStringOpt("x509 private key")
	serverCert, err := tls.LoadX509KeyPair(x509CertFilename, x509PrivateKeyFilename)
	o.MightFail(err, "Couldn't load certificates")
	sockConfig.Certificates = append(sockConfig.Certificates, serverCert)

	// load the CA certs
	CACertPool = x509.NewCertPool()
	caCertNames := GetCACertList()
	if caCertNames != nil {
		for _, filename := range caCertNames {
			fh, err := os.Open(filename)
			if err != nil {
				o.Warn("Whilst parsing CA certs, couldn't open %s: %s", filename, err)
				continue
			}
			defer fh.Close()
			fi, err := fh.Stat()
			o.MightFail(err, "Couldn't stat CA certificate file: %s", filename)
			data := make([]byte, fi.Size())
			fh.Read(data)
			CACertPool.AppendCertsFromPEM(data)
		}
	}
	sockConfig.ClientCAs = CACertPool

	// determine the server hostname.
	servername := GetStringOpt("server name")
	if servername != "" {
		o.Info("Using %s as the server name", servername)
		sockConfig.ServerName = servername
	} else {
		if bindAddr != nil {
			o.Warn("Probing for FQDN for bind address as none was provided")
			hostnames, err := net.LookupAddr(bindAddr.String())
			o.MightFail(err, "Failed to get full hostname for bind address")
			sockConfig.ServerName = hostnames[0]
		} else {
			o.Warn("Probing for FQDN as no server name was provided")
			sockConfig.ServerName = o.ProbeHostname()
		}
	}

	// ask the client to authenticate
	sockConfig.ClientAuth = tls.RequireAndVerifyClientCert
	if *DontVerifyPeer {
		sockConfig.ClientAuth = tls.RequestClientCert
	}

	/* convert the bindAddress to a string suitable for the Listen call */
	var laddr string
	if bindAddr == nil {
		laddr = fmt.Sprintf(":%d", o.DefaultMasterPort)
	} else {
		laddr = fmt.Sprintf("%s:%d", bindAddr.String(), o.DefaultMasterPort)
	}
	o.Info("Binding to %s...", laddr)
	listener, err := tls.Listen("tcp", laddr, &sockConfig)
	o.MightFail(err, "Couldn't bind TLS listener")

	for {
		o.Info("Waiting for connection...")
		c, err := listener.Accept()
		o.MightFail(err, "Couldn't accept TLS connection")
		o.Info("Connection received from %s", c.RemoteAddr().String())
		HandleConnection(c)
	}
}
Esempio n. 21
0
func (p *Pinger) procRecv(bytes []byte, ra net.Addr, ctx *context) {
	var ipaddr *net.IPAddr
	switch adr := ra.(type) {
	case *net.IPAddr:
		ipaddr = adr
	case *net.UDPAddr:
		ipaddr = &net.IPAddr{IP: adr.IP, Zone: adr.Zone}
	default:
		return
	}

	addr := ipaddr.String()
	p.mu.Lock()
	_, ok := p.addrs[addr]
	p.mu.Unlock()

	if !ok {
		return
	}

	var proto int
	if isIPv4(ipaddr.IP) {
		if p.network == "ip" {
			bytes = ipv4Payload(bytes)
		}
		proto = ProtocolICMP
	} else if isIPv6(ipaddr.IP) {
		proto = ProtocolIPv6ICMP
	} else {
		return
	}

	var m *icmp.Message
	var err error
	if m, err = icmp.ParseMessage(proto, bytes); err != nil {
		return
	}

	if m.Type != ipv4.ICMPTypeEchoReply && m.Type != ipv6.ICMPTypeEchoReply {
		return
	}

	var rtt time.Duration
	switch pkt := m.Body.(type) {
	case *icmp.Echo:
		if pkt.ID == p.id && pkt.Seq == p.seq {
			rtt = time.Since(bytesToTime(pkt.Data[:TimeSliceLength]))
		}
	default:
		return
	}

	if 0 == rtt {
		return
	}

	p.mu.Lock()
	delete(p.sent, addr)
	if len(p.sent) == 0 && !p.done {
		p.done = true
		close(ctx.done)
	}
	p.mu.Unlock()

	if p.OnRecv != nil {
		p.OnRecv(ipaddr, rtt)
	}
}
Esempio n. 22
0
func PingIP(hostname string, raddr *net.IPAddr, pcount int, debug bool) (sent int, received int, etimes []float64) {
	// Make the IP connection to the destination host
	ipconn, err := net.DialIP("ip4:icmp", nil, raddr)
	if err != nil {
		fmt.Printf("could not connect to %s: %v\n", raddr.IP, err)
		return
	}

	sendid := os.Getpid() & 0xffff
	sendseq := 1
	pingpktlen := 64

	//if debug {
	fmt.Printf("PING %s (%s): %d data bytes\n", hostname, raddr.String(), pingpktlen-8)
	//}

	for {
		var check4reply bool
		var etime float64

		// Generate our ICMP packet
		sendpkt := makePingRequest(sendid, sendseq, pingpktlen, []byte("Go Ping"))

		// Start timer
		start := time.Now()

		// Send ICMP packet
		n, err := ipconn.Write(sendpkt)

		// Err out if we couldn't send the full packet size
		if err != nil || n != pingpktlen {
			etime = elapsedTime(start)
			fmt.Printf("0 bytes from %s: icmp_req=%d time=%.3f ms ERR: Network is down\n", raddr.IP, sendseq, etime)
		} else {
			// We will check this flag later to see if we need to wait for a returned packet
			check4reply = true
		}

		// increment our sent counter
		sent++

		// set a 0.5 second timer as our max packet reply wait time
		var deadline = start.Add(500 * time.Millisecond)
		ipconn.SetReadDeadline(deadline)

		// Read response packet (or process timeout if it occurs)
		resp := make([]byte, 1024)
		for {
			if check4reply == false {
				break
			}

			n, _, err := ipconn.ReadFrom(resp)
			if err != nil {
				// Could not read response packet
				etime = elapsedTime(start)
				if debug {
					fmt.Printf("%d bytes from %s: icmp_req=%d time=%.3f ms ERR: %s\n", n, raddr.IP, sendseq, etime, err.Error())
				}
				break
			} else {
				// Response was okay

			}

			if resp[0] != ICMP_ECHO_REPLY {
				// Skip non-ICMP packets
				continue
			}

			rcvid, rcvseq := parsePingReply(resp)
			if rcvid != sendid || rcvseq != sendseq {
				etime = elapsedTime(start)
				if debug {
					fmt.Printf("%d bytes from %s: icmp_req=%d time=%.3f ms ERR: Out of sequence (0x%x,0x%x)\n", n, raddr.IP, sendseq, etime, rcvid, rcvseq)
				}
			} else {
				// Packet reply came back okay
				etime = elapsedTime(start)
				if debug {
					fmt.Printf("%d bytes from %s: icmp_req=%d time=%.3f ms\n", n, raddr.IP, sendseq, etime)
				}
				received++
				etimes = append(etimes, etime)
			}
			break
		}

		sendseq++
		if sendseq > pcount {
			// We've reached the maximum number of packets to send so return
			return
		} else {
			// Sleep 1 second before moving onto the next packet
			time.Sleep(1 * time.Second)
		}
	}
}