2013-01-09 56 views
0

我正在寫一個隧道內核模塊,我想爲自己的處理程序註冊一個特定的UDP端口。什麼是最好的方式來做到這一點?這個想法是註冊該處理程序,以便當該端口上的流量到達時,linux堆棧將調用我的處理程序。Linux內核:爲特定的UDP端口流量註冊處理程序?

[EDIT1]

通過套接字API的方法是結合於插座這樣

sin.sin_family = AF_INET; 
sin.sin_addr.s_addr = htonl(INADDR_ANY); 
sin.sin_port = htons(my_port); 

err = kernel_bind(rcv_socket, (struct sockaddr *)&sin, 
     sizeof(struct sockaddr_in)); 

udp_sk(rcv_socket->sk)->encap_rcv = my_handler; 

的問題是,該插座與INADDR_ANY相關聯,其對應於任何主機IP的在機器上。我想爲數據包中的任何IP執行此操作?這怎麼能實現?

插座不能在這種情況下使用我認爲,因爲任何IP意味着在堆棧中數據包通過ip_forward路徑而不是ip_local_delivery。將不會有這樣的數據包套接字。如何在這種情況下實現它?

+0

爲什麼你需要在內核模式下做到這一點?您所描述的要求似乎對於使用套接字API執行的用戶模式應用程序來說是完全正常的事情... –

+0

@ChrisStratton我理解您的擔憂,但此需求是需要在內部構建的更大圖片的一部分內核。 – auny

+0

我不是一個超級專家,但我認爲你無法獲得需要使用偵聽傳輸層數據的套接字轉發的數據包。在以太網級別工作的原始套接字怎麼樣?我知道這可能是一個痛苦=( –

回答

-1

我不知道相關的內核級別的功能,但我建議綁定到偵聽第2層幀的RAW SOCKET,並使用ip包的進一步過濾器。

像這樣:

fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));

那麼它是由你來剖析框架和提取您只需要UDP數據包。

在第2層工作應該會授予您100%通過主機傳輸的IP數據包。

0

向下投票:請評論爲什麼你投下了這個經過測試的答案?

以下示例很有幫助。根據需要,您可以通過添加過濾器來修改示例。

對於UDP以下變化需要存在在下面的例子中

sock_raw = socket(AF_INET , SOCK_RAW , IPPROTO_UDP);

http://www.binarytides.com/packet-sniffer-code-in-c-using-linux-sockets-bsd/ http://www.binarytides.com/packet-sniffer-code-in-c-using-linux-sockets-bsd-part-2/ [相關性]

我列出的代碼FYI

#include<netinet/in.h> 
#include<errno.h> 
#include<netdb.h> 
#include<stdio.h> //For standard things 
#include<stdlib.h> //malloc 
#include<string.h> //strlen 

#include<netinet/ip_icmp.h> //Provides declarations for icmp header 
#include<netinet/udp.h> //Provides declarations for udp header 
#include<netinet/tcp.h> //Provides declarations for tcp header 
#include<netinet/ip.h> //Provides declarations for ip header 
#include<netinet/if_ether.h> //For ETH_P_ALL 
#include<net/ethernet.h> //For ether_header 
#include<sys/socket.h> 
#include<arpa/inet.h> 
#include<sys/ioctl.h> 
#include<sys/time.h> 
#include<sys/types.h> 
#include<unistd.h> 

void ProcessPacket(unsigned char* , int); 
void print_ip_header(unsigned char* , int); 
void print_tcp_packet(unsigned char * , int); 
void print_udp_packet(unsigned char * , int); 
void print_icmp_packet(unsigned char* , int); 
void PrintData (unsigned char* , int); 

FILE *logfile; 
struct sockaddr_in source,dest; 
int tcp=0,udp=0,icmp=0,others=0,igmp=0,total=0,i,j; 

