Golang – 获取网络接口的混杂模式状态

huangapple go评论96阅读模式
英文:

Golang - get promiscuous mode status of network interfaces

问题

我使用以下Go代码来获取有关网络接口的一些信息。您对如何获取每个接口的混杂模式状态有什么建议吗?

type Iface struct {
    Name      string `json:"name"`
    Status    string `json:"status"`
    Multicast bool   `json:"multicast"`
    Broadcast bool   `json:"broadcast"`
}

func (c *InterfacesController) GetInterfaces() {
    interfaces, err := net.Interfaces()

    if err != nil {
        fmt.Println(err)
        return
    }

    var ifaceset []Iface
    var ifc Iface

    for _, i := range interfaces {
        ifc.Name = i.Name
        if strings.Contains(i.Flags.String(), "up") {
            ifc.Status = "UP"
        } else {
            ifc.Status = "DOWN"
        }
        if strings.Contains(i.Flags.String(), "multicast") {
            ifc.Multicast = true
        } else {
            ifc.Multicast = false
        }
        if strings.Contains(i.Flags.String(), "broadcast") {
            ifc.Broadcast = true
        } else {
            ifc.Broadcast = false
        }
        ifaceset = append(ifaceset, ifc)
    }
}

以上是您提供的代码。您想知道如何获取每个接口的混杂模式状态。

英文:

I use the following Go code to get some info about the network interfaces. Any suggestions on how I would be able to get the status of promiscuous mode for each interface?

type Iface struct {
  Name      string `json:"name"`
  Status    string `json:"status"`
  Multicast bool   `json:"multicast"`
  Broadcast bool   `json:"broadcast"`
}

func (c *InterfacesController) GetInterfaces() {
  interfaces, err := net.Interfaces()

  if err != nil {
	fmt.Println(err)
	return
  }

  var ifaceset []Iface
  var ifc Iface

  for _, i := range interfaces {
	ifc.Name = i.Name
	if strings.Contains(i.Flags.String(), "up") {
		ifc.Status = "UP"
	} else {
		ifc.Status = "DOWN"
	}
	if strings.Contains(i.Flags.String(), "multicast") {
		ifc.Multicast = true
	} else {
		ifc.Multicast = false
	}
	if strings.Contains(i.Flags.String(), "broadcast") {
		ifc.Broadcast = true
	} else {
		ifc.Broadcast = false
	}
	ifaceset = append(ifaceset, ifc)
  }
}

答案1

得分: 3

Go语言似乎没有一种跨平台的方式来检查PROMISC标志(我甚至无法确定Windows是否存在这样的标志)。以下是在Linux上获取该标志的方法,我猜你正在使用Linux:

package main

import (
	"fmt"
	"net"
	"os"
	"syscall"
	"unsafe"
)

func GetPromiscuous(i net.Interface) (bool, error) {
	tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
	if err != nil {
		return false, os.NewSyscallError("netlinkrib", err)
	}
	msgs, err := syscall.ParseNetlinkMessage(tab)
	if err != nil {
		return false, os.NewSyscallError("parsenetlinkmessage", err)
	}
loop:
	for _, m := range msgs {
		switch m.Header.Type {
		case syscall.NLMSG_DONE:
			break loop
		case syscall.RTM_NEWLINK:
			ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&m.Data[0]))
			if ifim.Index == int32(i.Index) {
				return (ifim.Flags & syscall.IFF_PROMISC) != 0, nil
			}
		}
	}
	return false, os.ErrNotExist
}

func main() {
	ints, err := net.Interfaces()
	if err != nil {
		panic(err)
	}

	for _, i := range ints {
		p, err := GetPromiscuous(i)
		if err != nil {
			panic(err)
		}
		fmt.Println(i.Name, p)
	}
}

这是基于标准库中的interfaceTable函数。它使用rtnetlink获取接口的标志。除非你想自己编写syscall.NetlinkRIB函数,否则该代码将始终获取每个网络设备的信息并过滤出所请求的信息。

另一种获取所需标志的方法是使用cgo和ioctl:

package main

