tcpliveplay.c 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186
  1. /*
  2. * Main Author & Publisher: Yazan H. Siam (tcpliveplay@gmail.com)
  3. * File: tcpliveplay.c
  4. * Started as a Senior Design project @ North Carolina State University
  5. * Last Updated Date: September 5, 2012
  6. *
  7. */
  8. /**
  9. * Program Description:
  10. * This program, 'tcpliveplay' replays a captured set of packets using new TCP connections with the
  11. * captured TCP payloads against a remote host in order to do comprehensive vulnerability testings.
  12. * This program takes in a "*.pcap" file that contains only one tcp flow connection and replays it
  13. * against a live host exactly how the captured packets are laid out. At the beginning, the program
  14. * establishes who the 'client' is and the 'server' is based on who initiates the SYN compares each
  15. * packet's source ip against the ip of the 'client' (which is named local in the code) and the 'server'
  16. * (remote) to correctly determine the expected seqs & acks. This also extracts the MACs of both local
  17. * and remote clients. The program is also capable of rewriting the local and remote MAC & IP so that
  18. * the packets are properly replayed when used on live networks. The current state of the program is that
  19. * it takes in a pcap file on command line and writes a new file called "newfile.pcap" which is used thereafter
  20. * for the rest of the program's calculations and set expectations. The program prints out a summary of the
  21. * new file on the command prompt. Once the program is done, "newfile.pcap" is cleaned up.
  22. * Program Design Overview:
  23. * Before replaying the packets, the program reads in the pcap file that contains one tcp flow,
  24. * and takes the SEQ/ACK #s.
  25. * Based on the number of packets, a struct schedule of events are is set up. Based on
  26. * the SEQ/ACK numbers read in, the schedule is setup to be relative numbers rather than
  27. * absolute. This is done by starting with local packets, subtracting the first SEQ (which
  28. * is that of the first SYN packet) from all the SEQs of the local packets then by subtracting
  29. * the first remote sequence (which is that of the SYN-ACK packet) from all the local packet's
  30. * ACKs. After the local side SEQ/ACK numbers are fixed to relative numbers, 'lseq_adjust'
  31. * the locally generated random number for the SYN packet gets added to all the local SEQs
  32. * to adjust the schedule to absolute number configuration. Then doing the remote side is similar
  33. * except we only fix the remote ACKs based on our locally generated random number because
  34. * we do not yet know the remote random number of the SYN-ACK packet. This means that at this
  35. * point the entire schedule of local packets and remote packets are set in such a way that
  36. * the local packets' SEQ's are absolute, but ACKs are relative and the remote packets' SEQ's are
  37. * relative but ACKs as absolute. Once this is set, the replay starts by sending first SYN packet.
  38. * If the remote host's acks with the SYN packet_SEQ+1 then we save their remote SEQ and adjust
  39. * the local ACKs and remote SEQs in the struct schedule to be absolute based this remote SEQ.
  40. * From this point on forward, we know or 'expect' what the remote host's ACKs and SEQs are exactly.
  41. * If the remote host responds correctly as we expect (checking the schedule position expectation
  42. * as packets are received) then we proceed in the schedule whether the next event is to send a local
  43. * packet or wait for a remote packet to arrive.
  44. *
  45. * Usage: tcpliveplay <eth0/eth1> <file.pcap> <Destination IP [1.2.3.4]> <Destination mac [0a:1b:2c:3d:4e:5f]> <'random'
  46. dst port OR specify dport #>
  47. *
  48. * Example:
  49. * yhsiam@yhsiam-VirtualBox:~$ tcpliveplay eth0 test1.pcap 192.168.1.4 52:57:01:11:31:92 random
  50. *
  51. * NOTE: This program may not completely replay the packets due to the remote host responding in an unexpected
  52. * fashion such as responding with packets never seen in the given *.pcap file or coupling packets together, etc.
  53. * if you have any suggestion on improving this software or if you find any bugs, please let me know at my
  54. * email: tcpliveplay@gmail.com
  55. *
  56. * Past Contributors (Last contributed May 4, 2012): Andrew Leonard & Beau Luck
  57. *
  58. */
  59. #include "tcpliveplay.h"
  60. #include "config.h"
  61. #include "common/sendpacket.h"
  62. #include "common/utils.h"
  63. #include "tcpliveplay_opts.h"
  64. #include <arpa/inet.h>
  65. #include <net/if.h>
  66. #include <netinet/in.h>
  67. #include <signal.h>
  68. #include <stdbool.h>
  69. #include <stdio.h>
  70. #include <stdlib.h>
  71. #include <string.h>
  72. #include <sys/ioctl.h>
  73. #include <sys/socket.h>
  74. #include <sys/types.h>
  75. #include <unistd.h>
  76. volatile int didsig;
  77. #ifdef DEBUG /* set -DDEBUG=1 */
  78. int debug = 0;
  79. #endif
  80. pcap_t *set_live_filter(char *dev, input_addr *hostip, unsigned int port);
  81. pcap_t *set_offline_filter(char *file);
  82. pcap_t *live_handle;
  83. unsigned int sched_index = 0;
  84. unsigned int initial_rseq = 0;
  85. sendpacket_t *sp;
  86. unsigned int seed = 0;
  87. /*g for Global header pointers used in pcap_loop callback*/
  88. tcp_hdr *tcphdr_rprev = NULL;
  89. unsigned int size_payload_prev = 0;
  90. unsigned int acked_index = 0;
  91. unsigned int diff_payload_index = 0;
  92. bool different_payload = false;
  93. volatile sig_atomic_t keep_going = 1;
  94. int random_port();
  95. unsigned int pkts_scheduled = 0; /* packet counter */
  96. struct tcp_sched *sched = NULL;
  97. void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);
  98. void catch_alarm(int sig);
  99. int iface_addrs(char *iface, input_addr *ip, struct mac_addr *mac);
  100. int extmac(char *new_rmac_ptr, struct mac_addr *new_remotemac);
  101. int extip(char *ip_string, input_addr *new_remoteip);
  102. int rewrite(input_addr *new_remoteip,
  103. struct mac_addr *new_remotemac,
  104. input_addr *myip,
  105. struct mac_addr *mymac,
  106. char *file,
  107. unsigned int new_src_port);
  108. int setup_sched(struct tcp_sched *schedule);
  109. int relative_sched(struct tcp_sched *schedule, u_int32_t first_rseq, int num_packets);
  110. int fix_all_checksum_liveplay(ipv4_hdr *iphdr);
  111. int compip(input_addr *lip, input_addr *rip, input_addr *pkgip);
  112. int do_checksum_liveplay(u_int8_t *data, int proto, int len);
  113. int do_checksum_math_liveplay(u_int16_t *data, int len);
  114. /**
  115. * This is the main function of the program that handles calling other
  116. * functions to implemented the needed operations of the replay functionaily.
  117. */
  118. int
  119. main(int argc, char **argv)
  120. {
  121. unsigned int k;
  122. int num_packets;
  123. static const char random_strg[] = "random";
  124. char *iface = argv[1];
  125. char *new_rmac_ptr;
  126. char *new_rip_ptr;
  127. input_addr new_remoteip;
  128. struct mac_addr new_remotemac;
  129. input_addr myip;
  130. struct mac_addr mymac;
  131. int new_src_port;
  132. unsigned int retransmissions = 0;
  133. pcap_t *local_handle;
  134. char errbuf[PCAP_ERRBUF_SIZE];
  135. char ebuf[SENDPACKET_ERRBUF_SIZE];
  136. int i;
  137. optionProcess(&tcpliveplayOptions, argc, argv); /*Process AutoOpts for manpage options*/
  138. if ((argc < 5) || (argv[1] == NULL) || (argv[2] == NULL) || (argv[3] == NULL) || (argv[4] == NULL) ||
  139. (argv[5] == NULL)) {
  140. printf("ERROR: Incorrect Usage!\n");
  141. printf("Usage: tcpliveplay <eth0/eth1> <file.pcap> <Destination IP [1.2.3.4]> <Destination mac [0a:1b:2c:3d:4e:5f]> <specify 'random' or specific port#>\n");
  142. printf("Example:\n yhsiam@yhsiam-VirtualBox:~$ sudo tcpliveplay eth0 test1.pcap 192.168.1.4 52:57:01:11:31:92 random\n\n");
  143. exit(0);
  144. }
  145. if (strlen(iface) > IFNAMSIZ - 1)
  146. errx(-1, "Invalid interface name %s\n", iface);
  147. if (iface_addrs(iface, &myip, &mymac) < 0) /* Extract MAC of interface replay is being request on */
  148. errx(-1, "Failed to access interface %s\n", iface);
  149. /* open send function socket*/
  150. if ((sp = sendpacket_open(iface, ebuf, TCPR_DIR_C2S, SP_TYPE_NONE, NULL)) == NULL)
  151. errx(-1, "Can't open %s: %s", argv[1], ebuf);
  152. /*for(int i = 0; i<10; i++) tolower(port_mode[i]);*/
  153. if (strcmp(argv[5], random_strg) == 0)
  154. new_src_port = random_port();
  155. else
  156. new_src_port = strtol(argv[5], NULL, 10);
  157. if (new_src_port < 0 || new_src_port > 65535)
  158. errx(new_src_port, "Cannot use source port %d", new_src_port);
  159. printf("new source port:: %d\n", new_src_port);
  160. /* Establish a handler for SIGALRM signals. */
  161. /* This is used as timeout for unresponsive remote hosts */
  162. signal(SIGALRM, catch_alarm);
  163. /* Extract new Remote MAC & IP inputed at command line */
  164. new_rmac_ptr = argv[4];
  165. new_rip_ptr = argv[3];
  166. /* These function setup the MAC & IP addresses in the mac_addr & in_addr structs */
  167. if (extmac(new_rmac_ptr, &new_remotemac) == ERROR)
  168. errx(-1, "failed to parse mac address %s\n", new_rmac_ptr);
  169. if (extip(new_rip_ptr, &new_remoteip) == ERROR)
  170. errx(-1, "failed to parse IP address %s\n", new_rip_ptr);
  171. /* Rewrites the given "*.pcap" file with all the new parameters and returns the number of packets */
  172. /* that need to be replayed */
  173. num_packets = rewrite(&new_remoteip, &new_remotemac, &myip, &mymac, argv[2], new_src_port);
  174. if (num_packets < 2)
  175. errx(-1, "Unable to rewrite PCAP file %s\n", argv[2]);
  176. /* create schedule & set it up */
  177. sched = (struct tcp_sched *)malloc(num_packets * sizeof(struct tcp_sched));
  178. if (!sched)
  179. err(-1, "out of memory\n");
  180. pkts_scheduled = setup_sched(sched); /* Returns number of packets in schedule*/
  181. /* Set up the schedule struct to be relative numbers rather than absolute*/
  182. for (i = 0; i < num_packets; i++) {
  183. sched[i].exp_rseq = 0;
  184. sched[i].exp_rack = 0;
  185. }
  186. relative_sched(sched, sched[1].exp_rseq, num_packets);
  187. printf("Packets Scheduled %u\n", pkts_scheduled);
  188. /* Open socket for savedfile traffic to be sent*/
  189. local_handle = pcap_open_offline("newfile.pcap", errbuf); /*call pcap library function*/
  190. if (local_handle == NULL) {
  191. fprintf(stderr, "Couldn't open pcap file %s: %s\n", "newfile.pcap", errbuf);
  192. free(sched);
  193. return (2);
  194. }
  195. /* Open socket for live traffic to be listed to*/
  196. live_handle =
  197. set_live_filter(iface, &myip, new_src_port); /* returns a pcap_t that filters out traffic other than TCP*/
  198. if (live_handle == NULL) {
  199. fprintf(stderr, "Error occurred while listing on traffic: %s\n", errbuf);
  200. free(sched);
  201. return (2);
  202. }
  203. /* Printout when no packets are scheduled */
  204. if (pkts_scheduled == 0) {
  205. printf("\n+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
  206. printf("+ ERROR:: There are no TCP packets to send +\n");
  207. printf("+ Closing replay... +\n");
  208. printf("+ Thank you for Playing, Play again! +\n");
  209. printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n");
  210. free(sched);
  211. return ERROR;
  212. }
  213. /* Start replay by sending the first packet, the SYN, from the schedule */
  214. else if (sched[0].local) { /* Send first packet*/
  215. sendpacket(sp, sched[sched_index].packet_ptr, sched[sched_index].pkthdr.len, &sched[sched_index].pkthdr);
  216. printf("Sending Local Packet............... [%u]\n", sched_index + 1);
  217. sched_index++; /* Proceed in the schedule */
  218. }
  219. /* Main while loop that handles the decision making and the replay oprations */
  220. while (sched_index < pkts_scheduled) {
  221. if (!keep_going) { /*Check the timeout variable */
  222. printf("\n======================================================================\n");
  223. printf("= TIMEOUT:: Remote host is not responding. You may have crashed =\n");
  224. printf("= the host you replayed these packets against OR the packet sequence =\n");
  225. printf("= changed since the capture was taken resulting in differing =\n");
  226. printf("= expectations. Closing replay... =\n");
  227. printf("======================================================================\n\n");
  228. break;
  229. }
  230. /* tcphdr_rprev carries the last remote tcp header */
  231. if (tcphdr_rprev == NULL) {
  232. // printf("FIRST PASS!\n");
  233. }
  234. /* Check if received RST or RST-ACK flagged packets*/
  235. else if ((tcphdr_rprev->th_flags == TH_RST) || (tcphdr_rprev->th_flags == (TH_RST | TH_ACK))) {
  236. printf("\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
  237. printf("+ ERROR:: Remote host has requested to RESET the connection. +\n");
  238. printf("+ Closing replay... +\n");
  239. printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n");
  240. break;
  241. }
  242. /* Do the following if we receive a packet that ACKs for the same ACKing of next packet */
  243. else if ((tcphdr_rprev->th_seq == htonl(sched[sched_index].exp_rseq)) &&
  244. (tcphdr_rprev->th_ack == htonl(sched[sched_index].exp_rack)) && (size_payload_prev > 0)) {
  245. printf("Received Remote Packet............... [%u]\n", sched_index + 1);
  246. printf("Skipping Packet...................... [%u] to Packet [%u]\n",
  247. sched_index + 1,
  248. sched_index + 2);
  249. printf("Next Remote Packet Expectation met.\nProceeding in replay...\n");
  250. sched_index++;
  251. }
  252. /* Do the following if payload does not meet expectation and re-attempt with the remote host for 3 tries*/
  253. else if (different_payload) {
  254. printf("\n+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
  255. printf("+ WARNING: Remote host is not meeting packet size expectations. +\n");
  256. printf("+ for packet %-u. Application layer data differs from capture being replayed. +\n",
  257. diff_payload_index + 1);
  258. printf("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n");
  259. printf("Requesting retransmission.\n Proceeding...\n");
  260. different_payload = false;
  261. }
  262. /* Local Packets */
  263. if (sched[sched_index].local) {
  264. /*Reset alarm timeout*/
  265. alarm(ALARM_TIMEOUT);
  266. printf("Sending Local Packet............... [%u]\n", sched_index + 1);
  267. /* edit each packet tcphdr before sending based on the schedule*/
  268. if (sched_index > 0) {
  269. sched[sched_index].tcphdr->th_ack = htonl(sched[sched_index].curr_lack);
  270. fix_all_checksum_liveplay(sched[sched_index].iphdr);
  271. }
  272. /* If 3 attempts of resending was made, then error out to the user */
  273. if (sched[sched_index].sent_counter == 3) {
  274. printf("\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
  275. printf("+ ERROR: Re-sent packet [%-u] 3 times, but remote host is not +\n", sched_index + 1);
  276. printf("+ responding as expected. 3 resend attempts are a maximum. +\n");
  277. printf("+ Closing replay... +\n");
  278. printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\n");
  279. break;
  280. }
  281. /* If nothing goes wrong, then send the packet scheduled to be sent, then proceed in the schedule */
  282. sendpacket(sp, sched[sched_index].packet_ptr, sched[sched_index].pkthdr.len, &sched[sched_index].pkthdr);
  283. sched[sched_index].sent_counter++; /* Keep track of how many times this specific packet was attempted */
  284. sched_index++; /* proceed */
  285. }
  286. /* Remote Packets */
  287. else if (sched[sched_index].remote) {
  288. alarm(ALARM_TIMEOUT);
  289. printf("Receiving Packets from remote host...\n");
  290. pcap_dispatch(live_handle, 1, got_packet, NULL); /* Listen in on NIC for tcp packets */
  291. // printf("pcap_loop returned\n");
  292. }
  293. } /* end of main while loop*/
  294. pcap_breakloop(live_handle);
  295. pcap_close(live_handle);
  296. sendpacket_close(sp); /* Close Send socket*/
  297. remove("newfile.pcap"); /* Remote the rewritten file that was created*/
  298. for (k = 0; k < pkts_scheduled; k++) {
  299. retransmissions += sched[k].sent_counter;
  300. }
  301. /* User Debug Result Printouts*/
  302. if (sched_index == pkts_scheduled) {
  303. printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
  304. printf("~ CONGRATS!!! You have successfully Replayed your pcap file '%s'\n", argv[2]);
  305. printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n");
  306. } else {
  307. printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
  308. printf("~ Unfortunately an error has occurred halting the replay of\n");
  309. printf("~ the pcap file '%s'. Please see error above for details...\n", argv[2]);
  310. printf("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n");
  311. }
  312. printf("----------------TCP Live Play Summary----------------\n");
  313. printf("- Packets Scheduled to be Sent & Received: %-u\n", pkts_scheduled);
  314. printf("- Actual Packets Sent & Received: %-u\n", sched_index);
  315. printf("- Total Local Packet Re-Transmissions due to packet\n");
  316. printf("- loss and/or differing payload size than expected: %-u\n", retransmissions);
  317. printf("- Thank you for Playing, Play again!\n");
  318. printf("----------------------------------------------------------\n\n");
  319. free(sched);
  320. restore_stdin();
  321. return 0;
  322. }
  323. /*end of main() function*/
  324. /**
  325. * This function serves as a timer alarm
  326. */
  327. void
  328. catch_alarm(int sig)
  329. {
  330. keep_going = 0;
  331. signal(sig, catch_alarm);
  332. }
  333. static int
  334. tcplp_rand(void)
  335. {
  336. struct timeval tv;
  337. if (!seed) {
  338. gettimeofday(&tv, NULL);
  339. seed = (unsigned int)tv.tv_sec ^ (unsigned int)tv.tv_usec;
  340. }
  341. return (int)tcpr_random(&seed);
  342. }
  343. /**
  344. * This function returns a random number between 49152 and 65535
  345. */
  346. int
  347. random_port()
  348. {
  349. int random = tcplp_rand();
  350. return (49152 + (random % 16383));
  351. }
  352. /**
  353. * This function sets up the scheduled local ACK and Remote SEQ to be relative numbers,
  354. * While it sets up the local SEQs and remote ACKs to be absolute within the schedule.
  355. */
  356. int
  357. relative_sched(struct tcp_sched *schedule, u_int32_t first_rseq, int num_packets)
  358. {
  359. int i;
  360. u_int32_t lseq_adjust = tcplp_rand();
  361. printf("Random Local SEQ: %u\n", lseq_adjust);
  362. u_int32_t first_lseq = schedule[0].curr_lseq; /* SYN Packet SEQ number */
  363. /* Fix schedule to relative and absolute */
  364. for (i = 0; i < num_packets; i++) {
  365. if (schedule[i].local) {
  366. schedule[i].curr_lseq = schedule[i].curr_lseq - first_lseq; /* Fix current local SEQ to relative */
  367. schedule[i].curr_lseq = schedule[i].curr_lseq +
  368. lseq_adjust; /* Make absolute. lseq_adjust is the locally generated random number */
  369. schedule[i].curr_lack = schedule[i].curr_lack - first_rseq; /* Fix current local ACK to relative */
  370. if (schedule[i].tcphdr)
  371. schedule[i].tcphdr->th_seq = htonl(schedule[i].curr_lseq); /* Edit the actual packet header data */
  372. fix_all_checksum_liveplay(schedule[i].iphdr); /* Fix the checksum */
  373. schedule[i].exp_rseq = schedule[i].exp_rseq - first_rseq;
  374. schedule[i].exp_rack = schedule[i].exp_rack - first_lseq;
  375. schedule[i].exp_rack = schedule[i].exp_rack + lseq_adjust;
  376. } else if (schedule[i].remote) {
  377. schedule[i].exp_rseq = schedule[i].exp_rseq - first_rseq; /* Fix expected remote SEQ to be relative */
  378. schedule[i].exp_rack = schedule[i].exp_rack - first_lseq; /* Fix expected remote ACK to be relative*/
  379. schedule[i].exp_rack = schedule[i].exp_rack + lseq_adjust; /* Fix expected remote ACK to be absolute */
  380. }
  381. }
  382. return SUCCESS;
  383. }
  384. /**
  385. * This function sets up the schedule for the rest of the program
  386. * extracting all the needed information from the given pcap file
  387. * and coping into memory (into a struct format)
  388. *
  389. */
  390. int
  391. setup_sched(struct tcp_sched *schedule)
  392. {
  393. input_addr sip, dip; /* Source & Destination IP */
  394. input_addr local_ip, remote_ip; /* ip address of client and server*/
  395. pcap_t *local_handle;
  396. const u_char *packet; /* The actual packet */
  397. unsigned int flags;
  398. struct pcap_pkthdr header; // The header that pcap gives us
  399. int pkt_counter = 0;
  400. bool remote = false; /* flags to test if data is from 'client'=local or 'server'=remote */
  401. bool local = false;
  402. unsigned int i = 0;
  403. local_ip.byte1 = 0;
  404. local_ip.byte2 = 0;
  405. local_ip.byte3 = 0;
  406. local_ip.byte4 = 0;
  407. remote_ip.byte1 = 0;
  408. remote_ip.byte2 = 0;
  409. remote_ip.byte3 = 0;
  410. remote_ip.byte4 = 0;
  411. char errbuf[PCAP_ERRBUF_SIZE];
  412. local_handle = pcap_open_offline("newfile.pcap", errbuf); /*call pcap library function*/
  413. if (local_handle == NULL) {
  414. fprintf(stderr, "Couldn't open pcap file %s: %s\n", "newfile.pcap", errbuf);
  415. return (2);
  416. }
  417. /*Before sending any packet, setup the schedule with the proper parameters*/
  418. while ((packet = safe_pcap_next(local_handle, &header))) {
  419. /*temporary packet buffers*/
  420. ether_hdr *etherhdr;
  421. tcp_hdr *tcphdr;
  422. ipv4_hdr *iphdr;
  423. unsigned int size_ip;
  424. unsigned int size_tcp;
  425. unsigned int size_payload;
  426. pkt_counter++; /*increment number of packets seen*/
  427. memcpy(&schedule[i].pkthdr, &header, sizeof(struct pcap_pkthdr));
  428. schedule[i].packet_ptr = safe_malloc(schedule[i].pkthdr.len);
  429. memcpy(schedule[i].packet_ptr, packet, schedule[i].pkthdr.len);
  430. /* extract necessary data */
  431. etherhdr = (ether_hdr *)(schedule[i].packet_ptr);
  432. iphdr = (ipv4_hdr *)(schedule[i].packet_ptr + SIZE_ETHERNET);
  433. size_ip = iphdr->ip_hl << 2;
  434. if (size_ip < 20) {
  435. printf("ERROR: Invalid IP header length: %u bytes\n", size_ip);
  436. return 0;
  437. }
  438. tcphdr = (tcp_hdr *)(schedule[i].packet_ptr + SIZE_ETHERNET + size_ip);
  439. size_tcp = tcphdr->th_off * 4;
  440. if (size_tcp < 20) {
  441. printf("ERROR: Invalid TCP header length: %u bytes\n", size_tcp);
  442. return 0;
  443. }
  444. /* payload = (u_char *)(schedule[i].packet_ptr + SIZE_ETHERNET + size_ip + size_tcp); */
  445. size_payload = ntohs(iphdr->ip_len) - (size_ip + (size_tcp));
  446. /* Source IP and Destination IP */
  447. sip = iphdr->ip_src;
  448. dip = iphdr->ip_dst;
  449. flags = tcphdr->th_flags;
  450. if (flags == TH_SYN) { /* set IPs who's local and who's remote based on the SYN flag */
  451. local_ip = sip;
  452. remote_ip = dip;
  453. }
  454. /*Compare IPs to see which packet is this coming from*/
  455. if (compip(&local_ip, &remote_ip, &sip) == LOCAL_IP_MATCH) {
  456. local = true;
  457. remote = false;
  458. }
  459. if (compip(&local_ip, &remote_ip, &sip) == REMOTE_IP_MATCH) {
  460. local = false;
  461. remote = true;
  462. }
  463. /* Setup rest of Schedule, parameter by parameter */
  464. /* Refer to header file for details on each of the parameters */
  465. schedule[i].etherhdr = etherhdr;
  466. schedule[i].iphdr = iphdr;
  467. schedule[i].tcphdr = tcphdr;
  468. schedule[i].size_ip = size_ip;
  469. schedule[i].size_tcp = size_tcp;
  470. schedule[i].size_payload = size_payload;
  471. schedule[i].sent_counter = 0;
  472. /* Do the following only for the first packet (SYN)*/
  473. if (i == 0) {
  474. schedule[i].length_last_ldata = 0;
  475. schedule[i].length_curr_ldata = 0;
  476. schedule[i].length_last_rdata = 0;
  477. schedule[i].length_curr_rdata = 0;
  478. schedule[i].local = true;
  479. schedule[i].remote = false;
  480. schedule[i].curr_lseq = ntohl(schedule[i].tcphdr->th_seq);
  481. schedule[i].curr_lack = 0;
  482. schedule[i].exp_rseq = 0; /* Keep track of previous remote seq & ack #s*/
  483. schedule[i].exp_rack = 0;
  484. }
  485. /* Local Packet operations */
  486. else if (local) {
  487. schedule[i].length_last_ldata = schedule[i - 1].length_curr_ldata;
  488. schedule[i].length_curr_ldata = size_payload;
  489. schedule[i].length_last_rdata = schedule[i - 1].length_curr_rdata;
  490. schedule[i].length_curr_rdata = 0;
  491. schedule[i].local = true;
  492. schedule[i].remote = false;
  493. schedule[i].curr_lseq = ntohl(schedule[i].tcphdr->th_seq);
  494. schedule[i].curr_lack = ntohl(schedule[i].tcphdr->th_ack);
  495. schedule[i].exp_rseq = schedule[i - 1].exp_rseq; /* Keep track of previous remote seq & ack #s*/
  496. schedule[i].exp_rack = schedule[i - 1].exp_rack;
  497. }
  498. /* Remote Packet operations */
  499. else if (remote) {
  500. schedule[i].length_last_ldata = schedule[i - 1].length_curr_ldata;
  501. schedule[i].length_curr_ldata = 0;
  502. schedule[i].length_last_rdata = schedule[i - 1].length_curr_rdata;
  503. schedule[i].length_curr_rdata = size_payload;
  504. schedule[i].local = false;
  505. schedule[i].remote = true;
  506. schedule[i].curr_lseq = schedule[i - 1].curr_lseq;
  507. schedule[i].curr_lack = schedule[i - 1].curr_lack;
  508. schedule[i].exp_rseq = ntohl(schedule[i].tcphdr->th_seq); /* Keep track of previous remote seq & ack #s*/
  509. schedule[i].exp_rack = ntohl(schedule[i].tcphdr->th_ack);
  510. }
  511. i++; /* increment schedule index */
  512. } /*end internal loop for reading packets (all in one file)*/
  513. pcap_close(local_handle); /*close the pcap file*/
  514. return pkt_counter; /* Return number of packets scheduled */
  515. }
  516. /**
  517. * This function returns a pcap_t for the live traffic handler which
  518. * filters out traffic other than TCP
  519. *
  520. */
  521. pcap_t *
  522. set_live_filter(char *dev, input_addr *hostip, unsigned int port)
  523. {
  524. pcap_t *handle = NULL; /* Session handle */
  525. char errbuf[PCAP_ERRBUF_SIZE]; /* Error string buffer */
  526. struct bpf_program fp; /* The compiled filter */
  527. char filter_exp[52];
  528. sprintf(filter_exp,
  529. "tcp and dst host %d.%d.%d.%d and dst port %u",
  530. hostip->byte1,
  531. hostip->byte2,
  532. hostip->byte3,
  533. hostip->byte4,
  534. port); /* The filter expression */
  535. bpf_u_int32 mask; /* Our network mask */
  536. bpf_u_int32 net; /* Our IP */
  537. /* Define the device */
  538. if (dev == NULL) {
  539. fprintf(stderr, "Couldn't find default device: %s\n", errbuf);
  540. return handle;
  541. }
  542. /* Find the properties for the device */
  543. if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {
  544. fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf);
  545. net = 0;
  546. mask = 0;
  547. }
  548. /* Open the session in promiscuous mode */
  549. handle = pcap_open_live(dev, BUFSIZ_PLUS, PROMISC_OFF, TIMEOUT_ms, errbuf);
  550. if (handle == NULL) {
  551. fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
  552. return handle;
  553. }
  554. /* Compile and apply the filter */
  555. if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
  556. fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
  557. return handle;
  558. }
  559. if (pcap_setfilter(handle, &fp) == -1) {
  560. fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
  561. return handle;
  562. }
  563. pcap_freecode(&fp);
  564. return handle;
  565. }
  566. /**
  567. * This function returns a pcap_t for the savedfile traffic handler which
  568. * filters out traffic other than TCP
  569. *
  570. */
  571. pcap_t *
  572. set_offline_filter(char *file)
  573. {
  574. pcap_t *handle; /* Session handle */
  575. char errbuf[PCAP_ERRBUF_SIZE]; /* Error string */
  576. struct bpf_program fp; /* The compiled filter */
  577. char filter_exp[] = "tcp";
  578. bpf_u_int32 net = 0; /* Our IP */
  579. /* Open savedfile */
  580. handle = pcap_open_offline(file, errbuf);
  581. if (handle == NULL) {
  582. fprintf(stderr, "Couldn't open file %s\n", errbuf);
  583. return handle;
  584. }
  585. /* Compile and apply the filter */
  586. if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
  587. fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
  588. return handle;
  589. }
  590. if (pcap_setfilter(handle, &fp) == -1) {
  591. fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
  592. return handle;
  593. }
  594. pcap_freecode(&fp);
  595. return handle;
  596. }
  597. /**
  598. * This is the callback function for pcap_loop
  599. * This function is called every time we receive a remote packet
  600. */
  601. void
  602. got_packet(_U_ u_char *args, _U_ const struct pcap_pkthdr *header, const u_char *packet)
  603. {
  604. tcp_hdr *tcphdr;
  605. ipv4_hdr *iphdr;
  606. unsigned int size_ip, size_tcp, size_payload;
  607. unsigned int flags;
  608. /* Extract and examine received packet headers */
  609. iphdr = (ipv4_hdr *)(packet + SIZE_ETHERNET);
  610. size_ip = iphdr->ip_hl << 2;
  611. if (size_ip < 20) {
  612. printf("ERROR: Invalid IP header length: %u bytes\n", size_ip);
  613. return;
  614. }
  615. tcphdr = (tcp_hdr *)(packet + SIZE_ETHERNET + size_ip);
  616. size_tcp = tcphdr->th_off * 4;
  617. if (size_tcp < 20) {
  618. printf("ERROR: Invalid TCP header length: %u bytes\n", size_tcp);
  619. return;
  620. }
  621. size_payload = ntohs(iphdr->ip_len) - (size_ip + (size_tcp));
  622. flags = tcphdr->th_flags;
  623. /* Check correct SYN-ACK expectation, if so then proceed in fixing entire schedule from relative to absolute
  624. * SEQs+ACKs */
  625. if ((flags == (TH_SYN | TH_ACK)) && (sched_index == 1) &&
  626. (tcphdr->th_ack == htonl(sched[sched_index - 1].curr_lseq + 1))) {
  627. unsigned int j;
  628. printf("Received Remote Packet............... [%u]\n", sched_index + 1);
  629. printf("Remote Packet Expectation met.\nProceeding in replay....\n");
  630. // printf("SYN-ACKed Random SEQ set!\n");
  631. initial_rseq = ntohl(tcphdr->th_seq);
  632. // printf("initial_rseq: %u\n", initial_rseq);
  633. /* After we receiving the first SYN-ACK, then adjust the entire sched to be absolute rather than relative #s*/
  634. sched[1].exp_rseq = sched[1].exp_rseq + initial_rseq;
  635. for (j = 2; j < pkts_scheduled;
  636. j++) { /* Based on correctly receiving the random SEQ from the SYN-ACK packet, do the following:*/
  637. if (sched[j].local) { /* Set local ACKs for entire sched to be absolute #s*/
  638. sched[j].curr_lack = sched[j].curr_lack + initial_rseq;
  639. } else if (sched[j].remote) { /* Set remote SEQs for entire sched to be absolute #s*/
  640. sched[j].exp_rseq = sched[j].exp_rseq + initial_rseq;
  641. }
  642. }
  643. sched_index++; /* Proceed in the schedule*/
  644. return;
  645. }
  646. printf(">Received a Remote Packet\n");
  647. printf(">>Checking Expectations\n");
  648. /* Handle Remote Packet Loss */
  649. if (sched[sched_index].exp_rack > ntohl(tcphdr->th_ack)) {
  650. // printf("Remote Packet Loss! Resending Lost packet\n");
  651. sched_index = acked_index; /* Reset the schedule index back to the last correctly ACKed packet */
  652. // printf("ACKED Index = %d\n", acked_index);
  653. while (!sched[sched_index].local) {
  654. sched_index++;
  655. }
  656. return;
  657. }
  658. /* Handle Local Packet Loss <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<COME BACK TO
  659. THIS<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
  660. else if ((sched[sched_index].exp_rseq < ntohl(tcphdr->th_seq)) && sched[sched_index].remote) {
  661. /* Resend immediate previous LOCAL packet */
  662. printf("Local Packet Loss! Resending Lost packet >> DupACK Issued!\n");
  663. sched_index = acked_index; /* Reset the schedule index back to the last correctly ACKed packet */
  664. /*sched[sched_index].sent_counter=0; Reset the re-transmission counter for this ACKed packet?*/
  665. // printf("ACKED Index = %d\n", acked_index);
  666. while (!sched[sched_index].local) {
  667. sched_index++;
  668. }
  669. return;
  670. }
  671. /* No Packet Loss... Proceed Normally (if expectations are met!) */
  672. else if ((tcphdr->th_seq == htonl(sched[sched_index].exp_rseq)) &&
  673. (tcphdr->th_ack == htonl(sched[sched_index].exp_rack))) {
  674. printf("Received Remote Packet............... [%d]\n", sched_index + 1);
  675. /* Handles differing payload size and does not trigger on unnecessary ACK + window update issues*/
  676. if ((sched[sched_index].size_payload != size_payload) && (size_payload != 0)) {
  677. printf("Payload size of received packet does not meet expectations\n");
  678. /* Resent last local packet, maybe remote host behaves this time*/
  679. different_payload = true;
  680. /* Set global variable of where differing payload size is not meeting expectations*/
  681. diff_payload_index = sched_index;
  682. /*Treat this as packet loss, and attempt resetting index to resend packets where*/
  683. /* packets were received matching expectation*/
  684. sched_index = acked_index; /* Reset the schedule index back to the last correctly ACKed packet */
  685. // printf("ACKED Index = %d\n", acked_index);
  686. while (!sched[sched_index].local) {
  687. sched_index++;
  688. }
  689. return;
  690. }
  691. printf("Remote Packet Expectation met.\nProceeding in replay....\n");
  692. sched_index++;
  693. acked_index = sched_index; /*Keep track correctly ACKed packet index*/
  694. }
  695. /* Global variable to keep tack of last received packet info */
  696. tcphdr_rprev = tcphdr;
  697. size_payload_prev = size_payload;
  698. }
  699. /**
  700. * This function compares two IPs,
  701. * returns 1 if match with local ip
  702. * returns 2 if matches with remote ip
  703. * returns 0 if no match
  704. *
  705. */
  706. int
  707. compip(input_addr *lip, input_addr *rip, input_addr *pkgip)
  708. {
  709. if ((lip->byte1 == pkgip->byte1) && (lip->byte2 == pkgip->byte2) && (lip->byte3 == pkgip->byte3) &&
  710. (lip->byte4 == pkgip->byte4))
  711. return LOCAL_IP_MATCH;
  712. else if ((rip->byte1 == pkgip->byte1) && (rip->byte2 == pkgip->byte2) && (rip->byte3 == pkgip->byte3) &&
  713. (rip->byte4 == pkgip->byte4))
  714. return REMOTE_IP_MATCH;
  715. else
  716. return NO_MATCH;
  717. }
  718. /**
  719. * This function sets the IP and MAC of a given interface (i.e. eth0)
  720. * into in_addr & mac_addr struct pointers
  721. *
  722. */
  723. int
  724. iface_addrs(char *iface, input_addr *ip, struct mac_addr *mac)
  725. {
  726. int s;
  727. struct ifreq buffer;
  728. s = socket(PF_INET, SOCK_DGRAM, 0);
  729. if (s < 0)
  730. return -1;
  731. memset(&buffer, 0x00, sizeof(buffer));
  732. strncpy(buffer.ifr_name, iface, sizeof(buffer.ifr_name) - 1);
  733. int res;
  734. if ((res = ioctl(s, SIOCGIFADDR, &buffer)) < 0)
  735. goto done;
  736. struct in_addr localip = ((struct sockaddr_in *)&buffer.ifr_addr)->sin_addr;
  737. #if defined(WORDS_BIGENDIAN)
  738. ip->byte1 = (localip.s_addr) >> 24;
  739. ip->byte2 = ((localip.s_addr) >> 16) & 255;
  740. ip->byte3 = ((localip.s_addr) >> 8) & 255;
  741. ip->byte4 = (localip.s_addr) & 255;
  742. #else
  743. ip->byte4 = (localip.s_addr) >> 24;
  744. ip->byte3 = ((localip.s_addr) >> 16) & 255;
  745. ip->byte2 = ((localip.s_addr) >> 8) & 255;
  746. ip->byte1 = (localip.s_addr) & 255;
  747. #endif
  748. if ((res = ioctl(s, SIOCGIFHWADDR, &buffer)) < 0)
  749. goto done;
  750. mac->byte1 = buffer.ifr_hwaddr.sa_data[0];
  751. mac->byte2 = buffer.ifr_hwaddr.sa_data[1];
  752. mac->byte3 = buffer.ifr_hwaddr.sa_data[2];
  753. mac->byte4 = buffer.ifr_hwaddr.sa_data[3];
  754. mac->byte5 = buffer.ifr_hwaddr.sa_data[4];
  755. mac->byte6 = buffer.ifr_hwaddr.sa_data[5];
  756. done:
  757. close(s);
  758. return res;
  759. }
  760. /**
  761. * This function rewrites the IPs and MACs of a given packet,
  762. * creates a newfile.pcap. It returns the number of packets of the newfile.
  763. * This function only starts rewriting the newfile once it sees the first
  764. * SYN packet. This is so that the first packet in the newfile is always
  765. * the first packet to be sent.
  766. */
  767. int
  768. rewrite(input_addr *new_remoteip,
  769. struct mac_addr *new_remotemac,
  770. input_addr *myip,
  771. struct mac_addr *mymac,
  772. char *file,
  773. unsigned int new_src_port)
  774. {
  775. char *newfile = "newfile.pcap";
  776. input_addr local_ip;
  777. input_addr remote_ip;
  778. const u_char *packet;
  779. struct pcap_pkthdr *header;
  780. pcap_dumper_t *dumpfile;
  781. input_addr sip; /* Source IP */
  782. int local_packets = 0;
  783. bool initstep1 = false; /* keep track of successful handshake step */
  784. bool warned = false;
  785. local_ip.byte1 = 0;
  786. local_ip.byte2 = 0;
  787. local_ip.byte3 = 0;
  788. local_ip.byte4 = 0;
  789. remote_ip.byte1 = 0;
  790. remote_ip.byte2 = 0;
  791. remote_ip.byte3 = 0;
  792. remote_ip.byte4 = 0;
  793. pcap_t *pcap = set_offline_filter(file);
  794. if (!pcap) {
  795. char ErrBuff[1024];
  796. fprintf(stderr, "Cannot open PCAP file '%s' for reading\n", file);
  797. fprintf(stderr, "%s\n", ErrBuff);
  798. return PCAP_OPEN_ERROR;
  799. }
  800. dumpfile = pcap_dump_open(pcap, newfile);
  801. if (!dumpfile) {
  802. fprintf(stderr, "Cannot open PCAP file '%s' for writing\n", newfile);
  803. return PCAP_OPEN_ERROR;
  804. }
  805. /*Modify each packet's IP & MAC based on the passed args then do a checksum of each packet*/
  806. while (safe_pcap_next_ex(pcap, &header, &packet) > 0) {
  807. unsigned int flags, size_ip;
  808. ether_hdr *etherhdr;
  809. ipv4_hdr *iphdr;
  810. tcp_hdr *tcphdr;
  811. unsigned int size_tcp;
  812. if (!warned && header->len > header->caplen) {
  813. fprintf(stderr, "warning: packet capture truncated to %d byte packets\n", header->caplen);
  814. warned = true;
  815. }
  816. etherhdr = (ether_hdr *)(packet);
  817. iphdr = (ipv4_hdr *)(packet + SIZE_ETHERNET);
  818. size_ip = iphdr->ip_hl << 2;
  819. if (size_ip < 20) {
  820. printf("ERROR: Invalid IP header length: %u bytes\n", size_ip);
  821. return ERROR;
  822. }
  823. tcphdr = (tcp_hdr *)(packet + SIZE_ETHERNET + size_ip);
  824. size_tcp = tcphdr->th_off * 4;
  825. if (size_tcp < 20) {
  826. printf("ERROR: Invalid TCP header length: %u bytes\n", size_tcp);
  827. return ERROR;
  828. }
  829. /* payload = (u_char *)(packet + SIZE_ETHERNET + size_ip + size_tcp); */
  830. sip = iphdr->ip_src;
  831. flags = tcphdr->th_flags;
  832. /* set IPs who's local and who's remote based on the SYN flag */
  833. if (flags == TH_SYN) {
  834. local_ip = iphdr->ip_src;
  835. remote_ip = iphdr->ip_dst;
  836. initstep1 = true; /* This flag is set to signify the first encounter of the SYN within the pacp*/
  837. }
  838. if (compip(&local_ip, &remote_ip, &sip) == LOCAL_IP_MATCH) {
  839. /* Set the source MAC */
  840. etherhdr->ether_shost[0] = mymac->byte1;
  841. etherhdr->ether_shost[1] = mymac->byte2;
  842. etherhdr->ether_shost[2] = mymac->byte3;
  843. etherhdr->ether_shost[3] = mymac->byte4;
  844. etherhdr->ether_shost[4] = mymac->byte5;
  845. etherhdr->ether_shost[5] = mymac->byte6;
  846. /* Set the source IP */
  847. iphdr->ip_src = *myip;
  848. /* Set the destination IP */
  849. iphdr->ip_dst = *new_remoteip;
  850. /* Set the destination MAC */
  851. etherhdr->ether_dhost[0] = new_remotemac->byte1;
  852. etherhdr->ether_dhost[1] = new_remotemac->byte2;
  853. etherhdr->ether_dhost[2] = new_remotemac->byte3;
  854. etherhdr->ether_dhost[3] = new_remotemac->byte4;
  855. etherhdr->ether_dhost[4] = new_remotemac->byte5;
  856. etherhdr->ether_dhost[5] = new_remotemac->byte6;
  857. /* This is to change the source port, whether it is specified as random or as a port # by the user */
  858. tcphdr->th_sport = htons(new_src_port);
  859. } else if (compip(&local_ip, &remote_ip, &sip) == REMOTE_IP_MATCH) {
  860. /* Set the destination MAC */
  861. etherhdr->ether_dhost[0] = mymac->byte1;
  862. etherhdr->ether_dhost[1] = mymac->byte2;
  863. etherhdr->ether_dhost[2] = mymac->byte3;
  864. etherhdr->ether_dhost[3] = mymac->byte4;
  865. etherhdr->ether_dhost[4] = mymac->byte5;
  866. etherhdr->ether_dhost[5] = mymac->byte6;
  867. /* Set the destination IP */
  868. iphdr->ip_dst = *myip;
  869. /* Set the source IP */
  870. iphdr->ip_src = *new_remoteip;
  871. /* Set the source MAC */
  872. etherhdr->ether_shost[0] = new_remotemac->byte1;
  873. etherhdr->ether_shost[1] = new_remotemac->byte2;
  874. etherhdr->ether_shost[2] = new_remotemac->byte3;
  875. etherhdr->ether_shost[3] = new_remotemac->byte4;
  876. etherhdr->ether_shost[4] = new_remotemac->byte5;
  877. etherhdr->ether_shost[5] = new_remotemac->byte6;
  878. /* This is to change the source port, whether it is specified as random or as a port # by the user */
  879. tcphdr->th_dport = htons(new_src_port);
  880. }
  881. /*Calculate & fix checksum for newly edited-packet*/
  882. fix_all_checksum_liveplay(iphdr);
  883. if (initstep1) { /*only start rewriting new pcap with SYN packets on wards*/
  884. local_packets++;
  885. pcap_dump((u_char *)dumpfile, header, packet);
  886. }
  887. } /* end of while loop */
  888. pcap_close(pcap);
  889. pcap_dump_close(dumpfile);
  890. return local_packets;
  891. }
  892. /**
  893. * This function extracts the MAC address (from command line format
  894. * and sets the mac_addr struct)
  895. *
  896. */
  897. int
  898. extmac(char *new_rmac_ptr, struct mac_addr *new_remotemac)
  899. {
  900. u_int8_t new_rmac[6];
  901. if (sscanf(new_rmac_ptr,
  902. "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
  903. &new_rmac[0],
  904. &new_rmac[1],
  905. &new_rmac[2],
  906. &new_rmac[3],
  907. &new_rmac[4],
  908. &new_rmac[5]) != 6)
  909. return ERROR;
  910. new_remotemac->byte1 = (unsigned char)new_rmac[0];
  911. new_remotemac->byte2 = (unsigned char)new_rmac[1];
  912. new_remotemac->byte3 = (unsigned char)new_rmac[2];
  913. new_remotemac->byte4 = (unsigned char)new_rmac[3];
  914. new_remotemac->byte5 = (unsigned char)new_rmac[4];
  915. new_remotemac->byte6 = (unsigned char)new_rmac[5];
  916. return SUCCESS;
  917. }
  918. /**
  919. * This function extracts the IP address (from command line format
  920. * and sets the in_addr struct)
  921. *
  922. */
  923. int
  924. extip(char *ip_string, input_addr *new_remoteip)
  925. {
  926. struct in_addr addr;
  927. if (inet_aton(ip_string, &addr) == 0)
  928. return ERROR;
  929. #if defined(WORDS_BIGENDIAN)
  930. new_remoteip->byte4 = (unsigned char)addr.s_addr & 0xff;
  931. new_remoteip->byte3 = (unsigned char)(addr.s_addr >> 8) & 0xff;
  932. new_remoteip->byte2 = (unsigned char)(addr.s_addr >> 16) & 0xff;
  933. new_remoteip->byte1 = (unsigned char)(addr.s_addr >> 24) & 0xff;
  934. #else
  935. new_remoteip->byte1 = (unsigned char)addr.s_addr & 0xff;
  936. new_remoteip->byte2 = (unsigned char)(addr.s_addr >> 8) & 0xff;
  937. new_remoteip->byte3 = (unsigned char)(addr.s_addr >> 16) & 0xff;
  938. new_remoteip->byte4 = (unsigned char)(addr.s_addr >> 24) & 0xff;
  939. #endif
  940. return SUCCESS;
  941. }
  942. /**
  943. * This function calls all the checksum function given the IP Header
  944. * and edits the checksums fixing them appropriately
  945. *
  946. */
  947. int
  948. fix_all_checksum_liveplay(ipv4_hdr *iphdr)
  949. {
  950. int ret;
  951. /*Calculate TCP Checksum*/
  952. ret = do_checksum_liveplay((u_char *)iphdr, iphdr->ip_p, ntohs(iphdr->ip_len) - (iphdr->ip_hl << 2));
  953. if (ret != TCPEDIT_OK) {
  954. printf("*******An Error Occurred calculating TCP Checksum*******\n");
  955. return -1;
  956. }
  957. /*Calculate IP Checksum*/
  958. do_checksum_liveplay((u_char *)iphdr, IPPROTO_IP, ntohs(iphdr->ip_len));
  959. return 0;
  960. }
  961. /************************************************************************************/
  962. /*[copied from Aaron Turnor's checksum.c, but omitting tcpedit_t structs] */
  963. /*[The following functions have been slightly modified to be integrated with tcpliveplay code structure] */
  964. /**
  965. * This code re-calcs the IP and Layer 4 checksums
  966. * the IMPORTANT THING is that the Layer 4 header
  967. * is contiguous in memory after *ip_hdr we're actually
  968. * writing to the layer 4 header via the ip_hdr ptr.
  969. * (Yes, this sucks, but that's the way libnet works, and
  970. * I was too lazy to re-invent the wheel.
  971. * Returns 0 on success, -1 on error
  972. */
  973. /**
  974. * Returns -1 on error and 0 on success, 1 on warn
  975. */
  976. int
  977. do_checksum_liveplay(u_int8_t *data, int proto, int len)
  978. {
  979. ipv4_hdr *ipv4;
  980. tcp_hdr *tcp;
  981. int ip_hl;
  982. volatile int sum; // <-- volatile works around a PPC g++ bug
  983. ipv4 = NULL;
  984. ipv4 = (ipv4_hdr *)data;
  985. ip_hl = ipv4->ip_hl << 2;
  986. switch (proto) {
  987. case IPPROTO_TCP:
  988. tcp = (tcp_hdr *)(data + ip_hl);
  989. #ifdef STUPID_SOLARIS_CHECKSUM_BUG
  990. tcp->th_sum = tcp->th_off << 2;
  991. return (TCPEDIT_OK);
  992. #endif
  993. tcp->th_sum = 0;
  994. /* Note, we do both src & dst IP's at the same time, that's why the
  995. * length is 2x a single IP
  996. */
  997. sum = do_checksum_math_liveplay((u_int16_t *)&ipv4->ip_src, 8);
  998. sum += ntohs(IPPROTO_TCP + len);
  999. sum += do_checksum_math_liveplay((u_int16_t *)tcp, len);
  1000. tcp->th_sum = CHECKSUM_CARRY(sum);
  1001. break;
  1002. case IPPROTO_IP:
  1003. ipv4->ip_sum = 0;
  1004. sum = do_checksum_math_liveplay((u_int16_t *)data, ip_hl);
  1005. ipv4->ip_sum = CHECKSUM_CARRY(sum);
  1006. break;
  1007. default:
  1008. printf("Unsupported protocol for checksum:\n");
  1009. return TCPEDIT_WARN;
  1010. }
  1011. return TCPEDIT_OK;
  1012. }
  1013. /**
  1014. * code to do a ones-compliment checksum
  1015. */
  1016. int
  1017. do_checksum_math_liveplay(u_int16_t *data, int len)
  1018. {
  1019. int sum = 0;
  1020. union {
  1021. u_int16_t s;
  1022. u_int8_t b[2];
  1023. } pad;
  1024. while (len > 1) {
  1025. sum += *data++;
  1026. len -= 2;
  1027. }
  1028. if (len == 1) {
  1029. pad.b[0] = *(u_int8_t *)data;
  1030. pad.b[1] = 0;
  1031. sum += pad.s;
  1032. }
  1033. return (sum);
  1034. }