tcpedit.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. /* $Id: tcpedit.c 1505 2006-07-17 02:56:37Z 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 <ctype.h>
  32. #include <fcntl.h>
  33. #include <stdio.h>
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include <sys/types.h>
  37. #include <unistd.h>
  38. #include <pcap.h>
  39. #include "config.h"
  40. #include "defines.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. ip_hdr_t *ip_hdr = NULL;
  64. arp_hdr_t *arp_hdr = NULL;
  65. int l2len = 0, l2proto;
  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 = (ip_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 = (ip_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. needtorecalc += rewrite_ipl3(tcpedit, ip_hdr, direction);
  126. }
  127. /* ARP packets */
  128. else if (l2proto == ETHERTYPE_ARP) {
  129. arp_hdr = (arp_hdr_t *)(&(*pktdata)[l2len]);
  130. /* unlike, rewrite_ipl3, we don't care if the packet changed
  131. * because we never need to recalc the checksums for an ARP
  132. * packet. So ignore the return value
  133. */
  134. rewrite_iparp(tcpedit, arp_hdr, direction);
  135. }
  136. }
  137. /* rewrite ports */
  138. if (tcpedit->portmap != NULL && (ip_hdr != NULL)) {
  139. needtorecalc += rewrite_ports(tcpedit, &ip_hdr);
  140. }
  141. /* Untruncate packet? Only for IP packets */
  142. if ((tcpedit->fixlen) && (ip_hdr != NULL)) {
  143. needtorecalc += untrunc_packet(tcpedit, *pkthdr, *pktdata, ip_hdr);
  144. }
  145. /* do we need to spoof the src/dst IP address? */
  146. if (tcpedit->seed) {
  147. if (ip_hdr != NULL) {
  148. needtorecalc += randomize_ipv4(tcpedit, *pkthdr, *pktdata,
  149. ip_hdr);
  150. } else {
  151. if (direction == CACHE_PRIMARY) {
  152. randomize_iparp(tcpedit, *pkthdr, *pktdata,
  153. pcap_datalink(tcpedit->runtime.pcap1));
  154. } else {
  155. randomize_iparp(tcpedit, *pkthdr, *pktdata,
  156. pcap_datalink(tcpedit->runtime.pcap2));
  157. }
  158. }
  159. }
  160. /* do we need to force fixing checksums? */
  161. if ((tcpedit->fixcsum || needtorecalc) && (ip_hdr != NULL)) {
  162. fix_checksums(tcpedit, *pkthdr, ip_hdr);
  163. }
  164. #ifdef FORCE_ALIGN
  165. /*
  166. * put back the layer 3 and above back in the pkt.data buffer
  167. * we can't edit the packet at layer 3 or above beyond this point
  168. */
  169. memcpy(&newpkt[l2len], ip_hdr, pkthdr_ptr->caplen - l2len);
  170. #endif
  171. tcpedit->runtime.total_bytes += (*pkthdr)->caplen;
  172. tcpedit->runtime.pkts_edited ++;
  173. return 1;
  174. }
  175. /*
  176. * initializes the tcpedit library. returns 0 on success, -1 on error.
  177. */
  178. int
  179. tcpedit_init(tcpedit_t *tcpedit, pcap_t *pcap1, pcap_t *pcap2)
  180. {
  181. assert(tcpedit);
  182. assert(pcap1);
  183. tcpedit->mtu = DEFAULT_MTU; /* assume 802.3 Ethernet */
  184. tcpedit->l2.len = dlt2layer2len(tcpedit, DLT_EN10MB);
  185. tcpedit->l2proto = ETHERTYPE_IP;
  186. tcpedit->mac_mask = 0x0;
  187. memset(&(tcpedit->runtime), 0, sizeof(tcpedit_runtime_t));
  188. tcpedit->runtime.pcap1 = pcap1;
  189. tcpedit->l2.dlt = pcap_datalink(tcpedit->runtime.pcap1);
  190. dbgx(1, "Input file (1) datalink type is %s\n",
  191. pcap_datalink_val_to_name(tcpedit->l2.dlt));
  192. if (pcap2 != NULL) {
  193. tcpedit->runtime.pcap2 = pcap2;
  194. dbgx(1, "Input file (2) datalink type is %s\n",
  195. pcap_datalink_val_to_name(pcap_datalink(pcap2)));
  196. if (pcap_datalink(pcap1) != pcap_datalink(pcap2)) {
  197. tcpedit_seterr(tcpedit, "Sorry, currently both inputs must have the same DLT type.");
  198. return -1;
  199. }
  200. } else {
  201. tcpedit->runtime.pcap2 = pcap1;
  202. }
  203. #ifdef FORCE_ALIGN
  204. if ((tcpedit->runtime.ipbuff = (u_char *)malloc(MAXPACKET)) == NULL)
  205. return -1;
  206. #endif
  207. return 0;
  208. }
  209. /*
  210. * Validates that given the current state of tcpedit that the given
  211. * pcap source and destination (based on DLT) can be properly rewritten
  212. * return 0 on sucess
  213. * return -1 on error
  214. */
  215. int
  216. tcpedit_validate(tcpedit_t *tcpedit, int srcdlt, int dstdlt)
  217. {
  218. assert(tcpedit);
  219. tcpedit->validated = 1;
  220. dbgx(1, "Input linktype is %s",
  221. pcap_datalink_val_to_description(srcdlt));
  222. dbgx(1, "Output linktype is %s",
  223. pcap_datalink_val_to_description(dstdlt));
  224. /*
  225. * make sure that the options in tcpedit are sane
  226. */
  227. if (tcpedit->mac_mask > 0x0F) {
  228. tcpedit_seterr(tcpedit, "Invalid mac_mask value: 0x%04x",
  229. tcpedit->mac_mask);
  230. return -1;
  231. }
  232. /* is bidir sane? */
  233. if (tcpedit->bidir != TCPEDIT_BIDIR_ON &&
  234. tcpedit->bidir != TCPEDIT_BIDIR_OFF) {
  235. tcpedit_seterr(tcpedit, "Invalid bidir value: 0x%4x");
  236. return -1;
  237. }
  238. /*
  239. * right now, output has to be ethernet, but in the future we'll
  240. * support other DLT types, and we don't want to have to change the
  241. * API, so we'll do the check here
  242. */
  243. if (dstdlt != DLT_EN10MB) {
  244. tcpedit_seterr(tcpedit, "Sorry, but tcpedit currently only "
  245. "supports writing to DLT_EN10MB output");
  246. return -1;
  247. }
  248. /*
  249. * user specified a full L2 header, so we're all set!
  250. */
  251. if (tcpedit->l2.enabled)
  252. return 0;
  253. /*
  254. * compare the linktype of the capture file to the information
  255. * provided on the CLI (src/dst MAC addresses)
  256. */
  257. switch (srcdlt) {
  258. case DLT_USER:
  259. /* user specified header, nothing to do */
  260. break;
  261. case DLT_VLAN:
  262. /* same as EN10MB, just different placement of proto field */
  263. break;
  264. case DLT_EN10MB:
  265. /* nothing to do here */
  266. break;
  267. case DLT_LINUX_SLL:
  268. /*
  269. * DLT_LINUX_SLL
  270. * Linux cooked socket has the source mac but not the destination mac
  271. * hence we look for the destination mac(s)
  272. */
  273. /* single output mode */
  274. if (! tcpedit->bidir) {
  275. /* if SLL, then either --dlink or --dmac are ok */
  276. if ((tcpedit->mac_mask & TCPEDIT_MAC_MASK_DMAC1) == 0) {
  277. tcpedit_seterr(tcpedit,
  278. "Input %s requires --dlink or --dmac <mac>",
  279. pcap_datalink_val_to_description(srcdlt));
  280. return -1;
  281. }
  282. }
  283. /* dual output mode */
  284. else {
  285. /* if using dual interfaces, make sure we have both dest MAC's */
  286. if (((tcpedit->mac_mask & TCPEDIT_MAC_MASK_DMAC1) == 0) ||
  287. ((tcpedit->mac_mask & TCPEDIT_MAC_MASK_DMAC2) == 0)) {
  288. tcpedit_seterr(tcpedit,
  289. "Input %s with --cachefile requires --dlink or\n"
  290. "\t--dmac <mac1>:<mac2>",
  291. pcap_datalink_val_to_description(srcdlt));
  292. return -1;
  293. }
  294. }
  295. break;
  296. case DLT_C_HDLC:
  297. case DLT_RAW:
  298. /*
  299. * DLT_C_HDLC
  300. * Cisco HDLC doesn't contain a source or destination mac,
  301. * but it does contain the L3 protocol type (just like an ethernet
  302. * header does) so we require either a full L2 or both src/dst mac's
  303. *
  304. * DLT_RAW is assumed always IP, so we know the protocol type
  305. */
  306. /* single output mode */
  307. if (! tcpedit->bidir) {
  308. /* Need both src/dst MAC's */
  309. if (((tcpedit->mac_mask & TCPEDIT_MAC_MASK_DMAC1) == 0) ||
  310. ((tcpedit->mac_mask & TCPEDIT_MAC_MASK_SMAC1) == 0)) {
  311. tcpedit_seterr(tcpedit,
  312. "Input %s requires --dlink or --smac <mac> and "
  313. "--dmac <mac>",
  314. pcap_datalink_val_to_description(srcdlt));
  315. return -1;
  316. }
  317. }
  318. /* dual output mode */
  319. else {
  320. /* Need to have src/dst MAC's for both directions */
  321. if (tcpedit->mac_mask !=
  322. TCPEDIT_MAC_MASK_SMAC1 + TCPEDIT_MAC_MASK_SMAC2 +
  323. TCPEDIT_MAC_MASK_DMAC1 + TCPEDIT_MAC_MASK_DMAC2) {
  324. tcpedit_seterr(tcpedit,
  325. "Input %s with --cachefile requires --dlink or\n"
  326. "\t--smac <mac1>:<mac2> and --dmac <mac1>:<mac2>",
  327. pcap_datalink_val_to_description(srcdlt));
  328. return -1;
  329. }
  330. }
  331. break;
  332. case DLT_NULL:
  333. /*
  334. * we should actually support DLT_NULL (no layer2 header, but does
  335. * give us the layer 3 protocol), but we don't right now,
  336. * so fall through to the default and complain
  337. */
  338. default:
  339. tcpedit_seterr(tcpedit, "Unsupported input datalink %s (0x%x)",
  340. pcap_datalink_val_to_description(srcdlt),
  341. srcdlt);
  342. return -1;
  343. break;
  344. }
  345. return 0;
  346. }
  347. /*
  348. * return the error string when a tcpedit() function returns
  349. * an error
  350. */
  351. char *
  352. tcpedit_geterr(tcpedit_t *tcpedit)
  353. {
  354. return tcpedit->runtime.errstr;
  355. }
  356. /*
  357. * used to set the error string when there is an error
  358. */
  359. void
  360. tcpedit_seterr(tcpedit_t *tcpedit, const char *fmt, ...)
  361. {
  362. va_list ap;
  363. va_start(ap, fmt);
  364. if (fmt != NULL) {
  365. dbgx(1, fmt, ap);
  366. (void)vsnprintf(tcpedit->runtime.errstr,
  367. (TCPEDIT_ERRSTR_LEN - 1), fmt, ap);
  368. }
  369. va_end(ap);
  370. }
  371. /*
  372. * Cleans up after ourselves. Return 0 on success.
  373. */
  374. int
  375. tcpedit_close(tcpedit_t *tcpedit)
  376. {
  377. dbgx(1, "tcpedit processed " COUNTER_SPEC " bytes in " COUNTER_SPEC
  378. " packets.\n", tcpedit->runtime.total_bytes,
  379. tcpedit->runtime.pkts_edited);
  380. /* free buffer if required */
  381. #ifdef FORCE_ALIGN
  382. free(tcpedit->runtime.ipbuff);
  383. #endif
  384. return 0;
  385. }
  386. /*
  387. Local Variables:
  388. mode:c
  389. indent-tabs-mode:nil
  390. c-basic-offset:4
  391. End:
  392. */