5

I'm trying to create a program for read, given IP address and port (in this case on localhost), of UDP packets on Mac OS X (current version 10.9.5).

The only one that gave me some useful data is tcpdump and nc (netcat), but it worked only 1 time. This is what I have done:

1° terminal window

$ 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° terminal window

$ nc -u 192.168.1.67 60000
Hello
$

I don't have a lot of knowledge on this argument, so the final question is:

If I need to create a program that needs to read any UDP packet given a port number and send UDP packets through the same port to any IP address, what's the easiest approach? I've tried to use also libpcap through C but without success.

genesisxyz
  • 778
  • 3
  • 14
  • 29
  • I.e., you want to receive all UDP packets sent to some particular port on your machine, and reply back to those UDP packets? And there's no need to be able to see any packets *other* than those packets - i.e., if it's sent to some other machine, or is sent to your machine but isn't a UDP packet, or if it's a UDP packet sent to your machine but not that port, you don't need to see it? If so, you don't need to use libpcap, you can just use regular UDP sockets. –  Dec 31 '15 at 01:11

2 Answers2

6

I have solved the problem with libpcap using the C library:

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;
}

The idea is that we pick the packet through pcap_loop and we analyze the data we get:

In my case, I have a Ethernet header at start, I used Wikipedia to understand how it is done Ethernet frame. The EtherType is set at 0x0800, that shows that the next bytes is IP Header IPv4 Header. The protocol here shows that is UDP Packet UDP Packet Structure.

I have compiled this on OS X 10.9 through Xcode with the pcap library, and it works just fine. The only problem is that this is really static, it requires Ethernet and works only for IPv4.

genesisxyz
  • 778
  • 3
  • 14
  • 29
  • Thank you for answer. Is there is the same implementation of my_callback() but for TCP packet? – Serge Mar 10 '16 at 13:39
  • for TCP is totally different, starting with the header, the UDP one is way easier and simple https://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_segment_structure I don't have a TCP implementation ready at the moment – genesisxyz Mar 10 '16 at 15:24
3

You can use "Packet Sender" application. It follows "GPL v2 or later" LICENSE.

It support not only "Mac OS X" but also "Windows XP ~ 10", "Linux Desktop".

Namo
  • 456
  • 5
  • 11