基于 socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL),UDP发送和接收,设定接收指定mac的数据。
时间: 2024-03-17 18:46:40 浏览: 57
好的,基于 socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL)) 的程序可以实现对网络数据的抓包和发送,可以通过指定接口名称或接口索引来选择抓取的网络接口,可以设置过滤规则来过滤不需要的数据包。下面是一个基于 socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL)) 的程序示例,实现了UDP发送和接收,并可以设定接收指定MAC地址的数据包:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#define BUF_SIZE 65536
int main(int argc, char *argv[]) {
char *ifname;
int sockfd;
char buf[BUF_SIZE];
struct sockaddr_ll sll;
struct ifreq ifr;
struct ethhdr *eth;
struct iphdr *ip;
struct udphdr *udp;
int len;
if (argc < 2) {
printf("Usage: %s <interface>\n", argv[0]);
return -1;
}
ifname = argv[1];
sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (sockfd < 0) {
perror("socket error");
return -1;
}
memset(&sll, 0, sizeof(sll));
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1);
if (ioctl(sockfd, SIOCGIFINDEX, &ifr) < 0) {
perror("ioctl error");
close(sockfd);
return -1;
}
sll.sll_family = PF_PACKET;
sll.sll_ifindex = ifr.ifr_ifindex;
sll.sll_protocol = htons(ETH_P_ALL);
if (bind(sockfd, (struct sockaddr *)&sll, sizeof(sll)) < 0) {
perror("bind error");
close(sockfd);
return -1;
}
while (1) {
len = recv(sockfd, buf, BUF_SIZE, 0);
if (len < 0) {
perror("recv error");
break;
}
eth = (struct ethhdr *)buf;
if (eth->h_proto != htons(ETH_P_IP)) {
continue;
}
ip = (struct iphdr *)(buf + sizeof(struct ethhdr));
if (ip->protocol != IPPROTO_UDP) {
continue;
}
udp = (struct udphdr *)(buf + sizeof(struct ethhdr) + sizeof(struct iphdr));
if (ntohs(udp->dest) != 1234) { // 接收指定端口的数据包
continue;
}
printf("Received UDP packet from %s:%d to %s:%d\n",
inet_ntoa(*(struct in_addr *)&ip->saddr), ntohs(udp->source),
inet_ntoa(*(struct in_addr *)&ip->daddr), ntohs(udp->dest));
// 发送UDP数据包
memset(buf, 0, BUF_SIZE);
eth = (struct ethhdr *)buf;
memcpy(eth->h_source, "\x00\x11\x22\x33\x44\x55", ETH_ALEN);
memcpy(eth->h_dest, "\x00\x11\x22\x33\x44\x66", ETH_ALEN);
eth->h_proto = htons(ETH_P_IP);
ip = (struct iphdr *)(buf + sizeof(struct ethhdr));
ip->ihl = 5;
ip->version = 4;
ip->tos = 0;
ip->tot_len = htons(sizeof(struct iphdr) + sizeof(struct udphdr));
ip->id = htons(12345);
ip->frag_off = htons(0);
ip->ttl = 64;
ip->protocol = IPPROTO_UDP;
ip->saddr = inet_addr("192.168.1.100");
ip->daddr = inet_addr("192.168.1.200");
ip->check = 0;
ip->check = htons(in_cksum((unsigned short *)ip, sizeof(struct iphdr)));
udp = (struct udphdr *)(buf + sizeof(struct ethhdr) + sizeof(struct iphdr));
udp->source = htons(1234);
udp->dest = htons(5678);
udp->len = htons(sizeof(struct udphdr));
udp->check = 0;
if (send(sockfd, buf, sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr), 0) < 0) {
perror("send error");
break;
}
}
close(sockfd);
return 0;
}
```
在程序中,首先创建一个 socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)) 的原始套接字,然后绑定到指定的网络接口上,通过 recv() 接收数据包,判断数据包是否是 IPv4 协议的 UDP 数据包,判断数据包的目的端口是否是指定端口,然后输出接收到的 UDP 数据包的源 IP 地址和端口号,最后发送一个 UDP 数据包。
注意:这段代码仅作为示例,实际使用中需要根据需求进行修改和优化。
阅读全文