/* This file is part of Netsukuku * (c) Copyright 2005 Andrea Lo Pumo aka AlpT * * This source code is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2 of the License, * or (at your option) any later version. * * This source code is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * Please refer to the GNU Public License for more details. * * You should have received a copy of the GNU Public License along with * this source code; if not, write to: * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * -- * netsukuku.c: * Where main() resides. */ #include "includes.h" #include "common.h" #include "conf.h" #include "libnetlink.h" #include "ll_map.h" #include "request.h" #include "pkts.h" #include "if.h" #include "bmap.h" #include "netsukuku.h" #include "qspn.h" #include "accept.h" #include "daemon.h" #include "crypto.h" #include "andna_cache.h" #include "andna.h" #include "radar.h" #include "hook.h" #include "rehook.h" #include "ntk-console-server.h" #include extern int errno; extern char *optarg; extern int optind, opterr, optopt; int destroy_netsukuku_mutex; int pid_saved; int options_parsed = 0; /* How many times parse_options() has been called */ void save_pid(void) { FILE *fd; if (!(fd = fopen(server_opt.pid_file, "w"))) error("Couldn't create pid file \"%s\": %s", server_opt.pid_file, strerror(errno)); fprintf(fd, "ntkd %ld\n", (long) getpid()); fclose(fd); pid_saved = 1; } /* * is_ntkd_already_running * * Returns 1 if there's already a ntkd running */ int is_ntkd_already_running(void) { pid_t oldpid; FILE *fd; if (!(fd = fopen(server_opt.pid_file, "r"))) { if (errno != ENOENT) error("Cannot read pid file \"%s\": %s", server_opt.pid_file, strerror(errno)); return 0; } fscanf(fd, "ntkd %d\n", &oldpid); if (ferror(fd)) { error("error reading pid file \"%s\": %s\n", server_opt.pid_file, strerror(errno)); fclose(fd); return 0; } fclose(fd); return !kill(oldpid, 0); } int ntk_load_maps(void) { if (file_exist(server_opt.int_map_file) && (me.int_map = load_map(server_opt.int_map_file, &me.cur_node))) debug(DBG_NORMAL, "Internal map loaded"); else me.int_map = init_map(0); #if 0 /* Don't load the bnode map, it's useless */ if ((me.bnode_map = load_bmap(server_opt.bnode_map_file, me.ext_map, FAMILY_LVLS, &me.bmap_nodes))) { debug(DBG_NORMAL, "Bnode map loaded"); } else #endif bmap_levels_init(BMAP_LEVELS(FAMILY_LVLS), &me.bnode_map, &me.bmap_nodes); bmap_counter_init(BMAP_LEVELS(FAMILY_LVLS), &me.bmap_nodes_closed, &me.bmap_nodes_opened); if (file_exist(server_opt.ext_map_file) && (me.ext_map = load_extmap(server_opt.ext_map_file, &me.cur_quadg))) debug(DBG_NORMAL, "External map loaded"); else me.ext_map = init_extmap(FAMILY_LVLS, 0); return 0; } int ntk_save_maps(void) { debug(DBG_NORMAL, "Saving the internal map"); save_map(me.int_map, me.cur_node, server_opt.int_map_file); #ifdef DEBUG debug(DBG_NORMAL, "Saving the border nodes map"); save_bmap(me.bnode_map, me.bmap_nodes, me.ext_map, me.cur_quadg, server_opt.bnode_map_file); #endif debug(DBG_NORMAL, "Saving the external map"); save_extmap(me.ext_map, MAXGROUPNODE, &me.cur_quadg, server_opt.ext_map_file); return 0; } int ntk_free_maps(void) { bmap_levels_free(me.bnode_map, me.bmap_nodes); bmap_counter_free(me.bmap_nodes_closed, me.bmap_nodes_opened); free_extmap(me.ext_map, FAMILY_LVLS, 0); free_map(me.int_map, 0); return 0; } void usage(void) { printf("Usage:\n" " ntkd [-hvaldrRD46] [-i net_interface] [-c conf_file] [-l logfile]\n\n" " -4 ipv4\n" " -6 ipv6\n" " -i Specify the interface after this\n\n" " -a Prevents running the ANDNA daemon\n" " -R Prevents editting /etc/resolv.conf\n" " -D Prevents running as daemon (Does not fork to the background)\n" "\n" " -r Runs in restricted mode\n" " -I Share your internet connection with other nodes\n" "\n" " -c configuration file\n" " -l Enables logging to file\n" "\n" " -d Debug (Add more ds to get more info)\n" " -h Shows this help\n" " -v Shows the version you are using\n" " -k Kills the running instance of ntkd\n" " -C Runs the console server for Ntk-Console to connect to\n" " -e Excludes an interface from usage I.E all interfaces except this one\n"); } /* * fill_default_options: fills the default values in the server_opt struct */ void fill_default_options(void) { setzero(&server_opt, sizeof(server_opt)); server_opt.family = AF_INET; server_opt.config_file = NTK_CONFIG_FILE; server_opt.pid_file = NTK_PID_FILE; server_opt.int_map_file = INT_MAP_FILE; server_opt.ext_map_file = EXT_MAP_FILE; server_opt.bnode_map_file = BNODE_MAP_FILE; server_opt.andna_hnames_file = ANDNA_HNAMES_FILE; server_opt.snsd_nodes_file = SNSD_NODES_FILE; server_opt.andna_cache_file = ANDNA_CACHE_FILE; server_opt.lclkey_file = LCLKEY_FILE; server_opt.lcl_file = LCL_FILE; server_opt.rhc_file = RHC_FILE; server_opt.counter_c_file = COUNTER_C_FILE; server_opt.daemon = 1; server_opt.dbg_lvl = 0; server_opt.disable_andna = 0; server_opt.disable_resolvconf = 0; server_opt.restricted = 0; server_opt.restricted_class = 0; server_opt.use_shared_inet = 1; server_opt.ip_masq_script = IPMASQ_SCRIPT_FILE; server_opt.tc_shaper_script = TCSHAPER_SCRIPT_FILE; server_opt.max_connections = MAX_CONNECTIONS; server_opt.max_accepts_per_host = MAX_ACCEPTS; server_opt.max_accepts_per_host_time = FREE_ACCEPT_TIME; } /* * fill_loaded_cfg_options * * stores in server_opt the options loaded from the configuration file */ void fill_loaded_cfg_options(void) { char *value; CONF_GET_STRN_VALUE(CONF_NTK_INT_MAP_FILE, &server_opt.int_map_file, NAME_MAX - 1); CONF_GET_STRN_VALUE(CONF_NTK_BNODE_MAP_FILE, &server_opt.bnode_map_file, NAME_MAX - 1); CONF_GET_STRN_VALUE(CONF_NTK_EXT_MAP_FILE, &server_opt.ext_map_file, NAME_MAX - 1); CONF_GET_STRN_VALUE(CONF_ANDNA_HNAMES_FILE, &server_opt.andna_hnames_file, NAME_MAX - 1); CONF_GET_STRN_VALUE(CONF_SNSD_NODES_FILE, &server_opt.snsd_nodes_file, NAME_MAX - 1); CONF_GET_STRN_VALUE(CONF_ANDNA_CACHE_FILE, &server_opt.andna_cache_file, NAME_MAX - 1); CONF_GET_STRN_VALUE(CONF_ANDNA_LCLKEY_FILE, &server_opt.lclkey_file, NAME_MAX - 1); CONF_GET_STRN_VALUE(CONF_ANDNA_LCL_FILE, &server_opt.lcl_file, NAME_MAX - 1); CONF_GET_STRN_VALUE(CONF_ANDNA_RHC_FILE, &server_opt.rhc_file, NAME_MAX - 1); CONF_GET_STRN_VALUE(CONF_ANDNA_COUNTER_C_FILE, &server_opt.counter_c_file, NAME_MAX - 1); CONF_GET_STRN_VALUE(CONF_NTK_PID_FILE, &server_opt.pid_file, NAME_MAX - 1); CONF_GET_INT_VALUE(CONF_NTK_MAX_CONNECTIONS, server_opt.max_connections); CONF_GET_INT_VALUE(CONF_NTK_MAX_ACCEPTS_PER_HOST, server_opt.max_accepts_per_host); CONF_GET_INT_VALUE(CONF_NTK_MAX_ACCEPTS_PER_HOST_TIME, server_opt.max_accepts_per_host_time); CONF_GET_INT_VALUE(CONF_DISABLE_ANDNA, server_opt.disable_andna); CONF_GET_INT_VALUE(CONF_DISABLE_RESOLVCONF, server_opt.disable_resolvconf); CONF_GET_INT_VALUE(CONF_NTK_RESTRICTED_MODE, server_opt.restricted); CONF_GET_INT_VALUE(CONF_NTK_RESTRICTED_CLASS, server_opt.restricted_class); CONF_GET_INT_VALUE(CONF_NTK_INTERNET_CONNECTION, server_opt.inet_connection); if ((value = CONF_GET_VALUE(CONF_NTK_INTERNET_GW))) { if (str_to_inet_gw(value, &server_opt.inet_gw, &server_opt.inet_gw_dev)) fatal ("Malformed `%s' option: \"%s\". Its syntax is \"IP:dev\"", config_str[CONF_NTK_INTERNET_GW], value); } CONF_GET_INT_VALUE(CONF_NTK_INTERNET_UPLOAD, server_opt.my_upload_bw); CONF_GET_INT_VALUE(CONF_NTK_INTERNET_DOWNLOAD, server_opt.my_dnload_bw); if (server_opt.my_upload_bw && server_opt.my_dnload_bw) me.my_bandwidth = bandwidth_in_8bit((server_opt.my_upload_bw + server_opt.my_dnload_bw) / 2); if ((value = CONF_GET_VALUE(CONF_NTK_INTERNET_PING_HOSTS))) { server_opt.inet_hosts = parse_internet_hosts(value, &server_opt. inet_hosts_counter); if (!server_opt.inet_hosts) fatal("Malformed `%s' option: \"%s\". " "Its syntax is host1:host2:...", config_str[CONF_NTK_INTERNET_PING_HOSTS], value); } CONF_GET_INT_VALUE(CONF_SHARE_INTERNET, server_opt.share_internet); CONF_GET_INT_VALUE(CONF_SHAPE_INTERNET, server_opt.shape_internet); CONF_GET_INT_VALUE(CONF_USE_SHARED_INET, server_opt.use_shared_inet); CONF_GET_STRN_VALUE(CONF_NTK_IP_MASQ_SCRIPT, &server_opt.ip_masq_script, NAME_MAX - 1); CONF_GET_STRN_VALUE(CONF_NTK_TC_SHAPER_SCRIPT, &server_opt.tc_shaper_script, NAME_MAX - 1); /* Clean the enviroment */ clear_config_env(); } void free_server_opt(void) { int i; if (server_opt.config_file != NTK_CONFIG_FILE) xfree(server_opt.config_file); if (server_opt.pid_file != NTK_PID_FILE) xfree(server_opt.pid_file); if (server_opt.int_map_file != INT_MAP_FILE) xfree(server_opt.int_map_file); if (server_opt.ext_map_file != EXT_MAP_FILE) xfree(server_opt.ext_map_file); if (server_opt.bnode_map_file != BNODE_MAP_FILE) xfree(server_opt.bnode_map_file); if (server_opt.andna_hnames_file != ANDNA_HNAMES_FILE) xfree(server_opt.andna_hnames_file); if (server_opt.snsd_nodes_file != SNSD_NODES_FILE) xfree(server_opt.snsd_nodes_file); if (server_opt.andna_cache_file != ANDNA_CACHE_FILE) xfree(server_opt.andna_cache_file); if (server_opt.lclkey_file != LCLKEY_FILE) xfree(server_opt.lclkey_file); if (server_opt.lcl_file != LCL_FILE) xfree(server_opt.lcl_file); if (server_opt.rhc_file != RHC_FILE) xfree(server_opt.rhc_file); if (server_opt.counter_c_file != COUNTER_C_FILE) xfree(server_opt.counter_c_file); if (server_opt.ip_masq_script != IPMASQ_SCRIPT_FILE) xfree(server_opt.ip_masq_script); if (server_opt.tc_shaper_script != TCSHAPER_SCRIPT_FILE) xfree(server_opt.tc_shaper_script); if (server_opt.inet_gw_dev) xfree(server_opt.inet_gw_dev); for (i = 0; i < MAX_INTERFACES && server_opt.ifs[i]; i++) xfree(server_opt.ifs[i]); } /* Removes specified existing interface, Ntkd should populate the device list * prior to this. * returns 0 on success, And closes ntkd on error. */ int exclude_interface(void) { int i; printf("Number of Interfaces in Use: %d\n", me.cur_ifs_n); for (i = 0; i < me.cur_ifs_n; i++) printf("Interface names in Use: %s", me.cur_ifs[i].dev_name); for (i = 0; i < me.cur_ifs_n; i++) { if (strcmp(me.cur_ifs[i].dev_name, optarg) == 0) { printf("Interface %s removed, And replaced with %s", me.cur_ifs[i].dev_name, me.cur_ifs[me.cur_ifs_n].dev_name); ifs_del(me.cur_ifs, &me.cur_ifs_n, i); return 0; } else fatal("Interface %s not found!", optarg); } } void ntk_thread_creatation(void) { int x; pthread_t console_recv_send_thread; if (pthread_create (&console_recv_send_thread, NULL, &console_recv_send, &x)) { fprintf(stderr, "Error creating thread\n"); exit(-1); } } void parse_options(int argc, char **argv) { int c, saved_argc = argc; optind = 0; while (1) { int option_index = 0; static struct option long_options[] = { {"help", 0, 0, 'h'}, {"iface", 1, 0, 'i'}, {"ipv6", 0, 0, '6'}, {"ipv4", 0, 0, '4'}, {"conf", 1, 0, 'c'}, {"logfile", 1, 0, 'l'}, {"no_andna", 0, 0, 'a'}, {"no_daemon", 0, 0, 'D'}, {"no_resolv", 0, 0, 'R'}, {"restricted", 0, 0, 'r'}, {"share-inet", 0, 0, 'I'}, {"debug", 0, 0, 'd'}, {"version", 0, 0, 'v'}, {"kill", 0, 0, 'k'}, {"exclude", 1, 0, 'e'}, {"console", 0, 0, 'C'}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "i:c:l:e:hvd64DRrIakC", long_options, &option_index); if (c == -1) break; switch (c) { case 'C': ntk_thread_creatation(); break; case 'v': printf("%s\n", VERSION_STR); exit(0); break; case 'e': exclude_interface(); break; case 'k': if (is_ntkd_already_running() == 1) { char process_name[256] = { 0 }; pid_t pid; printf("...Closing ntkd...\n"); FILE *fd = fopen(server_opt.pid_file, "r"); while (fscanf(fd, "%s %d", process_name, &pid) != EOF) { if (strcmp(process_name, "ntkd") == 0) { kill(pid, SIGINT); } } fclose(fd); exit(0); } else if (is_ntkd_already_running() == 0) { printf("ntkd is not running\n ...Exiting...\n"); exit(0); } break; case 'h': usage(); exit(0); break; case '4': server_opt.family = AF_INET; break; case '6': #ifdef IPV6_DISABLED fatal("The ipv6 is still not supported"); #endif loginfo ("WARNING: The ipv6 support is still experimental and under " "development, nothing is assured to work."); server_opt.family = AF_INET6; break; case 'c': server_opt.config_file = xstrndup(optarg, NAME_MAX - 1); break; case 'l': if (log_to_file(optarg) < 0) fatal(0); break; case 'i': break; case 'D': server_opt.daemon = 0; break; case 'a': server_opt.disable_andna = 1; break; case 'R': server_opt.disable_resolvconf = 1; break; case 'r': server_opt.restricted = 1; /*** * This is a very dirty hack, but it handles * the optional argument better than getopt. * * This is the problem: * ntkd -abcrdefg * If 'r' is an element that specifies an * optional argument, then the "defg" string * is taken as its arg, but this is not what * we want because in this case '-r' is * specified without its argument. * * So, what we do is checking if the argv * next to the arg of 'r' begins with a '-' * or not. If not, it is the option of '-r' * * The only thing that won't work is: * ntkd -rOPTION * it has to be specified in this way: * ntkd -r OPTION */ if (argc > optind && argv[optind][0] != '-') { server_opt.restricted_class = atoi(argv[optind]); saved_argc--; } /**/ break; case 'I': server_opt.share_internet = 1; if (!server_opt.restricted) { loginfo("Share_internet=1. Assuming restricted=1"); server_opt.restricted = 1; } if (!server_opt.inet_connection) { loginfo("Share_internet=1. Assuming inet_connection=1"); server_opt.inet_connection = 1; } break; case 'd': server_opt.dbg_lvl++; break; default: usage(); exit(1); break; } } if (optind < saved_argc && !options_parsed) { usage(); exit(1); } options_parsed++; } void check_conflicting_options(void) { #define FATAL_NOT_SPECIFIED(str) fatal("You didn't specified the `%s' " \ "option in netsukuku.conf", \ (str)); \ if (!server_opt.pid_file) FATAL_NOT_SPECIFIED("pid_file"); if (!server_opt.inet_hosts && server_opt.restricted) FATAL_NOT_SPECIFIED("internet_ping_hosts"); if (server_opt.restricted && server_opt.share_internet && !file_exist(server_opt.ip_masq_script)) fatal("ip_masquerade_script \"%s\" is inexistent", server_opt.ip_masq_script); if (server_opt.shape_internet && !file_exist(server_opt.tc_shaper_script)) fatal("tc_shaper_script \"%s\" is inexistent", server_opt.ip_masq_script); if (!server_opt.restricted && server_opt.inet_connection) fatal("inet_connection=1 but ntk_restricted_mode=0. If you " "want to be compatible with the Internet, " "set the restricted mode in the options"); if (!server_opt.restricted && (server_opt.share_internet)) fatal("You want to share your Internet connection," "but I am not running in restricted mode (-r), " "'cause I'm not sure of what you want... " "I'm aborting."); if (server_opt.share_internet && me.my_bandwidth < MIN_CONN_BANDWIDTH) fatal("You want to share your Internet connection but " "your bandwidth is just TOO small. Do not share " "it, or your connection will be saturated"); if (!server_opt.inet_connection && server_opt.share_internet) { loginfo("You want to share your Internet connection," "but `internet_connection' is set to 0." "We are assuming it is 1"); server_opt.inet_connection = 1; } if (server_opt.shape_internet && !server_opt.inet_connection) fatal("The Internet traffic shaping option is set, but " "the `internet_connection' is set to 0, please check " "your options."); #ifdef IPV6_DISABLED if (server_opt.inet_gw.family == AF_INET6) fatal("Ipv6 is not supported"); #endif } void init_netsukuku(char **argv) { xsrand(); if (geteuid()) fatal("Need root privileges"); destroy_netsukuku_mutex = pid_saved = 0; sigterm_timestamp = sighup_timestamp = sigalrm_timestamp = 0; setzero(&me, sizeof(struct current_globals)); if (is_ntkd_already_running()) fatal("ntkd is already running. If it is not, remove \"%s\"", server_opt.pid_file); else save_pid(); my_family = server_opt.family; restricted_mode = server_opt.restricted; restricted_class = server_opt.restricted_class ? RESTRICTED_172 : RESTRICTED_10; /* Check if the DATA_DIR exists, if not create it */ if (check_and_create_dir(DATA_DIR)) fatal("Cannot access to the %s directory. Exiting.", DATA_DIR); /* * Device initialization */ if (if_init_all(server_opt.ifs, server_opt.ifs_n, me.cur_ifs, &me.cur_ifs_n) < 0) fatal("Cannot initialize any network interfaces"); /* * ANDNA init */ if (!server_opt.disable_andna) andna_init(); /* * Initialize the Internet gateway stuff */ if (server_opt.my_upload_bw && server_opt.my_dnload_bw) me.my_bandwidth = bandwidth_in_8bit((server_opt.my_upload_bw + server_opt.my_dnload_bw) / 2); init_internet_gateway_search(); pkts_init(me.cur_ifs, me.cur_ifs_n, 0); qspn_init(FAMILY_LVLS); me.cur_erc = e_rnode_init(&me.cur_erc_counter); /* Radar init */ rq_wait_idx_init(rq_wait_idx); first_init_radar(); total_radars = 0; ntk_load_maps(); #if 0 /* TODO: activate and test it !! */ debug(DBG_NORMAL, "ACPT: Initializing the accept_tbl: \n" " max_connections: %d,\n" " max_accepts_per_host: %d,\n" " max_accept_per_host_time: %d", server_opt.max_connections, server_opt.max_accepts_per_host, server_opt.max_accepts_per_host_time); init_accept_tbl(server_opt.max_connections, server_opt.max_accepts_per_host, server_opt.max_accepts_per_host_time); #endif if (restricted_mode) loginfo("NetsukukuD is in restricted mode. " "Restricted class: %s", server_opt. restricted_class ? RESTRICTED_172_STR : RESTRICTED_10_STR); hook_init(); rehook_init(); me.uptime = time(0); } int destroy_netsukuku(void) { if (destroy_netsukuku_mutex) return -1; destroy_netsukuku_mutex = 1; unlink(server_opt.pid_file); ntk_save_maps(); ntk_free_maps(); if (!server_opt.disable_andna) andna_close(); close_internet_gateway_search(); last_close_radar(); e_rnode_free(&me.cur_erc, &me.cur_erc_counter); destroy_accept_tbl(); if_close_all(); qspn_free(); free_server_opt(); return 0; } void sigterm_handler(int sig) { time_t cur_t; if (sigterm_timestamp == (cur_t = time(0))) return; sigterm_timestamp = time(0); if (!destroy_netsukuku()) fatal("Termination signal caught. Dying, bye, bye"); } void * reload_hostname_thread(void *null) { /* * Reload the file where the hostnames to be registered are and * register the new ones */ loginfo("Reloading the andna hostnames file"); load_hostnames(server_opt.andna_hnames_file, &andna_lcl, &lcl_counter); load_snsd(server_opt.snsd_nodes_file, andna_lcl); andna_update_hnames(1); return 0; } void sighup_handler(int sig) { pthread_t thread; pthread_attr_t t_attr; time_t cur_t; if (sighup_timestamp == (cur_t = time(0))) return; sighup_timestamp = time(0); pthread_attr_init(&t_attr); pthread_attr_setdetachstate(&t_attr, PTHREAD_CREATE_DETACHED); pthread_create(&thread, &t_attr, reload_hostname_thread, 0); } void * rh_cache_flush_thread(void *null) { /* * Flush the resolved hostnames cache. */ loginfo("Flush the resolved hostnames cache"); rh_cache_flush(); return 0; } void sigalrm_handler(int sig) { pthread_t thread; pthread_attr_t t_attr; time_t cur_t; if (sigalrm_timestamp == (cur_t = time(0))) return; sigalrm_timestamp = time(0); pthread_attr_init(&t_attr); pthread_attr_setdetachstate(&t_attr, PTHREAD_CREATE_DETACHED); pthread_create(&thread, &t_attr, rh_cache_flush_thread, 0); } /* * The main flow shall never be stopped, and the sand of time will be * revealed. */ int main(int argc, char **argv) { struct udp_daemon_argv ud_argv; u_short *port; pthread_t daemon_tcp_thread, daemon_udp_thread, andna_thread; pthread_t ping_igw_thread; pthread_attr_t t_attr; log_init(argv[0], 0, 1); /* Options loading... */ fill_default_options(); parse_options(argc, argv); /* reinit the logs using the new `dbg_lvl' value */ log_init(argv[0], server_opt.dbg_lvl, 1); log_to_file(0); /* Load the option from the config file */ load_config_file(server_opt.config_file); fill_loaded_cfg_options(); /* If a same option was specified in the config file and in the * command line, give priority to the latter */ parse_options(argc, argv); check_conflicting_options(); /* Initialize the whole netsukuku source code */ init_netsukuku(argv); signal(SIGALRM, sigalrm_handler); signal(SIGHUP, sighup_handler); signal(SIGINT, sigterm_handler); signal(SIGTERM, sigterm_handler); signal(SIGQUIT, sigterm_handler); /* Angelic foreground or Daemonic background ? */ if (server_opt.daemon) { loginfo("Forking to background"); log_init(argv[0], server_opt.dbg_lvl, 0); if (daemon(0, 0) == -1) error("Impossible to daemonize: %s.", strerror(errno)); } pthread_attr_init(&t_attr); pthread_attr_setdetachstate(&t_attr, PTHREAD_CREATE_DETACHED); setzero(&ud_argv, sizeof(struct udp_daemon_argv)); port = xmalloc(sizeof(u_short)); /* * These are the daemons, the main threads that keeps NetsukukuD * up & running. */ debug(DBG_NORMAL, "Activating all daemons"); pthread_mutex_init(&udp_daemon_lock, 0); pthread_mutex_init(&tcp_daemon_lock, 0); debug(DBG_SOFT, "Evoking the netsukuku udp radar daemon."); ud_argv.port = ntk_udp_radar_port; pthread_mutex_lock(&udp_daemon_lock); pthread_create(&daemon_udp_thread, &t_attr, udp_daemon, (void *) &ud_argv); pthread_mutex_lock(&udp_daemon_lock); pthread_mutex_unlock(&udp_daemon_lock); debug(DBG_SOFT, "Evoking the netsukuku tcp daemon."); *port = ntk_tcp_port; pthread_mutex_lock(&tcp_daemon_lock); pthread_create(&daemon_tcp_thread, &t_attr, tcp_daemon, (void *) port); pthread_mutex_lock(&tcp_daemon_lock); pthread_mutex_unlock(&tcp_daemon_lock); /* Now we hook in Netsukuku */ netsukuku_hook(0, 0); /* * If not disabled, start the ANDNA daemon */ if (!server_opt.disable_andna) pthread_create(&andna_thread, &t_attr, andna_main, 0); xfree(port); if (restricted_mode && (server_opt.share_internet || server_opt.use_shared_inet)) { debug(DBG_SOFT, "Evoking the Internet Gateway Pinger daemon"); pthread_create(&ping_igw_thread, &t_attr, igw_monitor_igws_t, 0); } /* We use this same process for the radar_daemon. */ debug(DBG_SOFT, "Evoking radar daemon."); radar_daemon(0); /* Not reached, hahaha */ loginfo("Cya m8"); pthread_attr_destroy(&t_attr); destroy_netsukuku(); exit(0); }