之前用了一个牛逼的App,叫做Fing,它可以获取到本地局域网里面所有设备的IP、MAC地址和设备厂商。一直觉得很牛逼,今天好好想了想,发现也没那么多神秘。
穷举局域网里的IP
局域网IP一般有192
和10
两种形式。一般来说,10
开始的局域网高端一些,能容纳的设备比较多。
穷举所有IP,有一个方式是通过trancert
命令,记录访问某个网站经过的路径,那么第一条路径就是访问路由器,得到路由器IP之后,按最后一部分进行穷举。
但是这个方法有点麻烦,简化一点的,就是获取当前设备在局域网里面的IP,以此IP进行穷举。通过Golang获取IP的方法可以参考[1]。获取当前设备IP的方式可以参考:
func ExternalIP() (string, string, error) {
ifaces, err := net.Interfaces()
if err != nil {
return "", "", err
}
for _, iface := range ifaces {
if iface.Flags&net.FlagUp == 0 {
continue // interface down
}
if iface.Flags&net.FlagLoopback != 0 {
continue // loopback interface
}
addrs, err := iface.Addrs()
if err != nil {
return "", "", err
}
for _, addr := range addrs {
var ip net.IP
switch v := addr.(type) {
case *net.IPNet:
ip = v.IP
case *net.IPAddr:
ip = v.IP
}
if ip == nil || ip.IsLoopback() {
continue
}
ip = ip.To4()
if ip == nil {
continue // not an ipv4 address
}
return ip.String(), iface.HardwareAddr.String(), nil
}
}
return "", "", errors.New("are you connected to the network?")
}
Ping穷举的IP,获取MAC地址。
Ping穷举的IP地址,得到在线设备的IP,然后通过arp
协议得到设备的MAC地址。arp
协议就是用来将IP转换成MAC的协议。这两步可以用在GitHub开源的github.com/j-keck/arping
包辅助实现,这个包的文档可以参考[2]。简单的使用如下:
func Mac(ip string) (net.HardwareAddr, time.Duration, error) {
dstIP := net.ParseIP(ip)
return arping.Ping(dstIP)
}
获取设备的厂商,也就是俗称的Vendor
这步逼格最高。我一直以为设备的Vendor,就像HTTP协议里面的UserAgent
,可以通过这个东西来获取。所以有个协议可以用来得到这些东西。但是没找到。后来发现百度知道(没想到这个东西还是有点用的)里面有位大哥写了。
MAC
地址是国际上有个机构管理(好像是IEEE)的,它能保证每块网卡有不同的MAC
地址。而它在分配这些地址的时候,也不是随机分配的。MAC
地址有6个字节,简单的可以把前三个字节用来表示厂商编号,后3个字节用来区分厂商的网卡编号。那么,我们就能通过前3个字节来得到设备的Vendor
。
在IEEE的网站上,提供了查询方式,我把那个接口提取了出来,是向http://standards.ieee.org/cgi-bin/ouisearch
发送一个POST
的FORM
请求。还要将得到的HTML页面进行解析,就得到了Vendor
。
func Vendor(mac string) (string, error) {
macs := strings.Split(mac, ":")
if len(macs) != 6 {
return "", fmt.Errorf("MAC Error: %s", mac)
}
mac = strings.Join(macs[0:3], "-")
form := url.Values{}
form.Add("x", mac)
form.Add("submit2", "Search!")
res, err := goreq.Request{
Method: "POST",
Uri: "http://standards.ieee.org/cgi-bin/ouisearch",
ContentType: "application/x-www-form-urlencoded",
UserAgent: "Cyeam",
ShowDebug: true,
Body: form.Encode(),
}.Do()
if err != nil {
return "", err
}
body, err := res.Body.ToString()
if err != nil {
return "", err
}
vendor := body[strings.Index(body, strings.ToUpper(mac))+len(mac):]
vendor = strings.TrimLeft(vendor, "</b> (hex)")
vendor = strings.TrimSpace(vendor)
return strings.Split(vendor, "\n")[0], nil
}
HTTP请求通过goreq
发送,FORM请求application/x-www-form-urlencoded
格式,还需要用的net/url
包。
结果
最后放上运行结果:
第一个是我当前运行的设备,网卡是Intel的,剩下的是路由器和手机。
我将上述完整的功能进行封装,本文所涉及到的完整源码请参考。
参考文献
- How do I get the local IP address in Go? - Stackoverflow
- package arping - GoDoc
- go如何读取MAC地址或硬盘ID - Golang中国
- 如何通过MAC地址查询网络设备的厂家和型号 - 百度知道
原文链接:探测局域网里面的设备,转载请注明来源!
有疑问加站长微信联系(非本文作者)