int main() 
{ 
    int saddr_size , data_size; 
    struct sockaddr saddr; 

    unsigned char *buffer = (unsigned char *) malloc(65536); //Its Big! 

    logfile=fopen("log.txt","w"); 
    if(logfile==NULL) 
    { 
     printf("Unable to create log.txt file."); 
    } 
    printf("Starting...\n"); 

    int sock_raw = socket(AF_PACKET , SOCK_RAW , htons(ETH_P_ALL)) ; 
    //setsockopt(sock_raw , SOL_SOCKET , SO_BINDTODEVICE , "eth0" , strlen("eth0")+ 1); 

    if(sock_raw < 0) 
    { 
     //Print the error with proper message 
     perror("Socket Error"); 
     return 1; 
    } 
    while(1) 
    { 
     saddr_size = sizeof saddr; 
     //Receive a packet 
     data_size = recvfrom(sock_raw , buffer , 65536 , 0 , &saddr , (socklen_t*)&saddr_size); 
     if(data_size <0) 
     { 
      printf("Recvfrom error , failed to get packets\n"); 
      return 1; 
     } 
     //Now process the packet 
     ProcessPacket(buffer , data_size); 
    } 
    close(sock_raw); 
    printf("Finished"); 
    return 0; 
} 

void ProcessPacket(unsigned char* buffer, int size) 
{ 
    //Get the IP Header part of this packet , excluding the ethernet header 
    struct iphdr *iph = (struct iphdr*)(buffer + sizeof(struct ethhdr)); 
    ++total; 
    switch (iph->protocol) //Check the Protocol and do accordingly... 
    { 
     case 1: //ICMP Protocol 
      ++icmp; 
      print_icmp_packet(buffer , size); 
      break; 

     case 2: //IGMP Protocol 
      ++igmp; 
      break; 

     case 6: //TCP Protocol 
      ++tcp; 
      print_tcp_packet(buffer , size); 
      break; 

     case 17: //UDP Protocol 
      ++udp; 
      print_udp_packet(buffer , size); 
      break; 

     default: //Some Other Protocol like ARP etc. 
      ++others; 
      break; 
    } 
    printf("TCP : %d UDP : %d ICMP : %d IGMP : %d Others : %d Total : %d\r", tcp , udp , icmp , igmp , others , total); 
} 

void print_ethernet_header(unsigned char* Buffer, int Size) 
{ 
    struct ethhdr *eth = (struct ethhdr *)Buffer; 

    fprintf(logfile , "\n"); 
    fprintf(logfile , "Ethernet Header\n"); 
    fprintf(logfile , " |-Destination Address : %.2X-%.2X-%.2X-%.2X-%.2X-%.2X \n", eth->h_dest[0] , eth->h_dest[1] , eth->h_dest[2] , eth->h_dest[3] , eth->h_dest[4] , eth->h_dest[5]); 
    fprintf(logfile , " |-Source Address  : %.2X-%.2X-%.2X-%.2X-%.2X-%.2X \n", eth->h_source[0] , eth->h_source[1] , eth->h_source[2] , eth->h_source[3] , eth->h_source[4] , eth->h_source[5]); 
    fprintf(logfile , " |-Protocol   : %u \n",(unsigned short)eth->h_proto); 
} 

void print_ip_header(unsigned char* Buffer, int Size) 
{ 
    print_ethernet_header(Buffer , Size); 

    unsigned short iphdrlen; 

    struct iphdr *iph = (struct iphdr *)(Buffer + sizeof(struct ethhdr)); 
    iphdrlen =iph->ihl*4; 

    memset(&source, 0, sizeof(source)); 
    source.sin_addr.s_addr = iph->saddr; 

    memset(&dest, 0, sizeof(dest)); 
    dest.sin_addr.s_addr = iph->daddr; 

    fprintf(logfile , "\n"); 
    fprintf(logfile , "IP Header\n"); 
    fprintf(logfile , " |-IP Version  : %d\n",(unsigned int)iph->version); 
    fprintf(logfile , " |-IP Header Length : %d DWORDS or %d Bytes\n",(unsigned int)iph->ihl,((unsigned int)(iph->ihl))*4); 
    fprintf(logfile , " |-Type Of Service : %d\n",(unsigned int)iph->tos); 
    fprintf(logfile , " |-IP Total Length : %d Bytes(Size of Packet)\n",ntohs(iph->tot_len)); 
    fprintf(logfile , " |-Identification : %d\n",ntohs(iph->id)); 
    //fprintf(logfile , " |-Reserved ZERO Field : %d\n",(unsigned int)iphdr->ip_reserved_zero); 
    //fprintf(logfile , " |-Dont Fragment Field : %d\n",(unsigned int)iphdr->ip_dont_fragment); 
    //fprintf(logfile , " |-More Fragment Field : %d\n",(unsigned int)iphdr->ip_more_fragment); 
    fprintf(logfile , " |-TTL  : %d\n",(unsigned int)iph->ttl); 
    fprintf(logfile , " |-Protocol : %d\n",(unsigned int)iph->protocol); 
    fprintf(logfile , " |-Checksum : %d\n",ntohs(iph->check)); 
    fprintf(logfile , " |-Source IP  : %s\n",inet_ntoa(source.sin_addr)); 
    fprintf(logfile , " |-Destination IP : %s\n",inet_ntoa(dest.sin_addr)); 
} 