/*
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>

bool is_promisc(char *name) {
    int s = socket(AF_INET, SOCK_STREAM, 0);
    struct ifreq *i = malloc(sizeof *i);

    strncpy((char *)&(i->ifr_name), name, IFNAMSIZ);

    ioctl(s, SIOCGIFFLAGS, i);

	bool p = (i->ifr_flags & IFF_PROMISC) != 0;

	free(i);

	return p;
}
*/
import "C"
import (
	"fmt"
	"net"
)

func GetPromiscuous(i net.Interface) (bool, error) {
	set, err := C.is_promisc(C.CString(i.Name))
	return bool(set), err
}

func main() {
	ints, err := net.Interfaces()
	if err != nil {
		panic(err)
	}

	for _, i := range ints {
		p, err := GetPromiscuous(i)
		if err != nil {
			panic(err)
		}
		fmt.Println(i.Name, p)
	}

}

最后要注意的是,无论哪种方法,都可能无法准确告诉你接口是否实际处于混杂模式。请参阅此线程以获取更多详细信息。

根据我所了解,使用netlink路由应该能正常工作,但另一篇帖子说我们应该检查混杂计数。如果有人知道如何做到这一点,请告诉我,因为我找不到相关信息。关于这个问题,唯一的stackoverflow问题没有得到回答。

我认为只要你不进行任何复杂的网络操作(如桥接、VLAN接口、macvtap等),这两种方法都可以正常工作。如果你使用iproute2工具在接口上打开和关闭混杂模式,代码肯定可以正常工作。

英文:

It doesn't appear Go has a cross-platform way of checking the PROMISC flag (I can't even find out for sure if such a flag exists for windows.) Here is a way to get it on linux, which I'm guessing you're on:

package main

import (
	&quot;fmt&quot;
	&quot;net&quot;
	&quot;os&quot;
	&quot;syscall&quot;
	&quot;unsafe&quot;
)

func GetPromiscuous(i net.Interface) (bool, error) {
	tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
	if err != nil {
		return false, os.NewSyscallError(&quot;netlinkrib&quot;, err)
	}
	msgs, err := syscall.ParseNetlinkMessage(tab)
	if err != nil {
		return false, os.NewSyscallError(&quot;parsenetlinkmessage&quot;, err)
	}
loop:
	for _, m := range msgs {
		switch m.Header.Type {
		case syscall.NLMSG_DONE:
			break loop
		case syscall.RTM_NEWLINK:
			ifim := (*syscall.IfInfomsg)(unsafe.Pointer(&amp;m.Data[0]))
			if ifim.Index == int32(i.Index) {
				return (ifim.Flags &amp; syscall.IFF_PROMISC) != 0, nil
			}
		}
	}
	return false, os.ErrNotExist
}

func main() {
	ints, err := net.Interfaces()
	if err != nil {
		panic(err)
	}

	for _, i := range ints {
		p, err := GetPromiscuous(i)
		if err != nil {
			panic(err)
		}
		fmt.Println(i.Name, p)
	}
}

This is based of the interfaceTable function in the standard library. It uses rtnetlink to get the flags of the interface. Unless you want to roll your own syscall.NetlinkRIB function, this code will always pull the information for every network device and filter out the requested one.

A bit less magical way to get the flag you want is to use cgo and ioctl:

package main

/*
#include &lt;stdlib.h&gt;
#include &lt;stdbool.h&gt;
#include &lt;string.h&gt;
#include &lt;sys/socket.h&gt;
#include &lt;sys/ioctl.h&gt;
#include &lt;net/if.h&gt;

bool is_promisc(char *name) {
    int s = socket(AF_INET, SOCK_STREAM, 0);
    struct ifreq *i = malloc(sizeof *i);

    strncpy((char *)&amp;(i-&gt;ifr_name), name, IFNAMSIZ);

    ioctl(s, SIOCGIFFLAGS, i);

	bool p = (i-&gt;ifr_flags &amp; IFF_PROMISC) != 0;

	free(i);

	return p;
}
*/
import &quot;C&quot;
import (
	&quot;fmt&quot;
	&quot;net&quot;
)

