使用ioctl SIOCSIFHWADDR设置MAC要使用ARPHRD_ETHER

本文详细介绍了如何通过使用SIOCSIFHWADDR接口来设置MAC地址,并且强调了在操作前停用网络接口的重要性。文章还包含了设置和修改MAC地址的代码示例,以及调整网络接口状态(启用或禁用)的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用SIOCSIFHWADDR设置MAC要使用ARPHRD_ETHER,且要先停用网络接口。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/if_arp.h>
#define ETHER_ADDR_LEN    6
#define UP    1
#define DOWN    0
int get_mac_addr(char *ifname, char *mac)
{
    int fd, rtn;
    struct ifreq ifr;
    
    if( !ifname || !mac ) {
        return -1;
    }
    fd = socket(AF_INET, SOCK_DGRAM, 0 );
    if ( fd < 0 ) {
        perror("socket");
           return -1;
    }
    ifr.ifr_addr.sa_family = AF_INET;    
    strncpy(ifr.ifr_name, (const char *)ifname, IFNAMSIZ - 1 );

    if ( (rtn = ioctl(fd, SIOCGIFHWADDR, &ifr) ) == 0 )
        memcpy(    mac, (unsigned char *)ifr.ifr_hwaddr.sa_data, 6);
    close(fd);
    return rtn;
}

int set_mac_addr(char *ifname, char *mac)
{
    int fd, rtn;
    struct ifreq ifr;

    if( !ifname || !mac ) {
        return -1;
    }
    fd = socket(AF_INET, SOCK_DGRAM, 0 );
    if ( fd < 0 ) {
        perror("socket");
        return -1;
    }
    ifr.ifr_addr.sa_family = ARPHRD_ETHER;
    strncpy(ifr.ifr_name, (const char *)ifname, IFNAMSIZ - 1 );
    memcpy((unsigned char *)ifr.ifr_hwaddr.sa_data, mac, 6);
    
    if ( (rtn = ioctl(fd, SIOCSIFHWADDR, &ifr) ) != 0 ){
        perror("SIOCSIFHWADDR");
    }
    close(fd);
    return rtn;
}

int if_updown(char *ifname, int flag)
{
    int fd, rtn;
    struct ifreq ifr;        

    if (!ifname) {
        return -1;
    }

    fd = socket(AF_INET, SOCK_DGRAM, 0 );
    if ( fd < 0 ) {
        perror("socket");
        return -1;
    }
    
    ifr.ifr_addr.sa_family = AF_INET;
    strncpy(ifr.ifr_name, (const char *)ifname, IFNAMSIZ - 1 );

    if ( (rtn = ioctl(fd, SIOCGIFFLAGS, &ifr) ) == 0 ) {
        if ( flag == DOWN )
            ifr.ifr_flags &= ~IFF_UP;
        else if ( flag == UP ) 
            ifr.ifr_flags |= IFF_UP;
        
    }

    if ( (rtn = ioctl(fd, SIOCSIFFLAGS, &ifr) ) != 0) {
        perror("SIOCSIFFLAGS");
    }

    close(fd);

    return rtn;
}

/*
 * Convert Ethernet address string representation to binary data
 * @param    a    string in xx:xx:xx:xx:xx:xx notation
 * @param    e    binary data
 * @return    TRUE if conversion was successful and FALSE otherwise
 */

int
ether_atoe(const char *a, unsigned char *e)
{
    char *= (char *) a;
    int i = 0;

    memset(e, 0, ETHER_ADDR_LEN);
    for (;;) {
        e[i++] = (unsigned char) strtoul(c, &c, 16);
        if (!*c++ || i == ETHER_ADDR_LEN)
            break;
    }
    return (== ETHER_ADDR_LEN);
}


/*
 * Convert Ethernet address binary data to string representation
 * @param    e    binary data
 * @param    a    string in xx:xx:xx:xx:xx:xx notation
 * @return    a
 */

char *
ether_etoa(const unsigned char *e, char *a)
{
    char *= a;
    int i;

    for (= 0; i < ETHER_ADDR_LEN; i++) {
        if (i)
            *c++ = ':';
        c += sprintf(c, "%02X", e[i] & 0xff);
    }
    return a;
}

