« Shared-libary build fails on AMD_64 | Main | Install VMWare ESX Server 3 in VMWare Workstation »

December 23, 2006

o2.c

o2.c is an ethernet & ip packet grabber for linux adapted from Sean Walton's snooper.c.
This code was written in a college networking course to capture packets off the wire. I'd like to think it's a decent example of how to handle raw packets under Linux (granted there are newer methods now available).
The full source and very short documentation can be downloaded.

/*
o2.c - v2.4
 * Portions copyright (c) 2005 Kevin Bralten and Ryan Smit
 * Copyright (c) 2000 Sean Walton and Macmillan Publishers.
 *  
 * Use may be in whole or in part in accordance to the General Public
 * License (GPL).
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.

*/
/******************************
 * Version History
 * 
 * Dec. 1st 2005 v2.4
 * Added The 2 pages of comments that are seen after this History
 *
 * Nov. 24th 2005 v2.3
 * Added RTP functionality
 *
 * Nov. 10th 2005 - v2.2
 * Added TCP funtionality
 * Added the PrintAdderPlus function
 *
 * Nov. 3rd 2005 - v2.1
 * Added UDP functionality
 * Added frame limiter
 * Added Basic Help Option
 *
 * Oct. 21st 2005 - v2.0
 * Added Proper IP functionality
 * Added ARP packets
 * Added intial fixes to given code
 * 
 ********************************/

/*******************************
 * An Introduction to this code
 *
 * [cue music]
 *
 * Where The Data Goes
 * In the process of being adapted from the
 * limited functionality of the original
 * snooper.c to the new and improved o2.c
 * many many things have become interesting.
 * This overview attempts to teach you as much
 * about the code as we've discovered.
 *
 * In general, packets are captured by main and sent
 * up through the tree of dumpPacket style methods.
 *
 * Each dump packet method receives a void* pointer
 * to a block of memmory, in this memmory is everything
 * that belongs to this layer of encapsulation.
 * That would be headers + data. It also receives the
 * length of the data block.
 *
 * Each method then disects (in coperation with the
 * matching struct) it's block of data, prints
 * a summary header, and passes the data section
 * of the packet to the next layer of methods.
 *
 * eg: DumpPacket->DumpIP->DumpUDP->DumpRTP
 *
 * Some Naming Conventions
 * In general, you'll need to look up the name of
 * variables, structs, and methods you want to refer
 * to within this code. Apparently there is no standard.
 * Most methods start with Capital letters and have
 * studly caps throughout. Except the bunch that start
 * with lower case letters and have underscores,
 * or the ones taht start with lowercases and have
 * studly caps. Basicly, look it up first.
 * Most variables start with lower case and continue
 * with underscores, expect the ones without underscores,
 * or the ones with studly caps; look it up.
 *
 * Some Coding Conventions
 * Through out the stucts, members are defined as
 * type var_name:size;
 * the :size defines the number of bits reserved for this
 * variable. This is used to define things smaller then the
 * size of the type (but not larger).
 * This is used when you don't have a 3 byte char handy.
 * We had to look this one up, so we thought we'd helpo
 * you.
 * Frequently, structs are ended with 'uchar data[0];'.
 * This is _basicly_ a pointer to the data remaining
 * to be unencapsulated. Or, everything the first part
 * of the header didn't fit.
 *
 * About printf() Style
 * For consistency, values that count something are printed as
 * integers, of no predefined length. Values that represent arbitrary
 * peices of binary data (checksums, some sequence numbers, etc) are
 * printed in capital hex digits, preceded by an 0x and padded with
 * the correct number of leading 0s for the maximum size of the field.
 * 
 * Some Common Types
 * These all asume your c is like ours. Or most peoples.
 * You should know better if it isn't.
 * These are used to hold values in structs. Good for
 * all sorts of things.
 * ulong unsinged long, about 32 bits
 * uint unsigned int, about 16 bits
 * uchar unsigned char, 8 bits give or take
 * uchar[] an array of bytes, data.
 * 
 * Some Hints
 * You'll find a need to call ntohs, and ntohl fairly often.
 * Most of the data you find will be in the wrong order and
 * would look much better in host order (the little endian
 * morons). Sometimes data is already in host order, ntohs
 * here would be ugly and sometimes the data isn't in any
 * real order at all (eg echo sequence). Basicly, season
 * to taste and style.
 * For 8 bits and smaller, no ntohs needed.
 * For regular 16bit style data, ntohs is good.
 * For extra spicy cajun style 17bit and bigger data,
 * ntohl is the recomended spice.
 *
 * Comments have been added, mostly where they seem needed.
 * Some point out unobvious bits of network headers/decoding,
 * while others point out bits that seemed especially scary
 * when we wrote them or bits that seemed especially odd
 * when we read them. 
 *************************/

 /* code left from snooper.c
  * alot of code has changed, you _could_ run a diff
  * against snooper.c, this is a nice rundown.
  *
  * All of the includes have been maintained, but stdlib.h,
  * unistd.h, segfault.h, and ports.h are added.
  *
  * Much of the ip_packet struct remains, but the hardware
  * portion has been stripped and made into ether_packet.
  *
  * Dump is largely unchanged but the printf()s have
  * been revised to look prettier and work better.
  *
  * PrintAddr is intact, but is depreciated.
  * PrintAddrPlus does everything PrintAddr did, but
  * much more flexibly.
  *
  * GetProtocol is intact, but only used by the DumpIP
  * procedure.
  *
  * Panic remains.
  *
  * Main has been largely unchaged with the exception of
  * adding code to count frames and accept options.
  * 
  * In various methods sprinkled throughout, some lines
  * have been maintained.
  */

