예제 #1
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
}
예제 #2
0
파일: network.go 프로젝트: ssokol/stratux
func icmpEchoSender(c *icmp.PacketConn) {
	timer := time.NewTicker(5 * time.Second)
	for {
		<-timer.C
		// Collect IPs.
		ips := make(map[string]bool)
		for k, _ := range outSockets {
			ipAndPort := strings.Split(k, ":")
			ips[ipAndPort[0]] = true
		}
		// Send to all IPs.
		for ip, _ := range ips {
			wm := icmp.Message{
				Type: ipv4.ICMPTypeEcho, Code: 0,
				Body: &icmp.Echo{
					ID: os.Getpid() & 0xffff, Seq: 1,
					Data: []byte("STRATUX"),
				},
			}
			wb, err := wm.Marshal(nil)
			if err != nil {
				log.Printf("couldn't send ICMP Echo: %s\n", err.Error())
				continue
			}
			if _, err := c.WriteTo(wb, &net.IPAddr{IP: net.ParseIP(ip)}); err != nil {
				log.Printf("couldn't send ICMP Echo: %s\n", err.Error())
				continue
			}
			totalNetworkMessagesSent++
		}
	}
}
예제 #3
0
func ping(listener *icmp.PacketConn, message icmp.Message, raddr net.Addr, timeout time.Duration) (Pong, error) {
	data, err := message.Marshal(nil)
	if err != nil {
		return Pong{}, err
	}
	_, err = listener.WriteTo(data, raddr)
	if err != nil {
		return Pong{}, err
	}
	now := time.Now()
	done := make(chan Pong)
	go func() {
		for {
			buf := make([]byte, 10000)
			// bufio
			n, peer, err := listener.ReadFrom(buf)
			if err != nil {
				return
			}
			since := time.Since(now)
			input, err := icmp.ParseMessage(protocolICMP, buf[:n])
			if err != nil {
				return
			}
			if input.Type != ipv4.ICMPTypeEchoReply {
				continue
			}
			echo := input.Body.(*icmp.Echo)
			pong := Pong{
				Peer: peer,
				ID:   echo.ID,
				Seq:  echo.Seq,
				Data: echo.Data,
				Size: n,
				RTT:  since,
			}
			done <- pong
			return
		}
	}()
	select {
	case pong := <-done:
		return pong, nil
	case <-time.After(timeout):
		return Pong{}, errors.New("Timeout")
	}
}
예제 #4
0
// This checks if we can convert an URL to an IP
func testDNS(pr *pingResponse, pi pingInfo, conn *icmp.PacketConn) {
	start := time.Now()
	msg := createMessage()

	msg_bytes, err := msg.Marshal(nil)
	if err != nil {
		emsg := "Could not marshal the message to []byte."
		logger.WriteString(emsg)
		pr.err = errors.New(emsg)
		return
	}

	ip, _ := net.LookupHost(pi.externalurl)

	if _, err := conn.WriteTo(msg_bytes, &net.UDPAddr{IP: net.ParseIP(ip[0]), Zone: "en0"}); err != nil {
		emsg := "Could not write to the internal ip address: " + ip[0]
		logger.WriteString(emsg)
		pr.external_url = false
		pr.err = errors.New(emsg)
		return
	}

	pr.external_url = true

	response := make([]byte, 1500)
	count, peer, err := conn.ReadFrom(response)
	if err != nil {
		emsg := "Could not read the response."
		logger.WriteString(emsg)
		pr.external_url = false
		pr.err = errors.New(emsg)
		return
	}

	_, err = icmp.ParseMessage(protocolICMP, response[:count])
	if err != nil {
		emsg := "Could not parse the message received."
		logger.WriteString(emsg)
		pr.external_url = false
		pr.err = errors.New(emsg)
		return
	}

	logger.WriteString("Response " + strconv.Itoa(sequence) + " received from " + peer.String() +
		" after " + time.Now().Sub(start).String())
}
예제 #5
0
파일: ping.go 프로젝트: sparrc/go-ping
func (p *Pinger) sendICMP(conn *icmp.PacketConn) error {
	var typ icmp.Type
	if p.ipv4 {
		typ = ipv4.ICMPTypeEcho
	} else {
		typ = ipv6.ICMPTypeEchoRequest
	}

	var dst net.Addr = p.ipaddr
	if p.network == "udp" {
		dst = &net.UDPAddr{IP: p.ipaddr.IP, Zone: p.ipaddr.Zone}
	}

	t := timeToBytes(time.Now())
	if p.size-timeSliceLength != 0 {
		t = append(t, byteSliceOfSize(p.size-timeSliceLength)...)
	}
	bytes, err := (&icmp.Message{
		Type: typ, Code: 0,
		Body: &icmp.Echo{
			ID:   rand.Intn(65535),
			Seq:  p.sequence,
			Data: t,
		},
	}).Marshal(nil)
	if err != nil {
		return err
	}

	for {
		if _, err := conn.WriteTo(bytes, dst); err != nil {
			if neterr, ok := err.(*net.OpError); ok {
				if neterr.Err == syscall.ENOBUFS {
					continue
				}
			}
		}
		p.PacketsSent += 1
		p.sequence += 1
		break
	}
	return nil
}
func Send_UDP_Ping(c *icmp.PacketConn, targetIP string, concurrent int, timeout int, ch_lock chan struct{}, rCache *ResultCache) {
	ch_lock <- struct{}{}
	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 {
		return
	}
	timeForSend := time.Now()
	c.SetReadDeadline(timeForSend.Add(time.Duration(timeout) * time.Second))
	rCache.New(targetIP)
	if _, err := c.WriteTo(wb, &net.UDPAddr{IP: net.ParseIP(targetIP)}); err != nil {
		return
	}
	time.Sleep(time.Second)
	<-ch_lock
}
예제 #7
0
func (p *Pinger) sendICMP(conn, conn6 *icmp.PacketConn) (map[string]*net.IPAddr, error) {
	p.debugln("sendICMP(): Start")
	p.mu.Lock()
	p.id = rand.Intn(0xffff)
	p.seq = rand.Intn(0xffff)
	p.mu.Unlock()
	queue := make(map[string]*net.IPAddr)
	wg := new(sync.WaitGroup)
	for key, addr := range p.addrs {
		var typ icmp.Type
		var cn *icmp.PacketConn
		if isIPv4(addr.IP) {
			typ = ipv4.ICMPTypeEcho
			cn = conn
		} else if isIPv6(addr.IP) {
			typ = ipv6.ICMPTypeEchoRequest
			cn = conn6
		} else {
			continue
		}
		if cn == nil {
			continue
		}

		t := timeToBytes(time.Now())

		if p.Size-TimeSliceLength != 0 {
			t = append(t, byteSliceOfSize(p.Size-TimeSliceLength)...)
		}

		p.mu.Lock()
		bytes, err := (&icmp.Message{
			Type: typ, Code: 0,
			Body: &icmp.Echo{
				ID: p.id, Seq: p.seq,
				Data: t,
			},
		}).Marshal(nil)
		p.mu.Unlock()
		if err != nil {
			wg.Wait()
			return queue, err
		}

		queue[key] = addr
		var dst net.Addr = addr
		if p.network == "udp" {
			dst = &net.UDPAddr{IP: addr.IP, Zone: addr.Zone}
		}

		p.debugln("sendICMP(): Invoke goroutine")
		wg.Add(1)
		go func(conn *icmp.PacketConn, ra net.Addr, b []byte) {
			for {
				if _, err := conn.WriteTo(bytes, ra); err != nil {
					if neterr, ok := err.(*net.OpError); ok {
						if neterr.Err == syscall.ENOBUFS {
							continue
						}
					}
				}
				break
			}
			p.debugln("sendICMP(): WriteTo End")
			wg.Done()
		}(cn, dst, bytes)
	}
	wg.Wait()
	p.debugln("sendICMP(): End")
	return queue, nil
}
예제 #8
0
func (p *Pinger) sendICMP(conn, conn6 *icmp.PacketConn) error {
	type sendResult struct {
		addr *net.IPAddr
		err  error
	}

	p.id = rand.Intn(0xffff)
	p.seq = rand.Intn(0xffff)
	p.sent = make(map[string]*net.IPAddr)

	addrs := make(chan *net.IPAddr)
	results := make(chan sendResult, 1)
	errors := make(chan []error)

	collectErrors := func(results <-chan sendResult, errors chan<- []error) {
		var errs []error
		for r := range results {
			errs = append(errs, r.err)
		}
		errors <- errs
	}
	go collectErrors(results, errors)

	wg := new(sync.WaitGroup)
	sendPacket := func(addrs <-chan *net.IPAddr, results chan<- sendResult) {
		defer wg.Done()

		for addr := range addrs {
			var typ icmp.Type
			var cn *icmp.PacketConn
			if isIPv4(addr.IP) {
				typ = ipv4.ICMPTypeEcho
				cn = conn
			} else if isIPv6(addr.IP) {
				typ = ipv6.ICMPTypeEchoRequest
				cn = conn6
			} else {
				continue
			}
			if cn == nil {
				continue
			}

			t := timeToBytes(time.Now())

			if p.Size-TimeSliceLength != 0 {
				t = append(t, make([]byte, p.Size-TimeSliceLength)...)
			}

			bytes, err := (&icmp.Message{
				Type: typ, Code: 0,
				Body: &icmp.Echo{
					ID: p.id, Seq: p.seq,
					Data: t,
				},
			}).Marshal(nil)

			if err != nil {
				results <- sendResult{addr: nil, err: err}
				return
			}

			var dst net.Addr = addr
			if p.network == "udp" {
				dst = &net.UDPAddr{IP: addr.IP, Zone: addr.Zone}
			}

			// pre-add ip to sent
			addrString := addr.String()
			p.mu.Lock()
			p.sent[addrString] = addr
			p.mu.Unlock()

			for {
				if _, err := cn.WriteTo(bytes, dst); err != nil {
					if neterr, ok := err.(*net.OpError); ok {
						if neterr.Err == syscall.ENOBUFS {
							continue
						} else {
							// remove ip from `sent` list if not ok
							p.mu.Lock()
							delete(p.sent, addrString)
							p.mu.Unlock()
						}
					}
				}
				break
			}
		}
	}

	wg.Add(p.NumGoroutines)
	for i := 0; i < p.NumGoroutines; i++ {
		go sendPacket(addrs, results)
	}

	for _, addr := range p.addrs {
		addrs <- addr
	}

	close(addrs)
	wg.Wait()
	close(results)
	errs := <-errors

	if len(errs) > 0 {
		return errs[0]
	}
	return nil
}
예제 #9
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
}
예제 #10
0
파일: loop.go 프로젝트: andrewkroh/beats
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
}
예제 #11
0
func (self *HikarianIcmp) transportServer(clientConn *icmp.PacketConn, caddr net.Addr, dataChannel chan []byte) {
	for {
		body, ok := <-dataChannel
		if ok == false {
			return
		}
		hash := binary.BigEndian.Uint16(body[0:2]) + binary.BigEndian.Uint16(body[2:4])
		serverConn := self.TCPPool.Get(hash)
		if serverConn == nil {
			server, err := net.ResolveTCPAddr("tcp", self.server)
			if err != nil {
				log.Fatalln("resolve server address error: ", err.Error())
			}
			serverConn, err = net.DialTCP("tcp", nil, server)
			if err != nil {
				log.Println("connect remote address error:", err)
				return
			}
			// serverConn.SetDeadline(time.Now().Add(time.Second * 5))
			self.TCPPool.Set(hash, serverConn)
		}
		nw, err := serverConn.Write(body[4:])
		if err != nil {
			log.Println("write server error: ", err.Error())
			return
		}
		log.Println("get echo reply size ", nw)
		readChannel := make(chan []byte)
		go func() {
			rb := make([]byte, 1024)
			for {
				nr, err := serverConn.Read(rb)
				if err != nil && err != io.EOF {
					log.Println("read server error: ", err.Error())
					close(readChannel)
					return
				}
				if nr == 0 {
					continue
				}
				log.Println("read ", nr)
				readChannel <- rb[:nr]
			}
		}()
		go func() {
			for {
				wb, ok := <-readChannel
				if ok == false {
					return
				}
				log.Println("read from channel ", len(wb))
				reply, err := (&icmp.Message{
					Type: ipv4.ICMPTypeEchoReply,
					Code: MagicCode,
					Body: &icmp.Echo{
						ID:   int(binary.BigEndian.Uint16((body[0:2]))),
						Seq:  int(binary.BigEndian.Uint16((body[2:4]))),
						Data: wb,
					},
				}).Marshal(nil)
				if err != nil {
					log.Println("marshal echo reply error: ", err.Error())
					return
				}
				numWrite, err := clientConn.WriteTo(reply, caddr)
				if err != nil {
					log.Println("write echo reply error: ", err.Error())
					return
				}
				log.Println("write echo reply size ", numWrite)
			}
		}()
	}
}
예제 #12
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
		}
	}
}