tcpedit.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. /* $Id: tcpedit.c 1551 2006-07-31 02:59:09Z aturner $ */
  2. /*
  3. * Copyright (c) 2001-2006 Aaron Turner.
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. Neither the names of the copyright owners nor the names of its
  16. * contributors may be used to endorse or promote products derived from
  17. * this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
  20. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  21. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  22. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  23. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  24. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  25. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  26. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  27. * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  28. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  29. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. */
  31. #include "config.h"
  32. #include "defines.h"
  33. #include <ctype.h>
  34. #include <fcntl.h>
  35. #include <stdio.h>
  36. #include <stdlib.h>
  37. #include <string.h>
  38. #include <sys/types.h>
  39. #include <unistd.h>
  40. #include <stdarg.h>
  41. #include "tcpedit.h"
  42. #include "tcpedit_stub.h"
  43. #include "portmap.h"
  44. #include "common.h"
  45. #include "edit_packet.h"
  46. #include "../mac.h"
  47. #include "rewrite_l2.h"
  48. #include "parse_args.h"
  49. #include "lib/sll.h"
  50. #include "dlt.h"
  51. tOptDesc const* tcpedit_tcpedit_optDesc_p;
  52. /*
  53. * Processs a given packet and edit the pkthdr/pktdata structures
  54. * according to the rules in tcpedit
  55. * Returns: -1 on error
  56. * 0 on no change
  57. * 1 on change
  58. */
  59. int
  60. tcpedit_packet(tcpedit_t *tcpedit, struct pcap_pkthdr **pkthdr,
  61. u_char **pktdata, int direction)
  62. {
  63. ipv4_hdr_t *ip_hdr = NULL;
  64. arp_hdr_t *arp_hdr = NULL;
  65. int l2len = 0, l2proto, retval;
  66. int needtorecalc = 0; /* did the packet change? if so, checksum */
  67. assert(tcpedit);
  68. assert(pkthdr);
  69. assert(*pkthdr);
  70. assert(pktdata);
  71. assert(*pktdata);
  72. assert(tcpedit->validated);
  73. tcpedit->runtime.packetnum++;
  74. dbgx(2, "packet " COUNTER_SPEC " caplen %d",
  75. tcpedit->runtime.packetnum, (*pkthdr)->caplen);
  76. /*
  77. * remove the Ethernet FCS (checksum)?
  78. * note that this feature requires the end user to be smart and
  79. * only set this flag IFF the pcap has the FCS. If not, then they
  80. * just removed 2 bytes of ACTUAL PACKET DATA. Sucks to be them.
  81. */
  82. if (tcpedit->efcs)
  83. (*pkthdr)->caplen -= 2;
  84. /* Rewrite any Layer 2 data */
  85. if ((l2len = rewrite_l2(tcpedit, pkthdr, pktdata, direction)) == 0)
  86. return 0; /* packet is too long and we didn't trunc, so skip it */
  87. if (l2len < 0)
  88. errx(1, "fatal rewrite_l2 error: %s", tcpedit_geterr(tcpedit));
  89. if (direction == CACHE_PRIMARY) {
  90. l2proto = get_l2protocol(*pktdata, (*pkthdr)->caplen,
  91. pcap_datalink(tcpedit->runtime.pcap1));
  92. } else {
  93. l2proto = get_l2protocol(*pktdata, (*pkthdr)->caplen,
  94. pcap_datalink(tcpedit->runtime.pcap2));
  95. }
  96. /* does packet have an IP header? if so set our pointer to it */
  97. if (l2proto == ETHERTYPE_IP) {
  98. dbg(3, "Packet has an IP header...");
  99. #ifdef FORCE_ALIGN
  100. /*
  101. * copy layer 3 and up to our temp packet buffer
  102. * for now on, we have to edit the packetbuff because
  103. * just before we send the packet, we copy the packetbuff
  104. * back onto the pkt.data + l2len buffer
  105. * we do all this work to prevent byte alignment issues
  106. */
  107. ip_hdr = (ipv4_hdr_t *)tcpedit->runtime.ipbuff;
  108. memcpy(ip_hdr, (&(*pktdata)[l2len]), (*pkthdr)->caplen - l2len);
  109. #else
  110. /*
  111. * on non-strict byte align systems, don't need to memcpy(),
  112. * just point to 14 bytes into the existing buffer
  113. */
  114. ip_hdr = (ipv4_hdr_t *) (&(*pktdata)[l2len]);
  115. #endif
  116. } else {
  117. dbg(3, "Packet isn't IP...");
  118. /* non-IP packets have a NULL ip_hdr struct */
  119. ip_hdr = NULL;
  120. }
  121. /* rewrite IP addresses */
  122. if (tcpedit->rewrite_ip) {
  123. /* IP packets */
  124. if (ip_hdr != NULL) {
  125. if ((retval = rewrite_ipv4l3(tcpedit, ip_hdr, direction)) < 0)
  126. return -1;
  127. needtorecalc += retval;
  128. }
  129. /* ARP packets */
  130. else if (l2proto == ETHERTYPE_ARP) {
  131. arp_hdr = (arp_hdr_t *)(&(*pktdata)[l2len]);
  132. /* unlike, rewrite_ipl3, we don't care if the packet changed
  133. * because we never need to recalc the checksums for an ARP
  134. * packet. So ignore the return value
  135. */
  136. if (rewrite_iparp(tcpedit, arp_hdr, direction) < 0)
  137. return -1;
  138. }
  139. }
  140. /* rewrite ports */
  141. if (tcpedit->portmap != NULL && (ip_hdr != NULL)) {
  142. if ((retval = rewrite_ports(tcpedit, &ip_hdr)) < 0)
  143. return -1;
  144. needtorecalc += retval;
  145. }
  146. /* Untruncate packet? Only for IP packets */
  147. if ((tcpedit->fixlen) && (ip_hdr != NULL)) {
  148. if ((retval = untrunc_packet(tcpedit, *pkthdr, *pktdata, ip_hdr)) < 0)
  149. return -1;
  150. needtorecalc += retval;
  151. }
  152. /* do we need to spoof the src/dst IP address? */
  153. if (tcpedit->seed) {
  154. if (ip_hdr != NULL) {
  155. if ((retval = randomize_ipv4(tcpedit, *pkthdr, *pktdata,
  156. ip_hdr)) < 0)
  157. return -1;
  158. needtorecalc += retval;
  159. } else {
  160. if (direction == CACHE_PRIMARY) {
  161. if (randomize_iparp(tcpedit, *pkthdr, *pktdata,
  162. pcap_datalink(tcpedit->runtime.pcap1)) < 0)
  163. return -1;
  164. } else {
  165. if (randomize_iparp(tcpedit, *pkthdr, *pktdata,
  166. pcap_datalink(tcpedit->runtime.pcap2)) < 0)
  167. return -1;
  168. }
  169. }
  170. }
  171. /* do we need to force fixing checksums? */
  172. if ((tcpedit->fixcsum || needtorecalc) && (ip_hdr != NULL)) {
  173. if (fix_checksums(tcpedit, *pkthdr, ip_hdr) < 0)
  174. return -1;
  175. }
  176. #ifdef FORCE_ALIGN
  177. /*
  178. * put back the layer 3 and above back in the pkt.data buffer
  179. * we can't edit the packet at layer 3 or above beyond this point
  180. */
  181. memcpy(&newpkt[l2len], ip_hdr, pkthdr_ptr->caplen - l2len);
  182. #endif
  183. tcpedit->runtime.total_bytes += (*pkthdr)->caplen;
  184. tcpedit->runtime.pkts_edited ++;
  185. return 1;
  186. }
  187. /*
  188. * initializes the tcpedit library. returns 0 on success, -1 on error.
  189. */
  190. int
  191. tcpedit_init(tcpedit_t *tcpedit, pcap_t *pcap1, pcap_t *pcap2)
  192. {
  193. assert(tcpedit);
  194. assert(pcap1);
  195. tcpedit->mtu = DEFAULT_MTU; /* assume 802.3 Ethernet */
  196. tcpedit->l2.len = dlt2layer2len(tcpedit, DLT_EN10MB);
  197. tcpedit->l2proto = ETHERTYPE_IP;
  198. tcpedit->mac_mask = 0x0;
  199. memset(&(tcpedit->runtime), 0, sizeof(tcpedit_runtime_t));
  200. tcpedit->runtime.pcap1 = pcap1;
  201. tcpedit->l2.dlt = pcap_datalink(tcpedit->runtime.pcap1);
  202. dbgx(1, "Input file (1) datalink type is %s\n",
  203. pcap_datalink_val_to_name(tcpedit->l2.dlt));
  204. if (pcap2 != NULL) {
  205. tcpedit->runtime.pcap2 = pcap2;
  206. dbgx(1, "Input file (2) datalink type is %s\n",
  207. pcap_datalink_val_to_name(pcap_datalink(pcap2)));
  208. if (pcap_datalink(pcap1) != pcap_datalink(pcap2)) {
  209. tcpedit_seterr(tcpedit, "Sorry, currently both inputs must have the same DLT type.");
  210. return -1;
  211. }
  212. } else {
  213. tcpedit->runtime.pcap2 = pcap1;
  214. }
  215. #ifdef FORCE_ALIGN
  216. if ((tcpedit->runtime.ipbuff = (u_char *)malloc(MAXPACKET)) == NULL)
  217. return -1;
  218. #endif
  219. return 0;
  220. }
  221. /*
  222. * Validates that given the current state of tcpedit that the given
  223. * pcap source and destination (based on DLT) can be properly rewritten
  224. * return 0 on sucess
  225. * return -1 on error
  226. */
  227. int
  228. tcpedit_validate(tcpedit_t *tcpedit, int srcdlt, int dstdlt)
  229. {
  230. assert(tcpedit);
  231. tcpedit->validated = 1;
  232. dbgx(1, "Input linktype is %s",
  233. pcap_datalink_val_to_description(srcdlt));
  234. dbgx(1, "Output linktype is %s",
  235. pcap_datalink_val_to_description(dstdlt));
  236. /*
  237. * make sure that the options in tcpedit are sane
  238. */
  239. if (tcpedit->mac_mask > 0x0F) {
  240. tcpedit_seterr(tcpedit, "Invalid mac_mask value: 0x%04x",
  241. tcpedit->mac_mask);
  242. return -1;
  243. }
  244. /* is bidir sane? */
  245. if (tcpedit->bidir != TCPEDIT_BIDIR_ON &&
  246. tcpedit->bidir != TCPEDIT_BIDIR_OFF) {
  247. tcpedit_seterr(tcpedit, "Invalid bidir value: 0x%4x");
  248. return -1;
  249. }
  250. /*
  251. * right now, output has to be ethernet, but in the future we'll
  252. * support other DLT types, and we don't want to have to change the
  253. * API, so we'll do the check here
  254. */
  255. if (dstdlt != DLT_EN10MB) {
  256. tcpedit_seterr(tcpedit, "Sorry, but tcpedit currently only "
  257. "supports writing to DLT_EN10MB output");
  258. return -1;
  259. }
  260. /*
  261. * user specified a full L2 header, so we're all set!
  262. */
  263. if (tcpedit->l2.enabled)
  264. return 0;
  265. /*
  266. * compare the linktype of the capture file to the information
  267. * provided on the CLI (src/dst MAC addresses)
  268. */
  269. switch (srcdlt) {
  270. case DLT_USER:
  271. /* user specified header, nothing to do */
  272. break;
  273. case DLT_VLAN:
  274. /* same as EN10MB, just different placement of proto field */
  275. break;
  276. case DLT_EN10MB:
  277. /* nothing to do here */
  278. break;
  279. case DLT_LINUX_SLL:
  280. /*
  281. * DLT_LINUX_SLL
  282. * Linux cooked socket has the source mac but not the destination mac
  283. * hence we look for the destination mac(s)
  284. */
  285. /* single output mode */
  286. if (! tcpedit->bidir) {
  287. /* if SLL, then either --dlink or --dmac are ok */
  288. if ((tcpedit->mac_mask & TCPEDIT_MAC_MASK_DMAC1) == 0) {
  289. tcpedit_seterr(tcpedit,
  290. "Input %s requires --dlink or --dmac <mac>",
  291. pcap_datalink_val_to_description(srcdlt));
  292. return -1;
  293. }
  294. }
  295. /* dual output mode */
  296. else {
  297. /* if using dual interfaces, make sure we have both dest MAC's */
  298. if (((tcpedit->mac_mask & TCPEDIT_MAC_MASK_DMAC1) == 0) ||
  299. ((tcpedit->mac_mask & TCPEDIT_MAC_MASK_DMAC2) == 0)) {
  300. tcpedit_seterr(tcpedit,
  301. "Input %s with --cachefile requires --dlink or\n"
  302. "\t--dmac <mac1>:<mac2>",
  303. pcap_datalink_val_to_description(srcdlt));
  304. return -1;
  305. }
  306. }
  307. break;
  308. case DLT_C_HDLC:
  309. case DLT_RAW:
  310. /*
  311. * DLT_C_HDLC
  312. * Cisco HDLC doesn't contain a source or destination mac,
  313. * but it does contain the L3 protocol type (just like an ethernet
  314. * header does) so we require either a full L2 or both src/dst mac's
  315. *
  316. * DLT_RAW is assumed always IP, so we know the protocol type
  317. */
  318. /* single output mode */
  319. if (! tcpedit->bidir) {
  320. /* Need both src/dst MAC's */
  321. if (((tcpedit->mac_mask & TCPEDIT_MAC_MASK_DMAC1) == 0) ||
  322. ((tcpedit->mac_mask & TCPEDIT_MAC_MASK_SMAC1) == 0)) {
  323. tcpedit_seterr(tcpedit,
  324. "Input %s requires --dlink or --smac <mac> and "
  325. "--dmac <mac>",
  326. pcap_datalink_val_to_description(srcdlt));
  327. return -1;
  328. }
  329. }
  330. /* dual output mode */
  331. else {
  332. /* Need to have src/dst MAC's for both directions */
  333. if (tcpedit->mac_mask !=
  334. TCPEDIT_MAC_MASK_SMAC1 + TCPEDIT_MAC_MASK_SMAC2 +
  335. TCPEDIT_MAC_MASK_DMAC1 + TCPEDIT_MAC_MASK_DMAC2) {
  336. tcpedit_seterr(tcpedit,
  337. "Input %s with --cachefile requires --dlink or\n"
  338. "\t--smac <mac1>:<mac2> and --dmac <mac1>:<mac2>",
  339. pcap_datalink_val_to_description(srcdlt));
  340. return -1;
  341. }
  342. }
  343. break;
  344. case DLT_NULL:
  345. /*
  346. * we should actually support DLT_NULL (no layer2 header, but does
  347. * give us the layer 3 protocol), but we don't right now,
  348. * so fall through to the default and complain
  349. */
  350. default:
  351. tcpedit_seterr(tcpedit, "Unsupported input datalink %s (0x%x)",
  352. pcap_datalink_val_to_description(srcdlt),
  353. srcdlt);
  354. return -1;
  355. break;
  356. }
  357. return 0;
  358. }
  359. /*
  360. * return the error string when a tcpedit() function returns
  361. * an error
  362. */
  363. char *
  364. tcpedit_geterr(tcpedit_t *tcpedit)
  365. {
  366. return tcpedit->runtime.errstr;
  367. }
  368. /*
  369. * used to set the error string when there is an error
  370. */
  371. void
  372. tcpedit_seterr(tcpedit_t *tcpedit, const char *fmt, ...)
  373. {
  374. va_list ap;
  375. va_start(ap, fmt);
  376. if (fmt != NULL) {
  377. dbgx(1, fmt, ap);
  378. (void)vsnprintf(tcpedit->runtime.errstr,
  379. (TCPEDIT_ERRSTR_LEN - 1), fmt, ap);
  380. }
  381. va_end(ap);
  382. }
  383. /*
  384. * Cleans up after ourselves. Return 0 on success.
  385. */
  386. int
  387. tcpedit_close(tcpedit_t *tcpedit)
  388. {
  389. dbgx(1, "tcpedit processed " COUNTER_SPEC " bytes in " COUNTER_SPEC
  390. " packets.\n", tcpedit->runtime.total_bytes,
  391. tcpedit->runtime.pkts_edited);
  392. /* free buffer if required */
  393. #ifdef FORCE_ALIGN
  394. free(tcpedit->runtime.ipbuff);
  395. #endif
  396. return 0;
  397. }
  398. /*
  399. Local Variables:
  400. mode:c
  401. indent-tabs-mode:nil
  402. c-basic-offset:4
  403. End:
  404. */