Exemplo n.º 1
0
/** 
 * \fn int radix_trie_unit_test()
 * \params none
 * \return 0 on success
 * \return 1 on failure
 */
int radix_trie_unit_test () {
    struct radix_trie rt, rt2;
    enum status err;
    struct in_addr a[10];
    unsigned int af[10];
    unsigned int i;
    unsigned int test_failed = 0;
    unsigned int flag;
    zfile output;

    output = zattach(stdout, "w");
    if (output == NULL) {
        fprintf(stderr, "%s: error: could not initialize (possibly compressed) stdout for writing\n",
                __FUNCTION__);
    }
  
    for (i=0; i<32; i++) {
        flag = index_to_flag(i);
        printf("index: %u\tflag: %x\tindex: %u\n", i, flag, flag_to_index(flag));
    }

    err = radix_trie_init(&rt);
    if (err != ok) {
       fprintf(stderr, "%s: error: could not initialize radix_trie\n", __FUNCTION__);
    }
  
    a[0].s_addr = htonl(0xcafebabe); af[0] = 1;
    a[1].s_addr = htonl(0xcafedada); af[1] = 2;
    a[2].s_addr = htonl(0xbaddecaf); af[2] = 4;
    a[3].s_addr = htonl(0x01234567); af[3] = 8;
    a[4].s_addr = htonl(0xffeeddcc); af[4] = 16;
    a[5].s_addr = htonl(0x0a9b8c7d); af[5] = 32;
    a[6].s_addr = htonl(0xfedcba98); af[6] = 64;
    a[7].s_addr = htonl(0x76543210); af[7] = 128;
    a[8].s_addr = htonl(0xa1b2c3d4); af[8] = 256;

    printf("testing add\n");
    flag = 1;
    for (i=0; i<3; i++) {
        if (radix_trie_add_subnet(&rt, a[i], 32, af[i]) != ok) {
            zprintf(output, "error: could not add subnet %s\n", inet_ntoa(a[i]));
            test_failed = 1;
        }
    }

    for (i=6; i<9; i++) {
        if (radix_trie_add_subnet(&rt, a[i], 16, af[i]) != ok) {
            zprintf(output, "error: could not add subnet %s\n", inet_ntoa(a[i]));
            test_failed = 1;
        }
    }

    printf("testing lookup (expecting success)\n");
    for (i=0; i<3; i++) {
        if (radix_trie_lookup_addr(&rt, a[i]) != af[i]) {
            zprintf(output, "error: could not lookup subnet %s\n", inet_ntoa(a[i]));
            test_failed = 1;
        }
    }

    for (i=6; i<9; i++) {
        if (radix_trie_lookup_addr(&rt, a[i]) != af[i]) {
            zprintf(output, "error: could not lookup subnet %s\n", inet_ntoa(a[i]));
            test_failed = 1;
        }
    }

    printf("testing lookup (expecting failure)\n");
    for (i=3; i<6; i++) {
        if (radix_trie_lookup_addr(&rt, a[i]) != 0) {
            zprintf(output, "error: false positive lookup subnet %s\n", inet_ntoa(a[i]));
            test_failed = 1;
        }
    }

    printf("testing 14-bit add\n");
    for (i=0; i<3; i++) {
        if (radix_trie_add_subnet(&rt, a[i], 14, 0x100) != ok) {
            zprintf(output, "error: could not add subnet %s\n", inet_ntoa(a[i]));
            test_failed = 1;
        }
    }

    printf("testing 14-bit lookup (expecting success)\n");
    for (i=0; i<3; i++) {
        unsigned int f = radix_trie_lookup_addr(&rt, a[i]);
        if (f != (af[i] | 0x100)) {
            zprintf(output, "error: could not lookup address %s (%x), got %x instead\n", 
	           inet_ntoa(a[i]), htonl(a[i].s_addr), f);
            test_failed = 1;
        }
    }

    printf("testing 15-bit add\n");
    for (i=0; i<3; i++) {
        if (radix_trie_add_subnet(&rt, a[i], 15, 0x1000) != ok) {
            zprintf(output, "error: could not add subnet %s\n", inet_ntoa(a[i]));
            test_failed = 1;
        }
    }

    printf("testing 15-bit lookup (expecting success)\n");
    for (i=0; i<3; i++) {
        unsigned int f = radix_trie_lookup_addr(&rt, a[i]);
        if (f != (af[i] | 0x1000 | 0x100)) {
            zprintf(output, "error: could not lookup address %s (%x), got %x but expected %x\n", 
	           inet_ntoa(a[i]), htonl(a[i].s_addr), f, (af[i] | 0x1000 | 0x100));
            test_failed = 1;
        }
    }

    printf("testing lookup (expecting failure)\n");
    for (i=3; i<6; i++) {
        if (radix_trie_lookup_addr(&rt, a[i]) != 0) {
            zprintf(output, "error: false positive lookup address %s\n", inet_ntoa(a[i]));
            test_failed = 1;
        }
    }

    if (test_failed) {
        printf("FAILURE; at least one test failed\n");
    } else {
        printf("all tests passed\n");
    }
  
    printf("-----------------------------------\n");
    radix_trie_print(&rt);

    printf("testing high level interface\n");
    err = radix_trie_init(&rt2);
    if (err != ok) {
        fprintf(stderr, "error: could not initialize radix_trie\n");
    }

    attr_flags internal_attr, c2_attr, watchlist_attr, attr;
    struct in_addr addr;

    internal_attr = radix_trie_add_attr_label(&rt2, "internal");
    printf("attr: %x\n", internal_attr);
    c2_attr = radix_trie_add_attr_label(&rt2, "c2");
    watchlist_attr = radix_trie_add_attr_label(&rt2, "watchlist");

    addr = hex2addr(0xcafe0000);
    if (radix_trie_add_subnet(&rt2, addr, 16, internal_attr) != ok) { 
        zprintf(output, "error: could not add subnet %s\n", inet_ntoa(addr));
        test_failed = 1;
    }
    attr = radix_trie_lookup_addr(&rt2, addr); 
    if ((attr & internal_attr) == 0) {
        zprintf(output, "error: attribute lookup failed (expected %x, got %x)\n",
	       internal_attr, attr);
        test_failed = 1;
    }

    addr = hex2addr(0xdecaf000);
    if (radix_trie_add_subnet(&rt2, addr, 20, internal_attr) != ok) {
        zprintf(output, "error: could not add subnet %s\n", inet_ntoa(addr));
        test_failed = 1;
    }
    attr = radix_trie_lookup_addr(&rt2, addr); 
    if ((attr & internal_attr) == 0) {
        zprintf(output, "error: attribute lookup failed (expected %x, got %x)\n",
	       internal_attr, attr);
        test_failed = 1;
    }

    addr = hex2addr(0xdadacafe);
    if (radix_trie_add_subnet(&rt2, addr, 32, c2_attr) != ok) {
        zprintf(output, "error: could not add subnet %s\n", inet_ntoa(addr));
        test_failed = 1;
    }
    attr = radix_trie_lookup_addr(&rt2, addr); 
    if ((attr & c2_attr) == 0) {
        zprintf(output, "error: attribute lookup failed (expected %x, got %x)\n",
	       c2_attr, attr);
        test_failed = 1;
    }

    addr = hex2addr(0xdadacafe);
    if (radix_trie_add_subnet(&rt2, addr, 8, watchlist_attr) != ok) {
        zprintf(output, "error: could not add subnet %s\n", inet_ntoa(addr));
        test_failed = 1;
    }
    attr = radix_trie_lookup_addr(&rt2, addr); 
    if ((attr & watchlist_attr) == 0) {
        zprintf(output, "error: attribute lookup failed (expected %x, got %x)\n",
	       watchlist_attr, attr);
        test_failed = 1;
    }
 
    addr = hex2addr(0xffffffff);
    if (radix_trie_add_subnet(&rt2, addr, 1, watchlist_attr) != ok) {
        zprintf(output, "error: could not add subnet %s\n", inet_ntoa(addr));
        test_failed = 1;
    }
    attr = radix_trie_lookup_addr(&rt2, addr); 
    if ((attr & watchlist_attr) == 0) {
        zprintf(output, "error: attribute lookup failed (expected %x, got %x)\n",
	       c2_attr, attr);
        test_failed = 1;
    }
   
    if (test_failed) {
        printf("FAILURE; at least one test failed\n");
    } else {
        printf("all high level interface tests passed\n");
    }

    printf("-----------------------------------\n");
    radix_trie_print(&rt2);

    printf("-----------------------------------\n");

    if (radix_trie_high_level_unit_test() != ok) {
        test_failed = 1;
    }

    return test_failed; /* 0 on success, 1 otherwise */
}
Exemplo n.º 2
0
int main(int argc, char **argv) {
  char errbuf[PCAP_ERRBUF_SIZE]; 
  bpf_u_int32 net = PCAP_NETMASK_UNKNOWN;		
  char *filter_exp = "ip";	
  struct bpf_program fp;	
  int i;
  int c;
  int opt_count = 0;
  int tmp_ret;
  char *ifile = NULL;
  unsigned int file_count = 0;
  char filename[MAX_FILENAME_LEN];   /* output file */
  char pcap_filename[MAX_FILENAME_LEN*2];   /* output file */
  char *cli_interface = NULL; 
  char *cli_filename = NULL; 
  char *config_file = NULL;
  struct interface ifl[IFL_MAX];
  int num_interfaces;
  char *capture_if;
  unsigned int file_base_len = 0;
  unsigned int num_cmds = 0;
  unsigned int done_with_options = 0;
  struct stat sb;
  DIR *dir;
  struct dirent *ent;
  enum operating_mode mode = mode_none;

  /* sanity check sizeof() expectations */
  if (data_sanity_check() != ok) {
    fprintf(stderr, "error: failed data size sanity check\n");
  }

  /* sanity check arguments */
  for (i=1; i<argc; i++) {
    if (strchr(argv[i], '=')) { 
      if (done_with_options) {
	fprintf(stderr, "error: option (%s) found after filename (%s)\n", argv[i], argv[i-1]);
	exit(EXIT_FAILURE);
      }
    } else {
      done_with_options = 1;
    }
  }
  
  /*
   * set "info" to stderr; this output stream is used for
   * debug/info/warnings/errors.  setting it here is actually
   * defensive coding, just in case some function that writes to
   * "info" gets invoked before info gets set below (if we are in
   * online mode, it will be set to a log file)
   */
  info = stderr;

  /* in debug mode, turn off output buffering */
#if P2F_DEBUG
  setvbuf(stderr, NULL, _IONBF, 0); 
  setbuf(stdout, NULL);
#endif

  /*
   * set configuration from command line arguments that contain
   * LHS=RHS commands, then update argv/argc so that those arguments
   * are not subjected to any further processing
   */
  num_cmds = config_set_from_argv(&config, argv, argc);
  argv += num_cmds;
  argc -= num_cmds;

  /* process command line options */
  while (1) {
    int option_index = 0;
    struct option long_options[] = {
      {"help",  no_argument,         0, 'h' },
      {"xconfig", required_argument, 0, 'x' },
      {0,         0,                 0,  0  }
    };

    c = getopt_long(argc, argv, "hx:",
		    long_options, &option_index);
    if (c == -1)
      break;
    switch (c) {
    case 'x':
      config_file = optarg;
      opt_count++;
      break;
    case 'h':
    default:
      return usage(argv[0]);
    }
    opt_count++;
  }

  if (config_file) {
    /*
     * read in configuration from file; note that if we don't read in
     * a file, then the config structure will use the static defaults
     * set when it was declared
     */
    config_set_from_file(&config, config_file);
  } 
  if (config_file || (num_cmds != 0)) {
    /*
     * set global variables as needed, if we got some configuration
     * commands from the config_file or from command line arguments
     */
    bidir = config.bidir;
    include_zeroes = config.include_zeroes;
    byte_distribution = config.byte_distribution;
    report_entropy = config.report_entropy;
    report_wht = config.report_wht;
    report_hd = config.report_hd;
    include_tls = config.include_tls;
    include_classifier = config.include_classifier;
    output_level = config.output_level;
    report_idp = config.idp;
    report_dns = config.dns;
    salt_algo = config.type;
    nfv9_capture_port = config.nfv9_capture_port;
    if (config.bpf_filter_exp) {
      filter_exp = config.bpf_filter_exp;
    }
  }
  
  /*
   * allow some command line variables to override the config file
   */
  if (cli_filename) {
    /*
     * output filename provided on command line supersedes that
     * provided in the config file
     */
    config.filename = cli_filename;
  } 
  if (cli_interface) {
    /*
     * interface provided on command line supersedes that provided
     * in the config file
     */
    config.interface = cli_interface;
  }
  if (config.filename) {
    strncpy(filename, config.filename, MAX_FILENAME_LEN);
  }

  /*
   * set the operating mode to online or offline 
   */
  if (config.interface != NULL && strcmp(config.interface, NULL_KEYWORD)) {
    mode = mode_online;
  } else {
    mode = mode_offline;
  }
    
  /*
   * if we are doing a live capture, get interface list, and set "info"
   * output stream to log file
   */
  if (mode == mode_online) {

    if (config.logfile && strcmp(config.logfile, NULL_KEYWORD)) {
      info = fopen(config.logfile, "a");
      if (info == NULL) {
	fprintf(stderr, "error: could not open log file %s\n", config.logfile);
	return -1;
      }
      fprintf(stderr, "writing errors/warnings/info/debug output to %s\n", config.logfile);
    }
    
    /*
     * cheerful message to indicate the start of a new run of the
     * daemon
     */
    fprintf(info, "--- %s initialization ---\n", argv[0]);
    flocap_stats_output(info);

    num_interfaces = interface_list_get(ifl);
    if (num_interfaces == 0) {
      fprintf(info, "warning: could not obtain inferface information\n");    
    } else {
      for(i=0; i<num_interfaces; i++) {
	unsigned char *a = ifl[i].mac_addr;
	fprintf(info, "interface: %8s\tstatus: %s\t%02x%02x%02x%02x%02x%02x\n", 
		ifl[i].name, (ifl[i].active ? "up" : "down"), 
		a[0], a[1], a[2], a[3], a[4], a[5]); 
      }
    }    
  } else {
    info = stderr;
  }

  /*
   * report on running configuration (which may depend on the command
   * line, the config file, or both)
   */
  config_print(info, &config);

  /*
   * configure labeled subnets (which uses a radix trie to identify
   * addresses that match subnets associated with labels)
   */  
  if (config.num_subnets > 0) {
    attr_flags subnet_flag;
    enum status err;

    rt = radix_trie_alloc();
    if (rt == NULL) {
      fprintf(info, "could not allocate memory\n");
    }
    err = radix_trie_init(rt);
    if (err != ok) {
      fprintf(stderr, "error: could not initialize subnet labels (radix_trie)\n");
    }
    for (i=0; i<config.num_subnets; i++) {
      char label[LINEMAX], subnet_file[LINEMAX];
      int num;
      
      num = sscanf(config.subnet[i], "%[^=:]:%[^=:\n#]", label, subnet_file);
      if (num != 2) {
	fprintf(info, "error: could not parse command \"%s\" into form label:subnet\n", config.subnet[i]);
	exit(1);
      }
      
      subnet_flag = radix_trie_add_attr_label(rt, label);
      if (subnet_flag == 0) {
	fprintf(info, "error: count not add subnet label %s to radix_trie\n", label);
	exit(1);
      }
      
      err = radix_trie_add_subnets_from_file(rt, subnet_file, subnet_flag, info);
      if (err != ok) {
	fprintf(info, "error: could not add labeled subnets from file %s\n", subnet_file);
	exit(1);
      }
    }
    fprintf(info, "configured labeled subnets (radix_trie), using %u bytes of memory\n", get_rt_mem_usage());
    
  }

  if (config.anon_addrs_file != NULL) {
    if (anon_init(config.anon_addrs_file, info) == failure) {
      fprintf(info, "error: could not initialize anonymization subnets from file %s\n", 
	      config.anon_addrs_file); 
      return -1;
    }
  }

  if (config.filename != NULL) {
    char *outputdir;
    
    /*
     * set output directory 
     */
    if (config.outputdir) {
      outputdir = config.outputdir;
    } else {
      outputdir = ".";
    }

    /*
     * generate an "auto" output file name, based on the MAC address
     * and the current time, if we are "auto" configured
     */
    if (strncmp(config.filename, "auto", strlen("auto")) == 0) {

      if (mode == mode_online) {
	unsigned char *addr = ifl[0].mac_addr;
	time_t now = time(0);   
	struct tm *t = localtime(&now);
	
	snprintf(filename,  MAX_FILENAME_LEN, "%s/flocap-%02x%02x%02x%02x%02x%02x-h%d-m%d-s%d-D%d-M%d-Y%d-%s-", 
		 outputdir, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], 
		 t->tm_hour, t->tm_min, t->tm_sec, t->tm_mday, t->tm_mon, t->tm_year + 1900, t->tm_zone);
      } else {
	fprintf(info, "error: cannot use \"output = auto\" with no interface specified; use -o or -l options\n");
	return usage(argv[0]);
      }
      fprintf(info, "auto generated output filename: %s\n", filename);
      
    } else {    
      /* set output file based on command line or config file */
      
      if (cli_filename) {
	strncpy(filename, config.filename, MAX_FILENAME_LEN);
      } else {
	char tmp_filename[MAX_FILENAME_LEN];
	
	strncpy(tmp_filename, filename, MAX_FILENAME_LEN);
	snprintf(filename,  MAX_FILENAME_LEN, "%s/%s", outputdir, tmp_filename);
      }
    }
    file_base_len = strlen(filename);
    if (config.max_records != 0) {
      snprintf(filename + file_base_len, MAX_FILENAME_LEN - file_base_len, "%d", file_count);
    }
    output = fopen(filename, "w");
    if (output == NULL) {
      fprintf(info, "error: could not open output file %s (%s)\n", filename, strerror(errno));
      return -1;
    }
  } else {
    output = stdout;
  }
  
  if (ifile != NULL) {
    opt_count--;
    argv[1+opt_count] = ifile; 
  }

  if (mode == mode_online) {   /* live capture */
    int linktype;

    /*
     * sanity check: we can't be in both offline mode and online mode
     * simultaneously
     */
    if ((argc-opt_count > 1) || (ifile != NULL)) {
      fprintf(info, "error: both interface (%s) and pcap input file (%s) specified\n",
	      config.interface, argv[1+opt_count]);
      return usage(argv[0]);
    }

    anon_print_subnets(info);
    
    signal(SIGINT, sig_close);     /* Ctl-C causes graceful shutdown */
    signal(SIGTERM, sig_close);
    // signal(SIGHUP, sig_reload);
    // signal(SIGTSTP, sig_reload);
    signal(SIGQUIT, sig_reload);   /* Ctl-\ causes an info dump      */

    /*
     * set capture interface as needed
     */
    if (strncmp(config.interface, "auto", strlen("auto")) == 0) {
      capture_if = ifl[0].name;
      fprintf(info, "starting capture on interface %s\n", ifl[0].name);
    } else {
      capture_if = config.interface;
    }

    errbuf[0] = 0;
    handle = pcap_open_live(capture_if, 65535, config.promisc, 10000, errbuf);
    if (handle == NULL) {
      fprintf(info, "could not open device %s: %s\n", capture_if, errbuf);
      return -1;
    }
    if (errbuf[0] != 0) {
      fprintf(stderr, "warning: %s\n", errbuf);
    }

    /* verify that we can handle the link layer headers */
    linktype = pcap_datalink(handle);
    if (linktype != DLT_EN10MB) {
      fprintf(info, "device %s has unsupported linktype (%d)\n", 
	      capture_if, linktype);
      return -2;
    }
    
    if (filter_exp) {

      /* compile the filter expression */
      if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
	fprintf(info, "error: could not parse filter %s: %s\n",
		filter_exp, pcap_geterr(handle));
	return -3;
      }
      
      /* apply the compiled filter */
      if (pcap_setfilter(handle, &fp) == -1) {
	fprintf(info, "error: could not install filter %s: %s\n",
		filter_exp, pcap_geterr(handle));
	return -4;
      }

    }

    /*
     * run as daemon, if so configured, without closing stderr and
     * stdout, and without changing the working directory
     */
    if (config.daemon) {
      daemon(1, 1);  
    }
    
    /*
     * flush "info" output stream to ensure log file accuracy
     */
    fflush(info);

    /* 
     * write out JSON preamble
     */ 
    fprintf(output, "{\n");
    config_print_json(output, &config);
    fprintf(output, "\"appflows\": [\n");

    while(1) {
      struct timeval time_of_day, inactive_flow_cutoff;

      /* loop over packets captured from interface */
      pcap_loop(handle, NUM_PACKETS_IN_LOOP, process_packet, NULL);
      
      if (output_level > none) { 
	fprintf(output, "# pcap processing loop done\n");
      }

      if (config.report_exe) {
	/*
	 * periodically obtain host/process flow data
	 */ 
	if (get_host_flow_data() != 0) {
	  fprintf(info, "warning: could not obtain host/process flow data\n");
	}
      }

      /*
       * periodically report on progress
       */
      if ((flocap_stats_get_num_packets() % NUM_PACKETS_BETWEEN_STATS_OUTPUT) == 0) {
	flocap_stats_output(info);
      }

      /* print out inactive flows */
      gettimeofday(&time_of_day, NULL);
      timer_sub(&time_of_day, &time_window, &inactive_flow_cutoff);

      flow_record_list_print_json(&inactive_flow_cutoff);

      if (config.filename) {
	
	/* rotate output file if needed */
	if (config.max_records && (records_in_file > config.max_records)) {

	  /*
	   * write JSON postamble
	   */
	  fprintf(output, "\n] }\n");

	  fclose(output);
	  if (config.upload_servername) {
	    upload_file(filename, config.upload_servername, config.upload_key, config.retain_local);
	  }

	  // printf("records: %d\tmax_records: %d\n", records_in_file, config.max_records);
	  file_count++;
	  if (config.max_records != 0) {
	    snprintf(filename + file_base_len, MAX_FILENAME_LEN - file_base_len, "%d", file_count);
	  }
	  output = fopen(filename, "w");
	  if (output == NULL) {
	    perror("error: could not open output file");
	    return -1;
	  }
	  records_in_file = 0;
	  fprintf(output, "{ \"appflows\": [\n");
	}
      
	/*
	 * flush out buffered debug/info/log messages on the "info" stream
	 */
	fflush(info);
      }

      // fflush(output);
    }

    fprintf(output, "\n] }\n");
    
    if (filter_exp) {
      pcap_freecode(&fp);
    }

    pcap_close(handle);
 

  } else { /* mode = mode_offline */

    if ((argc-opt_count <= 1) && (ifile == NULL)) {
      fprintf(stderr, "error: missing pcap file name(s)\n");
      return usage(argv[0]);
    }

    fprintf(output, "{\n");
    config_print_json(output, &config);
    fprintf(output, "\"appflows\": [\n");

    flow_record_list_init();
    flocap_stats_timer_init();

    for (i=1+opt_count; i<argc; i++) {
    
      if (stat(argv[i], &sb) == 0 && S_ISDIR(sb.st_mode)) {
	if ((dir = opendir(argv[i])) != NULL) {

	  while ((ent = readdir(dir)) != NULL) {
	    if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, "..")) {
	      strcpy(pcap_filename, argv[i]);
	      if (pcap_filename[strlen(pcap_filename)-1] != '/') {
		strcat(pcap_filename, "/");
	      }
	      strcat(pcap_filename, ent->d_name);
	      tmp_ret = process_pcap_file(pcap_filename, filter_exp, &net, &fp);
	      if (tmp_ret < 0) {
		return tmp_ret;
	      }
	    }
	  }

	  closedir(dir);
	} else {
	  /* error opening directory*/
	  printf("Error opening directory: %s\n", argv[i]);
	  return -1;
	}

      } else {
	tmp_ret = process_pcap_file(argv[i], filter_exp, &net, &fp);
	if (tmp_ret < 0) {
	  return tmp_ret;
	}
      }
    }
    
    fprintf(output, "\n]");
    fprintf(output, "\n}\n");
    
  }

  flocap_stats_output(info);
  // config_print(info, &config);

  return 0;
}
Exemplo n.º 3
0
/*
 * Function to initiate the radix_trie unit tests
 * returns 0 on success
 * returns 1 on failure
 */