<think>问题分析: 在编译过程中出现了两个错误,提示 `ARPHRD_ETHER` 和 `ARPOP_REPLY` 未声明。这两个宏定义通常位于网络相关的头文件中。 原因: 1. `ARPHRD_ETHER` 是硬件类型,定义在 <net/if_arp.h> 头文件中,表示以太网。 2. `ARPOP_REPLY` 是ARP操作码,表示ARP响应,定义在 <net/if_arp.h> 或 <netinet/if_ether.h> 中。 解决方案: 在代码中包含必要的头文件,即: #include <net/if_arp.h> #include <netinet/if_ether.h> // 或者 #include <net/ethernet.h> 注意:不同的系统可能头文件有所不同,但通常包含 <net/if_arp.h> 即可。 修改代码: 在源文件168.c的开头,添加以下头文件: #include <net/if_arp.h> 如果编译仍然报错,可以尝试同时包含: #include <netinet/if_ether.h> 但注意,有些系统可能没有<netinet/if_ether.h>,而使用<net/ethernet.h>。 另外,确保已经包含了必要的网络头文件,例如: #include <arpa/inet.h> #include <netinet/in.h> 示例修改后的头文件部分: 原始代码可能缺少这些头文件,添加后重新编译。 如果问题仍然存在,可以尝试使用以下宏定义(不推荐,因为可移植性差): #define ARPHRD_ETHER 1 // 以太网类型 #define ARPOP_REPLY 2 // ARP响应操作码 但最好还是通过包含系统头文件来解决。 修改后的代码示例(在168.c中添加头文件):</think>### 编译错误分析与解决方案 #### 错误原因 编译错误表明代码中使用了未定义的宏: 1. `ARPHRD_ETHER`:表示以太网硬件类型(通常值为1) 2. `ARPOP_REPLY`:表示ARP响应操作码(通常值为2) 这些宏定义在Linux网络编程的头文件中,但未正确包含相关头文件。 #### 完整解决方案 ##### 1. 添加必要的头文件 在代码开头添加以下头文件包含: ```c #include <net/if_arp.h> // 包含ARPHRD_ETHER定义 #include <netinet/if_ether.h> // 包含ARPOP_REPLY定义 #include <netinet/ether.h> // 以太网相关函数 #include <net/if.h> // 网络接口相关 ``` ##### 2. 完整修正代码示例 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pcap.h> #include <netinet/ip.h> #include <netinet/ether.h> #include <net/if_arp.h> // 添加此头文件 #include <netinet/if_ether.h> // 添加此头文件 #include <arpa/inet.h> #include <sys/ioctl.h> #include <net/if.h> // ... 原有代码保持不变 ... void send_arp_response(pcap_t *handle, u_char *src_mac, u_char *src_ip, u_char *dst_mac, u_char *dst_ip) { struct ether_arp packet; // 填充以太网头 struct ether_header *eth_header = (struct ether_header *)packet; memcpy(eth_header->ether_dhost, dst_mac, 6); memcpy(eth_header->ether_shost, src_mac, 6); eth_header->ether_type = htons(ETHERTYPE_ARP); // 使用标准宏 // 填充ARP头 struct ether_arp *arp_req = (struct ether_arp *)(packet + sizeof(struct ether_header)); arp_req->ea_hdr.ar_hrd = htons(ARPHRD_ETHER); // 现在已定义 arp_req->ea_hdr.ar_pro = htons(ETHERTYPE_IP); arp_req->ea_hdr.ar_hln = 6; arp_req->ea_hdr.ar_pln = 4; arp_req->ea_hdr.ar_op = htons(ARPOP_REPLY); // 现在已定义 memcpy(arp_req->arp_sha, src_mac, 6); memcpy(arp_req->arp_spa, src_ip, 4); memcpy(arp_req->arp_tha, dst_mac, 6); memcpy(arp_req->arp_tpa, dst_ip, 4); // 发送数据包 if (pcap_sendpacket(handle, (u_char *)&packet, sizeof(packet)) != 0) { fprintf(stderr, "发送失败: %s\n", pcap_geterr(handle)); } } ``` #### 替代方案:使用预定义值 如果头文件不可用,可以直接使用数值常量: ```c // 在代码开头定义缺失的宏 #ifndef ARPHRD_ETHER #define ARPHRD_ETHER 1 // 以太网硬件类型 #endif #ifndef ARPOP_REPLY #define ARPOP_REPLY 2 // ARP响应操作码 #endif // 在函数中使用 packet.hw_type = htons(ARPHRD_ETHER); packet.opcode = htons(ARPOP_REPLY); ``` #### 验证编译 ```bash # 重新编译 gcc 168.c -o arp_spoof -lpcap # 运行(需要root权限) sudo ./arp_spoof ``` #### 关键点说明 1. **头文件依赖**: - `<net/if_arp.h>` 定义ARP硬件类型 - `<netinet/if_ether.h>` 定义ARP操作码和以太网类型 - 不同Linux发行版可能有差异(Ubuntu/Debian需安装`libpcap-dev`) 2. **跨平台考虑**: - BSD系统使用`<net/ethernet.h>` - Windows需使用WinPcap和不同头文件 - 使用`#ifdef`预处理指令确保可移植性 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值