Azinix

pktFile.c

Go to the documentation of this file.
00001 /** \file  pktFile.c
00002 
00003  \brief Routines for reading and writing packets to file, as well
00004  as creating packets
00005 */
00006 
00007 #include "pkt.h"
00008 
00009 /*AutomaticStart*************************************************************/
00010 
00011 /*---------------------------------------------------------------------------*/
00012 /* Static function prototypes                                                */
00013 /*---------------------------------------------------------------------------*/
00014 
00015 static Pkt_EthernetHdr_t *createPacketFromAttribValArray (array_t *
00016                               attribValueArray);
00017 static util_byte_array_t *createIpPktFromAttribValueArray (array_t *
00018                                attribValueArray,
00019                                util_byte_array_t *
00020                                l4Packet,
00021                                int l4Protocol);
00022 static util_byte_array_t *createIcmpPktFromAttribValueArray (array_t *
00023                                  attribValueArray);
00024 static util_byte_array_t *createUdpPktFromAttribValueArray (array_t *
00025                                 attribValueArray);
00026 static util_byte_array_t *createTcpPktFromAttribValueArray (array_t *
00027                                 attribValueArray);
00028 static Pkt_L4ProtType_t getL4Prot (array_t * attribValueArray);
00029 static Pkt_L3ProtType_t getL3Prot (array_t * attribValueArray);
00030 static st_table *parseIpOptions (char *value);
00031 
00032 /*AutomaticEnd***************************************************************/
00033 
00034 
00035 /*---------------------------------------------------------------------------*/
00036 /* Definition of exported functions                                          */
00037 /*---------------------------------------------------------------------------*/
00038 
00039 /**
00040   * \brief  Write an ethernet frame to file.
00041   * File is assumed to be open  and writable.  
00042   * Format: length followed by sequence of bytes.
00043   * 
00044   * If we used fprintf, we would need both the FILE * fp  AND 
00045   * the int fd as there's no simple way to go from one to the other.  
00046   * (We don't wan't to pass in the file name as the we'd have to 
00047   * keep opening and closing the file.)
00048   * 
00049   * The alternative is to write the length using write itself,
00050   * but then we need to worry about the byte order. (Or perhaps
00051   * not, as we can just read back without worrying about the order,
00052   * its the same in both cases.
00053   */
00054 
00055 int
00056 Pkt_EthPacketWriteToFile (int fd,
00057               Pkt_EthernetHdr_t * anEthPkt, unsigned int length)
00058 {
00059 
00060   char *lengthPtr = (char *) &length;
00061 
00062   if ((sizeof (char *) != write (fd, lengthPtr, sizeof (char *))) ||
00063       (length != (unsigned int) write (fd, anEthPkt, length)))
00064     {
00065       printf ("Write failed in Pkt_EthPacketWriteToFile\n");
00066       return -1;
00067     }
00068   return 0;
00069 
00070 }
00071 
00072 
00073 /**
00074   * \brief  Read an Ethernet frame from a file
00075   * Returns NIL if the file is empty, and otherwise a pointer to the
00076   * frame. Caller is responsible for freeing the memory
00077   * allocated for the frame.
00078   */
00079 
00080 int
00081 Pkt_EthPacketReadFromFile (int fd, Pkt_EthernetHdr_t ** anEthPktPtr)
00082 {
00083   int length;
00084   char *packet;
00085 
00086   if (sizeof (int) != read (fd, &length, sizeof (int)))
00087     {
00088       return 0;
00089     }
00090 
00091   if (length < (int) sizeof (Pkt_EthernetHdr_t))
00092     {
00093       // clear sign something is wrong
00094       printf ("Corrupt file in Pkt_EthPacketReadFromFile, bailing\n");
00095       assert (0);
00096     }
00097 
00098   packet = (char *) malloc (length);
00099   if (length != read (fd, packet, length))
00100     {
00101       printf ("Corrupt file in Pkt_EthPacketReadFromFile, bailing\n");
00102       assert (0);
00103     }
00104   *anEthPktPtr = (Pkt_EthernetHdr_t *) packet;
00105 
00106   return length;
00107 }
00108 
00109 
00110 /** \brief Create a packets from a textual description
00111   
00112 \sa Pkt_CreateRandIpPkt
00113 
00114 Format
00115 <pre>
00116   protocol: ip, udp, tcp, icmp
00117   offset is from 0 to 2^13 - 1
00118   ttl is from 0 to 255
00119   ipflag:RB,DF,MF (one of)
00120   tcpflag:fin,syn,rst,psh,ack,urg,ece,cwr  (one of)
00121   ipoptions:EOOL,NOP,SEC,LSR,TS,E-SEC,CIPSO,RR,SID,SSR,ZSU,
00122         MTUP,MTUR,FINN,VISA,ENCODE,IMITD,EIP,TR,ADDEXT,RTRALT,SDB,NSAPA,DPS,UMP 
00123   size is size of ENTIRE packet, including header (but not ethernet part)
00124   content:"foo"  --- use escapes, etc. appropriately
00125 
00126   Ex. 
00127   srcip:192.168.1.1; destip:1.2.3.4; ipflags:MF; ipoptions:EOOL; offset:1234; id:100; ttl:255; protocol:tcp; srcport:80; 
00128   destport:80; seq:100; ack:100; tcpflag:fin; size:100; content:"foo"; 
00129 </pre>
00130 
00131 */
00132 
00133 array_t *
00134 Pkt_CreatePktsFromString (char *pktFile)
00135 {
00136   array_t *result = array_alloc (Pkt_EthernetHdr_t *, 0);
00137   array_t *rawPktsAndMacrosArray = util_process_file (pktFile);
00138   st_table *defineTable = Hash_InitTable ( ( int(*)() ) strcmp,  ( int(*)() ) st_strhash);
00139   int i;
00140 
00141   for (i = 0; i < array_n (rawPktsAndMacrosArray); i++)
00142     {
00143       char *anEntry = array_fetch (char *, rawPktsAndMacrosArray, i);
00144       if (util_strequalN (anEntry, "var", 3))
00145     {
00146       Rlp_UpdateDefineTable (defineTable, anEntry);
00147     }
00148       else
00149     {
00150       array_t *attribValueArray = Rlp_L7StringParse (anEntry);
00151       /* useful for debugging
00152          int j;
00153          for ( j = 0 ; j < array_n( attribValueArray ); j++ ) {
00154          util_attrib_val_t *aComponent = array_fetch( util_attrib_val_t *, attribValueArray, j );
00155          printf("%d - %s, %s\n", j,  aComponent->rawAttribute, aComponent->rawValue );
00156          }
00157        */
00158       Pkt_EthernetHdr_t *pkt =
00159         createPacketFromAttribValArray (attribValueArray);
00160       array_insert_last (Pkt_EthernetHdr_t *, result, pkt);
00161     }
00162     }
00163   return result;
00164 }
00165 
00166 
00167 /**
00168   * \brief Create single packet from string.
00169   *
00170   *     Just calls Pkt_CreatePktsFromString and makes sure there is just one entry
00171   * in the returned array, and returns that entry.
00172   */
00173 
00174 Pkt_EthernetHdr_t *
00175 Pkt_CreatePktFromString (char *pktString)
00176 {
00177   array_t *pkts = Pkt_CreatePktsFromString (pktString);
00178   if (array_n (pkts) != 1)
00179     {
00180       fprintf (stderr, "Error, called Pkt_CreatePktFromString "
00181            "on a string that resulted in %d pkts", array_n (pkts));
00182       assert (0);
00183     }
00184   Pkt_EthernetHdr_t *result = array_fetch (Pkt_EthernetHdr_t *, pkts, 0);
00185   array_free (pkts);
00186   return result;
00187 }
00188 
00189 
00190 /**
00191   * \brief  Produce a packet based on the entries in the attrib-val array
00192   *
00193   *     \sa Pkt_CreateFromFile
00194   */
00195 
00196 static Pkt_EthernetHdr_t *
00197 createPacketFromAttribValArray (array_t * attribValueArray)
00198 {
00199   Pkt_L4ProtType_t l4Prot = getL4Prot (attribValueArray);
00200   util_byte_array_t *l4Packet;
00201   switch (l4Prot)
00202     {
00203     case Pkt_L4ProtTcp_c:
00204       l4Packet = createTcpPktFromAttribValueArray (attribValueArray);
00205       break;
00206     case Pkt_L4ProtUdp_c:
00207       l4Packet = createUdpPktFromAttribValueArray (attribValueArray);
00208       break;
00209     case Pkt_L4ProtIcmp_c:
00210       l4Packet = createIcmpPktFromAttribValueArray (attribValueArray);
00211       break;
00212     default:
00213       printf ("Error: no l4 protocol specified\n");
00214       assert (0);
00215     }
00216 
00217   Pkt_L3ProtType_t l3Prot = getL3Prot (attribValueArray);
00218   util_byte_array_t *l3Packet;
00219   switch (l3Prot)
00220     {
00221     case Pkt_L3ProtIp_c:
00222       l3Packet =
00223     createIpPktFromAttribValueArray (attribValueArray, l4Packet, l4Prot);
00224       break;
00225     case Pkt_L3ProtArp_c:
00226       /// \todo implement ARP generation
00227       // l3Packet = createArpPktFromAttribValueArray( attribValueArray, l4Packet, l4Prot );
00228       break;
00229     default:
00230       printf ("Error: no l3 protocol specified\n");
00231       assert (0);
00232     }
00233   Pkt_EthernetHdr_t *result =
00234     Pkt_CreateEthPkt ("000000", "111111", l3Packet, Pkt_L3ProtIp_c);
00235 
00236   return result;
00237 }
00238 
00239 
00240 /**
00241   * \brief Make an ip packet out from textual description and passed in l4 packet
00242   */
00243 
00244 static util_byte_array_t *
00245 createIpPktFromAttribValueArray (array_t * attribValueArray,
00246                  util_byte_array_t * l4Packet, int l4Protocol)
00247 {
00248   array_t *srcIps = array_alloc (u_int32_t, 0);
00249   array_t *destIps = array_alloc (u_int32_t, 0);
00250 
00251   array_t *offsets = array_alloc (u_int16_t, 0);
00252   array_t *ids = array_alloc (u_int16_t, 0);
00253   array_t *ttls = array_alloc (u_int8_t, 0);
00254 
00255   st_table *ipFlags = Hash_InitTable ( ( int(*)() ) strcmp,  ( int(*)() ) st_strhash);
00256   st_table *ipOptions = Hash_InitTable ( ( int(*)() ) strcmp,  ( int(*)() ) st_strhash);
00257 
00258   int i;
00259   for (i = 0; i < array_n (attribValueArray); i++)
00260     {
00261       util_attrib_val_t *avPair =
00262     array_fetch (util_attrib_val_t *, attribValueArray, i);
00263       char *attribute = avPair->rawAttribute;
00264       char *value = avPair->rawValue;
00265       if (util_strequal (attribute, "srcip"))
00266     {
00267       u_int32_t srcip = (u_int32_t) Rlp_DotToInt (value);
00268       array_insert_last (u_int32_t, srcIps, srcip);
00269     }
00270       else if (util_strequal (attribute, "destip"))
00271     {
00272       u_int32_t destip = Rlp_DotToInt (value);
00273       array_insert_last (u_int32_t, destIps, destip);
00274     }
00275       else if (util_strequal (attribute, "ttl"))
00276     {
00277       u_int32_t ttlDummy;
00278       sscanf (value, "%u", &ttlDummy);
00279       u_int8_t ttl = (u_int8_t) ttlDummy;
00280       array_insert_last (u_int8_t, ttls, ttl);
00281     }
00282       else if (util_strequal (attribute, "offset"))
00283     {
00284       u_int16_t offset;
00285       sscanf (value, "%hu", &offset);
00286       assert (offset < (2 << 13));
00287       array_insert_last (u_int16_t, offsets, offset);
00288     }
00289       else if (util_strequal (attribute, "id"))
00290     {
00291       u_int16_t id;
00292       sscanf (value, "%hu", &id);
00293       array_insert_last (u_int16_t, ids, id);
00294     }
00295       else if (util_strequal (attribute, "ipflags"))
00296     {
00297       assert (util_strequal (value, "DF") ||
00298           util_strequal (value, "RB") ||
00299           util_strequal (value, "MF") ||
00300           util_strequal (value, "!DF") ||
00301           util_strequal (value, "!RB") ||
00302           util_strequal (value, "!MF"));
00303       if (value[0] != '!')
00304         {
00305           Hash_Insert (ipFlags, strdup (value), (char *) 1);
00306         }
00307       else
00308         {
00309           Hash_Insert (ipFlags, strdup (value + 1), 0);
00310         }
00311     }
00312       else if (util_strequal (attribute, "ipopts"))
00313     {
00314       ipOptions = parseIpOptions (value);
00315     }
00316     }
00317   util_byte_array_t *l3Packet =
00318     Pkt_CreateIpPkt (srcIps, destIps, ipFlags, offsets, ids, ipOptions, ttls,
00319              l4Packet, l4Protocol);
00320 
00321   return l3Packet;
00322 }
00323 
00324 
00325 /** \brief Put together an icmp packet from attributes */
00326 
00327 static util_byte_array_t *
00328 createIcmpPktFromAttribValueArray (array_t * attribValueArray)
00329 {
00330   array_t *typeArray = array_alloc (u_int8_t, 0);
00331   array_t *codeArray = array_alloc (u_int8_t, 0);
00332 
00333   array_t *idArray = array_alloc (u_int16_t, 0);
00334   array_t *seqArray = array_alloc (u_int16_t, 0);
00335 
00336   int i;
00337   for (i = 0; i < array_n (attribValueArray); i++)
00338     {
00339       util_attrib_val_t *avPair =
00340     array_fetch (util_attrib_val_t *, attribValueArray, i);
00341       char *attribute = avPair->rawAttribute;
00342       char *value = avPair->rawValue;
00343       if (util_strequal (attribute, "itype"))
00344     {
00345       u_int32_t itypeDummy;
00346       u_int8_t itype;
00347       sscanf (value, "%u", &itypeDummy);
00348       itype = (u_int8_t) itypeDummy;
00349       array_insert_last (u_int8_t, typeArray, itype);
00350     }
00351       else if (util_strequal (attribute, "icmp_id"))
00352     {
00353       int icmpid;
00354       sscanf (value, "%u", &icmpid);
00355       array_insert_last (u_int16_t, idArray, icmpid);
00356     }
00357       else if (util_strequal (attribute, "icmp_seq"))
00358     {
00359       u_int16_t icmpseq;
00360       sscanf (value, "%hu", &icmpseq);
00361       array_insert_last (u_int16_t, seqArray, icmpseq);
00362     }
00363       else if (util_strequal (attribute, "icode"))
00364     {
00365       u_int8_t icodeDummy;
00366       u_int8_t icode;
00367       sscanf (value, "%u", &icodeDummy);
00368       icode = (u_int8_t) icodeDummy;
00369       array_insert_last (u_int8_t, codeArray, icode);
00370     }
00371     }
00372   util_byte_array_t *l4Packet =
00373     Pkt_CreateIcmpPkt (typeArray, codeArray, idArray, seqArray);
00374 
00375   return l4Packet;
00376 }
00377 
00378 
00379 /** \brief Put together a tcp packet from attributes */
00380 
00381 static util_byte_array_t *
00382 createUdpPktFromAttribValueArray (array_t * attribValueArray)
00383 {
00384   array_t *srcPorts = array_alloc (u_int16_t, 0);
00385   array_t *destPorts = array_alloc (u_int16_t, 0);
00386 
00387   array_t *sizes = array_alloc (u_int16_t, 0);
00388   array_t *byteStrings = array_alloc (util_byte_array_t *, 0);
00389 
00390   int i;
00391   for (i = 0; i < array_n (attribValueArray); i++)
00392     {
00393       util_attrib_val_t *avPair =
00394     array_fetch (util_attrib_val_t *, attribValueArray, i);
00395       char *attribute = avPair->rawAttribute;
00396       char *value = avPair->rawValue;
00397       if (util_strequal (attribute, "srcport"))
00398     {
00399       u_int16_t srcport;
00400       sscanf (value, "%hu", &srcport);
00401       array_insert_last (u_int16_t, srcPorts, srcport);
00402     }
00403       else if (util_strequal (attribute, "destport"))
00404     {
00405       u_int16_t destport;
00406       sscanf (value, "%hu", &destport);
00407       array_insert_last (u_int16_t, destPorts, destport);
00408     }
00409       else if (util_strequal (attribute, "size"))
00410     {
00411       u_int16_t size;
00412       sscanf (value, "%hu", &size);
00413       array_insert_last (u_int16_t, sizes, size);
00414     }
00415       else if (util_strequal (attribute, "content"))
00416     {
00417       array_insert_last (util_byte_array_t *, byteStrings,
00418                  util_byte_array_create (strdup (value),
00419                              strlen (value)));
00420     }
00421     }
00422   util_byte_array_t *l4Packet =
00423     Pkt_CreateUdpPkt (srcPorts, destPorts, sizes, byteStrings);
00424 
00425   return l4Packet;
00426 }
00427 
00428 
00429 /** \brief Put together a tcp packet from attributes */
00430 
00431 static util_byte_array_t *
00432 createTcpPktFromAttribValueArray (array_t * attribValueArray)
00433 {
00434   array_t *srcPorts = array_alloc (u_int16_t, 0);
00435   array_t *destPorts = array_alloc (u_int16_t, 0);
00436 
00437   array_t *seqNums = array_alloc (u_int32_t, 0);
00438   array_t *ackNums = array_alloc (u_int32_t, 0);
00439 
00440   st_table *tcpFlags = Hash_InitTable ( ( int(*)() ) strcmp,  ( int(*)() ) st_strhash);
00441 
00442   array_t *sizes = array_alloc (u_int16_t, 0);
00443   array_t *byteStrings = array_alloc (util_byte_array_t *, 0);
00444 
00445   int i;
00446   for (i = 0; i < array_n (attribValueArray); i++)
00447     {
00448       util_attrib_val_t *avPair =
00449     array_fetch (util_attrib_val_t *, attribValueArray, i);
00450       char *attribute = avPair->rawAttribute;
00451       char *value = avPair->rawValue;
00452       if (util_strequal (attribute, "srcport"))
00453     {
00454       u_int16_t srcport;
00455       sscanf (value, "%hu", &srcport);
00456       array_insert_last (u_int16_t, srcPorts, srcport);
00457     }
00458       else if (util_strequal (attribute, "destport"))
00459     {
00460       u_int16_t destport;
00461       sscanf (value, "%hu", &destport);
00462       array_insert_last (u_int16_t, destPorts, destport);
00463     }
00464       else if (util_strequal (attribute, "seq"))
00465     {
00466       u_int32_t seqnum;
00467       sscanf (value, "%u", &seqnum);
00468       array_insert_last (u_int32_t, seqNums, seqnum);
00469     }
00470       else if (util_strequal (attribute, "ack"))
00471     {
00472       u_int32_t acknum;
00473       sscanf (value, "%u", &acknum);
00474       array_insert_last (u_int32_t, ackNums, acknum);
00475     }
00476       else if (util_strequal (attribute, "size"))
00477     {
00478       u_int16_t size;
00479       sscanf (value, "%hu", &size);
00480       array_insert_last (u_int16_t, sizes, size);
00481     }
00482       else if (util_strequal (attribute, "tcpflags"))
00483     {
00484       assert (util_strequal (value, "F") ||
00485           util_strequal (value, "S") ||
00486           util_strequal (value, "R") ||
00487           util_strequal (value, "P") ||
00488           util_strequal (value, "A") ||
00489           util_strequal (value, "U") ||
00490           util_strequal (value, "E") ||
00491           util_strequal (value, "C") ||
00492           util_strequal (value, "!F") ||
00493           util_strequal (value, "!S") ||
00494           util_strequal (value, "!R") ||
00495           util_strequal (value, "!P") ||
00496           util_strequal (value, "!A") ||
00497           util_strequal (value, "!U") ||
00498           util_strequal (value, "!E") || util_strequal (value, "!C"));
00499       if (value[0] == '!')
00500         {
00501           Hash_Insert (tcpFlags, strdup (value + 1), 0);
00502         }
00503       else
00504         {
00505           Hash_Insert (tcpFlags, strdup (value), (char *) 1);
00506         }
00507     }
00508       else if (util_strequal (attribute, "content"))
00509     {
00510       array_insert_last (util_byte_array_t *, byteStrings,
00511                  util_byte_array_create (strdup (value),
00512                              strlen (value)));
00513     }
00514     }
00515   util_byte_array_t *l4Packet =
00516     Pkt_CreateTcpPkt (srcPorts, destPorts, seqNums, ackNums, tcpFlags, sizes,
00517               byteStrings);
00518 
00519   return l4Packet;
00520 }
00521 
00522 
00523 /** \brief Figure out what the layer 4 protocol is from the attributes passed in */
00524 
00525 static Pkt_L4ProtType_t
00526 getL4Prot (array_t * attribValueArray)
00527 {
00528   int i;
00529   for (i = 0; i < array_n (attribValueArray); i++)
00530     {
00531       util_attrib_val_t *avPair =
00532     array_fetch (util_attrib_val_t *, attribValueArray, i);
00533       char *attribute = avPair->rawAttribute;
00534       if (util_strequal (attribute, "protocol"))
00535     {
00536       char *value = avPair->rawValue;
00537       if (util_strequal (value, "tcp"))
00538         {
00539           return Pkt_L4ProtTcp_c;
00540         }
00541       else if (util_strequal (value, "icmp"))
00542         {
00543           return Pkt_L4ProtIcmp_c;
00544         }
00545       else if (util_strequal (value, "udp"))
00546         {
00547           return Pkt_L4ProtUdp_c;
00548         }
00549     }
00550     }
00551   return Pkt_L4ProtUndef_c;
00552 }
00553 
00554 
00555 /** \brief Figure out what the layer 3 protocol is from the attributes passed in */
00556 
00557 static Pkt_L3ProtType_t
00558 getL3Prot (array_t * attribValueArray)
00559 {
00560   int i;
00561   for (i = 0; i < array_n (attribValueArray); i++)
00562     {
00563       util_attrib_val_t *avPair =
00564     array_fetch (util_attrib_val_t *, attribValueArray, i);
00565       char *attribute = avPair->rawAttribute;
00566       if (util_strequal (attribute, "protocol"))
00567     {
00568       char *value = avPair->rawValue;
00569       if (util_strequal (value, "tcp") ||
00570           util_strequal (value, "udp") ||
00571           util_strequal (value, "icmp") || util_strequal (value, "ip"))
00572         {
00573           return Pkt_L3ProtIp_c;
00574         }
00575       else if (util_strequal (value, "arp"))
00576         {
00577           return Pkt_L3ProtArp_c;
00578         }
00579     }
00580     }
00581   return Pkt_L3ProtUndef_c;
00582 }
00583 
00584 
00585 /**
00586   * \brief Create a hash table containing all the ip options and their lengths
00587   *
00588   * Value is in the form "eol,nop,rr,rs,sec,lsrr,ssrr,satid"
00589   */
00590 
00591 static st_table *
00592 parseIpOptions (char *value)
00593 {
00594   st_table *result = Hash_InitTable ( ( int(*)() ) strcmp,  ( int(*)() ) st_strhash);
00595 
00596   char *comma;
00597   char *string = strdup (value);
00598   char *origstring = string;
00599   while (NIL (char) != (comma = strchr (string, ',')))
00600     {
00601       *comma = '\0';
00602       char *entry = strdup (string);
00603       Hash_Insert (result, entry, NIL (char));
00604       string = comma + 1;
00605     }
00606   char *lastentry = strdup (string);
00607   Hash_Insert (result, lastentry, NIL (char));
00608   free (origstring);
00609 
00610   return result;
00611 }