ZBLOG

c语言监听收到的arp报文,将监听句柄放在epoll上,回调处理函数中,对arp报文进行解析,将报文源地址与指定地址对比,符合条件则打印

以下是一个基本的示例代码,用于监听并处理收到的 ARP 报文:

#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 <linux/if_packet.h>
#include <net/ethernet.h>

#define MAX_PACKET_SIZE 2048

void process_arp_packet(const unsigned char* packet, int length, const char* target_ip) {
    struct ethhdr* ethernet_header = (struct ethhdr*)packet;
    if (ntohs(ethernet_header->h_proto) == ETH_P_ARP) {
        const unsigned char* arp_payload = packet + sizeof(struct ethhdr);
        short arp_opcode = ntohs(*(short*)(arp_payload + 6));

        if (arp_opcode == ARPOP_REQUEST || arp_opcode == ARPOP_REPLY) {
            const struct arphdr* arp_header = (const struct arphdr*)(arp_payload);
            unsigned char sender_ip[4];
            unsigned char target_ip_address[4];

            memcpy(sender_ip, arp_payload + 14, 4);
            memcpy(target_ip_address, arp_payload + 24, 4);

            // 比较源IP地址与指定地址
            if (memcmp(target_ip_address, inet_addr(target_ip), 4) == 0) {
                printf("ARP 包源 IP 地址与指定地址匹配\n");
                printf("Sender IP: %d.%d.%d.%d\n", sender_ip[0], sender_ip[1], sender_ip[2], sender_ip[3]);
                printf("Target IP: %s\n", target_ip);
            }
        }
    }
}

int main() {
    const char* interface_name = "eth0"; // 替换为你的网络接口名
    const char* target_ip = "192.168.0.100"; // 指定地址

    int sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if (sock < 0) {
        perror("Failed to create raw socket");
        return 1;
    }

    struct sockaddr_ll sa;
    memset(&sa, 0, sizeof(struct sockaddr_ll));

    struct ifreq ifr;
    strncpy((char*)ifr.ifr_name, interface_name, IFNAMSIZ);
    if (ioctl(sock, SIOCGIFINDEX, &ifr) == -1) {
        perror("Failed to get interface index");
        close(sock);
        return 1;
    }
    
    sa.sll_ifindex = ifr.ifr_ifindex;

    if (bind(sock, (struct sockaddr*)&sa, sizeof(struct sockaddr_ll)) == -1) {
        perror("Failed to bind raw socket to interface");
        close(sock);
        return 1;
    }

  	int epollfd = epoll_create(1);
  	if (epollfd < 0) {
    	perror("Failed to create epoll descriptor");
    	close(sock);
    	return 1;
  	}

  	struct epoll_event event;
  	event.events = EPOLLIN | EPOLLET; // 监听读事件并设置边缘触发模式
  	event.data.fd = sock;

  	if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sock, &event) == -1) {
    	perror("Failed to add socket to epoll");
    	close(epollfd);
    	close(sock);
    	return 1;
 	 }

	  while (1) {
    	struct epoll_event events[10];
    	
   		int nfds = epoll_wait(epollfd, events, 10, -1);
    	if (nfds == -1) {
      		perror("Failed to wait for epoll events");
      		close(epollfd);
      		close(sock);
      		return 1;
    	}
    	
	    for (int i = 0; i < nfds; ++i) {
	      if (events[i].events & EPOLLIN) { // 监听到读事件
	        unsigned char buffer[MAX_PACKET_SIZE];
	        
	        ssize_t length = recv(sock, buffer, sizeof(buffer), 0);
	        if (length > 0) {
	          process_arp_packet(buffer, length, target_ip);
	        }
	      }
	    }
	  }

  	close(epollfd);
  	close(sock);

    return 0;
}

这是一个简单的示例,可以在 Linux 环境下编译和运行。注意替换接口名(interface_name)和指定地址(target_ip)为你的实际情况。

这段代码创建了一个原始套接字并绑定到指定的网络接口上,然后使用 epoll 监听套接字的读事件。当收到 ARP 报文时,调用 process_arp_packet 函数进行解析,并与指定地址对比,如果匹配则打印相关信息。

请注意,此示例只处理 Ethernet II 帧中的 ARP 报文。根据你的需求,可能需要根据具体情况进行修改和扩展。


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://sdn.0voice.com/?id=1670

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?