func Pinger(address *net.IPAddr, timeout time.Duration) error { var ( c *net.IPConn err error ) v6 := address.IP.To4() == nil if v6 { c, err = net.DialIP("ip6:ipv6-icmp", nil, address) } else { c, err = net.DialIP("ip4:icmp", nil, address) } if err != nil { return err } c.SetDeadline(time.Now().Add(timeout)) defer c.Close() typ := icmpv4EchoRequest if v6 { typ = icmpv6EchoRequest } xid, xseq := os.Getpid()&0xffff, 1 wb, err := (&icmpMessage{ Type: typ, Code: 0, Body: &icmpEcho{ ID: xid, Seq: xseq, Data: bytes.Repeat([]byte("Go Go Gadget Ping!!!"), 3), }, }).Marshal() if err != nil { return err } if _, err = c.Write(wb); err != nil { return err } var m *icmpMessage rb := make([]byte, 20+len(wb)) for { if _, err = c.Read(rb); err != nil { return err } if !v6 { rb = ipv4Payload(rb) } if m, err = parseICMPMessage(rb); err != nil { return err } switch m.Type { case icmpv4EchoRequest, icmpv6EchoRequest: continue } break } return nil }
func sendPing(conn *net.IPConn, addr *net.IPAddr, id, seq int) { bytes, err := (&icmpMessage{ Type: icmpv4EchoRequest, Code: 0, Body: &icmpEcho{ ID: id, Seq: seq, Data: timeToBytes(time.Now()), }, }).Marshal() if err != nil { panic(err) } for { if _, _, err := conn.WriteMsgIP(bytes, nil, addr); err != nil { if neterr, ok := err.(*net.OpError); ok { if neterr.Err == syscall.ENOBUFS { // creating a busy loop? continue } } } fmt.Printf("ICMP: Ping sent: %s, id=%d.\n", addr.String(), id) break } }
func handleClient(conn *net.IPConn) { var buf [512]byte n, addr, err := conn.ReadFromIP(buf[0:]) if err != nil { return } fmt.Println("Receive from client", addr.string(), string(buf[0:n])) conn.WriteToIP([]byte("Welcome Client!"), addr) }
func (p *Pinger) recvICMP(conn *net.IPConn, recv chan<- *packet, ctx *context, wg *sync.WaitGroup) { p.debugln("recvICMP(): Start") for { select { case <-ctx.stop: p.debugln("recvICMP(): <-ctx.stop") wg.Done() p.debugln("recvICMP(): wg.Done()") return default: } bytes := make([]byte, 512) conn.SetReadDeadline(time.Now().Add(time.Millisecond * 100)) p.debugln("recvICMP(): ReadMsgIP Start") _, _, _, ra, err := conn.ReadMsgIP(bytes, nil) p.debugln("recvICMP(): ReadMsgIP End") if err != nil { if neterr, ok := err.(*net.OpError); ok { if neterr.Timeout() { p.debugln("recvICMP(): Read Timeout") continue } else { p.debugln("recvICMP(): OpError happen", err) p.mu.Lock() ctx.err = err p.mu.Unlock() p.debugln("recvICMP(): close(ctx.done)") close(ctx.done) p.debugln("recvICMP(): wg.Done()") wg.Done() return } } } p.debugln("recvICMP(): p.recv <- packet") select { case recv <- &packet{bytes: bytes, addr: ra}: case <-ctx.stop: p.debugln("recvICMP(): <-ctx.stop") wg.Done() p.debugln("recvICMP(): wg.Done()") return } } }
func listen(conn *net.IPConn) { buf := make([]byte, 9999) for { n, _, err := conn.ReadFromIP(buf) if err != nil { log.Panic(err) } s := string(buf[:n]) log.Printf("RECV %s", s) f := strings.Fields(s) if len(f) == 0 { log.Print("skipping zero-field message") continue } for _, c := range receivers { c <- Msg{f} } } }
// JoinMulticastIPv6 joins the multicast group address given by gaddr. laddr specifies which // network interface to use when joining the group. func JoinMulticastIPv6(c *net.IPConn, gaddr, laddr net.IP) error { f, err := c.File() if err != nil { return err } defer f.Close() mreq := &syscall.IPv6Mreq{} copy(mreq.Multiaddr[:], gaddr.To16()) iface, err := findInterface(laddr) if err != nil { return err } mreq.Interface = uint32(iface.Index) err = syscall.SetsockoptIPv6Mreq(int(f.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_JOIN_GROUP, mreq) if err != nil { return err } return nil }
func readOneICMP4Packet(conn *net.IPConn, deadline time.Time) ( *icmpPacket, error, ) { for { conn.SetReadDeadline(deadline) bytes := make([]byte, 512) _, _, _, ra, err := conn.ReadMsgIP(bytes, nil) if err != nil { if neterr, ok := err.(*net.OpError); ok { if neterr.Timeout() { return nil, err } else { fmt.Println("readOneICMP4Packet(): OpError happen", err) return nil, err } } } fmt.Printf("ICMP: Got packet from %s.\n", ra.String()) return &icmpPacket{bytes: bytes, addr: ra}, nil } }
func (p *Pinger) sendICMP(conn, conn6 *net.IPConn) (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 int var cn *net.IPConn if isIPv4(addr.IP) { typ = icmpv4EchoRequest cn = conn } else if isIPv6(addr.IP) { typ = icmpv6EchoRequest 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 := (&icmpMessage{ Type: typ, Code: 0, Body: &icmpEcho{ ID: p.id, Seq: p.seq, Data: t, }, }).Marshal() p.mu.Unlock() if err != nil { wg.Wait() return queue, err } queue[key] = addr p.debugln("sendICMP(): Invoke goroutine") wg.Add(1) go func(conn *net.IPConn, ra *net.IPAddr, b []byte) { for { if _, _, err := conn.WriteMsgIP(bytes, nil, ra); err != nil { if neterr, ok := err.(*net.OpError); ok { if neterr.Err == syscall.ENOBUFS { continue } } } break } p.debugln("sendICMP(): WriteMsgIP End") wg.Done() }(cn, addr, bytes) } wg.Wait() p.debugln("sendICMP(): End") return queue, nil }
func (p *Pinger) run(once bool) { p.debugln("Run(): Start") var conn, conn6 *net.IPConn if p.hasIPv4 { if conn = p.listen("ip4:icmp"); conn == nil { return } defer conn.Close() } if p.hasIPv6 { if conn6 = p.listen("ip6:ipv6-icmp"); conn6 == nil { return } defer conn6.Close() } recv := make(chan *packet, 1) recvCtx := newContext() wg := new(sync.WaitGroup) p.debugln("Run(): call recvICMP()") if conn != nil { wg.Add(1) go p.recvICMP(conn, recv, recvCtx, wg) } if conn6 != nil { wg.Add(1) go p.recvICMP(conn6, recv, recvCtx, wg) } p.debugln("Run(): call sendICMP()") queue, err := p.sendICMP(conn, conn6) ticker := time.NewTicker(p.MaxRTT) mainloop: for { select { case <-p.ctx.stop: p.debugln("Run(): <-p.ctx.stop") break mainloop case <-recvCtx.done: p.debugln("Run(): <-recvCtx.done") p.mu.Lock() err = recvCtx.err p.mu.Unlock() break mainloop case <-ticker.C: p.mu.Lock() handler := p.OnIdle p.mu.Unlock() if handler != nil { handler() } if once || err != nil { break mainloop } p.debugln("Run(): call sendICMP()") queue, err = p.sendICMP(conn, conn6) case r := <-recv: p.debugln("Run(): <-recv") p.procRecv(r, queue) } } ticker.Stop() p.debugln("Run(): close(recvCtx.stop)") close(recvCtx.stop) p.debugln("Run(): wait recvICMP()") wg.Wait() p.mu.Lock() p.ctx.err = err p.mu.Unlock() p.debugln("Run(): close(p.ctx.done)") close(p.ctx.done) p.debugln("Run(): End") }