【问题标题】:How to read and send UDP packets on Mac OS X?如何在 Mac OS X 上读取和发送 UDP 数据包?
【发布时间】:2014-10-09 09:33:45
【问题描述】:

我正在尝试创建一个程序,用于读取 Mac OS X(当前版本 10.9.5)上的 UDP 数据包,给定 IP 地址和端口(在本例中为本地主机)。

唯一给我一些有用数据的是 tcpdump 和 nc (netcat),但它只工作了 1 次。 这就是我所做的:

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,但没有成功。

【问题讨论】:

  • 即,您想接收发送到您机器上某个特定端口的所有 UDP 数据包,并回复这些 UDP 数据包?除了那些数据包之外,没有必要能够看到任何数据包其他 - 即,如果它被发送到其他机器,或者被发送到您的机器但不是 UDP 数据包,或者它是一个UDP数据包发送到你的机器但不是那个端口,你不需要看吗?如果是这样,您不需要使用 libpcap,您可以使用常规 UDP 套接字。

标签: macos udp libpcap tcpdump netcat


【解决方案1】:

我已经使用 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。 这里的protocol 显示为UDP Packet UDP Packet Structure

我已经通过 Xcode 使用 pcap 库在 OS X 10.9 上编译了它,它工作得很好。 唯一的问题是这真的是静态的,它需要以太网并且仅适用于 IPv4。

【讨论】:

  • 感谢您的回答。 my_callback() 是否有相同的实现,但用于 TCP 数据包?
  • TCP 完全不同,从标头开始,UDP 更简单en.wikipedia.org/wiki/…我目前没有准备好 TCP 实现
【解决方案2】:

您可以使用“Packet Sender”应用程序。 它遵循“GPL v2 或更高版本”许可证。

它不仅支持“Mac OS X”,还支持“Windows XP ~ 10”、“Linux Desktop”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-22
    • 1970-01-01
    • 2011-09-24
    相关资源
    最近更新 更多