Azinix

pktNet.c

Go to the documentation of this file.
00001 /** \file pktNet.c
00002 
00003   \brief Routines for reading and writing packets to the network.
00004 
00005 */
00006 
00007 #include "pkt.h"
00008 
00009 /**AutomaticStart*************************************************************/
00010 
00011 /*---------------------------------------------------------------------------*/
00012 /* Static function prototypes                                                */
00013 /*---------------------------------------------------------------------------*/
00014 
00015 
00016 /**AutomaticEnd***************************************************************/
00017 
00018 
00019 /**
00020   * \brief  Routine for creating an encapsulation of the libnet
00021   * data structures.  
00022   * 
00023   * If the interface name passed in is null, default to "eth0".
00024   */
00025 
00026 Pkt_LibNet_t *
00027 Pkt_InitLibNet (char *interfaceName)
00028 {
00029   Pkt_LibNet_t *result;
00030 
00031   result = (Pkt_LibNet_t *) malloc (sizeof (Pkt_LibNet_t));
00032 
00033   result->interfaceName = interfaceName ? strdup (interfaceName) : (char *) "eth0";
00034   result->errbuf = (char *) malloc (LIBNET_ERRBUF_SIZE * sizeof (char));
00035   result->l = libnet_init (LIBNET_LINK_ADV, /* injection type */
00036                result->interfaceName,   /* network interface */
00037                result->errbuf); /* error buffer */
00038 
00039   if (result->l == NIL (libnet_t))
00040     {
00041       fprintf (stderr, "Can not initialize libnet: interface %s"
00042            "\n\tLibnet error message: %s\n", result->interfaceName,
00043            result->errbuf);
00044       exit (-1);
00045     }
00046 
00047   return result;
00048 }
00049 
00050 
00051 /**
00052   * \brief  Finish using a Pkt_LibNet_t struct.
00053   */
00054 
00055 int
00056 Pkt_LibNetFinish (Pkt_LibNet_t * obj)
00057 {
00058   free (obj->interfaceName);
00059   free (obj->errbuf);
00060   libnet_destroy (obj->l);
00061   return 0;
00062 }
00063 
00064 
00065 /**
00066   * \brief  Transmit a raw ethernet frame.
00067   * 
00068   * Exits on fail, returns number of bytes written on success.
00069   */
00070 
00071 int
00072 Pkt_EthPktWrite (Pkt_EthernetHdr_t * anEth,
00073          int anEthLength, Pkt_LibNet_t * aNetObj)
00074 {
00075   int count;
00076   Pkt_HTON (anEth);
00077   count =
00078     libnet_adv_write_link (aNetObj->l, (u_int8_t *) anEth,
00079                (u_int32_t) anEthLength);
00080   if (count == -1)
00081     {
00082       // printf("Error in writing packet to network\n");
00083       return 0;
00084     }
00085   // we may not be done with it (eg if it's synthetic traffic
00086   // we're cycling through, so restore to host order
00087   Pkt_NTOH (anEth);
00088   return count;
00089 
00090 }
00091 
00092 
00093 /**
00094   * \brief Initialize an array of pcap objects, one per array entry
00095   */
00096 
00097 array_t *
00098 Pkt_InitLibPcapArray (array_t * inArray)
00099 {
00100   array_t *result = array_alloc (Pkt_LibPcap_t *, 0);
00101   int i;
00102   for (i = 0; i < array_n (inArray); i++)
00103     {
00104       char *ifName = array_fetch (char *, inArray, i);
00105       Pkt_LibPcap_t *aPcapObj = Pkt_InitLibPcap (ifName);
00106       array_insert_last (Pkt_LibPcap_t *, result, aPcapObj);
00107     }
00108   return result;
00109 }
00110 
00111 
00112 /**
00113   * \brief Initialize an array of libnet objects, one per array entry
00114   */
00115 
00116 array_t *
00117 Pkt_InitLibNetArray (array_t * outArray)
00118 {
00119   array_t *result = array_alloc (Pkt_LibNet_t *, 0);
00120   int i;
00121   for (i = 0; i < array_n (outArray); i++)
00122     {
00123       char *ifName = array_fetch (char *, outArray, i);
00124       Pkt_LibNet_t *aLibnetObj = Pkt_InitLibNet (ifName);
00125       array_insert_last (Pkt_LibNet_t *, result, aLibnetObj);
00126     }
00127   return result;
00128 }
00129 
00130 
00131 /**
00132   * \brief  Initialize our encapsulation of a pcap_t
00133   */
00134 
00135 Pkt_LibPcap_t *
00136 Pkt_InitLibPcap (char *interfaceName)
00137 {
00138   Pkt_LibPcap_t *result = (Pkt_LibPcap_t *) malloc (sizeof (Pkt_LibPcap_t));
00139   pcap_t *p;
00140   char *device;
00141   char errbuf[PCAP_ERRBUF_SIZE];
00142   struct bpf_program filterCode;
00143   u_int32_t localNet, netmask;
00144   bzero (errbuf, PCAP_ERRBUF_SIZE);
00145 
00146   device = NIL (char);
00147   device = interfaceName;
00148 
00149   if (device == NIL (char))
00150     {
00151       device = pcap_lookupdev (errbuf);
00152       if (device == NIL (char))
00153     {
00154       fprintf (stderr, "pcap_lookupdev() failed:%s\n", errbuf);
00155       exit (-1);
00156     }
00157     }
00158   result->interfaceName = device;
00159 
00160   /// \todo had 1500, leads to hangs?
00161   /// should be 1518, leaves 1500 for ip
00162   int snaplen = 1540;       // max ether frame size
00163   int promisc = 1;      // capture all packets seen on interface
00164   int timeout = -1;     // in milliseconds
00165 
00166   // from manpage for pcap_open_live:
00167   /* pcap_t *pcap_open_live(const char *device, int snaplen, int promisc, 
00168      int to_ms, char *errbuf)
00169 
00170      pcap_open_live()  is used to obtain a packet capture descriptor to look
00171      work  device  to  open;  on  Linux systems with 2.2 or later kernels, a
00172      device argument of "any" or NULL can be used to  capture  packets  from
00173      all  interfaces.  snaplen specifies the maximum number of bytes to cap-
00174      ture.  If this value is less than the size of a  packet  that  is  cap-
00175      tured, only the first snaplen bytes of that packet will be captured and
00176      provided as packet data.  A value of 65535  should  be  sufficient,  on
00177      most  if  not  all networks, to capture all the data available from the
00178      packet.  promisc specifies if the interface is to be put into promiscu-
00179      ous  mode.   (Note  that even if this parameter is false, the interface
00180      could well be in promiscuous mode for some  other  reason.)   For  now,
00181      this  doesn’t work on the "any" device; if an argument of "any" or NULL
00182      is supplied, the promisc flag is ignored.   to_ms  specifies  the  read
00183      timeout  in milliseconds.  The read timeout is used to arrange that the
00184      read not necessarily return immediately when a packet is seen, but that
00185      it  wait for some amount of time to allow more packets to arrive and to
00186      read multiple packets from the OS kernel in  one  operation.   Not  all
00187      platforms  support  a  read  timeout; on platforms that don’t, the read
00188      timeout is ignored.  A zero value for to_ms , on platforms that support
00189      a read timeout, will cause a read to wait forever to allow enough pack-
00190      ets to arrive, with no timeout.  On linux systems, using a mmap  shared
00191      memory ring buffer, the to_ms takes on these specific meanings:
00192 
00193      With  a  positive timeout a read will return if either, enough polls
00194      have been called to exhaust the timeout value based  on  the  packet
00195      time, or the timeout expires and no packets have been received.
00196 
00197      With  a zero timeout, a read will never return.  The timeout is con-
00198      sidered infinite.  Of course callbacks will continue for each packet
00199      that  arrives.  The PCAP_TIMEOUT environment variable can be used to
00200      signal an error of ETIMEDOUT which will cause the read to terminate.
00201      A nice clean way to quit at a certain time in a script.
00202 
00203      With  a  value  of -1, the read will return if either, there were no
00204      packets on the ring, or the packets that have  been  queued  on  the
00205      ring have all been processed.  This is essentially non-blocking.
00206    */
00207 
00208 
00209 
00210   p = pcap_open_live (device, snaplen, promisc, timeout, errbuf);
00211   if (p == NIL (pcap_t))
00212     {
00213       fprintf (stderr, "pcap_open_live() failed:%s\n", errbuf);
00214       exit (-1);
00215     }
00216 
00217   if (pcap_lookupnet (device, &localNet, &netmask, errbuf) == -1)
00218     {
00219       fprintf (stderr, "pcap_lookupnet() failed (no IP stack?):%s\n"
00220            "Using default 255.255.255.255\n", errbuf);
00221       localNet = ~0x0;
00222       netmask = ~0x0;
00223     }
00224   result->localNet = localNet;
00225   result->netmask = netmask;
00226 
00227   /// \todo had ip in filter before
00228   /// char *filter = "ip";
00229   char *filter = "";
00230   if (pcap_compile (p, &filterCode, filter, 1, netmask) == -1)
00231     {
00232       fprintf (stderr, "pcap_compile() failed:%s\n", errbuf);
00233       exit (-1);
00234     }
00235 
00236   if (pcap_setfilter (p, &filterCode) == -1)
00237     {
00238       fprintf (stderr, "pcap_setfilter() failed:%s\n", errbuf);
00239       exit (-1);
00240     }
00241   result->filterCode = filterCode;
00242 
00243   // AA: added to set direction
00244   pcap_setdirection (p, PCAP_D_IN);
00245 
00246   result->p = p;
00247 
00248   return result;
00249 }
00250 
00251 
00252 /** \brief  Finish using a Pkt_LibPcap_t struct. */
00253 
00254 int
00255 Pkt_LibPcapFinish (Pkt_LibPcap_t * obj)
00256 {
00257   pcap_close (obj->p);
00258   free (obj);
00259   return 0;
00260 }