void print_tcp_packet(unsigned char* Buffer, int Size) 
{ 
    unsigned short iphdrlen; 

    struct iphdr *iph = (struct iphdr *)(Buffer + sizeof(struct ethhdr)); 
    iphdrlen = iph->ihl*4; 

    struct tcphdr *tcph=(struct tcphdr*)(Buffer + iphdrlen + sizeof(struct ethhdr)); 

    int header_size = sizeof(struct ethhdr) + iphdrlen + tcph->doff*4; 

    fprintf(logfile , "\n\n***********************TCP Packet*************************\n"); 

    print_ip_header(Buffer,Size); 

    fprintf(logfile , "\n"); 
    fprintf(logfile , "TCP Header\n"); 
    fprintf(logfile , " |-Source Port  : %u\n",ntohs(tcph->source)); 
    fprintf(logfile , " |-Destination Port : %u\n",ntohs(tcph->dest)); 
    fprintf(logfile , " |-Sequence Number : %u\n",ntohl(tcph->seq)); 
    fprintf(logfile , " |-Acknowledge Number : %u\n",ntohl(tcph->ack_seq)); 
    fprintf(logfile , " |-Header Length  : %d DWORDS or %d BYTES\n" ,(unsigned int)tcph->doff,(unsigned int)tcph->doff*4); 
    //fprintf(logfile , " |-CWR Flag : %d\n",(unsigned int)tcph->cwr); 
    //fprintf(logfile , " |-ECN Flag : %d\n",(unsigned int)tcph->ece); 
    fprintf(logfile , " |-Urgent Flag   : %d\n",(unsigned int)tcph->urg); 
    fprintf(logfile , " |-Acknowledgement Flag : %d\n",(unsigned int)tcph->ack); 
    fprintf(logfile , " |-Push Flag   : %d\n",(unsigned int)tcph->psh); 
    fprintf(logfile , " |-Reset Flag   : %d\n",(unsigned int)tcph->rst); 
    fprintf(logfile , " |-Synchronise Flag  : %d\n",(unsigned int)tcph->syn); 
    fprintf(logfile , " |-Finish Flag   : %d\n",(unsigned int)tcph->fin); 
    fprintf(logfile , " |-Window   : %d\n",ntohs(tcph->window)); 
    fprintf(logfile , " |-Checksum  : %d\n",ntohs(tcph->check)); 
    fprintf(logfile , " |-Urgent Pointer : %d\n",tcph->urg_ptr); 
    fprintf(logfile , "\n"); 
    fprintf(logfile , "      DATA Dump       "); 
    fprintf(logfile , "\n"); 

    fprintf(logfile , "IP Header\n"); 
    PrintData(Buffer,iphdrlen); 

    fprintf(logfile , "TCP Header\n"); 
    PrintData(Buffer+iphdrlen,tcph->doff*4); 

    fprintf(logfile , "Data Payload\n");  
    PrintData(Buffer + header_size , Size - header_size); 

    fprintf(logfile , "\n###########################################################"); 
} 

