指定网卡发送数据包

11 篇文章 0 订阅

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()中的回调函数。

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
DMA(Direct Memory Access)是一种计算机技术,允许外部设备(如网卡)直接访问计算机内存,而无需通过中央处理器进行数据传输。通过DMA,网卡可以直接与内存进行读写操作,从而提高数据传输的效率。 网卡实现DMA机制接收和发送数据包的源代码可以按照以下步骤实现: 1. 初始化DMA控制器,配置DMA通道和相关寄存器。设置网卡接收数据包的DMA通道和发送数据包的DMA通道。 2. 当网卡接收到数据包时,触发DMA中断,DMA控制器将数据包直接拷贝到指定的接收缓冲区。 3. 网卡发送数据包时,将数据包内容写入发送缓冲区,然后触发DMA中断,DMA控制器将数据包直接从发送缓冲区传输到网卡发送队列,并发送到目标设备。 以下是伪代码示例: 初始化DMA控制器和相关寄存器: ``` initialize_DMA_controller(); configure_DMA_channel(Receive_channel, receive_buffer); configure_DMA_channel(Transmit_channel, transmit_buffer); ``` 接收数据包的DMA中断处理函数: ``` void DMA_Receive_Interrupt_Handler() { if (DMA_receive_channel_interrupt) { // 从DMA通道读取数据包到接收缓冲区 read_data_to_receive_buffer(); } } ``` 发送数据包的DMA中断处理函数: ``` void DMA_Transmit_Interrupt_Handler() { if (DMA_transmit_channel_interrupt) { // 从发送缓冲区将数据包传输到DMA通道 write_data_from_transmit_buffer(); } } ``` 通过以上源代码,网卡可以利用DMA机制实现高效地接收和发送数据包,避免了CPU的干预,提高了数据传输的效率。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值