#include <stdio.h>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/types.h>
#include <linux/if_ether.h>
#include <stdlib.h>
#include <unistd.h>        //needed
#include "segfault.h"        //need standard segfaulting ability
#include "ports.h" //standard port numbers

#define stuct struct

/* someone should really adapt to things other then ethernet and IPv4 */
#define IP_SIZE  4
#define ETH_SIZE 6

/* and I really don't like the method these belong to */
/* PrintAddrPlus is the new method, less hopeing and praying
 * and assuming things are prefined sizes. */
typedef enum { eETH_ADDR, eIP_ADDR } EAddress;

typedef unsigned char uchar;

/* frame number... yes, yes the frame number */
int cnt=0;

char dont_print_shit=0 /* err, don't print shit out.
                            like that c** about the frame
                            you know, that takes up pages
                            err, yeah */;

/*--------------------------------------------------------------------
 * Ethernet Frame
 *
 * This structure defines the fields within the ethernet frame. Since
 * this programs gets the lowest-level packet, fragmented packets are
 * not reassembled.  The first few fields contain the MAC addresses
 * of the source and destination. Note that this structure is set for
 * little-endian format.
 *--------------------------------------------------------------------*/

struct ether_packet{
        uchar dst_eth[ETH_SIZE];
        uchar src_eth[ETH_SIZE];
        uchar __unknwn[2]; /*not unknown, just misunderstood*/
        /* it's either the size of the type,
        * yes this could be looked up, but assume:
        * 0x0100 and better is type
        * 0x00FF and lesser is size
        * (big numbers are better!)
        */
        uchar data[0];
};             /* hardware header */

struct arp_packet {
        uint hw_type:16;
        uint proto_type:16;
        uchar hw_size;
        uchar ip_size;
        uint opcode:16;
        uchar hw_src[ETH_SIZE]; /* sender hw address */
        uchar ip_src[IP_SIZE]; /* sender IP address */
        uchar hw_dst[ETH_SIZE];
        uchar ip_dst[IP_SIZE];
        uchar __padding[0]; /* padding on the end of the packet... hmm */
};

/* UDP -- RFC 768
 * usually rides on IP packets
 */
struct udp_packet {
        uint src_port:16;
        uint dst_port:16;
        uint len:16; //header+data (data=len-8)
        uint checksum:16;
        uchar data[0];
};

/* ICMP Packets ride inside IP Packets
 * defined by RFC 792
 * ping/echo is usually carried inside ICMP Packets
 */
struct icmp_packet {
        uchar type;
        uchar code;
        uint checksum:16;
        uchar data[0];
};

