func ping(ip string) error { c, err := net.Dial("ip4:icmp", ip) if err != nil { panic(err) } glog.V(4).Infof("icmp to %s\n", ip) c.SetDeadline(time.Now().Add(time.Second)) defer c.Close() typ := icmpv4EchoRequest xid := os.Getpid() & 0xffff xseq := 1 wb, err := (&icmpMessage{Type: typ, Code: 0, Body: &icmpEcho{ID: xid, Seq: xseq, Data: bytes.Repeat([]byte("Go ping"), 10)}}).Marshal() if err != nil { return err } if _, err := c.Write(wb); err != nil { return err } rb := make([]byte, 20+len(wb)) var m *icmpMessage for { if _, err := c.Read(rb); err != nil { if strings.HasSuffix(err.Error(), "i/o timeout") { return fmt.Errorf("timeout: %v", err) } else { return (err) } } rb = ipv4Payload(rb) if m, err = parseICMPMessage(rb); err != nil { return (err) } switch m.Type { case icmpv4EchoRequest: continue } break } switch p := m.Body.(type) { case *icmpEcho: if p.ID != xid || p.Seq != xseq { fmt.Printf("bad xid %d != %d seq %d != %d\n", p.ID, xid, p.Seq, xseq) return fmt.Errorf("bad xid") } default: return fmt.Errorf("bad type") } glog.V(2).Infof("got %v", m) return nil }
func main() { var CIDR, dev, OUIFile string var timeout int64 JSON := false flag.BoolVar(&JSON, "json", false, "output JSON") flag.StringVar(&CIDR, "cidr", "", "CIDR to scan") flag.StringVar(&OUIFile, "ouifile", "ieee-oui.txt", "IEEE OUI database text file") flag.StringVar(&dev, "dev", "", "net device to use") flag.Int64Var(&timeout, "timeout", 5, "seconds to timeout") flag.Parse() if dev == "" || CIDR == "" { flag.Usage() os.Exit(1) } ch := make(chan *pingcap.PingScanResult, 1) startTime := time.Now().Unix() go func() { for { time.Sleep(time.Second) if (time.Now().Unix() - startTime) > timeout { glog.V(2).Infof("stopping after %d seconds.", timeout) os.Exit(1) } } }() go func() { for { res := <-ch if res.Type == "scan" { if JSON { jstr, err := json.Marshal(res.Scan) if err != nil { glog.Errorf("marshalling error: %v", err) continue } fmt.Println(string(jstr)) } else { fmt.Println(res.Scan) } } } }() err := pingcap.PingScan(CIDR, OUIFile, dev, ch) if err != nil { panic(err) } }
func pingAll(CIDR string, ch chan *PingScanResult) { ip, ipnet, err := net.ParseCIDR(CIDR) if err != nil { glog.Fatal(err) } targets := make([]string, 0) for ip := ip.Mask(ipnet.Mask); ipnet.Contains(ip); inc(ip) { glog.V(4).Infof("adding %v", ip) targets = append(targets, ip.String()) } var wg sync.WaitGroup for _, ip := range targets { wg.Add(1) go func(ipa string) { ping(ipa) psRes := PingScanResult{} psRes.Type = "ping" ch <- &psRes wg.Done() }(ip) } wg.Wait() }
func PingScan(CIDR, OUIFile, dev string, ch chan *PingScanResult) error { h, err := pcap.OpenLive(dev, 256, true, 500) if err != nil { return err } defer h.Close() err = h.SetFilter("icmp") if err != nil { return err } go func() { pingAll(CIDR, ch) }() ouiDB := make(map[string]string) ouiFileExists := true f, err := os.OpenFile(OUIFile, os.O_RDONLY, 0666) if err != nil { ouiFileExists = false } defer f.Close() if ouiFileExists { fc, err := ioutil.ReadFile(OUIFile) if err == nil { lines := strings.Split(string(fc), "\n") for _, line := range lines { if line == "" || strings.HasPrefix(line, "#") { continue } fields := strings.Fields(line) ouiDB[fields[0]] = strings.Join(fields[1:], " ") } } } sres := []ScanResult{} // REDFLAG: cannot put this loop in goroutine because of // runtime.sigpanic from pkg/runtime/os_linux.c:222 for pkt, r := h.NextEx(); r >= 0; pkt, r = h.NextEx() { if r == 0 { continue } pkt.Decode() srcVend := "?" destVend := "?" if len(ouiDB) > 0 { srcVend = fmt.Sprintf("%02X%02X%02X", pkt.SrcMac&0xff0000000000>>40, pkt.SrcMac&0xff00000000>>32, pkt.SrcMac&0xff000000>>24) srcVend = ouiDB[srcVend] destVend = fmt.Sprintf("%02X%02X%02X", pkt.DestMac&0xff0000000000>>40, pkt.DestMac&0xff00000000>>32, pkt.DestMac&0xff000000>>24) destVend = ouiDB[destVend] } glog.V(2).Infof("pkt: ether[%02X:%012X(%s):%012X(%s)] %v", pkt.Type, pkt.DestMac, destVend, pkt.SrcMac, srcVend, pkt) sr := ScanResult{} sr.SrcMACAddr = fmt.Sprintf("%012X", pkt.SrcMac) sr.SrcVendor = srcVend sr.SrcIPAddr = "" var ip *pcap.Iphdr for _, h := range pkt.Headers { glog.Infof("%v", reflect.TypeOf(h)) if reflect.TypeOf(h) == reflect.TypeOf(ip) { ip = h.(*pcap.Iphdr) sr.SrcIPAddr = ip.SrcAddr() } } sres = append(sres, sr) psRes := PingScanResult{} psRes.Type = "scan" psRes.Scan = sr ch <- &psRes } //not reached glog.V(2).Infof("exiting pcap capture. %v", h.Geterror()) return nil }