func GetPromiscuous(i net.Interface) (bool, error) {
	set, err := C.is_promisc(C.CString(i.Name))
	return bool(set), err
}

func main() {
	ints, err := net.Interfaces()
	if err != nil {
		panic(err)
	}

	for _, i := range ints {
		p, err := GetPromiscuous(i)
		if err != nil {
			panic(err)
		}
		fmt.Println(i.Name, p)
	}

}

A final note is that either way may not always tell you correctly whether an interface is actually in promiscuous mode or not. See this thread for more details.

From what I'm reading using the netlink route should work correctly, but another post says we should be checking the promiscuous count. Please let me know if someone knows how to do that, because I can't find how to. The only stackoverflow question on the matter has gone unanswered.

I think either of these methods will work as long as you're not doing any crazy networking stuff (bridge, vlan interfaces, macvtap, etc.) The code definitely works if you use iproute2 tools to turn promisc on and off on an interface.

答案2

得分: 2

工作环境是Ubuntu,我使用ifconfig命令并检查每个接口的详细信息,看看是否包含单词PROMISC。类似这样的代码:

//
// 获取接口
//
interfaces, err := net.Interfaces()

//
// 运行ifconfig命令
//
out, err := exec.Command("/bin/sh", "-c", "ifconfig").Output()

var ifc Iface
var ifaceset []Iface

//
// 拆分输出以单独处理每个接口
//
var ifaceDetails = strings.Split(string(out), "\n\n")

//
// 遍历接口
//
for _, i := range interfaces {
    ifc.Name = i.Name
	if strings.Contains(i.Flags.String(), "up") {
	ifc.Status = "UP"
	} else {
		ifc.Status = "DOWN"
	}
	if strings.Contains(i.Flags.String(), "multicast") {
		ifc.Multicast = true
	} else {
		ifc.Multicast = false
	}
	if strings.Contains(i.Flags.String(), "broadcast") {
		ifc.Broadcast = true
	} else {
		ifc.Broadcast = false
	}

    //
    // 尝试查找单词PROMISC以检查是否为UP
	//
    for _, ifdetails := range ifaceDetails {
		if strings.Contains(ifdetails, i.Name) {
			if strings.Contains(ifdetails, "PROMISC") {
				ifc.Promisc = true
			} else {
				ifc.Promisc = false
			}

		}
	}
	ifaceset = append(ifaceset, ifc)
}

}

英文:

The working environment is Ubuntu, I used the ifconfig command and checked each interface details to see if it contains the word PROMISC. Something like this:

//
// get the interfaces
//
interfaces, err := net.Interfaces()

//
// run the ifconfig command
//
out, err := exec.Command(&quot;/bin/sh&quot;, &quot;-c&quot;, &quot;ifconfig&quot;).Output()

var ifc Iface
var ifaceset []Iface

//
// split the output to handle each interface separately
//
var ifaceDetails = strings.Split(string(out), &quot;\n\n&quot;)

//
// iterate interfaces
//
for _, i := range interfaces {
    ifc.Name = i.Name
	if strings.Contains(i.Flags.String(), &quot;up&quot;) {
	ifc.Status = &quot;UP&quot;
	} else {
		ifc.Status = &quot;DOWN&quot;
	}
	if strings.Contains(i.Flags.String(), &quot;multicast&quot;) {
		ifc.Multicast = true
	} else {
		ifc.Multicast = false
	}
	if strings.Contains(i.Flags.String(), &quot;broadcast&quot;) {
		ifc.Broadcast = true
	} else {
		ifc.Broadcast = false
	}

    //
    // try to find the word PROMISC to check if it is UP
	//
    for _, ifdetails := range ifaceDetails {
		if strings.Contains(ifdetails, i.Name) {
			if strings.Contains(ifdetails, &quot;PROMISC&quot;) {
				ifc.Promisc = true
			} else {
				ifc.Promisc = false
			}

		}
	}
	ifaceset = append(ifaceset, ifc)
}

}

huangapple
  • 本文由 发表于 2015年11月27日 00:02:59
  • 转载请务必保留本文链接:https://go.coder-hub.com/33942828.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定