1 /*
2 * Copyright (c) 2001 Mark Fullmer and The Ohio State University
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $Id: support.c,v 1.35 2003/02/13 02:38:43 maf Exp $
27 */
28
29 #include "ftinclude.h"
30 #include "ftlib.h"
31
32 #ifdef HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
35
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <sys/socket.h>
39 #include <ctype.h>
40 #include <errno.h>
41 #include <limits.h>
42 #include <netdb.h>
43 #include <signal.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <syslog.h>
47 #include <time.h>
48 #include <fcntl.h>
49
50 #if !HAVE_STRSEP
51 char *strsep (char **, const char *);
52 #endif
53
54 #ifndef IN_CLASSD_NET
55 #define IN_CLASSD_NET 0xf0000000
56 #endif
57
58 /*
59 * lookup table for mask length to mask
60 *
61 * (first 8)
62 * 128.0.0.0 192.0.0.0 224.0.0.0 240.0.0.0
63 * 248.0.0.0 252.0.0.0 254.0.0.0 255.0.0.0
64 *
65 */
66 uint32_t mask_lookup[] = { 0xffffffff,
67 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000,
68 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000,
69 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000,
70 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000,
71 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000,
72 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00,
73 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0,
74 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff };
75
76 /*
77 * function ipv4_len2mask
78 *
79 * returns the 32 bit network mask given a length
80 *
81 */
ipv4_len2mask(uint8_t len)82 uint32_t ipv4_len2mask(uint8_t len)
83 {
84 return mask_lookup[(len > 32) ? 0 : len];
85 }
86
87 /*
88 * function: load_lookup
89 *
90 * loads a list of , seperated numbers into an array
91 * ! will invert the list
92 * - can be used as a range operator
93 *
94 * example
95 * 1,5-10 == 1,5,6,7,8,9,10
96 * !1 == all numbers in the range except for 1
97 */
load_lookup(char * s,int size,char * list)98 int load_lookup(char *s, int size, char *list)
99 {
100 char *p;
101 int j, k;
102 unsigned i, i2;
103
104 p = s;
105
106 while ((*p == ' ') || (*p == '\t')) ++p;
107 if (*p == '!') {
108 for (k = 0; k < size; ++k)
109 list[k] = 1;
110 k = 0;
111 ++p;
112 } else {
113 for (k = 0; k < size; ++k)
114 list[k] = 0;
115 k = 1;
116 }
117
118 while (*p) {
119
120 i = (unsigned)strtol(p, (char**)0L, 0);
121 if (i >= size) return -1;
122 list[i] = k;
123
124 /* skip to , or - */
125 while (*p && (*p != ',') && (*p != '-')) ++p;
126
127 if (*p == '-') {
128
129 ++p;
130 i2 = (unsigned)strtol(p, (char**)0L, 0);
131 if (i2 >= size) return -1;
132 for (j = i; j <= i2; ++j) list[j] = k;
133
134 /* skip to , or - */
135 while (*p && (*p != ',') && (*p != '-')) ++p;
136 }
137
138 /* skip past , and - */
139 while (*p && ((*p == ',') || (*p == '-'))) ++p;
140
141 } /* *p */
142
143 return 0;
144
145 } /* load_lookup */
146
147 /*
148 * function: scan_peeri
149 *
150 * scan peer identifier
151 *
152 * scan 1.2.3.4/1.2.3.4/nn[/nnl]
153 * locip remip port ttl
154 * into ftpeer struct
155 */
scan_peeri(char * input)156 struct ftpeeri scan_peeri(char *input)
157 {
158 struct ftpeeri ftpi;
159 char *s, *s2, *locip, *remip, *dstport, *ttl;
160
161 bzero (&ftpi, sizeof ftpi);
162 ftpi.dst_port = FT_PORT;
163
164 locip = remip = dstport = ttl = (char*)0L;
165
166 if (!(s = malloc(strlen(input)+1))) {
167 fterr_warn("malloc");
168 return ftpi;
169 }
170
171 /* keep track of original pointer to free */
172 s2 = s;
173
174 strcpy(s, input);
175
176 locip = s;
177 if (*s) {
178 }
179
180 for (; *s && *s != '/'; ++s);
181 if (*s) {
182 *s = 0;
183 remip = ++s;
184 }
185
186 for (; *s && *s != '/'; ++s);
187 if (*s) {
188 *s = 0;
189 dstport = ++s;
190 }
191
192 for (; *s && *s != '/'; ++s);
193 if (*s) {
194 *s = 0;
195 ttl = ++s;
196 }
197
198 if (locip)
199 ftpi.loc_ip = scan_ip(locip);
200 if (remip)
201 ftpi.rem_ip = scan_ip(remip);
202 if (dstport)
203 ftpi.dst_port = atoi(dstport);
204 if (ttl)
205 ftpi.ttl = atoi(ttl);
206
207 free (s2);
208
209 return ftpi;
210
211 } /* scan_peer */
212
scan_ip_prefix(char * input)213 struct ip_prefix scan_ip_prefix(char *input)
214 {
215 struct ip_prefix p;
216 char *s, *s2;
217 int has_slash;
218
219 has_slash = 0;
220
221 bzero(&p, sizeof p);
222
223 for (s = input; *s; ++s)
224 if (*s == '/') {
225 has_slash = 1;
226 break;
227 }
228
229 if (!has_slash) {
230 p.addr = scan_ip(input);
231 if ((IN_CLASSA(p.addr)) && (p.addr == (p.addr & IN_CLASSA_NET)))
232 p.len = 8;
233 else if ((IN_CLASSB(p.addr)) && (p.addr == (p.addr & IN_CLASSB_NET)))
234 p.len = 16;
235 else if ((IN_CLASSC(p.addr)) && (p.addr == (p.addr & IN_CLASSC_NET)))
236 p.len = 24;
237 else if ((IN_CLASSD(p.addr)) && (p.addr == (p.addr & IN_CLASSD_NET)))
238 p.len = 28;
239 else
240 p.len = 32;
241 } else {
242
243 if (!(s = malloc(strlen(input)+1))) {
244 fterr_warn("malloc");
245 return p;
246 }
247
248 s2 = s;
249
250 strcpy(s, input);
251
252 for (; *s2 && *s2 != '/'; ++s2);
253 if (*s2) {
254 *s2 = 0;
255 ++s2;
256 }
257
258 p.addr = scan_ip(s);
259 p.len = atoi(s2);
260
261 free (s);
262 }
263
264 if (p.len > 32)
265 p.len = 32;
266
267 return p;
268
269 } /* scan_ip_prefix */
270
271 /*
272 * function: scan_ip
273 *
274 * IP address in string S is converted to a u_long
275 * (borrowed from tcpdump)
276 *
277 * left shift any partial dotted quads, ie 10 is 0x0a000000 not 0x0a
278 * so scan_ip_prefix() works for standard prefix notation, ie 10/8
279 */
scan_ip(char * s)280 uint32_t scan_ip(char *s)
281 {
282 struct hostent *he;
283 struct in_addr *ina;
284 uint32_t addr = 0;
285 unsigned int n;
286 int dns, shift = 0;
287 char *t;
288
289 /* if there is anything ascii in here, this may be a hostname */
290 for (dns = 0, t = s; *t; ++t) {
291 if (islower((int)*t) || isupper((int)*t)) {
292 dns = 1;
293 break;
294 }
295 }
296
297 if (dns) {
298
299 if (!(he = gethostbyname(s)))
300 goto numeric;
301
302 if (he->h_addrtype != AF_INET)
303 goto numeric;
304
305 if (he->h_length != sizeof (uint32_t))
306 goto numeric;
307
308 ina = (struct in_addr*)*he->h_addr_list;
309 return (ntohl(ina->s_addr));
310
311 } /* dns */
312
313 numeric:
314 while (1) {
315
316 /* n is the nibble */
317 n = 0;
318
319 /* nibble's are . bounded */
320 while (*s && (*s != '.') && (*s != ' ') && (*s != '\t'))
321 n = n * 10 + *s++ - '0';
322
323 /* shift in the nibble */
324 addr <<=8;
325 addr |= n & 0xff;
326 ++shift;
327
328 /* return on end of string */
329 if ((!*s) || (*s == ' ') || (*s == '\t'))
330 goto ndone;
331
332 /* skip the . */
333 ++s;
334 } /* forever */
335
336 ndone:
337
338 for (; shift < 4; ++shift)
339 addr <<=8;
340
341 return addr;
342
343 } /* scan_ip */
344
345
346 /*
347 * function: print_3float
348 *
349 * format a floating point # to stdout w. 1 trailing space
350 *
351 */
print_3float(float f)352 void print_3float(float f)
353 {
354
355 char s[10], *c;
356 sprintf(s, "%-3.3f", f);
357 c = s + 1;
358 printf("%s ", c);
359
360 } /* print_3float */
361
362 /*
363 * function: print_3float2
364 *
365 * format a floating point # to stdout w. 2 trailing spaces
366 *
367 */
print_3float2(float f)368 void print_3float2(float f)
369 {
370
371 char s[10], *c;
372 sprintf(s, "%-3.3f", f);
373 c = s + 1;
374 printf("%s ", c);
375
376 } /* print_3float */
377
378 /* adapted from dd */
scan_size(char * val)379 int64_t scan_size(char *val)
380 {
381 uint64_t num, t;
382 char *expr;
383
384 if ((num = strtoul(val, &expr, 0)) == ULONG_MAX)
385 goto erange;
386
387 switch(*expr) {
388
389 case 0:
390 break;
391
392 case 'b':
393 t = num;
394 num *= 512;
395 if (t > num)
396 goto erange;
397 break;
398 case 'G':
399 t = num;
400 num *= 1024;
401 num *= 1024;
402 num *= 1024;
403 if (t > num)
404 goto erange;
405 break;
406 case 'K':
407 t = num;
408 num *= 1024;
409 if (t > num)
410 goto erange;
411 break;
412 case 'M':
413 t = num;
414 num *= 1024;
415 num *= 1024;
416 if (t > num)
417 goto erange;
418 break;
419 default:
420 goto erange;
421 }
422
423 return num;
424
425 erange:
426
427 return (int64_t)-1;
428
429 } /* scan_size */
430
431 #if HAVE_SIGACTION
432 /*
433 * Function: mysignal()
434 * POSIX style signals.
435 *
436 * signal() has different semantics over different versions of unix.
437 * this emulates signal() with sigaction() to behave like BSD.
438 *
439 * From Stevens Advanced Programming in the UNIX environment
440 *
441 */
mysignal(int signo,void * func)442 void *mysignal(int signo, void *func)
443 {
444 struct sigaction act, oact;
445
446 act.sa_handler = (void*)func;
447 sigemptyset(&act.sa_mask);
448 act.sa_flags = 0;
449
450 if (signo == SIGALRM) {
451 #ifdef SA_INTERRUPT
452 act.sa_flags |= SA_INTERRUPT; /* SunOS */
453 #endif
454 } else {
455 #ifdef SA_RESTART
456 act.sa_flags |= SA_RESTART; /* SVR4, 4.3+BSD */
457 #endif
458 }
459
460 if (sigaction(signo, &act, &oact) < 0)
461 return SIG_ERR;
462
463 return oact.sa_handler;
464 } /* signal */
465
466 #else /* SIGACTION */
467
mysignal(int signo,void * func)468 void *mysignal(int signo, void *func)
469 { return signal(signo, func) };
470
471 #endif /* SIGACTION */
472
473
474
475 int unlink_pidfile(int pid, char *file, uint16_t port)
476 {
477 char *c;
478 int ret;
479
480 if (!(c = (char*)malloc(strlen(file)+16)))
481 return -1;
482
483 sprintf(c, "%s.%d", file, (int)port);
484
485 if ((ret = unlink(c)) < 0)
486 fterr_warn("unlink(%s)", c);
487
488 free (c);
489
490 return ret;
491
492 } /* unlink_pidfile */
493
494
495 int write_pidfile(int pid, char *file, uint16_t port)
496 {
497 int fd, len;
498 char str[16], *c;
499
500 if (!(c = (char*)malloc(strlen(file)+16)))
501 return -1;
502
503 sprintf(c, "%s.%d", file, (int)port);
504
505 len = sprintf(str, "%u\n", (unsigned)pid);
506
507 if ((fd = open(c, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0 ) {
508 fterr_warn("open(%s)", c);
509 free (c);
510 return -1;
511 }
512
513
514 if (write(fd, str, len) != len) {
515 fterr_warn("write(%s)", c);
516 close (fd);
517 free (c);
518 return -1;
519 }
520
521 return close (fd);
522
523 } /* write_pidfile */
524
525
526 /*
527 * function get_gmtoff
528 *
529 * return offset from GMT in seconds
530 *
531 * based on compute_tz() code by Michael R. Elkins
532 */
533 int get_gmtoff(time_t t)
534 {
535 struct tm *tmp, local, gmt;
536 time_t t2;
537 int yday;
538 tmp = gmtime(&t);
539 bcopy(tmp, &gmt, sizeof gmt);
540
541 tmp = localtime(&t);
542 bcopy(tmp, &local, sizeof local);
543
544 /* calculate difference in seconds */
545 t2 = (local.tm_hour - gmt.tm_hour) * 60; /* to minutes */
546 t2 += (local.tm_min - gmt.tm_min); /* minutes */
547 t2 *= 60; /* to seconds */
548
549 /* diff day */
550 yday = (local.tm_yday - gmt.tm_yday);
551
552 if ((yday == -1) || (yday > 1))
553 t2 -= 86400; /* sub one day */
554 else if (yday != 0)
555 t2 += 86400; /* add one day */
556
557 return t2;
558
559 } /* get_gmtoff */
560
561 /*
562 * function: bigsockbuf
563 *
564 * There is no portable way to determine the max send and receive buffers
565 * that can be set for a socket, so guess then decrement that guess by
566 * 2K until the call succeeds. If n > 1MB then the decrement by .5MB
567 * instead.
568 *
569 * returns size or -1 for error
570 */
571 int bigsockbuf(int fd, int dir, int size)
572 {
573 int n, tries;
574
575 /* initial size */
576 n = size;
577 tries = 0;
578
579 while (n > 4096) {
580
581 if (setsockopt(fd, SOL_SOCKET, dir, (char*)&n, sizeof (n)) < 0) {
582
583 /* anything other than no buffers available is fatal */
584 if (errno != ENOBUFS) {
585 fterr_warn("setsockopt(size=%d)", n);
586 return -1;
587 }
588
589 /* try a smaller value */
590
591 if (n > 1024*1024) /* most systems not > 256K bytes w/o tweaking */
592 n -= 1024*1024;
593 else
594 n -= 2048;
595
596 ++tries;
597
598 } else {
599
600 fterr_info("setsockopt(size=%d)", n);
601 return n;
602
603 }
604
605 } /* while */
606
607 /* no increase in buffer size */
608 return 0;
609
610 } /* bigsockbuf */
611
612 /*
613 * function: mkpath
614 *
615 * make the path to a filename.
616 *
617 * returns 0: ok
618 * -1 fail
619 *
620 */
621 int mkpath(const char *path, mode_t mode)
622 {
623 char *c, *cs = NULL, *c2 = NULL, *p, *p2;
624 int len, ret, done, nodir;
625
626 len = strlen(path);
627 c = (char*)0L;
628 ret = -1;
629 done = 0;
630
631 if (!(c = (char*)malloc(len+1))) {
632 fterr_warn("malloc()");
633 goto mkpath_out;
634 }
635
636 if (!(c2 = (char*)malloc(len+1))) {
637 fterr_warn("malloc()");
638 goto mkpath_out;
639 }
640
641 cs = c;
642 strcpy(c, path);
643 c2[0] = 0;
644
645 while (c && !done) {
646
647 /* break out pathname components in p */
648 if (!(p = strsep(&c, "/")))
649 break;
650
651 /* end of string? */
652 if (!c)
653 break;
654
655 for (done = 1, p2 = c; p2 && *p2; ++p2)
656 if (*p2 == '/') {
657 done = 0;
658 break;
659 }
660
661 /* build path */
662 strcat(c2, p);
663 nodir = 0;
664
665 if (p[0] == '.' && p[1] == 0)
666 nodir = 1;
667
668 if (p[0] == '.' && p[1] == '.' && p[2] == 0)
669 nodir = 1;
670
671 if (p[0] == 0)
672 nodir = 1;
673
674 if (!nodir) {
675
676 if (mkdir(c2, mode) < 0) {
677 if (errno != EEXIST) {
678 fterr_warn("mkdir(%s)", c2);
679 goto mkpath_out;
680 }
681 }
682
683 } /* nodir */
684
685 strcat(c2, "/");
686
687 }
688
689 ret = 0;
690
691 mkpath_out:
692
693 if (cs)
694 free(cs);
695
696 if (c2)
697 free(c2);
698
699 return ret;
700
701 } /* mkpath */
702
703 /*
704 * function: udp_cksum
705 *
706 * calculate checksum of IP pseudo header plus UDP header
707 *
708 */
709 int udp_cksum(struct ip *ip, struct udphdr *up, int len)
710 {
711 uint16_t *word;
712 int sum;
713
714 word = (uint16_t*)&ip->ip_src.s_addr;
715 sum = *word++;
716 sum += *word;
717
718 word = (uint16_t*)&ip->ip_dst.s_addr;
719 sum += *word++;
720 sum += *word;
721
722 sum += htons(len);
723
724 sum += IPPROTO_UDP<<8;
725
726 word = (unsigned short*)up;
727 sum += *word++;
728 sum += *word++;
729 sum += *word++;
730
731 return sum;
732 } /* udp_cksum */
733
734