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