2014-10-09 71 views
2

我試圖在Mac OS X(當前版本10.9.5)上爲UDP數據包創建一個讀取給定IP地址和端口(在本例中爲localhost)的程序。如何在Mac OS X上讀取和發送UDP數據包?

唯一給了我一些有用數據的是tcpdump和nc(netcat),但它只有一次工作。 這是我做了什麼:

1°終端窗口

$ sudo tcpdump -i en0 -X -v 'udp port 60000' 
tcpdump: listening on en0, link-type EN10MB (Ethernet), capture size 65535 bytes 
* new packet with the string 'Hello' at the end * 

2°終端窗口

$ nc -u 192.168.1.67 60000 
Hello 
$ 

我沒有對這個說法有很多學問的,所以最終問題是:

如果我需要創建一個程序,需要讀取UDP數據包給定的端口號,並通過同一個端口發送UDP數據包到任何IP地址,什麼是最簡單的方法? 我試圖通過C也使用libpcap,但沒有成功。

+0

即,您希望接收發送到您計算機上某個特定端口的所有UDP數據包,並回復這些UDP數據包?並且不需要能夠看到比這些數據包更多的數據包,即,如果它被髮送到其他機器,或者發送到您的機器,但不是UDP數據包,或者它是發送給UDP數據包的UDP數據包你的機器,但不是那個端口,你不需要看到它?如果是這樣,你不需要使用libpcap,你可以使用普通的UDP套接字。 – 2015-12-31 01:11:26

回答

4

我已經解決了使用C庫libpcap的問題:

的main.c

#include <pcap.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <errno.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <netinet/if_ether.h> 
#include <netinet/ip.h> 
#include <string.h> 

void my_callback(u_char *user, const struct pcap_pkthdr *pkthdr, const u_char *packet) { 

    int i = 0; 
    int k = 0; 

    for (i = 0; i < pkthdr->len; i++) { 
     if ((i % 16) == 0) { 
      fprintf(stdout, "\n%03x0\t", k); 
      k++; 
     } 
     fprintf(stdout, "%02x ", packet[i]); 
    } 

    fprintf(stdout, "\n*******************************************************\n"); 

    u_char ethernet_packet[14]; 
    u_char ip_header[24]; 
    u_char udp_header[8]; 
    int udp_header_start = 34; 
    int data_length; 

    for (i = 0; i < 14; i++) { 
     ethernet_packet[i] = packet[0 + i]; 
    } 

    fprintf(stdout, "Destination Address\t\t%02X:%02X:%02X:%02X:%02X:%02X\n", ethernet_packet[0], ethernet_packet[1], ethernet_packet[2], ethernet_packet[3], ethernet_packet[4], ethernet_packet[5]); 
    fprintf(stdout, "Source Address\t\t\t%02X:%02X:%02X:%02X:%02X:%02X\n", ethernet_packet[6], ethernet_packet[7], ethernet_packet[8], ethernet_packet[9], ethernet_packet[10], ethernet_packet[11]); 

    if (ethernet_packet[12] == 0x08 && 
     ethernet_packet[13] == 0x00) { 

     fprintf(stdout, "Ethertype\t\t\t\tIP Packet\n"); 

     for (i = 0; i < 20; i++) { 
      ip_header[i] = packet[14 + i]; 
     } 

     fprintf(stdout, "Version\t\t\t\t\t%d\n", (ip_header[0] >> 4)); 
     fprintf(stdout, "IHL\t\t\t\t\t\t%d\n", (ip_header[0] & 0x0F)); 
     fprintf(stdout, "Type of Service\t\t\t%d\n", ip_header[1]); 
     fprintf(stdout, "Total Length\t\t\t%d\n", ip_header[2]); 
     fprintf(stdout, "Identification\t\t\t0x%02x 0x%02x\n", ip_header[3], ip_header[4]); 
     fprintf(stdout, "Flags\t\t\t\t\t%d\n", ip_header[5] >> 5); 
     fprintf(stdout, "Fragment Offset\t\t\t%d\n", (((ip_header[5] & 0x1F) << 8) + ip_header[6])); 
     fprintf(stdout, "Time To Live\t\t\t%d\n", ip_header[7]); 
     if (ip_header[9] == 0x11) { 

      fprintf(stdout, "Protocol\t\t\t\tUDP\n"); 
     } 
     else { 
      fprintf(stdout, "Protocol\t\t\t\t%d\n", ip_header[9]); 
     } 
     fprintf(stdout, "Header Checksum\t\t\t0x%02x 0x%02x\n", ip_header[10], ip_header[11]); 
     fprintf(stdout, "Source Address\t\t\t%d.%d.%d.%d\n", ip_header[12], ip_header[13], ip_header[14], ip_header[15]); 
     fprintf(stdout, "Destination Address\t\t%d.%d.%d.%d\n", ip_header[16], ip_header[17], ip_header[18], ip_header[19]); 
     if ((ip_header[0] & 0x0F) > 5) { 
      udp_header_start = 48; 
      fprintf(stdout, "Options\t\t\t\t\t0x%02x 0x%02x 0x%02x 0x%02x\n", ip_header[20], ip_header[21], ip_header[22], ip_header[23]); 
     } 

     if (ip_header[9] == 0x11) { 

      fprintf(stdout, "\t\t\t\tUDP HEADER\n"); 

      for (i = 0; i < 8; i++) { 
       udp_header[i] = packet[udp_header_start + i]; 
      } 

      fprintf(stdout, "Source Port\t\t\t\t%d\n", (udp_header[0] << 8) + udp_header[1]); 
      fprintf(stdout, "Destination Port\t\t%d\n", (udp_header[2] << 8) + udp_header[3]); 
      fprintf(stdout, "Length\t\t\t\t\t%d\n", (udp_header[4] << 8) + udp_header[5]); 
      fprintf(stdout, "Checksum\t\t\t\t0x%02x 0x%02x\n", udp_header[6], udp_header[7]); 

      data_length = pkthdr->len - (udp_header_start + 8); 

      fprintf(stdout, "Data\n"); 
      for (i = 0; i < data_length; i++) { 

       fprintf(stdout, "%02x ", packet[udp_header_start + 8 + i]); 
      } 
      fprintf(stdout, "\n"); 
     } 
    } 
    else { 
     fprintf(stdout, "Ethertype\t\t\t\tUnknow\n"); 
    } 
} 

