1 /*
2 read_config.c
3
4 Date Created: Sun Sep 18 22:03:40 2011
5 Author: Simon Leinen <simon.leinen@switch.ch>
6 */
7
8 #include "config.h"
9
10 #ifdef HAVE_STDLIB_H
11 #include <stdlib.h>
12 #endif
13 #include <stdarg.h>
14 #include <sys/types.h>
15 #ifdef HAVE_UNISTD_H
16 #include <unistd.h>
17 #endif
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #ifdef HAVE_ARPA_INET_H
21 # include <arpa/inet.h>
22 #endif
23 #include <netdb.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <errno.h>
27 #if STDC_HEADERS
28 # define bzero(b,n) memset(b,0,n)
29 #else
30 # include <strings.h>
31 # ifndef HAVE_MEMCPY
32 # define memcpy(d, s, n) bcopy ((s), (d), (n))
33 # endif
34 #endif
35 #ifdef HAVE_CTYPE_H
36 # include <ctype.h>
37 #endif
38
39 #include "samplicator.h"
40 #include "read_config.h"
41 #include "inet.h"
42 #include "rawsend.h"
43
44 #define PORT_SEPARATOR '/'
45 #define FREQ_SEPARATOR '/'
46 #define TTL_SEPARATOR ','
47
48 #define FLOWPORT "2000"
49
50 #define DEFAULT_SOCKBUFLEN 65536
51
52 #define MAX_PEERS 100
53 #define MAX_LINELEN 8000
54
55 static int parse_line (struct samplicator_context *, char *, const char *);
56 static int parse_addr_mask (const char *, const char *,
57 const struct samplicator_context *,
58 struct sockaddr_storage *,
59 struct sockaddr_storage *,
60 socklen_t *);
61 static void short_usage (const char *);
62 static void usage (const char *);
63
64 static int
parse_error(const struct samplicator_context * ctx,const char * fmt,...)65 parse_error (const struct samplicator_context *ctx, const char *fmt, ...)
66 {
67 va_list fmt_args;
68 va_start (fmt_args, fmt);
69 fprintf (stderr, "%s, line %d: ", ctx->config_file_name, ctx->config_file_lineno);
70 vfprintf (stderr, fmt, fmt_args);
71 fprintf (stderr, "\n");
72 va_end (fmt_args);
73 return -1;
74 }
75
76
77 /* copy_string_start_end (start, end)
78
79 Copy a string defined by a start and end pointer to a fresh
80 null-terminated string. This is useful when using library
81 functions that expect such strings.
82
83 Will return a null pointer if allocating space fails.
84
85 The copy should be free()'d when the caller is done with it.
86 */
87 static char *
copy_string_start_end(start,end)88 copy_string_start_end (start, end)
89 const char *start;
90 const char *end;
91 {
92 size_t len = end-start;
93 char *copy = malloc (len+1);
94 if (copy == 0)
95 return 0;
96 strncpy (copy, start, len);
97 copy[len] = 0;
98 return copy;
99 }
100
101 /* read_cf_file (file, ctx)
102
103 Read configuration file FILE into samplicator context CTX.
104
105 The file is opened and parsed line by line. The parser fills in
106 values of CTX.
107
108 The file name and a line counter are stored in CTX for use in
109 parser error messages.
110
111 Return value:
112
113 0, if the file could be parsed.
114 -1, if an error occurred during parsing.
115
116 If an error occurs, the parser will give up immediately. Contents
117 preceding the errors may have been processed and filled into CTX.
118 */
119 int
read_cf_file(file,ctx)120 read_cf_file (file, ctx)
121 const char *file;
122 struct samplicator_context *ctx;
123 {
124 FILE *cf;
125 char tmp_s[MAX_LINELEN];
126 ctx->config_file_name = file;
127 ctx->config_file_lineno = 0;
128
129 if ((cf = fopen (file,"r")) == NULL)
130 {
131 fprintf (stderr, "read_cf_file: cannot open %s. Aborting.\n", file);
132 return -1;
133 }
134 while (!feof (cf))
135 {
136 if (fgets (tmp_s, MAX_LINELEN, cf) == (char *) 0)
137 {
138 break;
139 }
140
141 ++ctx->config_file_lineno;
142 if (parse_line (ctx, tmp_s, tmp_s + strlen (tmp_s)) == -1)
143 {
144 return -1;
145 }
146 }
147 fclose (cf);
148 return 0;
149 }
150
151 /* resolve_addr (string, ctx, addrp, addrlenp)
152
153 Parses, and possibly resolves, an IP address given as a string.
154
155 The preferences in CTX are used to determine whether to return an
156 IPv4 or IPv6 address.
157
158 The address is stored in the sockaddr_storage structure pointed to
159 by ADDRP.
160
161 If ADDRLENP is non-null, it the length of the address structure
162 will be stored to it.
163
164 If an error occurs during parsing or resolution, the function will
165 return -1, and nothing will be stored in ADDRP or ADDRLENP.
166 */
167 static int
resolve_addr(const char * addrstring,const struct samplicator_context * ctx,struct sockaddr_storage * addrp,socklen_t * addrlenp)168 resolve_addr (const char *addrstring,
169 const struct samplicator_context *ctx,
170 struct sockaddr_storage *addrp,
171 socklen_t *addrlenp)
172 {
173 struct addrinfo hints, *res;
174
175 init_hints_from_preferences (&hints, ctx);
176
177 if (getaddrinfo (addrstring, 0, &hints, &res) != 0 || res == 0)
178 {
179 return parse_error (ctx, "Could not parse address %s", addrstring);
180 }
181 memcpy (addrp, res->ai_addr, res->ai_addrlen);
182 if (addrlenp != 0)
183 *addrlenp = res->ai_addrlen;
184 freeaddrinfo (res);
185 return 0;
186 }
187
188 static int
parse_addr_1(const char * start,const char * end,const struct samplicator_context * ctx,struct sockaddr_storage * addrp,socklen_t * addrlenp)189 parse_addr_1 (const char *start,
190 const char *end,
191 const struct samplicator_context *ctx,
192 struct sockaddr_storage *addrp,
193 socklen_t *addrlenp)
194 {
195 char *copy = copy_string_start_end (start, end);
196 int result;
197
198 if (copy == 0)
199 {
200 return parse_error (ctx, "Out of memory");
201 }
202 result = resolve_addr (copy, ctx, addrp, addrlenp);
203 free (copy);
204 return result;
205 }
206
207 static int
parse_addr(const char * start,const char * end,const struct samplicator_context * ctx,struct sockaddr_storage * addrp,socklen_t * addrlenp)208 parse_addr (const char *start,
209 const char *end,
210 const struct samplicator_context *ctx,
211 struct sockaddr_storage *addrp,
212 socklen_t *addrlenp)
213 {
214 while (start < end && isspace (*start))
215 ++start;
216 while (start < end && isspace (*(end-1)))
217 --end;
218 if (start < end && *start == '[')
219 {
220 ++start;
221 if (start < end && *(end-1) == ']')
222 --end;
223 else
224 {
225 return parse_error (ctx, "Mismatched brackets");
226 }
227 }
228 return parse_addr_1 (start, end, ctx, addrp, addrlenp);
229 }
230
231 static void
set_ipv4_netmask(struct sockaddr_in * maskp,int preflen)232 set_ipv4_netmask(struct sockaddr_in *maskp, int preflen)
233 {
234 in_addr_t *addrp = &maskp->sin_addr.s_addr;
235 int k;
236 unsigned long bit;
237 uint32_t haddr;
238
239 haddr = 0xffffffff;
240 preflen = 32-preflen;
241 for (k = 0, bit = 1; k < preflen; ++k, bit <<= 1)
242 {
243 haddr &= ~bit;
244 }
245 *addrp = htonl (haddr);
246 }
247
248 static void
set_ipv6_netmask(struct sockaddr_in6 * maskp,int preflen)249 set_ipv6_netmask(struct sockaddr_in6 *maskp, int preflen)
250 {
251 uint8_t *addrp = maskp->sin6_addr.s6_addr;
252 int k;
253 unsigned bit;
254 unsigned octet_index;
255
256 memset (addrp, 0, 16);
257 for (k = 0, bit = 128, octet_index = 0;
258 k < preflen;
259 ++k, bit >>= 1)
260 {
261 if (bit < 1)
262 {
263 bit = 128, octet_index++;
264 }
265 addrp[octet_index] |= bit;
266 }
267 }
268
269 static int
parse_mask(const char * start,const char * end,const struct samplicator_context * ctx,struct sockaddr_storage * maskp,struct sockaddr_storage * addrp)270 parse_mask (const char *start,
271 const char *end,
272 const struct samplicator_context *ctx,
273 struct sockaddr_storage *maskp,
274 struct sockaddr_storage *addrp)
275 {
276 if (addrp->ss_family == AF_INET)
277 {
278 const char *cp = start;
279 while (cp < end && *cp != '.')
280 ++cp;
281 if (cp < end) /* contains a dot, assume full netmask */
282 {
283 socklen_t addrlen1;
284 if (parse_addr_1 (start, end, ctx, maskp, &addrlen1) != 0)
285 {
286 return parse_error (ctx, "Cannot parse mask");
287 }
288 else
289 {
290 if (addrlen1 != sizeof (struct sockaddr_in))
291 {
292 return parse_error (ctx, "Inconsistent addr/mask structures");
293 }
294 return 0;
295 }
296 }
297 else
298 { /* no dot, assume this is a prefix length */
299 int preflen;
300 char *int_end;
301 preflen = strtol (start, &int_end, 10);
302 if (int_end == start || int_end < end || preflen < 0 || preflen > 32)
303 {
304 return parse_error (ctx, "Bogus prefix length");
305 }
306 bzero (maskp, sizeof (struct sockaddr_in));
307 ((struct sockaddr_in *)maskp)->sin_family = AF_INET;
308 set_ipv4_netmask((struct sockaddr_in *)maskp, preflen);
309 return 0;
310 }
311 }
312 else if (addrp->ss_family == AF_INET6)
313 {
314 int preflen;
315 char *int_end;
316 preflen = strtol (start, &int_end, 10);
317 if (int_end == start || int_end < end || preflen < 0 || preflen > 128)
318 {
319 return parse_error (ctx, "Bogus prefix length");
320 }
321 bzero (maskp, sizeof (struct sockaddr_in6));
322 ((struct sockaddr_in6 *)maskp)->sin6_family = AF_INET6;
323 set_ipv6_netmask((struct sockaddr_in6 *)maskp, preflen);
324 return 0;
325 }
326 else
327 {
328 return parse_error (ctx, "Unsupported address family");
329 }
330 }
331
332 static int
set_default_mask(const struct samplicator_context * ctx,struct sockaddr_storage * maskp,struct sockaddr_storage * addrp)333 set_default_mask (const struct samplicator_context *ctx,
334 struct sockaddr_storage *maskp,
335 struct sockaddr_storage *addrp)
336 {
337 if (addrp->ss_family == AF_INET)
338 {
339 bzero (maskp, sizeof (struct sockaddr_in));
340 maskp->ss_family = AF_INET;
341 memset (&((struct sockaddr_in *) maskp)->sin_addr, 0xff, 4);
342 return 0;
343 }
344 else if (addrp->ss_family == AF_INET6)
345 {
346 bzero (maskp, sizeof (struct sockaddr_in6));
347 maskp->ss_family = AF_INET6;
348 memset (&((struct sockaddr_in6 *) maskp)->sin6_addr, 0xff, 16);
349 return 0;
350 }
351 return parse_error (ctx, "Unknown address family %d", addrp->ss_family);
352 }
353
354 static int
parse_addr_mask(start,end,ctx,addrp,maskp,addrlenp)355 parse_addr_mask (start, end, ctx, addrp, maskp, addrlenp)
356 const char *start, *end;
357 const struct samplicator_context *ctx;
358 struct sockaddr_storage *addrp;
359 struct sockaddr_storage *maskp;
360 socklen_t *addrlenp;
361 {
362 const char *c, *slash = 0;
363
364 c = start;
365 while (c < end && *c != '/')
366 ++c;
367 if (c < end)
368 slash = c;
369
370 if (parse_addr (start, slash == 0 ? end : slash, ctx, addrp, addrlenp) == -1)
371 return -1;
372
373 if (slash != 0)
374 {
375 if (parse_mask (slash+1, end, ctx, maskp, addrp) == -1)
376 return -1;
377 }
378 else
379 set_default_mask (ctx, maskp, addrp);
380 return 0;
381 }
382
383 /*
384 parse_line (ctx, start, end)
385
386 Parse a single line of configuration file.
387
388 */
389 static int
parse_line(ctx,start,end)390 parse_line (ctx, start, end)
391 struct samplicator_context *ctx;
392 char *start;
393 const char *end;
394 {
395 struct source_context *sctx;
396 int argc;
397 const char *argv[MAX_PEERS];
398 const char *c, *e;
399 const char *lhs_start, *lhs_end;
400 const char *rhs_start;
401
402 /* move end before the start of any comment at the end of the line,
403 and before any whitepace preceding such a comment or EOL. */
404 for (c = start; c < end && *c != '#'; ++c) ;
405 if (c < end)
406 end = c;
407 while (end > start && isspace (*(end-1)))
408 --end;
409 if (start == end)
410 return 0; /* empty line; skip. */
411
412 /* non-empty lines should look like this:
413
414 ipadd[/mask]: dest[:port[/freq][,ttl]] dest2[:port2[/freq2][,ttl2]]...
415
416 The problematic case is where the ipadd is an IPv6 address,
417 because IPv6 addresses usually contain colons. We insist on the
418 convention that IPv6 addresses be enclosed in brackets. In
419 addition, for IPv6 we only accept prefix lengths, not arbitrary
420 netmasks.
421
422 [2001:db0:0:1::]/64: [2001:db0:0:2::3]:8000 [2001:db0:0:2::4]:8000
423 */
424
425 c = start;
426 while (c < end && isspace (*c))
427 ++c;
428 lhs_start = c;
429 if (*c == '[') {
430 while (c < end && *c != ']')
431 ++c;
432 while (c < end && *c != ':')
433 ++c;
434 } else {
435 c = start;
436 while (c < end && *c != ':')
437 ++c;
438 }
439 /* Now c either points at the colon that separates the left-hand
440 address/mask from the right hand destinations, or c is equal to
441 end because such a colon was not found. */
442
443 if (c < end)
444 {
445 lhs_end = c;
446 ++c; /* skip colon */
447 while (c < end && isspace (*c))
448 ++c;
449 rhs_start = c;
450 sctx = calloc (1, sizeof (struct source_context));
451
452 if (parse_addr_mask (lhs_start, lhs_end, ctx,
453 &sctx->source, &sctx->mask, &sctx->addrlen) != 0)
454 return -1;
455
456 argc = 0;
457 while (c < end)
458 {
459 while (c < end && isspace (*c))
460 c++;
461 if (c >= end) break;
462 e = c;
463 while((*e != 0) && !isspace ((int) *e))
464 e++;
465 argv[argc++] = copy_string_start_end (c, e);
466 c = e;
467 if (c < end)
468 c++;
469 }
470 if (argc > 0)
471 {
472 if (parse_receivers (argc, argv, ctx, sctx) == -1)
473 {
474 return -1;
475 }
476 }
477 }
478 else
479 {
480 return parse_error (ctx, "Missing colon");
481 }
482 return 0;
483 }
484
485 static int
parse_receiver(struct receiver * receiverp,const char * arg,struct samplicator_context * ctx)486 parse_receiver (struct receiver *receiverp,
487 const char *arg,
488 struct samplicator_context *ctx)
489 {
490 const char *start, *end;
491 const char *host_start, *host_end;
492 char portspec[NI_MAXSERV];
493 struct addrinfo hints, *res;
494 int result;
495
496 receiverp->flags = ctx->default_receiver_flags;
497 receiverp->freqcount = 0;
498 receiverp->freq = 1;
499 receiverp->ttl = DEFAULT_TTL;
500
501 start = arg; end = start + strlen (arg);
502 while (start < end && isspace (*start))
503 ++start;
504 while (start < end && isspace (*(end-1)))
505 --end;
506
507 if (start < end && *start == '[')
508 {
509 host_end = host_start = start+1;
510 while (host_end < end && *host_end != ']')
511 ++host_end;
512 if (host_end == end)
513 {
514 return parse_error (ctx, "Missing closing bracket");
515 }
516 start = host_end+1;
517 }
518 else
519 {
520 host_end = host_start = start;
521 while (host_end < end && *host_end != PORT_SEPARATOR)
522 ++host_end;
523 start = host_end;
524 }
525
526 /* extract the port part */
527 if (*start == PORT_SEPARATOR)
528 {
529 const char *port_start, *port_end;
530
531 ++start;
532 port_end = port_start = start;
533 while (port_end < end && *port_end != FREQ_SEPARATOR)
534 ++port_end;
535 if (port_end < end)
536 {
537 const char *freq_start, *freq_end;
538 freq_end = freq_start = port_end + 1;
539
540 /* extract the frequency part */
541 while (freq_end < end && *freq_end != TTL_SEPARATOR)
542 ++freq_end;
543
544 if (freq_start < freq_end)
545 {
546 int freq;
547 char *freq_parse_end;
548
549 freq = strtol (freq_start, &freq_parse_end, 10);
550 if (freq_parse_end == freq_start
551 || freq_parse_end != freq_end
552 || freq < 1)
553 {
554 return parse_error (ctx, "Illegal frequency .*s",
555 freq_end-freq_start, freq_start);
556 }
557 else
558 {
559 receiverp->freq = freq;
560 }
561 }
562 if (freq_end < end)
563 {
564 int ttl;
565 const char *ttl_start = freq_end + 1;
566 const char *ttl_end = end;
567 char *ttl_parse_end;
568
569 ttl = strtol (ttl_start, &ttl_parse_end, 10);
570 if (ttl_parse_end == ttl_start
571 || ttl_parse_end != ttl_end
572 || ttl < 1 || ttl > 255)
573 {
574 return parse_error (ctx, "Illegal TTL");
575 }
576 else
577 {
578 receiverp->ttl = ttl;
579 }
580 }
581 }
582 if (port_end - port_start >= NI_MAXSERV)
583 {
584 return parse_error (ctx, "Service name/port number (%.*s) too long",
585 port_end-port_start, port_start);
586 }
587 strncpy (portspec, port_start, port_end-port_start);
588 portspec[port_end-port_start] = 0;
589 }
590 else
591 strcpy (portspec, FLOWPORT);
592
593 init_hints_from_preferences (&hints, ctx);
594 {
595 char *tmp_buf = copy_string_start_end (host_start, host_end);
596 if (tmp_buf == 0)
597 {
598 return parse_error (ctx, "Out of memory");
599 }
600 result = getaddrinfo (tmp_buf, portspec, &hints, &res);
601 if (result != 0)
602 {
603 return parse_error (ctx, "Parsing IP address (%s with port spec %s) failed: %s",
604 tmp_buf, portspec, gai_strerror (result));
605 }
606 memcpy (&receiverp->addr, res->ai_addr, res->ai_addrlen);
607 receiverp->addrlen = res->ai_addrlen;
608 return 0;
609 }
610 }
611
612 int
parse_receivers(argc,argv,ctx,sctx)613 parse_receivers (argc, argv, ctx, sctx)
614 int argc;
615 const char **argv;
616 struct samplicator_context *ctx;
617 struct source_context *sctx;
618 {
619 int i;
620
621 /* allocate for argc receiver entries */
622 sctx->nreceivers = argc;
623
624 if (!(sctx->receivers = (struct receiver*) calloc (sctx->nreceivers, sizeof (struct receiver)))) {
625 return parse_error (ctx, "Out of memory");
626 }
627
628 /* fill in receiver entries */
629 for (i = 0; i < argc; ++i)
630 {
631 if (parse_receiver (&sctx->receivers[i], argv[i], ctx) != 0)
632 {
633 return -1;
634 }
635 }
636 if (ctx->sources == NULL)
637 {
638 ctx->sources = sctx;
639 }
640 else
641 {
642 struct source_context *ptr;
643 for (ptr = ctx->sources; ptr->next != NULL; ptr = ptr->next);
644 ptr->next = sctx;
645 }
646 return 0;
647 }
648
649 int
parse_args(argc,argv,ctx)650 parse_args (argc, argv, ctx)
651 int argc;
652 const char **argv;
653 struct samplicator_context *ctx;
654 {
655 extern char *optarg;
656 extern int errno, optind;
657 int i;
658 struct source_context *sctx = calloc (1, sizeof (struct source_context));
659
660 if (sctx == 0)
661 {
662 fprintf (stderr, "Out of memory\n");
663 return -1;
664 }
665
666 ctx->config_file_name = "<command line>";
667 ctx->config_file_lineno = 1;
668 sctx->nreceivers = 0;
669 ctx->sources = sctx;
670
671 sctx->next = (struct source_context *) NULL;
672
673 ctx->sockbuflen = DEFAULT_SOCKBUFLEN;
674 ctx->faddr_spec = 0;
675 bzero (&ctx->faddr, sizeof ctx->faddr);
676 ctx->fport_spec = FLOWPORT;
677 ctx->debug = 0;
678 ctx->ipv4_only = 0;
679 ctx->ipv6_only = 0;
680 ctx->fork = 0;
681 ctx->pid_file = (const char *) 0;
682 ctx->sources = 0;
683 ctx->default_receiver_flags = pf_CHECKSUM;
684 /* assume that command-line supplied receivers want to get all data */
685 sctx->source.ss_family = AF_INET;
686 ((struct sockaddr_in *) &sctx->source)->sin_addr.s_addr = 0;
687 ((struct sockaddr_in *) &sctx->mask)->sin_addr.s_addr = 0;
688
689 sctx->tx_delay = 0;
690
691 optind = 1;
692 while ((i = getopt (argc, (char **) argv, "hb:d:m:p:s:x:c:fSn46")) != -1)
693 {
694 switch (i)
695 {
696 case 'b': /* buflen */
697 ctx->sockbuflen = atol (optarg);
698 break;
699 case 'd': /* debug */
700 ctx->debug = atoi (optarg);
701 break;
702 case 'n': /* no UDP checksums */
703 ctx->default_receiver_flags &= ~pf_CHECKSUM;
704 break;
705 case 'p': /* flow port */
706 ctx->fport_spec = optarg;
707 break;
708 case 'm': /* make PID file */
709 ctx->pid_file = optarg;
710 break;
711 case 's': /* flow address */
712 ctx->faddr_spec = optarg;
713 break;
714 case 'x': /* transmit delay */
715 sctx->tx_delay = atoi (optarg);
716 break;
717 case 'S': /* spoof */
718 ctx->default_receiver_flags |= pf_SPOOF;
719 break;
720 case 'c': /* config file */
721 if (read_cf_file (optarg, ctx) != 0)
722 {
723 return -1;
724 }
725 break;
726 case 'f': /* fork */
727 ctx->fork = 1;
728 break;
729 case 'h': /* help */
730 usage (argv[0]);
731 exit (0);
732 break;
733 case '4':
734 ctx->ipv6_only = 0;
735 ctx->ipv4_only = 1;
736 break;
737 case '6':
738 ctx->ipv4_only = 0;
739 ctx->ipv6_only = 1;
740 break;
741 default:
742 short_usage (argv[0]);
743 return -1;
744 }
745 }
746
747 if (argc - optind > 0)
748 {
749 if (parse_receivers (argc - optind, argv + optind, ctx, sctx) == -1)
750 {
751 short_usage (argv[0]);
752 return -1;
753 }
754 }
755 return 0;
756 }
757
short_usage(progname)758 void short_usage (progname)
759 const char *progname;
760 {
761 fprintf (stderr, "Run \"%s -h\" for usage information.\n", progname);
762 }
763
764 static void
usage(progname)765 usage (progname)
766 const char *progname;
767 {
768 fprintf (stderr, "Usage: %s [option...] receiver...\n\
769 \n\
770 Supported options:\n\
771 \n\
772 -p <port> UDP port to accept flows on (default %s)\n\
773 -s <address> Interface address to accept flows on (default any)\n\
774 -d <level> debug level\n\
775 -b <size> set socket buffer size (default %lu)\n\
776 -n don't compute UDP checksum (leave at 0)\n\
777 -S maintain (spoof) source addresses\n\
778 -x <delay> transmit delay in microseconds\n\
779 -c <configfile> specify a config file to read\n\
780 -f fork program into background\n\
781 -m <pidfile> write process ID to file\n\
782 -4 IPv4 only\n\
783 -6 IPv6 only\n\
784 -h print this usage message and exit\n\
785 \n\
786 Specifying receivers:\n\
787 \n\
788 A.B.C.D[%cport[%cfreq][%cttl]]...\n\
789 where:\n\
790 A.B.C.D is the receiver's IP address\n\
791 port is the UDP port to send to (default %s)\n\
792 freq is the sampling rate (default 1)\n\
793 ttl is the outgoing packets' TTL value (default %d)\n\
794 \n\
795 Config file format:\n\
796 \n\
797 a.b.c.d[/e.f.g.h]: receiver ...\n\
798 where:\n\
799 a.b.c.d is the senders IP address\n\
800 e.f.g.h is a mask to apply to the sender (default 255.255.255.255)\n\
801 receiver see above.\n\
802 \n\
803 Receivers specified on the command line will get all packets, those\n\
804 specified in the config-file will get only packets with a matching source.\n\n\
805 ",
806 progname,
807 FLOWPORT, (unsigned long) DEFAULT_SOCKBUFLEN,
808 PORT_SEPARATOR, FREQ_SEPARATOR, TTL_SEPARATOR,
809 FLOWPORT,
810 DEFAULT_TTL);
811 }
812