struct echo_packet {
        /* this may all be filled with any data the sender likes
         * id and seq_num are set aside because it looks like a good idea
         * data is just a block of data
         * the receiver when (or if) replying must duplicate this data
         *
         * from RFC:
         * The data received in the echo message must be returned in the echo
         * reply message.

         * The identifier and sequence number may be used by the echo sender
         * to aid in matching the replies with the echo requests.  For
         * example, the identifier might be used like a port in TCP or UDP to
         * identify a session, and the sequence number might be incremented
         * on each echo request sent.  The echoer returns these same values
         * in the echo reply.
         */
        uint id:16;
        uint seq_num:16;
        uchar data[0];
};

struct rtp_packet {
        uint flags:16;
        uint sequence:16;
        ulong timestap:32;
        ulong sync:32;
        char data[0];
};

struct ip_packet {
        uint header_len:4;       /* header length in words in 32bit words */
        uint version:4;          /* 4-bit version */
        uint serve_type:8;       /* how to service packet */
        uint packet_len:16;      /* total size of packet in bytes */
        uint ID:16;              /* fragment ID */
        uint frag_offset:13;     /* to help reassembly */
        uint more_frags:1;       /* flag for "more frags to follow" */
        uint dont_frag:1;        /* flag to permit fragmentation */
        uint __reserved:1;       /* always zero */
        uint time_to_live:8;     /* maximum router hop count */
        uint protocol:8;         /* ICMP, UDP, TCP */
        uint hdr_chksum:16;      /* ones-comp. checksum of header */
        uchar IPv4_src[IP_SIZE]; /* IP address of originator */
        uchar IPv4_dst[IP_SIZE]; /* IP address of destination */
        uchar data[0];           /* message data up to 64KB */
};

/* TCP Header
 * Err, this is what TCP headers should look like
 * as taken from RFC 793
 */
/* the um, reserved bits were um, discarded
 * the RFC says these are useless and undefined
 * in the interest of making offset and flags easier
 * on the brain, they absorbed the bits from offset
 * and some crazy bitmasking madness goes on in the dump
 * method.
 *
 * So yeah, if you know of a reason to need the reserved bits
 * you'll be smart enough to get them back.
 * (Good Luck)
 */
struct tcp_packet {
        uint src_port:16;
        uint dst_port:16;

        /* The sequence number of the first data octet in this segment (except
    when SYN is present). If SYN is present the sequence number is the
    initial sequence number (ISN) and the first data octet is ISN+1. */
        uint sequence:32;

        /* If the ACK control bit is set this field contains the value of the
    next sequence number the sender of the segment is expecting to
    receive.  Once a connection is established this is always sent. */
        uint ack:32;
        
        /* The number of 32 bit words in the TCP Header.  This indicates where
    the data begins.  The TCP header (even one including options) is an
    integral number of 32 bits long. */
        uchar offset;
        
        /* URG:  Urgent Pointer field significant
    ACK:  Acknowledgment field significant
    PSH:  Push Function
    RST:  Reset the connection
    SYN:  Synchronize sequence numbers
    FIN:  No more data from sender */
        uchar flags;
        
        /* The number of data octets beginning with the one indicated in the
    acknowledgment field which the sender of this segment is willing to
    accept. */
        uint window:16;
        
        uint checksum:16;
        uint urgent_pointer:16;

        /* Options and padding and data... this requires slightly more work */
        uchar contents[0];
};