int main(int argc,char **argv) { 

    char *dev; 
    char errbuf[PCAP_ERRBUF_SIZE]; 
    pcap_t* descr; 
    struct bpf_program fp; 
    bpf_u_int32 maskp; 
    bpf_u_int32 netp; 

    dev = pcap_lookupdev(errbuf); 
    if(dev == NULL) { 
     fprintf(stderr,"%s\n",errbuf); exit(1); 
    } 

    pcap_lookupnet(dev, &netp, &maskp, errbuf); 
    descr = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf); 

    if(descr == NULL) { 
     printf("pcap_open_live(): %s\n",errbuf); 
     exit(1); 
    } 

    char filter[] = "udp"; 
    if(pcap_compile(descr,&fp, filter,0,netp) == -1) { 
     fprintf(stderr,"Error calling pcap_compile\n"); 
     exit(1); 
    } 

    if(pcap_setfilter(descr,&fp) == -1) { 
     fprintf(stderr,"Error setting filter\n"); 
     exit(1); 

    } 

    pcap_loop(descr,-1,my_callback,NULL);  

    /* write a packet 
    //define a new packet and for each position set its values 
    u_char packet[86]; 


    // Send down the packet 
    if (pcap_sendpacket(descr, packet, 86) != 0) { 

     fprintf(stderr,"\nError sending the packet: %s\n", pcap_geterr(descr)); 
     return 2; 
    } 
    */ 
    return 0; 
} 

的想法是,我們選擇的包通過pcap_loop,我們分析我們得到的數據:

在我的情況下,我有一個以太網頭在開始,我用維基百科瞭解它是如何完成的Ethernet frameEtherType設置爲0x0800,表明下一個字節是IP HeaderIPv4 Header。 這裏顯示的是UDP PacketUDP Packet Structure

我已經通過Xcode與pcap庫在OS X 10.9上編譯了它,它工作得很好。 唯一的問題是,這是非常靜態的,它需要以太網並且僅適用於IPv4。

+0

謝謝你的回答。是否有與my_callback()相同的實現,但是對於TCP數據包?對於TCP來說, – Sergio 2016-03-10 13:39:33

+0

是完全不同的,從頭部開始,UDP更容易和簡單https://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_segment_structure我目前沒有準備好TCP協議 – genesisxyz 2016-03-10 15:24:13