走的是1臭狗屎

以下是对上述C语言ARP子模块代码的详细解析,逐部分解释其功能和实现细节。

### 1. 头文件包含

```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/if_ether.h>
#include <netinet/if_arp.h>
#include <netpacket/packet.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <time.h>
#include <pthread.h>
```

- **标准库**:`stdio.h`, `stdlib.h`, `string.h`, `unistd.h`用于基本输入输出、内存管理、字符串操作和Unix标准函数。
- **网络相关**:`arpa/inet.h`用于IP地址转换,`netinet/if_ether.h`和`netinet/if_arp.h`用于以太网和ARP协议的定义,`netpacket/packet.h`用于原始套接字。
- **系统调用**:`sys/ioctl.h`和`net/if.h`用于网络接口的控制和信息获取。
- **时间和线程**:`time.h`用于时间处理,`pthread.h`用于多线程支持。

### 2. 常量定义

```c
#define ETHER_HEADER_LEN sizeof(struct ether_header)
#define ETHER_ARP_LEN sizeof(struct ether_arp)
#define ETHER_ARP_PACKET_LEN (ETHER_HEADER_LEN + ETHER_ARP_LEN)
#define BROADCAST_ADDR {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
#define IP_ADDR_LEN 4
#define MAX_ARP_ENTRIES 100
```

- **以太网和ARP包长度**:定义了以太网头部、ARP头部和完整ARP包的长度。
- **广播地址**:定义了一个广播地址,用于发送ARP请求。
- **IP地址长度**:定义了IP地址的字节长度(4字节)。
- **最大ARP条目数**:限制ARP条目的最大数量为100。

### 3. 数据结构定义

```c
typedef struct {
    unsigned char mac[ETH_ALEN];
    char ip[INET_ADDRSTRLEN];
    time_t last_seen;
} arp_entry_t;

typedef struct {
    int enabled;              // 功能开关
    int scan_interval;        // 扫描周期(秒)
    int entry_lifetime;       // 有效期(秒)
    int packet_interval;      // 发包间隔(毫秒)
    char start_ip[INET_ADDRSTRLEN];
    char end_ip[INET_ADDRSTRLEN];
    arp_entry_t arp_entries[MAX_ARP_ENTRIES];
    int entry_count;          // 当前ARP条目数量
    pthread_mutex_t lock;     // 互斥锁
} arp_config_t;
```

- **ARP条目结构**:`arp_entry_t`包含MAC地址、IP地址和最后一次被扫描的时间。
- **ARP配置结构**:`arp_config_t`包含ARP模块的配置参数,如功能开关、扫描周期、有效期、发包间隔、起始和结束IP地址、ARP条目数组、当前条目数量和互斥锁。

### 4. 全局配置变量

```c
arp_config_t arp_config = {
    .enabled = 1,                     // 功能开关开启
    .scan_interval = 60,              // 扫描周期为60秒
    .entry_lifetime = 300,            // 有效期为300秒
    .packet_interval = 100,            // 发包间隔为100毫秒
    .start_ip = "192.168.1.100",      // 起始IP
    .end_ip = "192.168.1.200",        // 结束IP
    .entry_count = 0                   // 初始化ARP条目数量
};
```

- **初始化ARP配置**:在代码中直接初始化ARP配置,设置功能开关为开启,定义扫描周期、有效期、发包间隔和IP范围。

### 5. 错误处理函数

```c
void err_exit(const char *err_msg) {
    perror(err_msg);
    exit(1);
}
```

- **错误处理**:`err_exit`函数用于打印错误信息并退出程序,使用`perror`函数输出系统错误信息。

### 6. 填充ARP包函数

```c
struct ether_arp *fill_arp_packet(const unsigned char *src_mac_addr, const char *src_ip, const char *dst_ip) {
    struct ether_arp *arp_packet = (struct ether_arp *)malloc(ETHER_ARP_LEN);
    unsigned char dst_mac_addr[ETH_ALEN] = BROADCAST_ADDR;
    struct in_addr src_in_addr, dst_in_addr;

    inet_pton(AF_INET, src_ip, &src_in_addr);
    inet_pton(AF_INET, dst_ip, &dst_in_addr);

    arp_packet->arp_hrd = htons(ARPHRD_ETHER);
    arp_packet->arp_pro = htons(ETHERTYPE_IP);
    arp_packet->arp_hln = ETH_ALEN;
    arp_packet->arp_pln = IP_ADDR_LEN;
    arp_packet->arp_op = htons(ARPOP_REQUEST);
    memcpy(arp_packet->arp_sha, src_mac_addr, ETH_ALEN);
    memcpy(arp_packet->arp_tha, dst_mac_addr, ETH_ALEN);
    memcpy(arp_packet->arp_spa, &src_in_addr, IP_ADDR_LEN);
    memcpy(arp_packet->arp_tpa, &dst_in_addr, IP_ADDR_LEN);

    return arp_packet;
}
```

- **创建ARP请求包**:`fill_arp_packet`函数用于创建和填充ARP请求包,设置ARP头部的各个字段,包括硬件类型、协议类型、操作码、源MAC地址、目标MAC地址、源IP地址和目标IP地址。

### 7. 添加ARP条目函数

