## 文章关键词
* go/golang
* gopacket
* 抓包
* pcap/libpcap
* arp
* nbns
* mdns
* manuf
## 程序截图
![image.png](http://upload-images.jianshu.io/upload_images/6285600-cec041b47b5f7b1f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
## 说明
本文对于Go语言本身的讲解不会太多,想把更多的时间花在几个网络协议的讲解上,希望本文对打算或正在用Go进行TCP/IP编程和抓包的朋友带来帮助。
github地址:[https://github.com/timest/goscan](https://github.com/timest/goscan)
## 程序思路
* 通过内网IP和子网掩码计算出内网IP范围
* 向内网广播ARP Request
* 监听并抓取ARP Response包,记录IP和Mac地址
* 发活跃IP发送MDNS和NBNS包,并监听和解析Hostname
* 根据Mac地址计算出厂家信息
## 通过内网IP和子网掩码计算出内网IP范围
如果仅仅只是知道一个IP地址,是无法得知内网IP的网段,不能只是简单的把本机IP的最后一个字节改成1-255。需要通过子网掩码来计算得出内网的网段,这块比较简单,这里不赘述了,有疑问的网上搜索子网掩码获取更多资料。值得一提的是IP地址的最后一个字段是不能为0和255,前者是RFC规定,后者一般是广播地址。
```go
// 单网卡模式
addrs, err := net.InterfaceAddrs()
if err != nil {
log.Fatal("无法获取本地网络信息:", err)
}
for i, a := range addrs {
if ip, ok := a.(*net.IPNet); ok && !ip.IP.IsLoopback() {
if ip.IP.To4() != nil {
fmt.Println("IP:", ip.IP)
fmt.Println("子网掩码:", ip.Mask)
it, _ := net.InterfaceByIndex(i)
fmt.Println("Mac地址:", it.HardwareAddr)
break
}
}
}
```
根据上面得到的IPNet,可以算出内网IP范围:
```go
type IP uint32
// 根据IP和mask换算内网IP范围
func Table(ipNet *net.IPNet) []IP {
ip := ipNet.IP.To4()
log.Info("本机ip:", ip)
var min, max IP
var data []IP
for i := 0; i < 4; i++ {
b := IP(ip[i] & ipNet.Mask[i])
min += b << ((3 - uint(i)) * 8)
}
one, _ := ipNet.Mask.Size()
max = min | IP(math.Pow(2, float64(32 - one)) - 1)
log.Infof("内网IP范围:%s --- %s", min, max)
// max 是广播地址,忽略
// i & 0x000000ff == 0 是尾段为0的IP,根据RFC的规定,忽略
for i := min; i < max; i++ {
if i & 0x000000ff == 0 {
continue
}
data = append(data, i)
}
return data
}
```
## 向内网广播ARP Request
> ARP(Address Resolution Protocol),地址解析协议,是根据IP地址获取物理地址的一个TCP/IP协议。主机发送信息时将包含目标IP地址的ARP请求广播到网络上的所有主机,并接收返回消息,以此确定目标的物理地址 ------百度百科
当我们要向以太网中另一台主机发送IP数据时,我们本地会根据目的主机的IP地址在**ARP高速缓存**中查询相应的以太网地址,ARP高速缓存是主机维护的一个IP地址到相应以太网地址的**映射表**。如果查询失败,ARP会广播一个询问(op字段为1)目的主机硬件地址的报文,等待目标主机的响应。
因为ARP高速缓存有时效性,读取到目标主机的硬件地址后,最好发送一个ICMP包验证目标是否在线。当然也可以选择不从高速缓存里读取数据,而是直接并发发送arp包,等待在线主机回应ARP报文。
原文地址:[https://github.com/timest/goscan/issues/1](https://github.com/timest/goscan/issues/1)
有疑问加站长微信联系(非本文作者)