插件窝 干货文章 Linux下C语言操作网卡的几个代码实例!特别实用

Linux下C语言操作网卡的几个代码实例!特别实用

include return perror ifr 580    来源:    2025-05-14

Linux下C语言操作网卡的实用代码示例

下面我将介绍几个在Linux下使用C语言操作网卡的实用代码示例,涵盖常见的网络接口操作。

1. 获取网络接口信息

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>

void get_interface_info(const char *ifname) {
    int fd;
    struct ifreq ifr;
    struct sockaddr_in *sin;

    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0) {
        perror("socket");
        return;
    }

    // 获取IP地址
    strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
    if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
        sin = (struct sockaddr_in *)&ifr.ifr_addr;
        printf("IP Address: %s\n", inet_ntoa(sin->sin_addr));
    } else {
        perror("SIOCGIFADDR");
    }

    // 获取网络掩码
    if (ioctl(fd, SIOCGIFNETMASK, &ifr) == 0) {
        sin = (struct sockaddr_in *)&ifr.ifr_netmask;
        printf("Netmask: %s\n", inet_ntoa(sin->sin_addr));
    } else {
        perror("SIOCGIFNETMASK");
    }

    // 获取MAC地址
    if (ioctl(fd, SIOCGIFHWADDR, &ifr) == 0) {
        unsigned char *mac = (unsigned char *)ifr.ifr_hwaddr.sa_data;
        printf("MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n",
               mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    } else {
        perror("SIOCGIFHWADDR");
    }

    close(fd);
}

int main() {
    get_interface_info("eth0"); // 替换为你的网卡名称
    return 0;
}

2. 设置网络接口IP地址

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>
#include <arpa/inet.h>

int set_interface_ip(const char *ifname, const char *ip_addr) {
    int fd;
    struct ifreq ifr;
    struct sockaddr_in *sin;

    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0) {
        perror("socket");
        return -1;
    }

    // 设置IP地址
    strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
    sin = (struct sockaddr_in *)&ifr.ifr_addr;
    sin->sin_family = AF_INET;

    if (inet_pton(AF_INET, ip_addr, &sin->sin_addr) <= 0) {
        perror("inet_pton");
        close(fd);
        return -1;
    }

    if (ioctl(fd, SIOCSIFADDR, &ifr) < 0) {
        perror("SIOCSIFADDR");
        close(fd);
        return -1;
    }

    close(fd);
    return 0;
}

int main() {
    if (set_interface_ip("eth0", "192.168.1.100") == 0) {
        printf("IP address set successfully\n");
    }
    return 0;
}

3. 启用/禁用网络接口

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>

int set_interface_state(const char *ifname, int state) {
    int fd;
    struct ifreq ifr;

    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd < 0) {
        perror("socket");
        return -1;
    }

    strncpy(ifr.ifr_name, ifname, IFNAMSIZ);

    // 获取当前标志
    if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
        perror("SIOCGIFFLAGS");
        close(fd);
        return -1;
    }

    // 设置新标志
    if (state) {
        ifr.ifr_flags |= IFF_UP;   // 启用接口
    } else {
        ifr.ifr_flags &= ~IFF_UP;  // 禁用接口
    }

    if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
        perror("SIOCSIFFLAGS");
        close(fd);
        return -1;
    }

    close(fd);
    return 0;
}

int main() {
    // 启用接口
    if (set_interface_state("eth0", 1) == 0) {
        printf("Interface enabled\n");
    }

    // 禁用接口
    // set_interface_state("eth0", 0);

    return 0;
}

4. 原始套接字抓包示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>

void packet_sniffer(const char *ifname) {
    int sockfd;
    struct sockaddr_ll saddr;
    unsigned char buffer[ETH_FRAME_LEN];
    ssize_t n;

    // 创建原始套接字
    sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (sockfd < 0) {
        perror("socket");
        return;
    }

    // 绑定到特定接口
    memset(&saddr, 0, sizeof(saddr));
    saddr.sll_family = AF_PACKET;
    saddr.sll_protocol = htons(ETH_P_ALL);
    saddr.sll_ifindex = if_nametoindex(ifname);
    if (saddr.sll_ifindex == 0) {
        perror("if_nametoindex");
        close(sockfd);
        return;
    }

    if (bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
        perror("bind");
        close(sockfd);
        return;
    }

    printf("Starting packet capture on %s...\n", ifname);

    while (1) {
        n = recvfrom(sockfd, buffer, sizeof(buffer), 0, NULL, NULL);
        if (n < 0) {
            perror("recvfrom");
            break;
        }

        // 这里简单打印接收到的包长度
        printf("Received packet of length %zd\n", n);

        // 实际应用中,这里可以解析包内容
    }

    close(sockfd);
}

int main() {
    packet_sniffer("eth0"); // 替换为你的网卡名称
    return 0;
}

5. 发送原始以太网帧

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>

int send_raw_frame(const char *ifname, const unsigned char *dest_mac, 
                   const unsigned char *src_mac, const unsigned char *data, 
                   size_t data_len) {
    int sockfd;
    struct sockaddr_ll saddr;
    unsigned char frame[ETH_FRAME_LEN];
    int ifindex;

    // 创建原始套接字
    sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (sockfd < 0) {
        perror("socket");
        return -1;
    }

    // 获取接口索引
    ifindex = if_nametoindex(ifname);
    if (ifindex == 0) {
        perror("if_nametoindex");
        close(sockfd);
        return -1;
    }

    // 准备以太网帧
    memset(frame, 0, sizeof(frame));

    // 设置目标MAC
    memcpy(frame, dest_mac, ETH_ALEN);

    // 设置源MAC
    memcpy(frame + ETH_ALEN, src_mac, ETH_ALEN);

    // 设置以太网类型 (这里使用0x0800表示IP协议)
    frame[12] = 0x08;
    frame[13] = 0x00;

    // 复制数据
    if (data_len > ETH_DATA_LEN) {
        fprintf(stderr, "Data too large for Ethernet frame\n");
        close(sockfd);
        return -1;
    }
    memcpy(frame + ETH_HLEN, data, data_len);

    // 准备目标地址结构
    memset(&saddr, 0, sizeof(saddr));
    saddr.sll_family = AF_PACKET;
    saddr.sll_ifindex = ifindex;
    saddr.sll_halen = ETH_ALEN;
    memcpy(saddr.sll_addr, dest_mac, ETH_ALEN);

    // 发送帧
    if (sendto(sockfd, frame, ETH_HLEN + data_len, 0, 
              (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
        perror("sendto");
        close(sockfd);
        return -1;
    }

    close(sockfd);
    return 0;
}

int main() {
    // 示例MAC地址和数据
    unsigned char dest_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; // 广播地址
    unsigned char src_mac[ETH_ALEN] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};  // 源MAC(替换为你的)
    unsigned char data[] = "Hello, Ethernet!";

    if (send_raw_frame("eth0", dest_mac, src_mac, data, sizeof(data)) == 0) {
        printf("Frame sent successfully\n");
    }

    return 0;
}

注意事项

  1. 这些示例需要root权限才能运行,因为涉及底层网络操作
  2. 在实际应用中,需要添加更多的错误检查和边界条件处理
  3. 对于生产环境代码,建议使用更高级的网络库如libpcap等
  4. 不同的Linux发行版可能有细微差异,可能需要调整

这些代码示例涵盖了常见的网卡操作场景,可以根据实际需求进行修改和扩展。