英文:
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 (
"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)
}
}
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 <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)
}
}
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("/bin/sh", "-c", "ifconfig").Output()
var ifc Iface
var ifaceset []Iface
//
// split the output to handle each interface separately
//
var ifaceDetails = strings.Split(string(out), "\n\n")
//
// iterate interfaces
//
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
}
//
// 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, "PROMISC") {
ifc.Promisc = true
} else {
ifc.Promisc = false
}
}
}
ifaceset = append(ifaceset, ifc)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论