utils.c 12 KB

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