static int radix_trie_high_level_unit_test () {
    struct radix_trie rt;
    attr_flags flag_internal, flag_malware, flag;
    char *configfile = "internal.net";
    struct in_addr addr;
    enum status err;
    unsigned test_failed = 0;
    zfile output;

    output = zattach(stdout, "w");
    if (output == NULL) {
        fprintf(stderr, "%s: error: could not initialize (possibly compressed) stdout for writing\n",
               __FUNCTION__);
    }

    /* initialize */
    err = radix_trie_init(&rt);
    if (err != ok) {
       fprintf(stderr, "%s: error: could not initialize radix_trie\n", __FUNCTION__);
    }

    /* create a label */
    flag_internal = radix_trie_add_attr_label(&rt, "internal");
    if (flag_internal == 0) {
        fprintf(stderr, "%s: error: count not add label\n", __FUNCTION__);
        test_failed = 1;
        return failure;
    }
    flag_malware = radix_trie_add_attr_label(&rt, "malware");
    if (flag_internal == 0) {
        fprintf(stderr, "%s: error: count not add label\n", __FUNCTION__);
        test_failed = 1;
        return failure;
    }

    /* add subnets from file */
    err = radix_trie_add_subnets_from_file(&rt, configfile, flag_internal, stderr);
    if (err != ok) {
        fprintf(stderr, "%s: error: could not add subnets to radix_trie from file %s\n",
                __FUNCTION__, configfile);
        test_failed = 1;
    }  
    printf("++++++++++++\n");
    err = radix_trie_add_subnets_from_file(&rt, configfile, flag_malware, stderr);
    if (err != ok) {
        fprintf(stderr, "%s: error: could not add subnets to radix_trie from file %s\n",
                __FUNCTION__, configfile);
        test_failed = 1;
    }
  
    /* verify addresses and labels */
    addr.s_addr = htonl(0xc0a80101);   /* 192.168.1.1 */
    flag = radix_trie_lookup_addr(&rt, addr); 
    if ((flag & flag_internal) == 0) {
        zprintf(output, "error: attribute lookup failed (expected %x, got %x)\n",
	       flag_internal, flag);
        test_failed = 1;
    }
    attr_flags_json_print_labels(&rt, flag, "addr", output);
  
    addr.s_addr = htonl(0x08080808);   /* not internal */
    flag = radix_trie_lookup_addr(&rt, addr); 
    if ((flag & flag_internal) == 1) {
        zprintf(output, "error: attribute lookup failed (did not expect %x, but got %x)\n",
	       flag_internal, flag);
        test_failed = 1;
    }
    attr_flags_json_print_labels(&rt, flag, "addr", output);

    printf("\n==================\n");
    radix_trie_print(&rt);
  
    if (test_failed) {
        printf("FAILURE; at least one test failed\n");
    } else {
        printf("all tests passed\n");
    }
  
    return test_failed; /* 0 on success, 1 otherwise */
}