/*--------------------------------------------------------------------*/
/* dump                                                               */
/*                                                                    */
/* Dump a block of data in hex & ascii.                               */
/*--------------------------------------------------------------------*/
void dump(void* b, int len)
{   unsigned char *buf = b;
    int i, cnt=0;
    char str[17];
    memset(str, 0, 17);
    for ( i = 0; i < len; i++ )
    {
        if ( cnt % 16 == 0 )
        {
            printf("  %16s\n%3X: ", str, cnt);
            memset(str, 0, 17);
        }
        if ( buf[cnt] < ' '  ||  buf[cnt] >= 127 )
            str[cnt%16] = '.';
        else
            str[cnt%16] = buf[cnt];
        printf("%02X ", buf[cnt++]);
    }
    /* About The %*s
     * the * after the % indicated the width of this feild is
     * found by the preceding paramter in the code. In this
     * case, that scary equation before the "".
     *
     * This particular line uses some math of add enough spaces
     * to align the last line of data.
     */
    printf("  %*s%s\n", (0!=len%16?3*(16-(len%16)):0), "", str);
    /* About the spacing equation
     * The last line ends with some arbitrary number of bytes.
     * The other lines are all 16 bytes long. In order to make
     * things pretty, the above printf is used to align the
     * end of the line. Basicly, we figure out how many bytes
     * are on the last line, subtract from 16, and add that many
     * spaces * 3 (each byte needs 3 spaces).
     * An embeded if is used to check if no spaces are needed.
     * Finally, the last line of ASCII data is printed.
     *
     * The original snooper.c had a simpiler line her, but
     * one that didn't quite cut it. (Left 16 spaces sometimes)
     */
}

/*--------------------------------------------------------------------*/
/* PrintAddr                                                          */
/*                                                                    */
/* Print the different types of address (MAC or IP).                  */
/*--------------------------------------------------------------------*/
void PrintAddr(char* msg, uchar *addr, EAddress is_ip)
{        int i;
        static struct {
                int len;
                char *fmt;
                char delim;
        } addr_fmt[] = {{ETH_SIZE, "%02X", ':'}, {IP_SIZE, "%d", '.'}};

        printf("%s", msg);
        for ( i = 0; i < addr_fmt[is_ip].len; i++ )
        {
                printf(addr_fmt[is_ip].fmt, addr[i]);
                if ( i < addr_fmt[is_ip].len-1 )
                        putchar(addr_fmt[is_ip].delim);
        }
}

void PrintAddrPlus(const char* msg, const uchar * addr, const char addr_len, const char seperator, const char* format){
        int i;

        printf("%s",msg);
        for(i=0;i<addr_len;i++){
                printf(format,addr[i]);
                if(i<addr_len-1)
                        putchar(seperator);
        }
}

/*--------------------------------------------------------------------*/
/* GetProtocol                                                        */
/*                                                                    */
/* Convert the protocol value into the alphabetic representation.     */
/*--------------------------------------------------------------------*/
char* GetProtocol(int value)
{
        switch (value)
        {
                case IPPROTO_IP: return "IP";
                case IPPROTO_ICMP: return "ICMP";
                case IPPROTO_IGMP: return "IGMP";
                case IPPROTO_IPIP: return "IPIP";
                case IPPROTO_TCP: return "TCP";
                case IPPROTO_EGP: return "EGP";
                case IPPROTO_PUP: return "PUP";
                case IPPROTO_UDP: return "UDP";
                case IPPROTO_IDP: return "IDP";
                case IPPROTO_RSVP: return "RSVP";
                case IPPROTO_GRE: return "GRE";
                case IPPROTO_IPV6: return "IPV6/4";
                case IPPROTO_PIM: return "PIM";
                case IPPROTO_RAW: return "RAW";
                default: return "???";
        }
}

/* decodes TCP, or atleast how I think TCP packets are structured, 
 * seems to need more then just a cast to the structure. */
void DumpTCPPacket(char *buffer, int len){
        struct tcp_packet *tcp=(void*)(buffer);
        /* you _are_ expected to understand this, sorry
         * 
         * tcp->offset contains (in it's upper 4 bits) the number
          * of 32bit words between the start of the TCP header and the data
         * in it. 
         * tcp points to the start of the tcp packet.
         * by casting tcp to a char*, we can add offset
         * (times 4 because it's 32bit words, and we want bytes)
          * and get a pointer to the start of the data within the 
         * tcp byte stream.
         * This way, we can pass data to any child protos as
         * their packet.
         *
         * the difference between tcp->contents and the newly calculated
         * data pointer is the options.
         */
        char* data=((char*)tcp)+((tcp->offset&0xF0)>>4)*4;

        printf("\nSource port: %d, Destination port: %d, Sequence #: 0x%08X\n", ntohs(tcp->src_port), ntohs(tcp->dst_port), ntohl(tcp->sequence));
        printf("Acknowledge: 0x%08X, Flags: 0x%02X, Window: %d\n", ntohl(tcp->ack), tcp->flags&0x3F, ntohl(tcp->window));
        printf("Checksum: 0x%04X, Urgent Pointer: %d\n", ntohs(tcp->checksum), ntohs(tcp->urgent_pointer));
        printf("Data Offset: %d\n", ((tcp->offset&0xF0)>>4)*4); /* some scary bit shifty voodoo to make offset work, it's the top 4 bits followed by some junk */
}

