指定網絡卡傳送資料包
阿新 • • 發佈:2018-12-21
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()中的回撥函式。