예제 #1
0
func Ping(pi pingInfo) pingResponse {
	pr := pingResponse{}
	pr.err = nil

	conn, err := icmp.ListenPacket("udp4", configuration.GetDeviceIP())

	if err != nil {
		msg := "Could not create a packet endpoint on ip: " + configuration.GetDeviceIP()
		fmt.Println(err)
		logger.WriteString(msg)
		pr.err = errors.New(msg)
		return pr
	}

	defer conn.Close()

	logger.WriteString("Starting test number " + strconv.Itoa(sequence))

	testNetwork(&pr, pi, conn)
	testInternet(&pr, pi, conn)
	// testDNS(&pr, pi, conn)

	logger.WriteString("Finished test number " + strconv.Itoa(sequence))

	sequence++
	return pr
}
예제 #2
0
func Ping(ip *net.IPAddr, packetConn *icmp.PacketConn) (int, error) {
	if ip == nil && &ip != nil {
		error := errors.New("ip = nil ")
		return 0, error
	}
	var duration int
	var data []byte
	var err error
	timeNow := time.Now().Nanosecond()
	if packetConn == nil {
		packetConn, err = icmp.ListenPacket("ip4:icmp", "")
		if err != nil {
			log.Print("icmp ListenPacket error ")
		}
	}
	errorCode, err := packetConn.WriteTo(data, ip)
	duration = time.Now().Nanosecond() - timeNow
	if errorCode == 0 {
		return duration / 1000, nil
	}
	if err != nil {
		return duration, err
	}
	return duration / 1000, err
}
예제 #3
0
func TestConcurrentNonPrivilegedListenPacket(t *testing.T) {
	if testing.Short() {
		t.Skip("avoid external network")
	}
	switch runtime.GOOS {
	case "darwin":
	case "linux":
		t.Log("you may need to adjust the net.ipv4.ping_group_range kernel state")
	default:
		t.Skipf("not supported on %s", runtime.GOOS)
	}

	network, address := "udp4", "127.0.0.1"
	if !nettest.SupportsIPv4() {
		network, address = "udp6", "::1"
	}
	const N = 1000
	var wg sync.WaitGroup
	wg.Add(N)
	for i := 0; i < N; i++ {
		go func() {
			defer wg.Done()
			c, err := icmp.ListenPacket(network, address)
			if err != nil {
				t.Error(err)
				return
			}
			c.Close()
		}()
	}
	wg.Wait()
}
예제 #4
0
func (p *Pinger) listen(netProto string, source string) *icmp.PacketConn {
	conn, err := icmp.ListenPacket(netProto, source)
	if err != nil {
		p.ctx.err = err
		close(p.ctx.done)
		return nil
	}
	return conn
}
예제 #5
0
파일: ping.go 프로젝트: sparrc/go-ping
func (p *Pinger) listen(netProto string, source string) *icmp.PacketConn {
	conn, err := icmp.ListenPacket(netProto, source)
	if err != nil {
		fmt.Printf("Error listening for ICMP packets: %s\n", err.Error())
		close(p.done)
		return nil
	}
	return conn
}
예제 #6
0
func (self *HikarianIcmp) Run() {
	if self.mode == "decrypt" {
		clientConn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
		if err != nil {
			log.Fatal(err)
		}
		defer clientConn.Close()
		for {
			buf := make([]byte, 1024)
			nr, caddr, err := clientConn.ReadFrom(buf)
			request, err := icmp.ParseMessage(ProtocolICMP, buf)
			if err != nil {
				log.Println("parse icmp request error: ", err.Error())
				return
			}
			if request.Code == 0 {
				return
			}

			body, err := request.Body.Marshal(ProtocolICMP)
			if err != nil {
				log.Println("marshal body error: ", err.Error())
				continue
			}
			hash := binary.BigEndian.Uint16(body[0:2]) + binary.BigEndian.Uint16(body[2:4])
			dataChannel := self.DataChannelPool.Get(hash)
			if dataChannel == nil {
				dataChannel = make(chan []byte)
				self.DataChannelPool.Set(hash, dataChannel)
				go self.transportServer(clientConn, caddr, dataChannel)
			}
			if request.Code == MagicCode {
				log.Println("receive magic")
				dataChannel <- body[:nr-4]
			}
		}
	} else if self.mode == "encrypt" {
		client, err := net.ResolveTCPAddr("tcp", self.client)
		if err != nil {
			log.Fatalln("resolve client address error: ", err.Error())
		}
		l, err := net.ListenTCP("tcp", client)
		if err != nil {
			log.Fatal(err)
		}
		defer l.Close()
		for {
			clientConn, err := l.AcceptTCP()
			if err != nil {
				log.Println("accept error: ", err.Error())
				continue
			}
			defer clientConn.Close()
			go self.transportClient(clientConn)
		}
	}
}
예제 #7
0
파일: network.go 프로젝트: ssokol/stratux
// Monitor clients going in/out of sleep mode via ICMP unreachable packets.
func sleepMonitor() {
	c, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
	if err != nil {
		log.Printf("error listening for udp - sending data to all ports for all connected clients. err: %s", err)
		return
	}
	go icmpEchoSender(c)
	defer c.Close()
	for {
		buf := make([]byte, 1500)
		n, peer, err := c.ReadFrom(buf)
		if err != nil {
			log.Printf("%s\n", err.Error())
			continue
		}
		msg, err := icmp.ParseMessage(1, buf[:n])
		if err != nil {
			continue
		}

		ip := peer.String()

		// Look for echo replies, mark it as received.
		if msg.Type == ipv4.ICMPTypeEchoReply {
			pingResponse[ip] = stratuxClock.Time
			continue // No further processing needed.
		}

		// Only deal with ICMP Unreachable packets (since that's what iOS and Android seem to be sending whenever the apps are not available).
		if msg.Type != ipv4.ICMPTypeDestinationUnreachable {
			continue
		}
		// Packet parsing.
		mb, err := msg.Body.Marshal(1)
		if err != nil {
			continue
		}
		if len(mb) < 28 {
			continue
		}

		// The unreachable port.
		port := (uint16(mb[26]) << 8) | uint16(mb[27])
		ipAndPort := ip + ":" + strconv.Itoa(int(port))

		netMutex.Lock()
		p, ok := outSockets[ipAndPort]
		if !ok {
			// Can't do anything, the client isn't even technically connected.
			netMutex.Unlock()
			continue
		}
		p.LastUnreachable = stratuxClock.Time
		outSockets[ipAndPort] = p
		netMutex.Unlock()
	}
}
예제 #8
0
func (p *Pinger) listen(netProto string) *icmp.PacketConn {
	conn, err := icmp.ListenPacket(netProto, "")
	if err != nil {
		p.mu.Lock()
		p.ctx.err = err
		p.mu.Unlock()
		p.debugln("Run(): close(p.ctx.done)")
		close(p.ctx.done)
		return nil
	}
	return conn
}
예제 #9
0
파일: loop.go 프로젝트: andrewkroh/beats
func newICMPLoop() (*icmpLoop, error) {
	conn4, err := icmp.ListenPacket("ip4:icmp", "")
	if err != nil {
		return nil, err
	}

	conn6, err := icmp.ListenPacket("ip6:ipv6-icmp", "")
	if err != nil {
		conn4.Close()
		return nil, err
	}

	l := &icmpLoop{
		conn4:    conn4,
		conn6:    conn6,
		recv:     make(chan packet, 16),
		requests: map[requestID]*requestContext{},
	}
	go l.runICMPRecv(conn4, protocolICMP)
	go l.runICMPRecv(conn6, protocolIPv6ICMP)

	return l, nil
}
예제 #10
0
파일: goping.go 프로젝트: jtahaney/ping
func main() {
	timeout := 5
	t1 := time.Now()
	c, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
	if err != nil {
		checkError(err, "listen err, ")
	}
	c.SetDeadline(t1.Add(time.Second * time.Duration(timeout)))
	defer c.Close()

	wm := icmp.Message{
		Type: ipv4.ICMPTypeEcho, Code: 0,
		Body: &icmp.Echo{
			ID: os.Getpid() & 0xffff, Seq: 1,
			Data: []byte("HELLO-R-U-THERE"),
		},
	}
	wb, err := wm.Marshal(nil)
	if err != nil {
		log.Fatal(err)
	}
	// Send ICMP echo and start timer
	starttime := time.Now()
	if _, err := c.WriteTo(wb, &net.IPAddr{IP: net.ParseIP(targetIP)}); err != nil {
		log.Fatalf("WriteTo err, %s", err)
	}

	rb := make([]byte, 1500)
	// Look for ICMP response and stop time
	n, peer, err := c.ReadFrom(rb)
	stoptime := time.Now()
	if err != nil {
		log.Fatal(err)
	}
	//rm, err := icmp.ParseMessage(iana.ProtocolICMP, rb[:n])
	rm, err := icmp.ParseMessage(1, rb[:n])
	if err != nil {
		log.Fatal(err)
	}
	switch rm.Type {
	case ipv4.ICMPTypeEchoReply:
		log.Printf("got reflection from %v", peer)
		log.Printf("ICMP echo request sent on ", starttime)
		log.Printf("ICMP echo response received on ", stoptime)
	default:
		log.Printf("got %+v; want echo reply", rm)
	}
}
예제 #11
0
func New(laddr, raddr string) (*ICMP, error) {
	addr, err := net.ResolveIPAddr("ip4", laddr)
	if err != nil {
		return nil, err
	}
	listener, err := icmp.ListenPacket("ip4:icmp", addr.String())
	if err != nil {
		return nil, err
	}
	r, err := net.ResolveIPAddr("ip4", raddr)
	i := &ICMP{
		listener: listener,
		raddr:    r,
	}
	return i, nil
}
예제 #12
0
func ExamplePacketConn_nonPrivilegedPing() {
	switch runtime.GOOS {
	case "darwin":
	case "linux":
		log.Println("you may need to adjust the net.ipv4.ping_group_range kernel state")
	default:
		log.Println("not supported on", runtime.GOOS)
		return
	}

	c, err := icmp.ListenPacket("udp6", "fe80::1%en0")
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()

	wm := icmp.Message{
		Type: ipv6.ICMPTypeEchoRequest, Code: 0,
		Body: &icmp.Echo{
			ID: os.Getpid() & 0xffff, Seq: 1,
			Data: []byte("HELLO-R-U-THERE"),
		},
	}
	wb, err := wm.Marshal(nil)
	if err != nil {
		log.Fatal(err)
	}
	if _, err := c.WriteTo(wb, &net.UDPAddr{IP: net.ParseIP("ff02::1"), Zone: "en0"}); err != nil {
		log.Fatal(err)
	}

	rb := make([]byte, 1500)
	n, peer, err := c.ReadFrom(rb)
	if err != nil {
		log.Fatal(err)
	}
	rm, err := icmp.ParseMessage(58, rb[:n])
	if err != nil {
		log.Fatal(err)
	}
	switch rm.Type {
	case ipv6.ICMPTypeEchoReply:
		log.Printf("got reflection from %v", peer)
	default:
		log.Printf("got %+v; want echo reply", rm)
	}
}
예제 #13
0
파일: icmpping.go 프로젝트: abrander/alerto
func init() {
	var err error
	conn, err = icmp.ListenPacket("ip4:icmp", "0.0.0.0")
	if err != nil {
		if err.Error() == "listen ip4:icmp 0.0.0.0: socket: operation not permitted" {
			logger.Error("icmpping", "Please run:\nsudo setcap cap_net_raw=ep %s\n", os.Args[0])
		} else {
			logger.Error("icmpping", err.Error())
		}
	}

	active = make(map[uint16]chan IcmpReply)

	plugins.Register("icmp4", NewIcmpPing)

	go ListenLoop()
}
예제 #14
0
// Send Echo-Request to remote host and wait Echo-Reply.
// raddr is an address of remote host.
func (i *ICMP4Pinger) Ping(raddr string) (Pong, error) {
	message := icmp.Message{
		Type: ipv4.ICMPTypeEcho,
		Code: 0,
		Body: &icmp.Echo{
			ID:  i.id,
			Seq: i.counter,
		},
	}
	i.counter++
	listener, err := icmp.ListenPacket("ip4:icmp", i.laddr.String())
	if err != nil {
		return Pong{}, err
	}
	defer listener.Close()
	addr, err := net.ResolveIPAddr("ip4", raddr)
	if err != nil {
		return Pong{}, err
	}
	return ping(listener, message, addr, i.timeout)
}
예제 #15
0
func ExamplePacketConn_nonPrivilegedPing() {
	c, err := icmp.ListenPacket("udp6", "fe80::1%en0")
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()

	wm := icmp.Message{
		Type: ipv6.ICMPTypeEchoRequest, Code: 0,
		Body: &icmp.Echo{
			ID: os.Getpid() & 0xffff, Seq: 1,
			Data: []byte("HELLO-R-U-THERE"),
		},
	}
	wb, err := wm.Marshal(nil)
	if err != nil {
		log.Fatal(err)
	}
	if _, err := c.WriteTo(wb, &net.UDPAddr{IP: net.ParseIP("ff02::1"), Zone: "en0"}); err != nil {
		log.Fatal(err)
	}

	rb := make([]byte, 1500)
	n, peer, err := c.ReadFrom(rb)
	if err != nil {
		log.Fatal(err)
	}
	rm, err := icmp.ParseMessage(iana.ProtocolIPv6ICMP, rb[:n])
	if err != nil {
		log.Fatal(err)
	}
	switch rm.Type {
	case ipv6.ICMPTypeEchoReply:
		log.Printf("got reflection from %v", peer)
	default:
		log.Printf("got %+v; want echo reply", rm)
	}
}
예제 #16
0
파일: ping.go 프로젝트: Wang/ping
func SetDevice(d string) {
	var err error
	conn, err = icmp.ListenPacket("ip4:icmp", "0.0.0.0")
	if err != nil {
		panic(err.Error())
	}
	queue = NewQueue()

	pingServer = NewServer(d, ProcessId)
	pingServer.Start()

	c := make(chan IcmpEchoReply)
	pingServer.ReceivingIcmp(c)
	go func(c <-chan IcmpEchoReply) {
		for e := range c {
			k := fmt.Sprintf("%s:%d", e.srcIp, e.seq)
			//log.Println(e.srcIp, ">", e.dstIp, e.seq, k)
			p, ok := queue.Get(k)
			if ok {
				p.done <- k
			}
		}
	}(c)
}
예제 #17
0
func doPing(host string, tt *Ping, seq int) error {
	c, err := icmp.ListenPacket(tt.network, tt.address)
	if err != nil {
		return err
	}
	defer c.Close()

	dst, err := getAddr(host, c, tt.protocol)
	if err != nil {
		return err
	}

	now := time.Now()
	today := now.Truncate(24*time.Hour).UnixNano() / 1000000
	transmitTime := uint32(now.UnixNano()/1000000 - today)
	wm := icmp.Message{
		Type: tt.mtype,
		Code: 0,
		Body: &Timestamp{
			ID: os.Getpid() & 0xffff, Seq: 1 << uint(seq),
			OriginTimestamp: transmitTime,
		},
	}

	wb, err := wm.Marshal(nil)
	if err != nil {
		return err
	}
	if n, err := c.WriteTo(wb, dst); err != nil {
		return err
	} else if n != len(wb) {
		return fmt.Errorf("got %v; want %v", n, len(wb))
	}

	rb := make([]byte, 1500)
	if err := c.SetReadDeadline(time.Now().Add(3 * time.Second)); err != nil {
		return err
	}
	n, peer, err := c.ReadFrom(rb)
	if err != nil {
		return err
	}
	receivedTime := time.Now().UnixNano()/1000000 - today
	rm, err := icmp.ParseMessage(tt.protocol, rb[:n])
	if err != nil {
		return err
	}
	switch rm.Type {
	case ipv4.ICMPTypeTimestampReply:
		b, _ := rm.Body.Marshal(iana.ProtocolICMP)
		ts, err := ParseTimestamp(b)
		if err != nil {
			fmt.Errorf("ParseTimestamp error: %s", err)
		}
		remoteReceiveTime := int64(ts.ReceiveTimestamp)
		rtt := int64(math.Abs(float64(remoteReceiveTime - int64(transmitTime) + receivedTime - int64(ts.TransmitTimestamp))))
		delta := rtt/2 + int64(transmitTime) - remoteReceiveTime
		w := new(tabwriter.Writer)
		w.Init(os.Stdout, 0, 4, 0, '\t', 0)
		fmt.Fprintf(w, "ICMP timestamp:\tOriginate=%d Receive=%d Transmit=%d\n", ts.OriginTimestamp, ts.ReceiveTimestamp, ts.TransmitTimestamp)
		fmt.Fprintf(w, "ICMP timestamp RTT:\ttsrtt=%d\n", rtt)
		fmt.Fprintf(w, "Time difference:\tdelta=%d\n", delta)
		w.Flush()
		return nil
	default:
		return fmt.Errorf("got %+v from %v; want echo reply", rm, peer)
	}
}
예제 #18
0
func probeICMP(target string, w http.ResponseWriter, module Module) (success bool) {
	deadline := time.Now().Add(module.Timeout)
	socket, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
	if err != nil {
		log.Errorf("Error listening to socket: %s", err)
		return
	}
	defer socket.Close()

	ip, err := net.ResolveIPAddr("ip4", target)
	if err != nil {
		log.Errorf("Error resolving address %s: %s", target, err)
		return
	}

	seq := getICMPSequence()
	pid := os.Getpid() & 0xffff

	wm := icmp.Message{
		Type: ipv4.ICMPTypeEcho, Code: 0,
		Body: &icmp.Echo{
			ID: pid, Seq: int(seq),
			Data: []byte("Prometheus Blackbox Exporter"),
		},
	}
	wb, err := wm.Marshal(nil)
	if err != nil {
		log.Errorf("Error marshalling packet for %s: %s", target, err)
		return
	}
	if _, err := socket.WriteTo(wb, ip); err != nil {
		log.Errorf("Error writing to socker for %s: %s", target, err)
		return
	}

	rb := make([]byte, 1500)
	if err := socket.SetReadDeadline(deadline); err != nil {
		log.Errorf("Error setting socket deadline for %s: %s", target, err)
		return
	}
	for {
		n, peer, err := socket.ReadFrom(rb)
		if err != nil {
			if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
				log.Infof("Timeout reading from socket for %s: %s", target, err)
				return
			}
			log.Errorf("Error reading from socket for %s: %s", target, err)
			continue
		}
		if peer.String() != ip.String() {
			continue
		}
		rm, err := icmp.ParseMessage(iana.ProtocolICMP, rb[:n])
		if err != nil {
			log.Warnf("Error parsing ICMP message for %s: %s", target, err)
			continue
		}
		if rm.Type == ipv4.ICMPTypeEchoReply {
			// The ICMP package does not support unmarshalling
			// messages, so assume this is the right sequence number.
			success = true
			return
		}
	}
	return
}
예제 #19
0
func doPing(tt pingTest, seq int) error {
	c, err := icmp.ListenPacket(tt.network, tt.address)
	if err != nil {
		return err
	}
	defer c.Close()

	dst, err := googleAddr(c, tt.protocol)
	if err != nil {
		return err
	}

	if tt.protocol == iana.ProtocolIPv6ICMP {
		var f ipv6.ICMPFilter
		f.SetAll(true)
		f.Accept(ipv6.ICMPTypeDestinationUnreachable)
		f.Accept(ipv6.ICMPTypePacketTooBig)
		f.Accept(ipv6.ICMPTypeTimeExceeded)
		f.Accept(ipv6.ICMPTypeParameterProblem)
		f.Accept(ipv6.ICMPTypeEchoReply)
		if err := c.IPv6PacketConn().SetICMPFilter(&f); err != nil {
			return err
		}
	}

	wm := icmp.Message{
		Type: tt.mtype, Code: 0,
		Body: &icmp.Echo{
			ID: os.Getpid() & 0xffff, Seq: 1 << uint(seq),
			Data: []byte("HELLO-R-U-THERE"),
		},
	}
	wb, err := wm.Marshal(nil)
	if err != nil {
		return err
	}
	if n, err := c.WriteTo(wb, dst); err != nil {
		return err
	} else if n != len(wb) {
		return fmt.Errorf("got %v; want %v", n, len(wb))
	}

	rb := make([]byte, 1500)
	if err := c.SetReadDeadline(time.Now().Add(3 * time.Second)); err != nil {
		return err
	}
	n, peer, err := c.ReadFrom(rb)
	if err != nil {
		return err
	}
	rm, err := icmp.ParseMessage(tt.protocol, rb[:n])
	if err != nil {
		return err
	}
	switch rm.Type {
	case ipv4.ICMPTypeEchoReply, ipv6.ICMPTypeEchoReply:
		return nil
	default:
		return fmt.Errorf("got %+v from %v; want echo reply", rm, peer)
	}
}
예제 #20
0
func main() {

	if len(os.Args) < 4 {
		os.Exit(10)
	}

	hostfile := os.Args[1]
	hdlr, err := os.Open(hostfile)
	if err != nil {
		fmt.Println(os.Stderr, "Failed to open with ", hostfile, err)
		os.Exit(11)
	}
	defer hdlr.Close()

	size, err := strconv.Atoi(os.Args[2])
	if err != nil {
		fmt.Println(os.Stderr, "Failed to convert with ", os.Args[2])
		os.Exit(2)
	}

	intv, err := strconv.ParseUint(os.Args[3], 10, 64)
	if err != nil {
		fmt.Println(os.Stderr, "Failed to convert with ", os.Args[3])
		os.Exit(7)
	}

	data := make([]byte, size)
	for i := 0; i < size; i++ {
		data[i] = uint8(i)
	}

	rand.Seed(time.Now().UnixNano())

	exitch := make(chan int, 1)
	collch := make(chan int, 1)
	repch := make(chan int, 1)

	pingnum := 0
	scanner := bufio.NewScanner(hdlr)
	for scanner.Scan() {
		host := scanner.Text()

		addr, err := net.ResolveIPAddr("ip4", host)
		if err != nil {
			fmt.Println(os.Stderr, "Failed to resolve with ", host, err)
			os.Exit(1)
		}

		conn, err := icmp.ListenPacket("ip4:icmp", "")
		if err != nil {
			fmt.Println(os.Stderr, "Failed to listen ip4:icmp (%s)", err)
			os.Exit(3)
		}
		defer conn.Close()

		id := rand.Intn(65535)

		p := &Ping{
			PingNet{addr, conn},
			PingData{id, data, size, intv},
			PingNum{0, 0},
			PingChan{exitch, collch},
		}

		go p.doPing()

		pingnum += 1
	}

	sigch := make(chan os.Signal, 1)
	signal.Notify(sigch, syscall.SIGINT)

	allrecs := 0
	go func() {
		_ = <-sigch
		close(exitch)
		for i := 0; i < pingnum; i++ {
			allrecs += <-collch
		}
		repch <- allrecs
	}()

	start := time.Now()
	_ = <-exitch
	finish := time.Now()
	rep := <-repch

	fmt.Println("")
	fmt.Println("--- perfpinger statistics ---")

	dur := finish.Sub(start).Seconds() / time.Second.Seconds()
	thr := float64(rep) * (float64(size) * float64(pingnum) * 8) / (dur * 1024 * 2)
	fmt.Printf("Total %d packets in %.2f sec : %.2f Kbps of both UL and DL.\n", rep, dur, thr)

}
예제 #21
0
파일: ping.go 프로젝트: krhubert/ping
// Pinger pings requested address.
// It returns nil when IcmpEchoReplay is recived, error otherwishe.
func Pinger(address string, timeout time.Duration) (err error) {
	addr, err := net.ResolveIPAddr("ip", address)
	if err != nil {
		return err
	}

	network := "ip4:icmp"
	if addr.IP.To4() == nil {
		network = "ip6:ipv6-icmp"
	}

	c, err := icmp.ListenPacket(network, address)
	if err != nil {
		return err
	}
	defer func() {
		if cerr := c.Close(); cerr != nil && err == nil {
			err = cerr
		}
	}()

	wm := icmp.Message{
		Type: ipv4.ICMPTypeEcho, Code: 0,
		Body: &icmp.Echo{
			ID: os.Getpid() & 0xffff, Seq: 1,
			Data: []byte("ping"),
		},
	}

	if addr.IP.To4() == nil {
		wm.Type = ipv6.ICMPTypeEchoRequest
	}

	wb, err := wm.Marshal(nil)
	if err != nil {
		return err
	}

	if err := c.SetDeadline(time.Now().Add(timeout)); err != nil {
		return err
	}

	if _, err = c.WriteTo(wb, addr); err != nil {
		return err
	}

	rb := make([]byte, 1500)
	n, _, err := c.ReadFrom(rb)
	if err != nil {
		return err
	}

	rm, err := icmp.ParseMessage(ProtocolICMP, rb[:n])
	if err != nil {
		return err
	}

	if addr.IP.To4() == nil {
		if rm.Type == ipv6.ICMPTypeEchoReply {
			return ErrNoImcpReplay
		}
		return nil
	}

	if rm.Type == ipv4.ICMPTypeEchoReply {
		return ErrNoImcpReplay
	}
	return nil
}
예제 #22
0
// ListenICMP listens to incoming ICMP packet
func ListenICMP() (*icmp.PacketConn, error) {
	return icmp.ListenPacket("ip4:icmp", "0.0.0.0")
}
예제 #23
0
func probeICMP(target string, w http.ResponseWriter, module Module) (success bool) {
	var (
		socket           *icmp.PacketConn
		requestType      icmp.Type
		replyType        icmp.Type
		fallbackProtocol string
	)

	deadline := time.Now().Add(module.Timeout)

	// Defaults to IPv4 to be compatible with older versions
	if module.ICMP.Protocol == "" {
		module.ICMP.Protocol = "icmp"
	}

	// In case of ICMP prefer IPv6 by default
	if module.ICMP.Protocol == "icmp" && module.ICMP.PreferredIpProtocol == "" {
		module.ICMP.PreferredIpProtocol = "ip6"
	}

	if module.ICMP.Protocol == "icmp4" {
		module.ICMP.PreferredIpProtocol = "ip4"
		fallbackProtocol = ""
	} else if module.ICMP.Protocol == "icmp6" {
		module.ICMP.PreferredIpProtocol = "ip6"
		fallbackProtocol = ""
	} else if module.ICMP.PreferredIpProtocol == "ip6" {
		fallbackProtocol = "ip4"
	} else {
		fallbackProtocol = "ip6"
	}

	ip, err := net.ResolveIPAddr(module.ICMP.PreferredIpProtocol, target)
	if err != nil && fallbackProtocol != "" {
		ip, err = net.ResolveIPAddr(fallbackProtocol, target)
	}
	if err != nil {
		log.Errorf("Error resolving address %s: %s", target, err)
	}

	if ip.IP.To4() == nil {
		requestType = ipv6.ICMPTypeEchoRequest
		replyType = ipv6.ICMPTypeEchoReply
		socket, err = icmp.ListenPacket("ip6:ipv6-icmp", "::")
		fmt.Fprintf(w, "probe_ip_protocol 6\n")
	} else {
		requestType = ipv4.ICMPTypeEcho
		replyType = ipv4.ICMPTypeEchoReply
		socket, err = icmp.ListenPacket("ip4:icmp", "0.0.0.0")
		fmt.Fprintf(w, "probe_ip_protocol 4\n")
	}

	if err != nil {
		log.Errorf("Error listening to socket: %s", err)
		return
	}
	defer socket.Close()

	if err != nil {
		log.Errorf("Error resolving address %s: %s", target, err)
		return
	}

	seq := getICMPSequence()
	pid := os.Getpid() & 0xffff

	wm := icmp.Message{
		Type: requestType,
		Code: 0,
		Body: &icmp.Echo{
			ID: pid, Seq: int(seq),
			Data: []byte("Prometheus Blackbox Exporter"),
		},
	}

	wb, err := wm.Marshal(nil)
	if err != nil {
		log.Errorf("Error marshalling packet for %s: %s", target, err)
		return
	}
	if _, err := socket.WriteTo(wb, ip); err != nil {
		log.Errorf("Error writing to socker for %s: %s", target, err)
		return
	}

	// Reply should be the same except for the message type.
	wm.Type = replyType
	wb, err = wm.Marshal(nil)
	if err != nil {
		log.Errorf("Error marshalling packet for %s: %s", target, err)
		return
	}

	rb := make([]byte, 1500)
	if err := socket.SetReadDeadline(deadline); err != nil {
		log.Errorf("Error setting socket deadline for %s: %s", target, err)
		return
	}
	for {
		n, peer, err := socket.ReadFrom(rb)
		if err != nil {
			if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
				log.Infof("Timeout reading from socket for %s: %s", target, err)
				return
			}
			log.Errorf("Error reading from socket for %s: %s", target, err)
			continue
		}
		if peer.String() != ip.String() {
			continue
		}
		if replyType == ipv6.ICMPTypeEchoReply {
			// Clear checksum to make comparison succeed.
			rb[2] = 0
			rb[3] = 0
		}
		if bytes.Compare(rb[:n], wb) == 0 {
			success = true
			return
		}
	}
}
예제 #24
0
func TestPingGoogle(t *testing.T) {
	if testing.Short() {
		t.Skip("to avoid external network")
	}
	switch runtime.GOOS {
	case "darwin":
	case "linux":
		t.Log("you may need to adjust the net.ipv4.ping_group_range kernel state")
	default:
		t.Skipf("not supported on %q", runtime.GOOS)
	}

	for i, tt := range pingGoogleTests {
		if tt.network[:2] == "ip" && os.Getuid() != 0 {
			continue
		}
		c, err := icmp.ListenPacket(tt.network, tt.address)
		if err != nil {
			t.Error(err)
			continue
		}
		defer c.Close()

		dst, err := googleAddr(c, tt.protocol)
		if err != nil {
			t.Error(err)
			continue
		}

		wm := icmp.Message{
			Type: tt.mtype, Code: 0,
			Body: &icmp.Echo{
				ID: os.Getpid() & 0xffff, Seq: 1 << uint(i),
				Data: []byte("HELLO-R-U-THERE"),
			},
		}
		wb, err := wm.Marshal(nil)
		if err != nil {
			t.Error(err)
			continue
		}
		if n, err := c.WriteTo(wb, dst); err != nil {
			t.Error(err, dst)
			continue
		} else if n != len(wb) {
			t.Errorf("got %v; want %v", n, len(wb))
			continue
		}

		rb := make([]byte, 1500)
		n, peer, err := c.ReadFrom(rb)
		if err != nil {
			t.Error(err)
			continue
		}
		rm, err := icmp.ParseMessage(tt.protocol, rb[:n])
		if err != nil {
			t.Error(err)
			continue
		}
		switch rm.Type {
		case ipv4.ICMPTypeEchoReply, ipv6.ICMPTypeEchoReply:
			t.Logf("got reflection from %v", peer)
		default:
			t.Errorf("got %+v; want echo reply", rm)
		}
	}
}
예제 #25
0
func probeICMP(target string, w http.ResponseWriter, module Module) (success bool) {
	deadline := time.Now().Add(module.Timeout)
	socket, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0")
	if err != nil {
		log.Errorf("Error listening to socket: %s", err)
		return
	}
	defer socket.Close()

	ip, err := net.ResolveIPAddr("ip4", target)
	if err != nil {
		log.Errorf("Error resolving address %s: %s", target, err)
		return
	}

	seq := getICMPSequence()
	pid := os.Getpid() & 0xffff

	wm := icmp.Message{
		Type: ipv4.ICMPTypeEcho, Code: 0,
		Body: &icmp.Echo{
			ID: pid, Seq: int(seq),
			Data: []byte("Prometheus Blackbox Exporter"),
		},
	}
	wb, err := wm.Marshal(nil)
	if err != nil {
		log.Errorf("Error marshalling packet for %s: %s", target, err)
		return
	}
	if _, err := socket.WriteTo(wb, ip); err != nil {
		log.Errorf("Error writing to socker for %s: %s", target, err)
		return
	}

	// Reply should be the same except for the message type.
	wm.Type = ipv4.ICMPTypeEchoReply
	wb, err = wm.Marshal(nil)
	if err != nil {
		log.Errorf("Error marshalling packet for %s: %s", target, err)
		return
	}

	rb := make([]byte, 1500)
	if err := socket.SetReadDeadline(deadline); err != nil {
		log.Errorf("Error setting socket deadline for %s: %s", target, err)
		return
	}
	for {
		n, peer, err := socket.ReadFrom(rb)
		if err != nil {
			if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
				log.Infof("Timeout reading from socket for %s: %s", target, err)
				return
			}
			log.Errorf("Error reading from socket for %s: %s", target, err)
			continue
		}
		if peer.String() != ip.String() {
			continue
		}
		if bytes.Compare(rb[:n], wb) == 0 {
			success = true
			return
		}
	}
	return
}
예제 #26
0
// Sends a single ICMP echo to an IP and returns success and latency information.
// Borrowed from BrianBrazil's blackbox exporter
func Ping(ip net.IP, maxRTT time.Duration) (success bool, latency time.Duration) {
	deadline := time.Now().Add(maxRTT)

	var socket *icmp.PacketConn
	var err error
	if isIPv4(ip) {
		socket, err = icmp.ListenPacket("ip4:icmp", "0.0.0.0")
	} else if isIPv6(ip) {
		socket, err = icmp.ListenPacket("ip6:ipv6-icmp", "::")
	} else {
		log.Errorln("IP did not match any known types?")
		return
	}

	if err != nil {
		log.Errorf("Error listening to socket: %s", err)
		return
	}
	defer socket.Close()

	seq := getICMPSequence()
	pid := os.Getpid() & 0xffff

	// Build the packet
	var wm icmp.Message
	if isIPv4(ip) {
		wm = icmp.Message{
			Type: ipv4.ICMPTypeEcho, Code: 0,
			Body: &icmp.Echo{
				ID: pid, Seq: int(seq),
				Data: []byte("poller_exporter"),
			},
		}
	} else if isIPv6(ip) {
		wm = icmp.Message{
			Type: ipv6.ICMPTypeEchoRequest, Code: 0,
			Body: &icmp.Echo{
				ID: pid, Seq: int(seq),
				Data: []byte("poller_exporter"),
			},
		}
	} else {
		log.Errorln("IP did not match any known types?")
		return
	}

	wb, err := wm.Marshal(nil)
	if err != nil {
		log.Errorf("Error marshalling packet for %s: %s", ip.String(), err)
		return
	}

	sendTime := time.Now()

	var dst *net.IPAddr
	dst = &net.IPAddr{IP: ip}

	if _, err := socket.WriteTo(wb, dst); err != nil {
		log.Errorf("Error writing to socket for %s: %s", ip.String(), err)
		return
	}

	// Reply should be the same except for the message type.
	if isIPv4(ip) {
		wm.Type = ipv4.ICMPTypeEchoReply
	} else if isIPv6(ip) {
		wm.Type = ipv6.ICMPTypeEchoReply
	} else {
		log.Errorln("IP did not match any known types?")
		return
	}

	wb, err = wm.Marshal(nil)
	if err != nil {
		log.Errorf("Error marshalling packet for %s: %s", ip.String(), err)
		return
	}

	rb := make([]byte, 1500)
	if err := socket.SetReadDeadline(deadline); err != nil {
		log.Errorf("Error setting socket deadline for %s: %s", ip.String(), err)
		return
	}
	for {
		n, peer, err := socket.ReadFrom(rb)
		if err != nil {
			if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
				log.Infof("Timeout reading from socket for %s: %s", ip.String(), err)
				return
			}
			log.Errorf("Error reading from socket for %s: %s", ip.String(), err)
			continue
		}
		if peer.String() != ip.String() {
			continue
		}
		if bytes.Compare(rb[:n], wb) == 0 {
			success = true
			latency = time.Now().Sub(sendTime)
			return
		}
	}
	return
}
예제 #27
0
파일: main.go 프로젝트: facebook/fbtracert
// ICMPReceiver runs on its own collecting ICMP responses until its explicitly told to stop
func ICMPReceiver(done <-chan struct{}, af string, srcAddr net.IP) (chan interface{}, error) {
	var (
		minInnerIPHdrSize int
		icmpMsgType       byte
		listenNet         string
	)

	switch af {
	case "ip4":
		minInnerIPHdrSize = minIP4HeaderSize // the size of the original IPv4 header that was on the TCP packet sent out
		icmpMsgType = 11                     // time to live exceeded
		listenNet = "ip4:1"                  // IPv4 ICMP proto number
	case "ip6":
		minInnerIPHdrSize = ip6HeaderSize // the size of the original IPv4 header that was on the TCP packet sent out
		icmpMsgType = 3                   // time to live exceeded
		listenNet = "ip6:58"              // IPv6 ICMP proto number
	default:
		return nil, fmt.Errorf("sender: unsupported network %q", af)
	}

	conn, err := icmp.ListenPacket(listenNet, srcAddr.String())
	if err != nil {
		return nil, err
	}

	glog.V(2).Infoln("ICMPReceiver is starting...")

	recv := make(chan interface{})

	go func() {
		// TODO: remove hardcode; 20 bytes for IP header, 8 bytes for ICMP header, 8 bytes for TCP header
		packet := make([]byte, icmpHdrSize+maxIP4HeaderSize+maxTCPHdrSize)
		for {
			n, from, err := conn.ReadFrom(packet)
			if err != nil {
				break
			}
			// extract the 8 bytes of the original TCP header
			if n < icmpHdrSize+minInnerIPHdrSize+minTCPHdrSize {
				continue
			}
			// not ttl exceeded
			if packet[0] != icmpMsgType || packet[1] != 0 {
				continue
			}
			glog.V(4).Infof("Received ICMP response message %d: %x\n", n, packet[:n])
			tcpHdr := parseTCPHeader(packet[icmpHdrSize+minInnerIPHdrSize : n])

			// extract ttl bits from the ISN
			ttl := int(tcpHdr.SeqNum) >> 24

			// extract the timestamp from the ISN
			ts := tcpHdr.SeqNum & 0x00ffffff
			// scale the current time
			now := uint32(time.Now().UnixNano()/(1000*1000)) & 0x00ffffff
			recv <- ICMPResponse{Probe: Probe{srcPort: int(tcpHdr.Source), ttl: ttl}, fromAddr: net.ParseIP(from.String()), rtt: now - ts}
		}
	}()

	out := make(chan interface{})
	go func() {
		defer conn.Close()
		defer close(out)
		for {
			select {
			// read ICMP struct
			case response := <-recv:
				out <- response
			case <-done:
				glog.V(2).Infoln("ICMPReceiver done")
				return
			}
		}
	}()

	return out, nil
}
func main() {

	timeout := flag.Int("t", 5, "timeout for ttl")
	concurrent := flag.Int("c", 100, "concurrent for each channel")
	maxPing := flag.Int("m", 5000000, "max ips number")
	log.Print(maxPing)
	flag.Parse()

	//初始化状态判定
	switch runtime.GOOS {
	case "darwin":
	case "linux":
		log.Println("you may need to adjust the net.ipv4.ping_group_range kernel state")
	default:
		log.Fatal("Not supported Device")
	}

	//数据库链接初始化

	session, err := mgo.Dial(config.MongodbIP)
	if err != nil {
		panic(err)
	}
	session.SetMode(mgo.Monotonic, true)
	connectMongoDB := session.DB("pingvalue").C("ping")
	log.Print(connectMongoDB)

	//初始化存储结果的缓存区域
	resultCache := ResultCache{cache: make(map[string]PingResult)}
	//初始化ip缓存
	// IPPing_Map := make(map[string]*PingResult)

	ch_ping := make(chan string, *concurrent)
	ch_pingResult := make(chan PingResult, *concurrent)
	ch_lock := make(chan struct{}, *concurrent)

	var finishedNumber int
	log.Print(finishedNumber)
	c, err := icmp.ListenPacket("udp4", localAddr)
	if err != nil {
		log.Fatal(err)
	}
	defer c.Close()
	go func() {
		// 程序退出时关闭file
		f, err := os.Open(file)
		if err != nil {
			log.Panicf("File open error:%v", err)
		}
		defer f.Close()
		reader := csv.NewReader(f)
		for {
			record, err := reader.Read()
			if err == io.EOF {
				break
			} else if err != nil {
				fmt.Println("Error:", err)
				log.Panic("File error")
			}
			// fmt.Println(record[0]) // record has the type []string
			netAddr := strings.Split(record[0], ".")
			for i := 1; i < 256; i++ {
				netAddr[3] = strconv.Itoa(i)
				ch_ping <- strings.Join(netAddr, ".")
			}
		}
	}()

	//读取监听的数据流
	go func(c *icmp.PacketConn) {
		defer func() {
			fmt.Printf("return ")
		}()
		for {
			rb := make([]byte, 1500)
			_, peer, err := c.ReadFrom(rb)
			if err != nil {
				continue
			} else {
				ipaddr, _, _ := net.SplitHostPort(peer.String())

				if err := resultCache.UpdateTTL(ipaddr, time.Now()); err != nil {
					log.Printf("%v", err)
				}
			}
		}

	}(c)
	for {
		select {
		case result := <-ch_pingResult:
			log.Printf("Prepare to save : %v", result)
			// err:=connectMongoDB.Insert(&result)
			// if err!=nil {
			// 		log.Printf("Error : %v",err)
			// }else{
			// 		log.Printf("Save success")
			// 		finishedNumber++
			// 		if finishedNumber>*maxPing {
			// 			return
			// 		}else{
			// 			log.Print(finishedNumber)
			// 		}
			// }

		case ip := <-ch_ping:
			// resultCache.New(ip)
			// fmt.Print(ip)
			go Send_UDP_Ping(c, ip, *concurrent, *timeout, ch_lock, &resultCache)

		}
	}
}