utils.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. /* $Id$ */
  2. /*
  3. * Copyright (c) 2001-2010 Aaron Turner <aturner at synfin dot net>
  4. * Copyright (c) 2013-2024 Fred Klassen <tcpreplay at appneta dot com> - AppNeta
  5. *
  6. * The Tcpreplay Suite of tools is free software: you can redistribute it
  7. * and/or modify it under the terms of the GNU General Public License as
  8. * published by the Free Software Foundation, either version 3 of the
  9. * License, or with the authors permission any later version.
  10. *
  11. * The Tcpreplay Suite is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with the Tcpreplay Suite. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "defines.h"
  20. #include "config.h"
  21. #include "common.h"
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #ifdef HAVE_SYS_IOCTL_H
  25. #include <sys/ioctl.h>
  26. #endif
  27. /**
  28. * this is wrapped up in a #define safe_malloc
  29. * This function, detects failures to malloc memory and zeros out the
  30. * memory before returning
  31. */
  32. void *
  33. our_safe_malloc(size_t len, const char *funcname, int line, const char *file)
  34. {
  35. u_char *ptr;
  36. if ((ptr = malloc(len)) == NULL) {
  37. fprintf(stderr, "ERROR in %s:%s() line %d: Unable to malloc() %zu bytes/n", file, funcname, line, len);
  38. exit(-1);
  39. }
  40. /* zero memory */
  41. memset(ptr, 0, len);
  42. /* wrapped inside an #ifdef for better performance */
  43. dbgx(5, "Malloc'd %zu bytes in %s:%s() line %d", len, file, funcname, line);
  44. return (void *)ptr;
  45. }
  46. /**
  47. * this is wrapped up in a #define safe_realloc
  48. * This function, detects failures to realloc memory and zeros
  49. * out the NEW memory if len > current len. As always, remember
  50. * to use it as:
  51. * ptr = safe_realloc(ptr, size)
  52. */
  53. void *
  54. our_safe_realloc(void *ptr, size_t len, const char *funcname, int line, const char *file)
  55. {
  56. if ((ptr = realloc(ptr, len)) == NULL) {
  57. fprintf(stderr,
  58. "ERROR: in %s:%s() line %d: Unable to remalloc() buffer to %zu bytes",
  59. file,
  60. funcname,
  61. line,
  62. len);
  63. exit(-1);
  64. }
  65. dbgx(5, "Remalloc'd buffer to %zu bytes in %s:%s() line %d", len, file, funcname, line);
  66. return ptr;
  67. }
  68. /**
  69. * this is wrapped up in a #define safe_strdup
  70. * This function, detects failures to realloc memory
  71. */
  72. char *
  73. our_safe_strdup(const char *str, const char *funcname, int line, const char *file)
  74. {
  75. char *newstr;
  76. if ((newstr = (char *)malloc(strlen(str) + 1)) == NULL) {
  77. fprintf(stderr, "ERROR in %s:%s() line %d: Unable to strdup() %zu bytes\n", file, funcname, line, strlen(str));
  78. exit(-1);
  79. }
  80. memcpy(newstr, str, strlen(str) + 1);
  81. return newstr;
  82. }
  83. pcap_t*
  84. tcpr_pcap_open(const char *path, char *ebuf)
  85. {
  86. #ifdef HAVE_PCAP_OPEN_OFFLINE_WITH_TSTAMP_PRECISION
  87. return pcap_open_offline_with_tstamp_precision(path, PCAP_TSTAMP_PRECISION_NANO, ebuf);
  88. #else
  89. return pcap_open_offline(path, ebuf);
  90. #endif
  91. }
  92. /**
  93. * calls free and sets to NULL.
  94. */
  95. void
  96. our_safe_free(void *ptr, const char *funcname, int line, const char *file)
  97. {
  98. assert(funcname);
  99. assert(line);
  100. assert(file);
  101. if (ptr == NULL)
  102. return;
  103. free(ptr);
  104. }
  105. /**
  106. * get next packet in pcap file
  107. */
  108. u_char *
  109. our_safe_pcap_next(pcap_t *pcap, struct pcap_pkthdr *pkthdr, const char *funcname, int line, const char *file)
  110. {
  111. u_char *pktdata = (u_char *)pcap_next(pcap, pkthdr);
  112. if (pktdata) {
  113. if (pkthdr->len > MAX_SNAPLEN) {
  114. fprintf(stderr,
  115. "safe_pcap_next ERROR: Invalid packet length in %s:%s() line %d: %u is greater than maximum %u\n",
  116. file,
  117. funcname,
  118. line,
  119. pkthdr->len,
  120. MAX_SNAPLEN);
  121. exit(-1);
  122. }
  123. if (!pkthdr->len || !pkthdr->caplen) {
  124. fprintf(stderr,
  125. "safe_pcap_next ERROR: Invalid packet length in %s:%s() line %d: packet length=%u capture length=%u\n",
  126. file,
  127. funcname,
  128. line,
  129. pkthdr->len,
  130. pkthdr->caplen);
  131. exit(-1);
  132. }
  133. /* attempt to correct invalid captures */
  134. if (pkthdr->len < pkthdr->caplen) {
  135. dbgx(1, "Correcting invalid packet capture length %d: packet length=%u", pkthdr->caplen, pkthdr->len);
  136. pkthdr->caplen = pkthdr->len;
  137. }
  138. } else {
  139. /* this will be reported as a failed packet in final report */
  140. dbg(1, "No data found in packet");
  141. }
  142. return pktdata;
  143. }
  144. /**
  145. * get next packet in pcap file (extended)
  146. */
  147. int
  148. our_safe_pcap_next_ex(pcap_t *pcap,
  149. struct pcap_pkthdr **pkthdr,
  150. const u_char **pktdata,
  151. const char *funcname,
  152. int line,
  153. const char *file)
  154. {
  155. int res = pcap_next_ex(pcap, pkthdr, pktdata);
  156. if (*pktdata && *pkthdr) {
  157. if ((*pkthdr)->len > MAXPACKET) {
  158. fprintf(stderr,
  159. "safe_pcap_next_ex ERROR: Invalid packet length in %s:%s() line %d: %u is greater than maximum %u\n",
  160. file,
  161. funcname,
  162. line,
  163. (*pkthdr)->len,
  164. MAXPACKET);
  165. exit(-1);
  166. }
  167. if (!(*pkthdr)->len || (*pkthdr)->len < (*pkthdr)->caplen) {
  168. fprintf(stderr,
  169. "safe_pcap_next_ex ERROR: Invalid packet length in %s:%s() line %d: packet length=%u capture length=%u\n",
  170. file,
  171. funcname,
  172. line,
  173. (*pkthdr)->len,
  174. (*pkthdr)->caplen);
  175. exit(-1);
  176. }
  177. if ((*pkthdr)->len < (*pkthdr)->caplen) {
  178. dbgx(1, "Correcting invalid packet capture length %d: packet length=%u", (*pkthdr)->caplen, (*pkthdr)->len);
  179. (*pkthdr)->caplen = (*pkthdr)->len;
  180. }
  181. } else {
  182. /* this will be reported as a failed packet in final report */
  183. dbgx(1, "No data found in packet 0x%p and/or header 0x%p", *pktdata, *pkthdr);
  184. }
  185. return res;
  186. }
  187. /**
  188. * Print various packet statistics
  189. */
  190. void
  191. packet_stats(const tcpreplay_stats_t *stats)
  192. {
  193. struct timespec diff;
  194. COUNTER diff_us;
  195. COUNTER bytes_sec = 0;
  196. u_int32_t bytes_sec_10ths = 0;
  197. COUNTER mb_sec = 0;
  198. u_int32_t mb_sec_100ths = 0;
  199. u_int32_t mb_sec_1000ths = 0;
  200. COUNTER pkts_sec = 0;
  201. u_int32_t pkts_sec_100ths = 0;
  202. timessub(&stats->end_time, &stats->start_time, &diff);
  203. diff_us = TIMESPEC_TO_MICROSEC(&diff);
  204. if (diff_us && stats->pkts_sent && stats->bytes_sent) {
  205. COUNTER bytes_sec_X10;
  206. COUNTER pkts_sec_X100;
  207. COUNTER mb_sec_X1000;
  208. COUNTER mb_sec_X100;
  209. if (stats->bytes_sent > 1000 * 1000 * 1000 && diff_us > 1000 * 1000) {
  210. bytes_sec_X10 = (stats->bytes_sent * 10 * 1000) / (diff_us / 1000);
  211. pkts_sec_X100 = (stats->pkts_sent * 100 * 1000) / (diff_us / 1000);
  212. } else {
  213. bytes_sec_X10 = (stats->bytes_sent * 10 * 1000 * 1000) / diff_us;
  214. pkts_sec_X100 = (stats->pkts_sent * 100 * 1000 * 1000) / diff_us;
  215. }
  216. bytes_sec = bytes_sec_X10 / 10;
  217. bytes_sec_10ths = bytes_sec_X10 % 10;
  218. mb_sec_X1000 = (bytes_sec * 8) / 1000;
  219. mb_sec_X100 = mb_sec_X1000 / 10;
  220. mb_sec = mb_sec_X1000 / 1000;
  221. mb_sec_100ths = mb_sec_X100 % 100;
  222. mb_sec_1000ths = mb_sec_X1000 % 1000;
  223. pkts_sec = pkts_sec_X100 / 100;
  224. pkts_sec_100ths = pkts_sec_X100 % 100;
  225. }
  226. if (diff_us >= 1000 * 1000) {
  227. printf("Actual: " COUNTER_SPEC " packets (" COUNTER_SPEC " bytes) sent in %zd.%02zd seconds\n",
  228. stats->pkts_sent,
  229. stats->bytes_sent,
  230. (ssize_t)diff.tv_sec,
  231. (ssize_t)(diff.tv_nsec / (10 * 1000000)));
  232. } else {
  233. printf("Actual: " COUNTER_SPEC " packets (" COUNTER_SPEC " bytes) sent in %zd.%06zd seconds\n",
  234. stats->pkts_sent,
  235. stats->bytes_sent,
  236. (ssize_t)diff.tv_sec,
  237. (ssize_t)diff.tv_nsec / 1000);
  238. }
  239. if (mb_sec >= 1)
  240. printf("Rated: %llu.%1u Bps, %llu.%02u Mbps, %llu.%02u pps\n",
  241. bytes_sec,
  242. bytes_sec_10ths,
  243. mb_sec,
  244. mb_sec_100ths,
  245. pkts_sec,
  246. pkts_sec_100ths);
  247. else
  248. printf("Rated: %llu.%1u Bps, %llu.%03u Mbps, %llu.%02u pps\n",
  249. bytes_sec,
  250. bytes_sec_10ths,
  251. mb_sec,
  252. mb_sec_1000ths,
  253. pkts_sec,
  254. pkts_sec_100ths);
  255. fflush(NULL);
  256. if (stats->failed)
  257. printf("Failed write attempts: " COUNTER_SPEC "\n", stats->failed);
  258. }
  259. /**
  260. * fills a buffer with a string representing the given time
  261. *
  262. * @param when: the time that should be formatted
  263. * @param buf: a buffer to write to
  264. * @param len: length of the buffer
  265. * @return: string containing date, or -1 on error
  266. */
  267. int
  268. format_date_time(struct timespec *when, char *buf, size_t len)
  269. {
  270. struct tm *tm;
  271. char tmp[64];
  272. assert(len);
  273. tm = localtime(&when->tv_sec);
  274. if (!tm)
  275. return -1;
  276. strftime(tmp, sizeof tmp, "%Y-%m-%d %H:%M:%S.%%09u", tm);
  277. return snprintf(buf, len, tmp, when->tv_nsec);
  278. }
  279. /**
  280. * reads a hexstring in the format of xx,xx,xx,xx spits it back into *hex
  281. * up to hexlen bytes. Returns actual number of bytes returned. On error
  282. * it just calls errx() since all errors are fatal.
  283. */
  284. int
  285. read_hexstring(const char *l2string, u_char *hex, int hexlen)
  286. {
  287. int numbytes = 0;
  288. unsigned int value;
  289. char *l2byte;
  290. u_char databyte;
  291. char *token = NULL;
  292. char *string;
  293. string = safe_strdup(l2string);
  294. if (hexlen <= 0)
  295. err(-1, "Hex buffer must be > 0");
  296. memset(hex, '\0', hexlen);
  297. /* data is hex, comma separated, byte by byte */
  298. /* get the first byte */
  299. l2byte = strtok_r(string, ",", &token);
  300. if (l2byte == NULL)
  301. err(-1, "Hex buffer must contain something");
  302. value = strtol(l2byte, NULL, 16);
  303. if (value > 0xff)
  304. errx(-1, "Invalid hex string byte: %s", l2byte);
  305. databyte = (u_char)value;
  306. memcpy(&hex[numbytes], &databyte, 1);
  307. /* get remaining bytes */
  308. while ((l2byte = strtok_r(NULL, ",", &token)) != NULL) {
  309. numbytes++;
  310. if (numbytes + 1 > hexlen) {
  311. warn("Hex buffer too small for data- skipping data");
  312. goto done;
  313. }
  314. value = strtol(l2byte, NULL, 16);
  315. if (value > 0xff)
  316. errx(-1, "Invalid hex string byte: %s", l2byte);
  317. databyte = (u_char)value;
  318. memcpy(&hex[numbytes], &databyte, 1);
  319. }
  320. numbytes++;
  321. done:
  322. safe_free(string);
  323. dbgx(1, "Read %d bytes of hex data", numbytes);
  324. return (numbytes);
  325. }
  326. #ifdef USE_CUSTOM_INET_ATON
  327. int
  328. inet_aton(const char *name, struct in_addr *addr)
  329. {
  330. in_addr_t a = inet_addr(name);
  331. addr->s_addr = a;
  332. return a != (in_addr_t)-1;
  333. }
  334. #endif
  335. #if SIZEOF_LONG == 4
  336. uint32_t
  337. __div64_32(uint64_t *n, uint32_t base)
  338. {
  339. uint64_t rem = *n;
  340. uint64_t b = base;
  341. uint64_t res, d = 1;
  342. uint32_t high = rem >> 32;
  343. /* Reduce the thing a bit first */
  344. res = 0;
  345. if (high >= base) {
  346. high /= base;
  347. res = (uint64_t)high << 32;
  348. rem -= (uint64_t)(high * base) << 32;
  349. }
  350. while ((int64_t)b > 0 && b < rem) {
  351. b = b + b;
  352. d = d + d;
  353. }
  354. do {
  355. if (rem >= b) {
  356. rem -= b;
  357. res += d;
  358. }
  359. b >>= 1;
  360. d >>= 1;
  361. } while (d);
  362. *n = res;
  363. return rem;
  364. }
  365. #endif /* SIZEOF_LONG == 4 */
  366. /**
  367. * Implementation of rand_r that is consistent across all platforms
  368. * This algorithm is mentioned in the ISO C standard, here extended
  369. * for 32 bits.
  370. * @param: seed
  371. * @return: random number
  372. */
  373. uint32_t
  374. tcpr_random(uint32_t *seed)
  375. {
  376. unsigned int next = *seed;
  377. int result;
  378. next *= 1103515245;
  379. next += 12345;
  380. result = (int)(next / 65536) % 2048;
  381. next *= 1103515245;
  382. next += 12345;
  383. result <<= 10;
  384. result ^= (int)(next / 65536) % 1024;
  385. next *= 1103515245;
  386. next += 12345;
  387. result <<= 10;
  388. result ^= (int)(next / 65536) % 1024;
  389. *seed = next;
  390. return result;
  391. }
  392. /**
  393. * #416 - Ensure STDIN is not left in non-blocking mode after closing
  394. * a program. BSD and Unix derivatives should utilize `FIONBIO` due to known
  395. * issues with reading from tty with a 0 byte read returning -1 opposed to 0.
  396. */
  397. void
  398. restore_stdin(void)
  399. {
  400. #ifdef FIONBIO
  401. int nb = 0;
  402. ioctl(0, FIONBIO, &nb);
  403. #else
  404. fcntl(0, F_SETFL, fcntl(0, F_GETFL) | O_NONBLOCK);
  405. #endif /* FIONBIO */
  406. }