edit_packet.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. /* $Id: edit_packet.c 1341 2005-06-09 05:13:31Z aturner $ */
  2. /*
  3. * Copyright (c) 2001-2004 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 "common.h"
  34. #include "tcprewrite.h"
  35. #include "tcprewrite_opts.h"
  36. #include "edit_packet.h"
  37. #include "lib/sll.h"
  38. #include "dlt.h"
  39. extern int maxpacket;
  40. extern tcprewrite_opt_t options;
  41. /*
  42. * this code re-calcs the IP and Layer 4 checksums
  43. * the IMPORTANT THING is that the Layer 4 header
  44. * is contiguious in memory after *ip_hdr we're actually
  45. * writing to the layer 4 header via the ip_hdr ptr.
  46. * (Yes, this sucks, but that's the way libnet works, and
  47. * I was too lazy to re-invent the wheel.
  48. */
  49. void
  50. fix_checksums(struct pcap_pkthdr *pkthdr, ip_hdr_t * ip_hdr)
  51. {
  52. /* calc the L4 checksum */
  53. if (libnet_do_checksum(options.l, (u_char *) ip_hdr, ip_hdr->ip_p,
  54. ntohs(ip_hdr->ip_len) - (ip_hdr->ip_hl << 2)) < 0)
  55. warnx("Layer 4 checksum failed: %s", libnet_geterror(options.l));
  56. /* calc IP checksum */
  57. if (libnet_do_checksum(options.l, (u_char *) ip_hdr, IPPROTO_IP,
  58. ntohs(ip_hdr->ip_len)) < 0)
  59. warnx("IP checksum failed: %s", libnet_geterror(options.l));
  60. }
  61. /*
  62. * returns a new 32bit integer which is the randomized IP
  63. * based upon the user specified seed
  64. */
  65. u_int32_t
  66. randomize_ip(u_int32_t ip)
  67. {
  68. return ((ip ^ options.seed) - (ip & options.seed));
  69. }
  70. /*
  71. * randomizes the source and destination IP addresses based on a
  72. * pseudo-random number which is generated via the seed.
  73. * return 1 since we changed one or more IP addresses
  74. */
  75. int
  76. randomize_ipv4(struct pcap_pkthdr *pkthdr, u_char * pktdata,
  77. ip_hdr_t * ip_hdr)
  78. {
  79. char srcip[16], dstip[16];
  80. strlcpy(srcip, libnet_addr2name4(ip_hdr->ip_src.s_addr,
  81. LIBNET_DONT_RESOLVE), 16);
  82. strlcpy(dstip, libnet_addr2name4(ip_hdr->ip_dst.s_addr,
  83. LIBNET_DONT_RESOLVE), 16);
  84. /* randomize IP addresses based on the value of random */
  85. dbg(1, "Old Src IP: %s\tOld Dst IP: %s", srcip, dstip);
  86. ip_hdr->ip_dst.s_addr = randomize_ip(ip_hdr->ip_dst.s_addr);
  87. ip_hdr->ip_src.s_addr = randomize_ip(ip_hdr->ip_src.s_addr);
  88. strlcpy(srcip, libnet_addr2name4(ip_hdr->ip_src.s_addr,
  89. LIBNET_DONT_RESOLVE), 16);
  90. strlcpy(dstip, libnet_addr2name4(ip_hdr->ip_dst.s_addr,
  91. LIBNET_DONT_RESOLVE), 16);
  92. dbg(1, "New Src IP: %s\tNew Dst IP: %s\n", srcip, dstip);
  93. return(1);
  94. }
  95. /*
  96. * this code will untruncate a packet via padding it with null
  97. * or resetting the actual packet len to the snaplen. In either case
  98. * it will recalcuate the IP and transport layer checksums.
  99. * return 0 if no change, 1 if change
  100. */
  101. int
  102. untrunc_packet(struct pcap_pkthdr *pkthdr, u_char * pktdata,
  103. ip_hdr_t * ip_hdr)
  104. {
  105. /* if actual len == cap len or there's no IP header, don't do anything */
  106. if ((pkthdr->caplen == pkthdr->len) || (ip_hdr == NULL)) {
  107. return(0);
  108. }
  109. /* Pad packet or truncate it */
  110. if (options.fixlen == FIXLEN_PAD) {
  111. /*
  112. * this should be an unnecessary check
  113. * but I've gotten a report that sometimes the caplen > len
  114. * which seems like a corrupted pcap
  115. */
  116. if (pkthdr->len > pkthdr->caplen) {
  117. memset(pktdata + pkthdr->caplen, 0, pkthdr->len - pkthdr->caplen);
  118. pkthdr->caplen = pkthdr->len;
  119. } else {
  120. /* i guess this is necessary if we've got a bogus pcap */
  121. ip_hdr->ip_len = htons(pkthdr->caplen);
  122. }
  123. }
  124. else if (options.fixlen == FIXLEN_TRUNC) {
  125. ip_hdr->ip_len = htons(pkthdr->caplen);
  126. }
  127. else {
  128. errx(1, "Invalid options.fixlen value: 0x%x", options.fixlen);
  129. }
  130. /* fix checksums */
  131. fix_checksums(pkthdr, ip_hdr);
  132. return(1);
  133. }
  134. /*
  135. * Extracts the layer 7 data from the packet for TCP, UDP, ICMP
  136. * returns the number of bytes and a pointer to the layer 7 data.
  137. * Returns 0 for no data
  138. */
  139. int
  140. extract_data(const u_char *pktdata, int caplen, int datalink, char *l7data[])
  141. {
  142. int datalen = 0;
  143. ip_hdr_t *ip_hdr = NULL;
  144. tcp_hdr_t *tcp_hdr = NULL;
  145. udp_hdr_t *udp_hdr = NULL;
  146. u_char ipbuff[MAXPACKET];
  147. u_char *dataptr = NULL;
  148. /* grab our IPv4 header */
  149. dataptr = ipbuff;
  150. if ((ip_hdr = get_ipv4(pktdata, caplen, datalink, &dataptr)) == NULL)
  151. return 0;
  152. /* figure out the actual datalen which might be < the caplen
  153. * due to ethernet padding
  154. */
  155. if (caplen > ntohs(ip_hdr->ip_len)) {
  156. datalen = ntohs(ip_hdr->ip_len);
  157. } else {
  158. datalen = caplen - options.l2.len;
  159. }
  160. /* update the datlen to not include the IP header len */
  161. datalen -= ip_hdr->ip_hl << 2;
  162. dataptr += ip_hdr->ip_hl << 2;
  163. if (datalen <= 0)
  164. goto nodata;
  165. /* TCP ? */
  166. if (ip_hdr->ip_p == IPPROTO_TCP) {
  167. tcp_hdr = (tcp_hdr_t *) get_layer4(ip_hdr);
  168. datalen -= tcp_hdr->th_off << 2;
  169. if (datalen <= 0)
  170. goto nodata;
  171. dataptr += tcp_hdr->th_off << 2;
  172. }
  173. /* UDP ? */
  174. else if (ip_hdr->ip_p == IPPROTO_UDP) {
  175. udp_hdr = (udp_hdr_t *) get_layer4(ip_hdr);
  176. datalen -= LIBNET_UDP_H;
  177. if (datalen <= 0)
  178. goto nodata;
  179. dataptr += LIBNET_UDP_H;
  180. }
  181. /* ICMP ? just ignore it for now */
  182. else if (ip_hdr->ip_p == IPPROTO_ICMP) {
  183. dbg(2, "Ignoring any possible data in ICMP packet");
  184. goto nodata;
  185. }
  186. /* unknown proto, just dump everything past the IP header */
  187. else {
  188. dbg(2, "Unknown protocol, dumping everything past the IP header");
  189. dataptr = (char *)ip_hdr;
  190. }
  191. dbg(2, "packet had %d bytes of layer 7 data", datalen);
  192. memcpy(l7data, dataptr, datalen);
  193. return datalen;
  194. nodata:
  195. dbg(2, "packet has no data, skipping...");
  196. return 0;
  197. }
  198. /*
  199. * takes a CIDR notation netblock and uses that to "remap" given IP
  200. * onto that netblock. ie: 10.0.0.0/8 and 192.168.55.123 -> 10.168.55.123
  201. * while 10.150.9.0/24 and 192.168.55.123 -> 10.150.9.123
  202. */
  203. u_int32_t
  204. remap_ip(cidr_t *cidr, const u_int32_t original)
  205. {
  206. u_int32_t ipaddr = 0, network = 0, mask = 0, result = 0;
  207. mask = 0xffffffff; /* turn on all the bits */
  208. /* shift over by correct # of bits */
  209. mask = mask << (32 - cidr->masklen);
  210. /* apply the mask to the network */
  211. network = htonl(cidr->network) & mask;
  212. /* apply the reverse of the mask to the IP */
  213. mask = mask ^ 0xffffffff;
  214. ipaddr = ntohl(original) & mask;
  215. /* merge the network portion and ip portions */
  216. result = network ^ ipaddr;
  217. /* return the result in network byte order */
  218. return(htonl(result));
  219. }
  220. /*
  221. * rewrite IP address (layer3)
  222. * uses -N to rewrite (map) one subnet onto another subnet
  223. * return 0 if no change, 1 or 2 if changed
  224. */
  225. int
  226. rewrite_ipl3(ip_hdr_t * ip_hdr, int cache_mode)
  227. {
  228. cidrmap_t *cidrmap1 = NULL, *cidrmap2 = NULL;
  229. int didsrc = 0, diddst = 0, loop = 1;
  230. /* anything to rewrite? */
  231. if (options.cidrmap1 == NULL)
  232. return(0);
  233. /* don't play with the main pointers */
  234. if (cache_mode == CACHE_PRIMARY) {
  235. cidrmap1 = options.cidrmap1;
  236. cidrmap2 = options.cidrmap2;
  237. } else {
  238. cidrmap1 = options.cidrmap2;
  239. cidrmap2 = options.cidrmap1;
  240. }
  241. /* loop through the cidrmap to rewrite */
  242. do {
  243. if ((! diddst) && ip_in_cidr(cidrmap2->from, ip_hdr->ip_dst.s_addr)) {
  244. ip_hdr->ip_dst.s_addr = remap_ip(cidrmap2->to, ip_hdr->ip_dst.s_addr);
  245. dbg(2, "Remapped dst addr to: %s", inet_ntoa(ip_hdr->ip_dst));
  246. diddst = 1;
  247. }
  248. if ((! didsrc) && ip_in_cidr(cidrmap1->from, ip_hdr->ip_src.s_addr)) {
  249. ip_hdr->ip_src.s_addr = remap_ip(cidrmap1->to, ip_hdr->ip_src.s_addr);
  250. dbg(2, "Remapped src addr to: %s", inet_ntoa(ip_hdr->ip_src));
  251. didsrc = 1;
  252. }
  253. /*
  254. * loop while we haven't modified both src/dst AND
  255. * at least one of the cidr maps have a next pointer
  256. */
  257. if ((! (diddst && didsrc)) &&
  258. (! ((cidrmap1->next == NULL) && (cidrmap2->next == NULL)))) {
  259. /* increment our ptr's if possible */
  260. if (cidrmap1->next != NULL)
  261. cidrmap1 = cidrmap1->next;
  262. if (cidrmap2->next != NULL)
  263. cidrmap2 = cidrmap2->next;
  264. } else {
  265. loop = 0;
  266. }
  267. /* Later on we should support various IP protocols which embed
  268. * the IP address in the application layer. Things like
  269. * DNS and FTP.
  270. */
  271. } while (loop);
  272. /* return how many changes we made */
  273. return (diddst + didsrc);
  274. }
  275. /*
  276. * Randomize the IP addresses in an ARP packet based on the user seed
  277. * return 0 if no change, or 1 for a change
  278. */
  279. int
  280. randomize_iparp(struct pcap_pkthdr *pkthdr, u_char *pktdata, int datalink)
  281. {
  282. arp_hdr_t *arp_hdr = NULL;
  283. int l2len = 0;
  284. u_int32_t *ip, tempip;
  285. u_char *add_hdr;
  286. l2len = get_l2len(pktdata, pkthdr->caplen, datalink);
  287. arp_hdr = (arp_hdr_t *)(pktdata + l2len);
  288. /*
  289. * only rewrite IP addresses from REPLY/REQUEST's
  290. */
  291. if ((ntohs(arp_hdr->ar_pro) == ETHERTYPE_IP) &&
  292. ((ntohs(arp_hdr->ar_op) == ARPOP_REQUEST) ||
  293. (ntohs(arp_hdr->ar_op) == ARPOP_REPLY))) {
  294. /* jump to the addresses */
  295. add_hdr = (u_char *)arp_hdr;
  296. add_hdr += sizeof(arp_hdr_t) + arp_hdr->ar_hln;
  297. ip = (u_int32_t *)add_hdr;
  298. tempip = randomize_ip(*ip);
  299. memcpy(ip, &tempip, sizeof(u_int32_t));
  300. add_hdr += arp_hdr->ar_pln + arp_hdr->ar_hln;
  301. ip = (u_int32_t *)add_hdr;
  302. tempip = randomize_ip(*ip);
  303. memcpy(ip, &tempip, sizeof(u_int32_t));
  304. }
  305. return 1; /* yes we changed the packet */
  306. }
  307. /*
  308. * rewrite IP address (arp)
  309. * uses -a to rewrite (map) one subnet onto another subnet
  310. * pointer must point to the WHOLE and CONTIGOUS memory buffer
  311. * because the arp_hdr_t doesn't have the space for the IP/MAC
  312. * addresses
  313. * return 0 if no change, 1 or 2 if changed
  314. */
  315. int
  316. rewrite_iparp(arp_hdr_t *arp_hdr, int cache_mode)
  317. {
  318. u_char *add_hdr = NULL;
  319. u_int32_t *ip1 = NULL, *ip2 = NULL;
  320. u_int32_t newip = 0;
  321. cidrmap_t *cidrmap1 = NULL, *cidrmap2 = NULL;
  322. int didsrc = 0, diddst = 0, loop = 1;
  323. /* figure out what mapping to use */
  324. if (cache_mode == CACHE_PRIMARY) {
  325. cidrmap1 = options.cidrmap1;
  326. cidrmap2 = options.cidrmap2;
  327. } else if (cache_mode == CACHE_SECONDARY) {
  328. cidrmap1 = options.cidrmap2;
  329. cidrmap2 = options.cidrmap1;
  330. }
  331. /* anything to rewrite? */
  332. if (cidrmap1 == NULL || cidrmap2 == NULL)
  333. return(0);
  334. /*
  335. * must be IPv4 and request or reply
  336. * Do other op codes use the same subheader stub?
  337. * If so we won't need to check the op code.
  338. */
  339. if ((ntohs(arp_hdr->ar_pro) == ETHERTYPE_IP) &&
  340. ((ntohs(arp_hdr->ar_op) == ARPOP_REQUEST) ||
  341. (ntohs(arp_hdr->ar_op) == ARPOP_REPLY)))
  342. {
  343. /* jump to the addresses */
  344. add_hdr = (u_char *)arp_hdr;
  345. add_hdr += sizeof(arp_hdr_t) + arp_hdr->ar_hln;
  346. ip1 = (u_int32_t *)add_hdr;
  347. add_hdr += arp_hdr->ar_pln + arp_hdr->ar_hln;
  348. ip2 = (u_int32_t *)add_hdr;
  349. /* loop through the cidrmap to rewrite */
  350. do {
  351. /* arp request ? */
  352. if (ntohs(arp_hdr->ar_op) == ARPOP_REQUEST) {
  353. if ((!diddst) && ip_in_cidr(cidrmap2->from, *ip1)) {
  354. newip = remap_ip(cidrmap2->to, *ip1);
  355. memcpy(ip1, &newip, 4);
  356. diddst = 1;
  357. }
  358. if ((!didsrc) && ip_in_cidr(cidrmap1->from, *ip2)) {
  359. newip = remap_ip(cidrmap1->to, *ip2);
  360. memcpy(ip2, &newip, 4);
  361. didsrc = 1;
  362. }
  363. }
  364. /* else it's an arp reply */
  365. else {
  366. if ((!diddst) && ip_in_cidr(cidrmap2->from, *ip2)) {
  367. newip = remap_ip(cidrmap2->to, *ip2);
  368. memcpy(ip2, &newip, 4);
  369. diddst = 1;
  370. }
  371. if ((!didsrc) && ip_in_cidr(cidrmap1->from, *ip1)) {
  372. newip = remap_ip(cidrmap1->to, *ip1);
  373. memcpy(ip1, &newip, 4);
  374. didsrc = 1;
  375. }
  376. }
  377. /*
  378. * loop while we haven't modified both src/dst AND
  379. * at least one of the cidr maps have a next pointer
  380. */
  381. if ((! (diddst && didsrc)) &&
  382. (! ((cidrmap1->next == NULL) && (cidrmap2->next == NULL)))) {
  383. /* increment our ptr's if possible */
  384. if (cidrmap1->next != NULL)
  385. cidrmap1 = cidrmap1->next;
  386. if (cidrmap2->next != NULL)
  387. cidrmap2 = cidrmap2->next;
  388. } else {
  389. loop = 0;
  390. }
  391. } while (loop);
  392. } else {
  393. warn("ARP packet isn't for IPv4! Can't rewrite IP's");
  394. }
  395. return(didsrc + diddst);
  396. }
  397. /*
  398. Local Variables:
  399. mode:c
  400. indent-tabs-mode:nil
  401. c-basic-offset:4
  402. End:
  403. */