void print_udp_packet(unsigned char *Buffer , int Size) 
{ 

    unsigned short iphdrlen; 

    struct iphdr *iph = (struct iphdr *)(Buffer + sizeof(struct ethhdr)); 
    iphdrlen = iph->ihl*4; 

    struct udphdr *udph = (struct udphdr*)(Buffer + iphdrlen + sizeof(struct ethhdr)); 

    int header_size = sizeof(struct ethhdr) + iphdrlen + sizeof udph; 

    fprintf(logfile , "\n\n***********************UDP Packet*************************\n"); 

    print_ip_header(Buffer,Size);   

    fprintf(logfile , "\nUDP Header\n"); 
    fprintf(logfile , " |-Source Port  : %d\n" , ntohs(udph->source)); 
    fprintf(logfile , " |-Destination Port : %d\n" , ntohs(udph->dest)); 
    fprintf(logfile , " |-UDP Length  : %d\n" , ntohs(udph->len)); 
    fprintf(logfile , " |-UDP Checksum  : %d\n" , ntohs(udph->check)); 

    fprintf(logfile , "\n"); 
    fprintf(logfile , "IP Header\n"); 
    PrintData(Buffer , iphdrlen); 

    fprintf(logfile , "UDP Header\n"); 
    PrintData(Buffer+iphdrlen , sizeof udph); 

    fprintf(logfile , "Data Payload\n");  

    //Move the pointer ahead and reduce the size of string 
    PrintData(Buffer + header_size , Size - header_size); 

    fprintf(logfile , "\n###########################################################"); 
} 

void print_icmp_packet(unsigned char* Buffer , int Size) 
{ 
    unsigned short iphdrlen; 

    struct iphdr *iph = (struct iphdr *)(Buffer + sizeof(struct ethhdr)); 
    iphdrlen = iph->ihl * 4; 

    struct icmphdr *icmph = (struct icmphdr *)(Buffer + iphdrlen + sizeof(struct ethhdr)); 

    int header_size = sizeof(struct ethhdr) + iphdrlen + sizeof icmph; 

    fprintf(logfile , "\n\n***********************ICMP Packet*************************\n"); 

    print_ip_header(Buffer , Size); 

    fprintf(logfile , "\n"); 

    fprintf(logfile , "ICMP Header\n"); 
    fprintf(logfile , " |-Type : %d",(unsigned int)(icmph->type)); 

    if((unsigned int)(icmph->type) == 11) 
    { 
     fprintf(logfile , " (TTL Expired)\n"); 
    } 
    else if((unsigned int)(icmph->type) == ICMP_ECHOREPLY) 
    { 
     fprintf(logfile , " (ICMP Echo Reply)\n"); 
    } 

    fprintf(logfile , " |-Code : %d\n",(unsigned int)(icmph->code)); 
    fprintf(logfile , " |-Checksum : %d\n",ntohs(icmph->checksum)); 
    //fprintf(logfile , " |-ID  : %d\n",ntohs(icmph->id)); 
    //fprintf(logfile , " |-Sequence : %d\n",ntohs(icmph->sequence)); 
    fprintf(logfile , "\n"); 

    fprintf(logfile , "IP Header\n"); 
    PrintData(Buffer,iphdrlen); 

    fprintf(logfile , "UDP Header\n"); 
    PrintData(Buffer + iphdrlen , sizeof icmph); 

    fprintf(logfile , "Data Payload\n");  

    //Move the pointer ahead and reduce the size of string 
    PrintData(Buffer + header_size , (Size - header_size)); 

    fprintf(logfile , "\n###########################################################"); 
} 

void PrintData (unsigned char* data , int Size) 
{ 
    int i , j; 
    for(i=0 ; i < Size ; i++) 
    { 
     if(i!=0 && i%16==0) //if one line of hex printing is complete... 
     { 
      fprintf(logfile , "   "); 
      for(j=i-16 ; j<i ; j++) 
      { 
       if(data[j]>=32 && data[j]<=128) 
        fprintf(logfile , "%c",(unsigned char)data[j]); //if its a number or alphabet 

       else fprintf(logfile , "."); //otherwise print a dot 
      } 
      fprintf(logfile , "\n"); 
     } 

     if(i%16==0) fprintf(logfile , " "); 
      fprintf(logfile , " %02X",(unsigned int)data[i]); 

     if(i==Size-1) //print the last spaces 
     { 
      for(j=0;j<15-i%16;j++) 
      { 
       fprintf(logfile , " "); //extra spaces 
      } 

      fprintf(logfile , "   "); 

      for(j=i-i%16 ; j<=i ; j++) 
      { 
       if(data[j]>=32 && data[j]<=128) 
       { 
        fprintf(logfile , "%c",(unsigned char)data[j]); 
       } 
       else 
       { 
        fprintf(logfile , "."); 
       } 
      } 

      fprintf(logfile , "\n"); 
     } 
    } 
} 

在Linux運行帶有前綴「sudo」的代碼。 :)

相關問題