指定网卡发送数据包
程序员文章站
2022-04-24 14:26:06
...
1. 指定网卡发送数据
指定网卡名需要使用struct sockaddr_ll,struct ifreq, 使用ioctl()函数获取网卡索引号,使用原始套接字发送UDP数据,代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/ether.h>
#include <netpacket/packet.h>
unsigned short checksum(unsigned short *buf, int nword)
{
unsigned long sum;
for(sum=0; nword>0; nword--)
{
sum+=htons(*buf);
buf++;
}
sum=(sum>>16) + (sum&0xffff);
sum+=(sum>>16);
return (~sum);
}
int main(int argc, char *argv[])
{
int sock_raw_fd=socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
unsigned char send_msg[1024]=
{
0x74,0x27,0xea,0xb5,0xef,0xd8, // 目的mac
0x24,0x6e,0x96,0xc9,0x8a,0x82, // 源mac
0x08,0x00, // 协议类型
// IP
0x45,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,
0x80,17, 0x00,0x00,
10, 221, 20, 11,
10, 221, 20, 10,
// UDP
0x1f,0x90,0x1f,0x90,
0x00,0x00,0x00,0x00
};
int len=sprintf(send_msg+42,"%s","this is for the udp test");
if(len%2==1)
{
len++;
}
*((unsigned short*)&send_msg[16])=htons(20+8+len);
*((unsigned short*)&send_msg[14+20+4])=htons(8+len);
unsigned char pseudo_head[1024]={
10,221,20,11,
10,221,20,10,
0x00,17,0x00,0x00
};
*((unsigned short*)&pseudo_head[10])=htons(8+len);
memcpy(pseudo_head+12, send_msg+34, 8+len);
*((unsigned short*)&send_msg[24])=htons(checksum((unsigned short*)(send_msg+14), 20/2));
*((unsigned short*)&send_msg[40])=htons(checksum((unsigned short *)pseudo_head, (12+8+len)/2));
struct sockaddr_ll sll;
struct ifreq req;
char dst_mac[6]={0x00,0x01,0x02,0x03,0x04,0x05};
strncpy(req.ifr_name,argv[1],IFNAMSIZ);
if(-1==ioctl(sock_raw_fd, SIOCGIFINDEX, &req))
{
perror("ioctl");
close(sock_raw_fd);
exit(1);
}
bzero(&sll, sizeof(sll));
sll.sll_ifindex=req.ifr_ifindex;
sll.sll_family=AF_PACKET;
sll.sll_halen=ETHER_ADDR_LEN;
sll.sll_protocol=htons(ETH_P_IP);
memcpy(sll.sll_addr,dst_mac,ETHER_ADDR_LEN);
len=sendto(sock_raw_fd, send_msg, 14+20+8+len, 0, (struct sockaddr*)&sll, sizeof(sll));
if(len==-1)
{
perror("sendto");
}
return 0;
}
2. 指定网卡捕获数据
使用libpcap库捕获数据包,代码如下:
#include <stdio.h>
#include <pcap.h>
#include <netinet/if_ether.h>
void deal(u_char *user, const struct pcap_pkthdr *hdr, const u_char *packet){
static int count = 0;
struct ether_header *eth_header;
u_char *ptr;
printf("Packet length %d\n", hdr->len);
printf("length of portion present: %d\n", hdr->caplen);
eth_header = (struct ether_header*)packet;
if(ntohs(eth_header->ether_type) != ETHERTYPE_IP){
printf("not ethernet packet\n");
return;
}
ptr = eth_header->ether_dhost;
int i = 0;
printf("destination address(MAC):");
while(i < ETHER_ADDR_LEN){
printf(" %x", *ptr++);
i++;
}
printf("\nsource address(MAC):");
ptr = eth_header->ether_shost;
i = 0;
while(i < ETHER_ADDR_LEN){
printf(" %x", *ptr++);
i++;
}
printf("\nfinish deal with %d packet\n", count);
count++;
}
int main(int argc, char **argv){
if(argc!=2)
{
printf("usage: %s interface_name\n",argv[0]);
}
pcap_t *sniffer_des;
char errbuf[PCAP_ERRBUF_SIZE];
char *net_dev;
bpf_u_int32 net, mask;
struct bpf_program fp;
const u_char *packet;
struct pcap_pkthdr hdr;
int ret;
char filter[] = "port 80";
net_dev = pcap_lookupdev(errbuf);
if(net_dev == NULL){
printf("get device error:%s\n", errbuf);
return 1;
}
net_dev = argv[1];
if(pcap_lookupnet(net_dev, &net, &mask, errbuf) == -1){
printf("get net error:%s\n", errbuf);
return 1;
}
sniffer_des = pcap_open_live(net_dev, 65535, 1, 5000, errbuf);
if(sniffer_des == NULL){
printf("pcap_open_live%s\n", errbuf);
return 1;
}
if(pcap_compile(sniffer_des, &fp, filter, 0, mask) == -1){
printf("pcap_compile error\n");
return 1;
}
if(pcap_setfilter(sniffer_des, &fp) == -1){
printf("pcap_setfilter() error\n");
return 1;
}
ret = pcap_loop(sniffer_des, -1, deal, NULL); // 无限捕获
if(ret == -1 || ret == -2){
printf("cannot get the pcaket\n");
return 1;
}
return 0;
}
3. 将指定网卡的数据转发到另一个网卡发送
通过将上述两个结合,将指定网卡上捕获的数据,通过原始套接字在另一个网卡发送出去,只需要修改pcap_loop()中的回调函数。
上一篇: Hibernate多对多配置
下一篇: JS实现的简单四则运算计算器功能示例