/* this method takes the conservitive stance that you're looking up
 * IPv4 across Ethernet... otherwise things could get interesting
 * you could potentially redefine PrintAddr to accept more parameters and make things pritier.
 */
void DumpARPPacket(char *buffer, int len){
        struct arp_packet *arp=(void*)(buffer);

        printf("\nARP Hardware Type: 0x%04X, Protocol Type: 0x%04X Op-code: %s (0x%04X)\n",ntohs(arp->hw_type),ntohs(arp->proto_type),(arp->opcode?"request":"reply"),ntohs(arp->opcode));
        PrintAddr("Source=", arp->hw_src,eETH_ADDR);
        PrintAddr(" (",arp->ip_src,eIP_ADDR);
        printf("), ");
        PrintAddr("Destination=", arp->hw_dst,eETH_ADDR);
        PrintAddr(" (",arp->ip_dst,eIP_ADDR);
        printf("), ");
}

void DumpRTPPacket(buf,len) char *buf; int len; {
        stuct rtp_packet *rtp = (void *)(buf);
        printf("\nFlags: 0x%04X, Sequence: %d\n",ntohs(rtp->flags),ntohs(rtp->sequence));
        printf("Timestamp: 0x%08X Synchronization 0x%08X\n",ntohl(rtp->timestap), ntohl(rtp->sync));        
}
        
void DumpUDPPacket(char *buf, int len){
  struct udp_packet *udp = (void *)(buf);
  int imp_port=0;
  
  printf("\nSource Port = %d, Dest Port = %d\n Length = %d, checksum 0x%04X\n", ntohs(udp->src_port), ntohs(udp->dst_port), ntohs(udp->len), ntohs(udp->checksum));  

  /* more guess work
   * based on http://www.ncftp.com/ncftpd/doc/misc/ephemeral_ports.html
   * "...Linux 2.4 kernel will default the range of 32768 through 61000..."
   * for ephemeral ports. We're gonna go ahead and assume this is true.
   *
   * So, based on this assumption, and assuming that the non-ephmeral
   * port is the important one, try to find the non-ephemeral port.
   */
  if(ntohs(udp->dst_port)<EPHEMERAL)
          imp_port=ntohs(udp->dst_port);
  if(ntohs(udp->src_port)<EPHEMERAL)
          imp_port=ntohs(udp->src_port);
  switch(imp_port){
        case 0:
                  /* we have no idea what it is */
                  break;
        case UDP_RTP:
                  /* RTP, I hope */
                  DumpRTPPacket(udp->data,len-8);
                  break;
  }
}

void DumpIPPacket(char *buffer, int len){
        struct ip_packet *ip=(void*)(buffer);
printf("\nIPv%d: header-len=%d, type=%d, packet-size=%d, ID=%d\n",
                ip->version, ip->header_len*4, ip->serve_type,
                ntohs(ip->packet_len), ntohs(ip->ID));
        printf("frag=%c, more=%c, offset=%d, TTL=%d, protocol=%d (%s)\n",
                (ip->dont_frag? 'N': 'Y'),
                (ip->more_frags? 'N': 'Y'),
                ip->frag_offset,
                ip->time_to_live, ip->protocol, GetProtocol(ip->protocol));
        printf("checksum=%d, ", ntohs(ip->hdr_chksum));
        PrintAddr("source=", ip->IPv4_src, eIP_ADDR);
        PrintAddr(", destination=", ip->IPv4_dst, eIP_ADDR);

        switch(ip->protocol){
                case 6:
                        DumpTCPPacket(ip->data, len-20);
                        break;
                case 17:
                       DumpUDPPacket(ip->data, len-20);
                       break;         
        }
}

