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 }
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 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() }
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 }
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 }
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) } } }
// 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() } }
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 }
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 }
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) } }
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 }
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) } }
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() }
// 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) }
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) } }
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) }
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) } }
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 }
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) } }
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) }
// 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 }
// ListenICMP listens to incoming ICMP packet func ListenICMP() (*icmp.PacketConn, error) { return icmp.ListenPacket("ip4:icmp", "0.0.0.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 } } }
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) } } }
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 }
// 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 }
// 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) } } }