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