#include "config.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <sys/socket.h>
#include <netinet/in.h>
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
#endif
#include <stdio.h>
#include <string.h>
#include <errno.h>
#if STDC_HEADERS
# define bzero(b,n) memset(b,0,n)
#else
# include <strings.h>
# ifndef HAVE_STRCHR
# define strchr index
# endif
# ifndef HAVE_MEMCPY
# define memcpy(d, s, n) bcopy ((s), (d), (n))
# define memmove(d, s, n) bcopy ((s), (d), (n))
# endif
#endif
#ifdef HAVE_CTYPE_H
# include <ctype.h>
#endif
#ifndef HAVE_INET_ATON
extern int inet_aton (const char *, struct in_addr *);
#endif
#include "rawsend.h"
/* the maximum size of "PDUs" that we can process.
We now use the maximum payload size of a UDP datagram. This is 65527
bytes - 65535, which is the maximum value of the UDP header's length
field, minus 8, which is the size of the UDP header. */
#define PDU_SIZE 65527
#define FLOWPORT 2000
#define DEFAULT_SOCKBUFLEN 65536
#define PORT_SEPARATOR '/'
#define FREQ_SEPARATOR '/'
#define TTL_SEPARATOR ','
#define MAX_PEERS 100
#define MAX_LINELEN 1000
enum peer_flags
{
pf_SPOOF = 0x0001,
pf_CHECKSUM = 0x0002,
};
struct peer {
int fd;
struct sockaddr_in addr;
int port;
int freq;
int freqcount;
int ttl;
enum peer_flags flags;
};
struct samplicator_context {
struct source_context *sources;
struct in_addr faddr;
int fport;
int sockbuflen;
int debug;
int fork;
enum peer_flags defaultflags;
unsigned default_tx_delay;
int fsockfd;
};
struct source_context {
struct source_context *next;
struct in_addr source;
struct in_addr mask;
struct peer * peers;
unsigned npeers;
unsigned tx_delay;
int debug;
};
static void usage(const char *);
static void announce_version (void);
static int send_pdu_to_peer (struct peer *, const void *, size_t,
struct sockaddr_in *);
static void parse_args (int, char **, struct samplicator_context *, struct source_context *);
static int parse_peers (int, char **, struct samplicator_context *, struct source_context *);
static int init_samplicator (struct samplicator_context *);
static int samplicate (struct samplicator_context *);
static int make_cooked_udp_socket (int);
static void read_cf_file (const char *, struct samplicator_context *);
/* Work around a GCC compatibility problem with respect to the
inet_ntoa() system function */
#undef inet_ntoa
#define inet_ntoa(x) my_inet_ntoa(&(x))
static const char *
my_inet_ntoa (const struct in_addr *in)
{
unsigned a = ntohl (in->s_addr);
static char buffer[16];
sprintf (buffer, "%d.%d.%d.%d",
(a >> 24) & 0xff,
(a >> 16) & 0xff,
(a >> 8) & 0xff,
a & 0xff);
return buffer;
}
int main(argc, argv)
int argc;
char **argv;
{
struct samplicator_context ctx;
struct source_context cmd_line;
cmd_line.source.s_addr = 0;
cmd_line.mask.s_addr = 0;
cmd_line.npeers = 0;
ctx.sources = &cmd_line;
cmd_line.next = (struct source_context *) NULL;
parse_args (argc, argv, &ctx, &cmd_line);
if (init_samplicator (&ctx) == -1)
exit (1);
if (samplicate (&ctx) != 0) /* actually, samplicate() should never return. */
exit (1);
exit (0);
}
static void
parse_args (argc, argv, ctx, sctx)
int argc;
char **argv;
struct samplicator_context *ctx;
struct source_context *sctx;
{
extern char *optarg;
extern int errno, optind;
int i;
ctx->sockbuflen = DEFAULT_SOCKBUFLEN;
ctx->faddr.s_addr = htonl (INADDR_ANY);
ctx->fport = FLOWPORT;
ctx->debug = 0;
ctx->fork = 0;
ctx->sources = NULL;
ctx->defaultflags = pf_CHECKSUM;
/* assume that command-line supplied peers want to get all data */
sctx->source.s_addr = 0;
sctx->mask.s_addr = 0;
ctx->default_tx_delay = sctx->tx_delay = 0;
while ((i = getopt (argc, argv, "hVb:d:p:s:x:c:fSn")) != -1)
{
switch (i)
{
case 'b': /* buflen */
ctx->sockbuflen = atoi (optarg);
break;
case 'd': /* debug */
ctx->debug = atoi (optarg);
break;
case 'n': /* no UDP checksums */
ctx->defaultflags &= ~pf_CHECKSUM;
break;
case 'p': /* flow port */
ctx->fport = atoi (optarg);
if (ctx->fport < 0
|| ctx->fport > 65535)
{
fprintf (stderr,
"Illegal receive port %d - \
should be between 0 and 65535\n",
ctx->fport);
usage (argv[0]);
exit (1);
}
break;
case 's': /* flow address */
if (inet_aton (optarg, &ctx->faddr) == 0)
{
fprintf (stderr, "parsing IP address (%s) failed\n", optarg);
usage (argv[0]);
exit (1);
}
break;
case 'x': /* transmit delay */
ctx->default_tx_delay = sctx->tx_delay = atoi (optarg);
break;
case 'S': /* spoof */
ctx->defaultflags |= pf_SPOOF;
break;
case 'c': /* config file */
read_cf_file(optarg,ctx);
break;
case 'f': /* fork */
ctx->fork = 1;
break;
case 'h': /* help */
usage (argv[0]);
exit (0);
break;
case 'V': /* version */
announce_version ();
exit (0);
break;
default:
usage (argv[0]);
exit (1);
break;
}
}
if (argc - optind > 0)
{
if (parse_peers (argc - optind, argv + optind, ctx, sctx) == -1)
{
usage (argv[0]);
exit (1);
}
}
}
static int
parse_peers (argc, argv, ctx, sctx)
int argc;
char **argv;
struct samplicator_context *ctx;
struct source_context *sctx;
{
int i;
char tmp_buf[256];
static int cooked_sock = -1;
static int raw_sock = -1;
char *c;
struct source_context *ptr;
/* allocate for argc peer entries */
sctx->npeers = argc;
if (!(sctx->peers = (struct peer*) malloc (sctx->npeers * sizeof (struct peer)))) {
fprintf(stderr, "malloc(): failed.\n");
return -1;
}
/* zero out malloc'd memory */
bzero(sctx->peers, sctx->npeers*sizeof (struct peer));
/* fill in peer entries */
for (i = 0; i < argc; ++i)
{
sctx->peers[i].flags = ctx->defaultflags;
if (strlen (argv[i]) > 255)
{
fprintf (stderr, "ouch!\n");
return -1;
}
strcpy (tmp_buf, argv[i]);
/* skip to end or port seperator */
for (c = tmp_buf; (*c != PORT_SEPARATOR) && (*c); ++c);
/* extract the port part */
if (*c == PORT_SEPARATOR)
{
int port;
*c = 0;
++c;
port = atoi(c);
if (port < 0 || port > 65535)
{
fprintf (stderr, "Illegal destination port %d - \
should be between 0 and 65535\n", port);
return -1;
}
sctx->peers[i].addr.sin_port = htons (port);
}
else
sctx->peers[i].addr.sin_port = htons (FLOWPORT);
/* extract the frequency part */
sctx->peers[i].freqcount = 0;
sctx->peers[i].freq = 1;
for (; (*c != FREQ_SEPARATOR) && (*c); ++c)
if (*c == TTL_SEPARATOR) goto TTL;
if (*c == FREQ_SEPARATOR)
{
*c = 0;
++c;
sctx->peers[i].freq = atoi(c);
}
/* printf("Frequency: %d\n", sctx->peers[i].freq); */
/* extract the TTL part */
for (; (*c != TTL_SEPARATOR) && (*c); ++c);
TTL:
if ((*c == TTL_SEPARATOR) && (*(c+1) > 0))
{
*c = 0;
++c;
sctx->peers[i].ttl = atoi (c);
if (sctx->peers[i].ttl < 1
|| sctx->peers[i].ttl > 255)
{
fprintf (stderr,
"Illegal value %d for TTL - should be between 1 and 255.\n",
sctx->peers[i].ttl);
return -1;
}
}
else
sctx->peers[i].ttl = DEFAULT_TTL;
/* extract the ip address part */
if (inet_aton (tmp_buf, & sctx->peers[i].addr.sin_addr) == 0)
{
fprintf (stderr, "parsing IP address (%s) failed\n", tmp_buf);
return -1;
}
sctx->peers[i].addr.sin_family = AF_INET;
if (sctx->peers[i].flags & pf_SPOOF)
{
if (raw_sock == -1)
{
if ((raw_sock = make_raw_udp_socket (ctx->sockbuflen)) < 0)
{
if (errno == EPERM)
{
fprintf (stderr, "Not enough privilege for -S option---try again