/*--------------------------------------------------------------------*/
/* DumpPacket                                                         */
/*                                                                    */
/* Display the read packet with data and fields.                      */
/*--------------------------------------------------------------------*/
void DumpPacket(char *buffer, int len)
{        
        struct ether_packet *hw=(void*)buffer;

        #ifdef _DEBUG_FILTER_
                if(0x00==hw->src_eth[0] && 0x60==hw->src_eth[1] && 0x08==hw->src_eth[2] && 0x57==hw->src_eth[3] && 0x06==hw->src_eth[4] && 0xB7==hw->src_eth[5])
                        return;
                if(0x00==hw->dst_eth[0] && 0x60==hw->dst_eth[1] && 0x08==hw->dst_eth[2] && 0x57==hw->dst_eth[3] && 0x06==hw->dst_eth[4] && 0xB7==hw->dst_eth[5])
                        return;
        #endif

        printf("\n-------------------------------------------------\n");
        printf("Frame: %d, Type/Size: 0x%02X%02X\n", cnt+1, hw->__unknwn[0],hw->__unknwn[1]);
        PrintAddr("Destination MAC=", hw->dst_eth, eETH_ADDR);
        PrintAddr(", Source MAC=", hw->src_eth, eETH_ADDR);
        /* SCARY
         * the __unknwn bits here (2 bytes worth) represent
         * size under 802.3 packets and apear to be less then 
         * 0x0100. Otherwise, this is the type of packet riding
         * in the ethernet frame.
         * Unfortunetly, this is a 16bit value stored in 2
         * bytes; therefore the multiplication and adding bits.
         */
        switch(hw->__unknwn[0]*0x100+hw->__unknwn[1]){
                case(0x0806):
                        //Looks to be usually an ARP packet (we hope)
                        DumpARPPacket(hw->data,len-14);
                        break;
                case(0x0800):
                        //these look like IP type things
                        DumpIPPacket(hw->data,len-14);
                        break;
                default:
                        /* an asumption: 802.3 packets look unlike ethernet II packets
                         * because 802.3 packets have their length in the LSB of the
                         * type/size field.
                         *
                         * This could be horribly wrong.
                         */
                        if((hw->__unknwn[0]*0x100+hw->__unknwn[1])<0x100){
                                printf("\nLooks like an 802.3 packet. Good Luck.\n");
                        }else{
                                printf("\nAnd now for something completely Different.\n");
                        }
        }
        printf("\n");
        if(!dont_print_shit)
                dump(buffer, len);
        /* ryan doesn't like these :(
         printf("-------------------------------------------------\n");
         */
        fflush(stdout);
}

void PANIC(char *msg);
#define PANIC(msg)        {perror(msg);exit(0);}

/*--------------------------------------------------------------------*/
/* main                                                               */
/*                                                                    */
/* Open socket.  Repeatedly read and display records.                 */
/*--------------------------------------------------------------------*/
int main(int argc, char *argv[])
{   int sd, bytes_read;
    int numFrames = 0, opt;                                    
    char data[65535]; //this would be a right properly large sized packet

    /* this program operates in two modes, little endian and crash */
    endian_segfault(1);

    while ((opt = getopt(argc, argv, "f:hy")) != -1) {
             switch (opt) {
                 case 'f':          // Number of Frames to Read
                     numFrames = atoi(optarg);
                     break;
                 case 'y':
                     dont_print_shit = 1;
                     break;
                 default:
                 case 'h':          // Print Help
                     printf("Usage: %s [-y] [ -f frames]\n", argv[0]);
                     exit(0);

             }
    }

    sd  = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL));
    if ( sd < 0 )
                PANIC("o2 : You should have been root. You should be pleased you got this instead of a core dump ");

    do {
            bytes_read = recvfrom(sd, data, sizeof(data), 0, 0, 0);
        if ( bytes_read > 0 )
                        DumpPacket(data, bytes_read);
        cnt++;
    } while ( bytes_read > 0 && cnt!=numFrames);                       
    return 0;
}


Posted by spiffed at December 23, 2006 3:16 PM

Comments

Post a comment