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 }
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++ } } }
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") } }
// 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()) }
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 }
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 }
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 }
// 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 }
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 }
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) } }() } }
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 } } }