```c
void add_arp_entry(const char *ip, const unsigned char *mac) {
    pthread_mutex_lock(&arp_config.lock);
    if (arp_config.entry_count < MAX_ARP_ENTRIES) {
        strcpy(arp_config.arp_entries[arp_config.entry_count].ip, ip);
        memcpy(arp_config.arp_entries[arp_config.entry_count].mac, mac, ETH_ALEN);
        arp_config.arp_entries[arp_config.entry_count].last_seen = time(NULL);
        arp_config.entry_count++;
    }
    pthread_mutex_unlock(&arp_config.lock);
}
```

- **添加ARP条目**:`add_arp_entry`函数用于将新的ARP条目添加到ARP条目列表中,并更新最后一次被扫描的时间。使用互斥锁确保线程安全。

### 8. 清理过期ARP条目函数

```c
void cleanup_arp_entries() {
    pthread_mutex_lock(&arp_config.lock);
    time_t now = time(NULL);
    for (int i = 0; i < arp_config.entry_count; i++) {
        if (now - arp_config.arp_entries[i].last_seen > arp_config.entry_lifetime) {
            // 删除过期条目
            for (int j = i; j < arp_config.entry_count - 1; j++) {
                arp_config.arp_entries[j] = arp_config.arp_entries[j + 1];
            }
            arp_config.entry_count--;
            i--; // 调整索引
        }
    }
    pthread_mutex_unlock(&arp_config.lock);
}
```

- **清理过期条目**:`cleanup_arp_entries`函数检查并删除过期的ARP条目,使用互斥锁确保线程安全。

### 9. ARP扫描函数

```c
void arp_scan(const char *if_name) {
    struct sockaddr_ll saddr_ll;
    struct ether_header *eth_header;
    struct ether_arp *arp_packet;
    struct ifreq ifr;
    char buf[ETHER_ARP_PACKET_LEN];
    unsigned char src_mac_addr[ETH_ALEN];
    char src_ip[INET_ADDRSTRLEN];
    int sock_raw_fd;

    if ((sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ARP))) == -1)
        err_exit("socket()");

    memset(&saddr_ll, 0, sizeof(struct sockaddr_ll));
    memset(&ifr, 0, sizeof(struct ifreq));
    memcpy(ifr.ifr_name, "eth0", strlen("eth0")); // 使用默认接口名

    if (ioctl(sock_raw_fd, SIOCGIFINDEX, &ifr) == -1)
        err_exit("ioctl() get ifindex");
    saddr_ll.sll_ifindex = ifr.ifr_ifindex;
    saddr_ll.sll_family = PF_PACKET;

    if (ioctl(sock_raw_fd, SIOCGIFADDR, &ifr) == -1)
        err_exit("ioctl() get ip");
    strcpy(src_ip, inet_ntoa(((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr));

    if (ioctl(sock_raw_fd, SIOCGIFHWADDR, &ifr) == -1)
        err_exit("ioctl() get mac");
    memcpy(src_mac_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);

    while (arp_config.enabled) {
        char target_ip[INET_ADDRSTRLEN];
        for (int i = inet_addr(arp_config.start_ip); i <= inet_addr(arp_config.end_ip); i++) {
            struct in_addr addr;
            addr.s_addr = i;
            strcpy(target_ip, inet_ntoa(addr));

            memset(buf, 0, ETHER_ARP_PACKET_LEN);
            eth_header = (struct ether_header *)buf;
            memcpy(eth_header->ether_shost, src_mac_addr, ETH_ALEN);
            memcpy(eth_header->ether_dhost, BROADCAST_ADDR, ETH_ALEN);
            eth_header->ether_type = htons(ETHERTYPE_ARP);

            arp_packet = fill_arp_packet(src_mac_addr, src_ip, target_ip);
            memcpy(buf + ETHER_HEADER_LEN, arp_packet, ETHER_ARP_LEN);

            sendto(sock_raw_fd, buf, ETHER_ARP_PACKET_LEN, 0, (struct sockaddr *)&saddr_ll, sizeof(struct sockaddr_ll));
            free(arp_packet);

            printf("ARP request sent to %s\n", target_ip);
            usleep(arp_config.packet_interval * 1000); // 发包间隔
        }

        cleanup_arp_entries(); // 清理过期的ARP条目
        sleep(arp_config.scan_interval); // 等待下一次扫描
    }

    close(sock_raw_fd);
}
```

- **ARP扫描**:`arp_scan`函数用于在指定网段内扫描主机,发送ARP请求并维护ARP条目。
  - 创建原始套接字以发送ARP请求。
  - 获取网络接口的索引、IP地址和MAC地址。
  - 在循环中,遍历指定的IP范围,构建ARP请求包并发送。
  - 每发送一次ARP请求后,调用`cleanup_arp_entries`清理过期条目,并在扫描周期内等待。

### 10. 主程序

```c
int main() {
    arp_scan("eth0"); // 启动ARP扫描,使用默认接口
    return 0;
}
```

- **主函数**:直接调用`arp_scan`函数,启动ARP扫描,使用默认的网络接口`eth0`。

### 总结

该程序实现了一个简单的ARP扫描工具,能够在指定的IP范围内发送ARP请求并维护ARP条目。通过使用互斥锁确保线程安全,程序能够在多线程环境中安全地操作ARP条目。所有配置参数在代码中直接定义,简化了使用过程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值