1 /*
2 * Copyright 2004-2009 Rob Beverly
3 * Copyright 2015-2021 The Regents of the University of California
4 * All rights reserved.
5 *
6 * This file is part of Spoofer.
7 *
8 * Spoofer is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * Spoofer is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with Spoofer. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 /****************************************************************************
23 Program: $Id: util.cc,v 1.64 2021/04/28 17:39:07 kkeys Exp $
24 Author: Rob Beverly <rbeverly at csail.mit.edu>
25 Ken Keys, CAIDA
26 Date: $Date: 2021/04/28 17:39:07 $
27 Description: Spoofer utility routines
28 ****************************************************************************/
29
30 #ifdef _WIN32
31 #define _CRT_RAND_S // for rand_s() in <stdlib.h>
32 #endif
33
34 #include <stdarg.h>
35 #include <ctype.h>
36 #include <fcntl.h> // for open()
37 #include "spoof.h"
38 #ifdef HAVE_GETTIMEOFDAY
39 #include <sys/time.h>
40 #endif
41
42 int verbosity = OFF;
43
44 static const std::string pbs_magic_array[] = {
45 std::string("SPOOFER\n\n", 9), // preferred as of version 1.1.0
46 std::string("SPOOFER\0", 8), // used in version <= 1.0.8
47 std::string() // sentry
48 };
49 const std::string *pbs_magic = pbs_magic_array;
50
51
52 #ifdef _WIN32
53 // Windows' snprintf() and vsnprintf() prior to VC2015 do not handle buffer
54 // overflow as specified by C99:
55 // - it doesn't write the terminating NUL
56 // - it returns -1 instead of the would-be string length
57 // - %n arguments past the overflow point will not be set
58 // Windows' sprintf_s() doesn't match either: it guarantees NUL-termination,
59 // but writes an empty string instead of as much as possible.
60 // This version fixes all the issues.
spoofer_snprintf(char * buf,size_t size,const char * fmt,...)61 int spoofer_snprintf(char *buf, size_t size, const char *fmt, ...)
62 {
63 va_list ap;
64 int n = -1;
65 if (buf) {
66 va_start(ap, fmt);
67 n = vsnprintf(buf, size, fmt, ap);
68 va_end(ap);
69 buf[size-1] = '\0';
70 if (n >= 0) return n; // success
71 }
72 // work around broken overflow handling
73 va_start(ap, fmt);
74 FILE *file = fopen("NUL", "w");
75 if (!file) return n; // shouldn't happen
76 n = vfprintf(file, fmt, ap); // returns correct length and sets %n arguments
77 va_end(ap);
78 fclose(file);
79 return n;
80 }
81 #endif
82
is_interactive(void)83 int is_interactive(void)
84 {
85 #ifdef _WIN32
86 HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
87 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
88 if (hIn == INVALID_HANDLE_VALUE || hOut == INVALID_HANDLE_VALUE) return 0;
89 DWORD dummyMode;
90 return GetConsoleMode(hIn, &dummyMode) && GetConsoleMode(hOut, &dummyMode);
91 #else
92 return isatty(STDIN_FILENO) && isatty(STDOUT_FILENO);
93 #endif
94 }
95
exitpause(int status)96 NORETURN void exitpause(int status) {
97 #ifdef _WIN32
98 DWORD proclist[1];
99 if (is_interactive() && GetConsoleProcessList(proclist, 1) <= 1) {
100 // This console has no other processes; it will close when we exit.
101 fprintf(stdout, "\nPress Enter to Exit.\n"); \
102 fflush(stdout); \
103 while (getchar() != '\n');
104 }
105 #endif
106 exit(status);
107 }
108
109 /**
110 * Fatal error condition function
111 */
fatal(const char * fmt,...)112 NORETURN void fatal(const char *fmt, ...) {
113 va_list ap;
114 fflush(stdout);
115 va_start(ap, fmt);
116 fprintf(stderr, "*** ");
117 vfprintf(stderr, fmt, ap);
118 va_end(ap);
119 exitpause(-1);
120 }
121
122 /**
123 * Fatal error condition function; prints error
124 */
pfatal(const char * fmt,...)125 NORETURN void pfatal(const char *fmt, ...) {
126 va_list ap;
127 fflush(stdout);
128 va_start(ap, fmt);
129 vfprintf(stderr, fmt, ap);
130 fprintf(stderr, " ");
131 perror("Error");
132 va_end(ap);
133 exitpause(-1);
134 }
135
136 /**
137 * binDump - Debug routine for examining raw packets/buffer/char strings
138 *
139 * @param[in] msg pointer to message buffer
140 * @param[in] len length of buffer to print
141 * @param[in] pretty if true, pretty print
142 * @param[in] prefix prefix for each line (if pretty)
143 */
binDump(const void * msg,size_t len,int pretty,const char * prefix)144 void binDump(const void *msg, size_t len, int pretty, const char *prefix) {
145 size_t i;
146 const unsigned char *p = static_cast<const unsigned char*>(msg);
147 // Use a buffer so print is atomic (if len is small enough)
148 size_t buflen = !pretty ? len*2 + 1 :
149 (len/16+1) * ((prefix ? strlen(prefix) : 0) + 51) + 2;
150 char *buf = new char[buflen];
151 int off = 0; // offset in buf
152 for (i = 1; i <= len; i++) {
153 if (pretty) {
154 if (prefix && (i-1)%16 == 0) off += sprintf(buf+off, "%s", prefix);
155 off += sprintf(buf+off, "%02x ", *p++);
156 if (i >= len) break;
157 if (i%16 == 0) buf[off-1] = '\n';
158 else if (i%4 == 0) buf[off++] = ' ';
159 } else {
160 off += sprintf(buf+off, "%02x", *p++);
161 }
162 }
163 if (pretty) buf[off++] = '\n';
164 buf[off++] = '\0';
165 fputs(buf, stdout);
166 delete[] buf;
167 }
168
169 /**
170 * win_init - Windows socket API startup
171 */
172 #ifdef _WIN32
win_init(void)173 void win_init(void) {
174 WSADATA wsd;
175 if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0) {
176 fatal("WSAStartup() failed");
177 }
178 }
179 #endif
180
181 /**
182 * Pseudo-random number generator
183 */
184
spoofer_rand_stir()185 void spoofer_rand_stir()
186 {
187 #if defined(HAVE_ARC4RANDOM)
188 #if defined(HAVE_ARC4RANDOM_STIR)
189 // On some newer platforms, the arc4random() function is not actually the
190 // RC4 algorithm, and there is no arc4random_stir() function.
191 arc4random_stir();
192 #endif
193 #elif defined(HAVE_SRANDOMDEV)
194 srandomdev();
195 #else
196 unsigned int seed = 0;
197 int fd = open("/dev/urandom", O_RDONLY);
198 if (fd >= 0) {
199 if (read(fd, &seed, sizeof(seed)) < (ssize_t)sizeof(seed))
200 seed = 0;
201 close(fd);
202 }
203 if (!seed) {
204 #if defined(HAVE_GETTIMEOFDAY)
205 struct timeval tv;
206 gettimeofday(&tv, nullptr);
207 seed = static_cast<unsigned int>(tv.tv_sec * tv.tv_usec);
208 #else
209 seed = static_cast<unsigned int>(time(nullptr));
210 #endif
211 #ifndef _WIN32
212 seed ^= static_cast<unsigned int>(getpid());
213 #endif
214 }
215 #if defined(HAVE_SRANDOM)
216 srandom(seed);
217 #else
218 srand(seed);
219 #endif
220 #endif
221 }
222
223 #if defined(HAVE_ARC4RANDOM) || defined(_WIN32)
224 #define spoofer_rand_stir_if_needed() /* empty */
225 #else
spoofer_rand_stir_if_needed()226 static void spoofer_rand_stir_if_needed()
227 {
228 // Make sure to re-stir if we've forked, so we don't generate the
229 // same pseudorandom sequence as the parent or siblings.
230 static pid_t stirred_pid = 0;
231 pid_t my_pid = getpid();
232 if (stirred_pid != my_pid) {
233 spoofer_rand_stir();
234 stirred_pid = my_pid;
235 }
236 }
237 #endif
238
spoofer_rand(unsigned long max)239 unsigned long spoofer_rand(unsigned long max)
240 {
241 spoofer_rand_stir_if_needed();
242 #if defined(_WIN32)
243 unsigned int r;
244 rand_s(&r);
245 return r % max;
246 #elif defined(HAVE_ARC4RANDOM)
247 return static_cast<unsigned long>(arc4random_uniform(static_cast<uint32_t>(max)));
248 #elif defined(HAVE_SRANDOM)
249 return static_cast<unsigned long>(random()) % max;
250 #else
251 return static_cast<unsigned long>(rand()) % max;
252 #endif
253 }
254
255 /**
256 * msleep - Portable millisecond sleep
257 */
msleep(unsigned int msec)258 void msleep(unsigned int msec) {
259 #ifdef _WIN32
260 Sleep(msec);
261 #else
262 usleep(msec * 1000);
263 #endif
264 }
265
266 /**
267 * spoofSleep - Portable 0.1 - 0.5 s random sleep
268 */
spoofSleep(void)269 void spoofSleep(void) {
270 msleep(100 + static_cast<unsigned>(spoofer_rand(400)));
271 }
272
273 /**
274 * timestring - form time/date string
275 */
timestring(void)276 char *timestring(void) {
277 static char str[BUFSIZE];
278 time_t now;
279 struct tm *t;
280
281 now = time(nullptr);
282 t = localtime(&now);
283 snprintf(str, sizeof(str), "%d/%02d/%02d %02d:%02d:%02d", t->tm_year + 1900,
284 t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
285 return (str);
286 }
287
288 /**
289 * streamSetup - set stdout to be unbuffered, replicate stdout
290 * to the stderr file descriptor. useful with
291 * the authorization services API (for osx gui)
292 * which doesn't pipe back stderr and prevents
293 * weird interleaving of stderr, stdout messages.
294 */
streamSetup(void)295 void streamSetup(void) {
296 if (setvbuf(stdout, nullptr, _IONBF, 0) == EOF) {
297 perror("setvbuf");
298 }
299 if (dup2(1,2) < 0) {
300 perror("dup2");
301 }
302 }
303
304 /* Unified IPv4/IPv6 address field helper routines.
305 * Ex:
306 * char bob[IPV6ADDRLEN];
307 * uint32_t alice = 91232354;
308 * h4to6n(alice, bob);
309 * printf("Alice: %u %u\n", alice, n6toh4(bob));
310 */
311 /* network byte-order IPv6 to network byte-order IPv4 */
n6ton4(const unsigned char * addr)312 uint32_t n6ton4(const unsigned char *addr) {
313 const unsigned char *begin = addr + (IPV6ADDRLEN - IPV4ADDRLEN);
314 uint32_t res;
315 memcpy(&res, begin, IPV4ADDRLEN);
316 return (res);
317 }
318
319 /* network byte-order IPv6 to host byte-order IPv4 */
n6toh4(const unsigned char * addr)320 uint32_t n6toh4(const unsigned char *addr) {
321 return (ntohl(n6ton4(addr)));
322 }
323
324 /* network byte-order IPv4 to network byte-order IPv6 */
n4ton6(const uint32_t ip,unsigned char * addr)325 int n4ton6(const uint32_t ip, unsigned char *addr) {
326 unsigned char *begin = addr + (IPV6ADDRLEN - IPV4ADDRLEN);
327 memcpy(begin, &ip, IPV4ADDRLEN);
328 return TRUE;
329 }
330
331 /* host byte-order IPv4 to network byte-order IPv6 */
h4ton6(const uint32_t ip,unsigned char * addr)332 int h4ton6(const uint32_t ip, unsigned char *addr) {
333 unsigned char *begin = addr + (IPV6ADDRLEN - IPV4ADDRLEN);
334 uint32_t res = htonl(ip);
335 memcpy(begin, &res, IPV4ADDRLEN);
336 return TRUE;
337 }
338
n6tohexstring(const unsigned char * addr,char * res)339 int n6tohexstring(const unsigned char *addr, char *res) {
340 int i=0;
341 snprintf(res, 3, "0x");
342 for (i=1;i<=IPV6ADDRLEN;i++) {
343 snprintf(res + (i*2), 3, "%02x", *addr);
344 addr++;
345 }
346 return TRUE;
347 }
348
isIPv4(const unsigned char * addr)349 int isIPv4(const unsigned char *addr) {
350 int i=0;
351 const unsigned char *d = addr;
352 for (i=0;i<(IPV6ADDRLEN - IPV4ADDRLEN);i++) {
353 if (*d++ != 0x00)
354 return FALSE;
355 }
356 return TRUE;
357 }
358
isIPv6(const unsigned char * addr)359 int isIPv6(const unsigned char *addr) {
360 return (isIPv4(addr) ? FALSE : TRUE);
361 }
362
isIPv6Equal(const unsigned char * a1,const unsigned char * a2)363 int isIPv6Equal(const unsigned char *a1, const unsigned char *a2) {
364 int ret = memcmp(a1, a2, IPV6ADDRLEN);
365 return (ret == 0 ? TRUE : FALSE);
366 }
367
printIPv6(const unsigned char * a)368 char *printIPv6(const unsigned char *a) {
369 static char v6string[SMALLBUF];
370 inet_ntop(AF_INET6, a, v6string, SMALLBUF);
371 return v6string;
372 }
373
374 // portable version of BSD's strnstr()
strstrPortable(const char * a,const char * b,size_t n)375 const char *strstrPortable(const char *a, const char *b, size_t n) {
376 size_t alen, blen, i;
377 // don't depend on there being a \0 within the first n chars
378 for (alen = 0; alen < n; alen++)
379 if (a[alen] == '\0') break;
380 blen = strlen(b);
381 if (blen > alen) return nullptr;
382 if (n > alen - blen)
383 n = alen - blen;
384 for (i = 0; i <= n; i++) {
385 if (memcmp(a+i, b, blen) == 0)
386 return a+i;
387 }
388 return nullptr;
389 }
390