如何在Python中调用SIOCSIFHWADDR ioctl来更改MAC地址?

1 投票
3 回答
6299 浏览
提问于 2025-04-16 18:28

我有一段Python代码,它用来创建一个Linux的TAP接口,但每次创建时,系统都会自动生成一个随机的MAC地址。为了方便测试,我想在接口初始化后手动指定一个MAC地址。我知道可以通过这个ioctl命令和结构来实现,但我对具体的实现有几个问题。

这里是C语言中的结构体:

struct ifreq
{
# define IFHWADDRLEN    6
# define IFNAMSIZ       IF_NAMESIZE
union
  {
    char ifrn_name[IFNAMSIZ];       /* Interface name, e.g. "en0".  */
  } ifr_ifrn;

union
  {
    struct sockaddr ifru_addr;
    struct sockaddr ifru_dstaddr;
    struct sockaddr ifru_broadaddr;
    struct sockaddr ifru_netmask;
    struct sockaddr ifru_hwaddr;
    short int ifru_flags;
    int ifru_ivalue;
    int ifru_mtu;
    struct ifmap ifru_map;
    char ifru_slave[IFNAMSIZ];      /* Just fits the size */
    char ifru_newname[IFNAMSIZ];
    __caddr_t ifru_data;
  } ifr_ifru;
};

我觉得我只需要填写这个字段,但因为这是一个联合体,我不太确定在Python中该如何创建这个结构。

在Python中,调用这个ioctl命令并使用来改变接口的MAC地址,最好的方法是什么呢?

谢谢!

3 个回答

0

你可以把/sbin/ip当作一个子进程来启动,比如这样:

/sbin/ip link set dev dummy0 address 02:23:45:67:89:ab

这样做可以省去很多麻烦。

0

一个 union 的意思就是可以用多种方式来理解里面的内容。你只需要关注其中一种,这种:

struct ifreq_set_hwaddr
{
# define IFHWADDRLEN    6
# define IFNAMSIZ       IF_NAMESIZE
    char ifrn_name[IFNAMSIZ];       /* Interface name, e.g. "en0".  */
    struct sockaddr ifru_hwaddr;
};

注意,我假设 struct sockaddr 的对齐要求和其他的 union 成员是一样的(或者是最严格的)。如果不是,你可能需要添加一些填充。

6

来自: http://nullege.com/codes/show/src@p@y@pynetlinux-1.0@pynetlinux@ifconfig.py

def set_mac(self, newmac):
    ''' Set the device's mac address. Device must be down for this to
        succeed. '''
    macbytes = [int(i, 16) for i in newmac.split(':')]
    ifreq = struct.pack('16sH6B8x', self.name, AF_UNIX, *macbytes)
    fcntl.ioctl(sockfd, SIOCSIFHWADDR, ifreq)

我用过这个模块里的很多网络方法,真的很有用!

撰写回答