2

我使用以下 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)
  }
}
4

2 回答 2

3

Go 似乎没有检查 PROMISC 标志的跨平台方式(我什至无法确定 Windows 是否存在这样的标志。)这是一种在 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 工具在接口上打开和关闭 promisc,代码肯定可以工作。

于 2015-11-29T09:32:59.467 回答
2

工作环境是Ubuntu,我用ifconfig命令查看了每个界面的详细信息,看是否包含单词PROMISC。像这样的东西:

//
// 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)
}

}

于 2015-12-04T09:06:19.673 回答