Flowgrind
Advanced TCP traffic generator
flowgrindd.c File Reference

Flowgrind daemon. More...

#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <signal.h>
#include <syslog.h>
#include <string.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <fcntl.h>
#include <netdb.h>
#include <sys/stat.h>
#include <xmlrpc-c/base.h>
#include <xmlrpc-c/server.h>
#include <xmlrpc-c/server_abyss.h>
#include <xmlrpc-c/util.h>
#include "common.h"
#include "daemon.h"
#include "fg_log.h"
#include "fg_affinity.h"
#include "fg_error.h"
#include "fg_math.h"
#include "fg_progname.h"
#include "fg_string.h"
#include "fg_time.h"
#include "fg_definitions.h"
#include "debug.h"
#include "fg_argparser.h"
#include "fg_rpc_server.h"
#include "fg_pcap.h"

Go to the source code of this file.

Macros

#define daemon   fake_daemon_function
 Temporarily renaming daemon() so compiler does not see the warning on OS X. More...
 
#define PARSE_ERR(err_msg, ...)
 Print error message, usage string and exit. More...
 

Functions

void bind_daemon_to_core (void)
 
void create_daemon_thread ()
 
int daemon (int, int)
 Remap daemon() function. More...
 
int main (int argc, char *argv[])
 
static void parse_cmdline (int argc, char *argv[])
 Parse command line options to initialize global options. More...
 
int process_dump_dir ()
 
static void sanity_check (void)
 
static void sighandler (int sig)
 Signal handler to catching signals. More...
 
static void tear_down_daemon (void)
 Gracefully tear down daemon. More...
 
static void usage (short status)
 Print usage or error message and exit. More...
 

Variables

static int core
 CPU core to which flowgrindd should bind to. More...
 
static struct arg_parser parser
 Command line option parser. More...
 
static unsigned port = DEFAULT_LISTEN_PORT
 
const char * progname
 String containing name the program is called with. More...
 
static char * rpc_bind_addr = NULL
 

Detailed Description

Flowgrind daemon.

Definition in file flowgrindd.c.

Macro Definition Documentation

◆ daemon

#define daemon   fake_daemon_function

Temporarily renaming daemon() so compiler does not see the warning on OS X.

Definition at line 36 of file flowgrindd.c.

◆ PARSE_ERR

