1. 程式人生 > >指定網絡卡傳送資料包

指定網絡卡傳送資料包

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()中的回撥函式。