欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

指定网卡发送数据包

程序员文章站 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()中的回调函数。