#define PARSE_ERR (   err_msg,
  ... 
)
Value:
do { \
errx(err_msg, ##__VA_ARGS__); \
usage(EXIT_FAILURE); \
} while (0)

Print error message, usage string and exit.

Used for cmdline parsing errors.

Definition at line 86 of file flowgrindd.c.

Function Documentation

◆ bind_daemon_to_core()

void bind_daemon_to_core ( void  )

Definition at line 202 of file flowgrindd.c.

203 {
204  pthread_t thread = pthread_self();
205  int rc = pthread_setaffinity(thread, core);
206 
207  if (rc)
208  logging(LOG_WARNING, "failed to bind %s (PID %d) to CPU core %i",
209  progname, getpid(), core);
210  else
211  DEBUG_MSG(LOG_INFO, "bind %s (PID %d) to CPU core %i",
212  progname, getpid(), core);
213 }

◆ create_daemon_thread()

void create_daemon_thread ( )

Definition at line 184 of file flowgrindd.c.

185 {
186  int flags;
187 
188  if (pipe(daemon_pipe) == -1)
189  crit("could not create pipe");
190 
191  if ((flags = fcntl(daemon_pipe[0], F_GETFL, 0)) == -1)
192  flags = 0;
193  fcntl(daemon_pipe[0], F_SETFL, flags | O_NONBLOCK);
194 
195  pthread_mutex_init(&mutex, NULL);
196 
197  int rc = pthread_create(&daemon_thread, NULL, daemon_main, 0);
198  if (rc)
199  critc(rc, "could not start thread");
200 }

◆ daemon()

int daemon ( int  ,
int   
)

Remap daemon() function.

◆ main()

int main ( int  argc,
char *  argv[] 
)

Definition at line 365 of file flowgrindd.c.

366 {
367  /* Info about the xmlrpc server */
368  struct fg_rpc_server server;
369 
370  /* Initialize sighandler */
371  struct sigaction sa;
372  sa.sa_handler = sighandler;
373  sa.sa_flags = 0;
374  sigemptyset (&sa.sa_mask);
375  if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
376  crit("could not ignore SIGPIPE");
377  if (sigaction (SIGHUP, &sa, NULL))
378  critx("could not set handler for SIGUP");
379  if (sigaction (SIGALRM, &sa, NULL))
380  critx("could not set handler for SIGALRM");
381  if (sigaction (SIGCHLD, &sa, NULL))
382  critx("could not set handler for SIGCHLD");
383  if (sigaction(SIGINT, &sa, NULL))
384  critx("could not set handler for SIGINT");
385  if (sigaction(SIGTERM, &sa, NULL))
386  critx("could not set handler for SIGTERM");
387 
388  set_progname(argv[0]);
389  parse_cmdline(argc, argv);
390  sanity_check();
391 
392  /* Initialize logging */
393  if (!ap_is_used(&parser, 'd'))
395  else
397 
399 
400 #ifdef HAVE_LIBPCAP
401  fg_pcap_init();
402 #endif /* HAVE_LIBPCAP */
403 
405 
406  /* Push flowgrindd into the background */
407  if (!ap_is_used(&parser, 'd')) {
408  /* Need to call daemon() before creating the thread because
409  * it internally calls fork() which does not copy threads. */
410  if (daemon(0, 0) == -1)
411  crit("daemon() failed");
412  logging(LOG_NOTICE, "flowgrindd daemonized");
413  }
414 
415  if (ap_is_used(&parser, 'c'))
417 
419 
420  /* This will block */
421  run_rpc_server(&server);
422  critx("control should never reach end of main()");
423 }

◆ parse_cmdline()

static void parse_cmdline ( int  argc,
char *  argv[] 
)
static

Parse command line options to initialize global options.

Parameters
[in]argcnumber of command line arguments
[in]argvarguments provided by the command line

Definition at line 254 of file flowgrindd.c.

255 {
256  const struct ap_Option options[] = {
257  {'b', 0, ap_yes, 0, 0},
258  {'c', 0, ap_yes, 0, 0},
259 #ifdef DEBUG
260  {'d', "debug", ap_no, 0, 0},
261 #else /* DEBUG */
262  {'d', 0, ap_no, 0, 0},
263 #endif
264  {'h', "help", ap_no, 0, 0},
265  {'o', 0, ap_yes, 0, 0},
266  {'p', 0, ap_yes, 0, 0},
267  {'v', "version", ap_no, 0, 0},
268 #ifdef HAVE_LIBPCAP
269  {'w', 0, ap_yes, 0, 0},
270 #endif /* HAVE_LIBPCAP */
271  {0, 0, ap_no, 0, 0}
272  };
273 
274  if (!ap_init(&parser, argc, (const char* const*) argv, options, 0))
275  critx("could not allocate memory for option parser");
276  if (ap_error(&parser))
277  PARSE_ERR("%s", ap_error(&parser));
278 
279  /* parse command line */
280  for (int argind = 0; argind < ap_arguments(&parser); argind++) {
281  const int code = ap_code(&parser, argind);
282  const char *arg = ap_argument(&parser, argind);
283 
284  switch (code) {
285  case 0:
286  PARSE_ERR("invalid argument: %s", arg);
287  case 'b':
288  rpc_bind_addr = strdup(arg);
289  if (sscanf(arg, "%s", rpc_bind_addr) != 1)
290  PARSE_ERR("failed to parse bind address");
291  break;
292  case 'c':
293  if (sscanf(arg, "%u", &core) != 1)
294  PARSE_ERR("failed to parse CPU number");
295  break;
296  case 'd':
297 #ifdef DEBUG
299 #endif /* DEBUG */
300  break;
301  case 'h':
302  usage(EXIT_SUCCESS);
303  break;
304  case 'p':
305  if (sscanf(arg, "%u", &port) != 1)
306  PARSE_ERR("failed to parse port number");
307  break;
308 #ifdef HAVE_LIBPCAP
309  case 'w':
310  dump_dir = strdup(arg);
311  break;
312 #endif /* HAVE_LIBPCAP */
313  case 'v':
314  fprintf(stdout, "%s %s\%s\n%s\n\n%s\n", progname,
317  exit(EXIT_SUCCESS);
318  break;
319  default:
320  PARSE_ERR("uncaught option: %s", arg);
321  break;
322  }
323  }
324 
325 #ifdef HAVE_LIBPCAP
326  if (!process_dump_dir()) {
327  if (ap_is_used(&parser, 'w'))
328  PARSE_ERR("the dump directory %s for tcpdumps does "
329  "either not exist or you have insufficient "
330  "permissions to write to it", dump_dir);
331  else
332  warnx("tcpdumping will not be available since you "
333  "don't have sufficient permissions to write to "
334  "%s", dump_dir);
335  }
336 #endif /* HAVE_LIBPCAP */
337 }

◆ process_dump_dir()

int process_dump_dir ( )

Definition at line 216 of file flowgrindd.c.

216  {
217  if (!dump_dir)
218  dump_dir = getcwd(NULL, 0);
219 
220  struct stat dirstats;
221 
222  if (stat(dump_dir, &dirstats) == -1) {
223  DEBUG_MSG(LOG_WARNING, "unable to stat %s: %s", dump_dir,
224  strerror(errno));
225  return 0;
226  }
227 
228  if (!S_ISDIR(dirstats.st_mode)) {
229  DEBUG_MSG(LOG_ERR, "provided path %s is not a directory",
230  dump_dir);
231  return 0;
232  }
233 
234  if (access(dump_dir, W_OK | X_OK) == -1) {
235  DEBUG_MSG(LOG_ERR, "insufficent permissions to access %s: %s",
236  dump_dir, strerror(errno));
237  return 0;
238  }
239 
240  /* ensure path contains terminating slash */
241  if (dump_dir[strlen(dump_dir) - 1] != '/')
242  asprintf_append(&dump_dir, "/");
243 
244  return 1;
245 }

◆ sanity_check()

static void sanity_check ( void  )
static
Todo:
more sanity checks... (e.g. if port is in valid range)

Definition at line 339 of file flowgrindd.c.

340 {
341  if (core < 0) {
342  errx("CPU binding failed. Given CPU ID is negative");
343  exit(EXIT_FAILURE);
344  }
345 
346  if (core > get_ncores(NCORE_CURRENT)) {
347  errx("CPU binding failed. Given CPU ID is higher then "
348  "available CPU cores");
349  exit(EXIT_FAILURE);
350  }
351 
352  /* TODO more sanity checks... (e.g. if port is in valid range) */
353 }

◆ sighandler()

static void sighandler ( int  sig)
static

Signal handler to catching signals.

Parameters
[in]sigsignal to catch

Definition at line 154 of file flowgrindd.c.

155 {
156  int status;
157 
158  switch (sig) {
159  case SIGCHLD:
160  while (waitpid(-1, &status, WNOHANG) > 0)
161  logging(LOG_NOTICE, "child returned (status = %d)",
162  status);
163  break;
164  case SIGHUP:
165  logging(LOG_NOTICE, "caught SIGHUP. don't know what to do.");
166  break;
167  case SIGALRM:
168  logging(LOG_NOTICE, "caught SIGALRM, don't know what to do.");
169  break;
170  case SIGPIPE:
171  break;
172  case SIGINT:
173  case SIGTERM:
174  logging(LOG_NOTICE, "caught SIGINT/SIGTERM, tear down daemon");
176  break;
177  default:
178  logging(LOG_ALERT, "caught signal %d, but don't remember "
179  "intercepting it, aborting...", sig);
180  abort();
181  }
182 }

◆ tear_down_daemon()

static void tear_down_daemon ( void  )
static

Gracefully tear down daemon.

Definition at line 358 of file flowgrindd.c.

359 {
360  ap_free(&parser);
361  close_logging();
362  exit(EXIT_SUCCESS);
363 }

◆ usage()

static void usage ( short  status)
static

Print usage or error message and exit.

Depending on exit status status print either the usage or an error message. In all cases it call exit() with the given exit status status.

Parameters
[in]statusexit status

Definition at line 118 of file flowgrindd.c.

119 {
120  /* Syntax error. Emit 'try help' to stderr and exit */
121  if (status != EXIT_SUCCESS) {
122  fprintf(stderr, "Try '%s -h' for more information\n", progname);
123  exit(status);
124  }
125 
126  fprintf(stdout,
127  "Usage: %1$s [OPTION]...\n"
128  "Advanced TCP traffic generator for Linux, FreeBSD, and Mac OS X.\n\n"
129 
130  "Mandatory arguments to long options are mandatory for short options too.\n"
131  " -b ADDR XML-RPC server bind address\n"
132  " -c # bound daemon to specific CPU. First CPU is 0\n"
133 #ifdef DEBUG
134  " -d, --debug increase debugging verbosity. Add option multiple times to\n"
135  " increase the verbosity (no daemon, log to stderr)\n"
136 #else /* DEBUG */
137  " -d don't fork into background, log to stderr\n"
138 #endif /* DEBUG */
139  " -h, --help display this help and exit\n"
140  " -p # XML-RPC server port\n"
141 #ifdef HAVE_LIBPCAP
142  " -w DIR target directory for dump files. The daemon must be run as root\n"
143 #endif /* HAVE_LIBPCAP */
144  " -v, --version print version information and exit\n",
145  progname);
146  exit(EXIT_SUCCESS);
147 }

Variable Documentation

◆ core

int core
static

CPU core to which flowgrindd should bind to.

Definition at line 101 of file flowgrindd.c.

◆ parser

struct arg_parser parser
static

Command line option parser.

Definition at line 104 of file flowgrindd.c.

◆ port

unsigned port = DEFAULT_LISTEN_PORT
static

Definition at line 95 of file flowgrindd.c.

◆ progname

const char* progname

String containing name the program is called with.

Definition at line 35 of file fg_progname.c.

◆ rpc_bind_addr

char* rpc_bind_addr = NULL
static

Definition at line 98 of file flowgrindd.c.

DEBUG_MSG
#define DEBUG_MSG(LVL, MSG,...)
Print debug message to standard error.
Definition: debug.h:49
sanity_check
static void sanity_check(void)
Definition: flowgrindd.c:339
fg_pcap_init
int fg_pcap_init(void)
Initialize flowgrind's pcap library.
Definition: fg_pcap.c:84
daemon
#define daemon
Temporarily renaming daemon() so compiler does not see the warning on OS X.
Definition: flowgrindd.c:36
daemon_main
void * daemon_main(void *ptr __attribute__((unused)))
Definition: daemon.c:800
ap_code
int ap_code(const struct arg_parser *const ap, const int i)
Returns the code of a parsed option with given index.
Definition: fg_argparser.c:468
tear_down_daemon
static void tear_down_daemon(void)
Gracefully tear down daemon.
Definition: flowgrindd.c:358
ap_argument
const char * ap_argument(const struct arg_parser *const ap, const int i)
Returns the argument of a parsed option.
Definition: fg_argparser.c:478
ap_error
const char * ap_error(const struct arg_parser *const ap)
Get the string containing errors encountered during parsing.
Definition: fg_argparser.c:458
init_rpc_server
void init_rpc_server(struct fg_rpc_server *server, char *rpc_bind_addr, unsigned port)
Initializes the xmlrpc server.
Definition: fg_rpc_server.c:835
crit
#define crit(...)
To report an critical error w/ the corresponding system error message.
Definition: fg_error.h:36
FLOWGRIND_COPYRIGHT
#define FLOWGRIND_COPYRIGHT
Flowgrind's copyright year.
Definition: common.h:82
NCORE_CURRENT
@ NCORE_CURRENT
Processors available to the current process.
Definition: fg_affinity.h:40
port
static unsigned port
Definition: flowgrindd.c:95
LOGGING_STDERR
@ LOGGING_STDERR
Log to stderr.
Definition: fg_log.h:41
logging
void logging(int priority, const char *fmt,...)
Definition: fg_log.c:69
ap_no
@ ap_no
Option without argument (flag).
Definition: fg_argparser.h:37
warnx
#define warnx(...)
To report a warning w/ a system error message.
Definition: fg_error.h:54
sighandler
static void sighandler(int sig)
Signal handler to catching signals.
Definition: flowgrindd.c:154
fg_rpc_server
Information about the daemons XMLrpc server.
Definition: fg_rpc_server.h:49
rpc_bind_addr
static char * rpc_bind_addr
Definition: flowgrindd.c:98
ap_yes
@ ap_yes
Argument required.
Definition: fg_argparser.h:39
run_rpc_server
void run_rpc_server(struct fg_rpc_server *server)
Enters the xmlrpc server mainloop.
Definition: fg_rpc_server.c:878
get_ncores
int get_ncores(enum ncore_query query)
Return either the total number of configured or available cores.
Definition: fg_affinity.c:56
ap_Option::code
int code
Short option letter or code (code != 0).
Definition: fg_argparser.h:47
ap_is_used
bool ap_is_used(const struct arg_parser *const ap, int code)
Returns true if the option specified by code was given at least once.
Definition: fg_argparser.c:503
mutex
pthread_mutex_t mutex
Definition: daemon.c:93
increase_debuglevel
void increase_debuglevel()
Decrease debug level.
Definition: debug.c:50
errx
#define errx(...)
To report an error w/o a system error message.
Definition: fg_error.h:47
ap_free
void ap_free(struct arg_parser *const ap)
Free internal state of arg-parser.
Definition: fg_argparser.c:448
critc
#define critc(code,...)
To report an critical error w/ the system error message 'code'.
Definition: fg_error.h:38
FLOWGRIND_COPYING
#define FLOWGRIND_COPYING
Standard GPL3 no warranty message.
Definition: common.h:85
critx
#define critx(...)
To report an critical error w/o a system error message.
Definition: fg_error.h:40
FLOWGRIND_AUTHORS
#define FLOWGRIND_AUTHORS
Flowgrind's authors in a printable string.
Definition: common.h:91
parse_cmdline
static void parse_cmdline(int argc, char *argv[])
Parse command line options to initialize global options.
Definition: flowgrindd.c:254
ap_arguments
int ap_arguments(const struct arg_parser *const ap)
Number of arguments parsed (may be different from argc).
Definition: fg_argparser.c:463
usage
static void usage(short status) __attribute__((noreturn))
Print usage or error message and exit.
Definition: flowgrindd.c:118
core
static int core
CPU core to which flowgrindd should bind to.
Definition: flowgrindd.c:101
dump_dir
char * dump_dir
Definition: daemon.c:91
ap_Option
Defines a valid command line option.
Definition: fg_argparser.h:45
HAVE_LIBPCAP
#define HAVE_LIBPCAP
Definition: config.h:53
FLOWGRIND_VERSION
#define FLOWGRIND_VERSION
Flowgrind version number.
Definition: common.h:44
bind_daemon_to_core
void bind_daemon_to_core(void)
Definition: flowgrindd.c:202
daemon_pipe
int daemon_pipe[2]
Definition: daemon.c:87
parser
static struct arg_parser parser
Command line option parser.
Definition: flowgrindd.c:104
set_progname
void set_progname(const char *argv0)
Set global variable 'progname', based on argv[0].
Definition: fg_progname.c:37
close_logging
void close_logging(void)
Close logging stream.
Definition: fg_log.c:57
daemon_thread
pthread_t daemon_thread
Definition: daemon.c:89
process_dump_dir
int process_dump_dir()
Definition: flowgrindd.c:216
asprintf_append
int asprintf_append(char **strp, const char *fmt,...)
Definition: fg_string.c:98
PARSE_ERR
#define PARSE_ERR(err_msg,...)
Print error message, usage string and exit.
Definition: flowgrindd.c:86
pthread_setaffinity
int pthread_setaffinity(pthread_t thread, unsigned core)
Set CPU affinity of the thread thread to the core core.
Definition: fg_affinity.c:75
progname
const char * progname
String containing name the program is called with.
Definition: fg_progname.c:35
flows
struct linked_list flows
Definition: daemon.c:103
create_daemon_thread
void create_daemon_thread()
Definition: flowgrindd.c:184
ap_init
bool ap_init(struct arg_parser *const ap, const int argc, const char *const argv[], const struct ap_Option options[], const char in_order)
Initialize the arg-parser given command line and user-defined options.
Definition: fg_argparser.c:374
fg_list_init
int fg_list_init(struct linked_list *const list)
Initializes the list by setting its head and tail to NULL and its size to 0.
Definition: fg_list.c:34
init_logging
void init_logging(enum log_streams stream)
Open logging stream.
Definition: fg_log.c:43
LOGGING_SYSLOG
@ LOGGING_SYSLOG
Log to syslog.
Definition: fg_log.h:39