Esempio n. 1
0
int main() {
    struct rlimit rl;
    rl.rlim_max = rl.rlim_cur = 1024*64;
    if (setrlimit(RLIMIT_NOFILE, &rl) < -1) {
        return -1;
    }

    fiber_mutex_init(&mtx);
    memset((char*)sharedArr, 0, 64);

    const char *server_ip = "127.0.0.1";

    struct Scheduler *sch = create_scheduler(8);
    if (sch == NULL) return 0;
    struct TcpServer *server = create_tcp_server(server_ip, 12400, data_processor);
    if (server == NULL) return 0;

    start_scheduler(sch);
    run_tcp_server(sch, server);

    return 0;
}
Esempio n. 2
0
/* The nfq capture routine.
*/
int
nfq_capture(fko_srv_options_t *opts)
{
    int                 res, child_pid, fd_flags;
    int                 nfq_errcnt = 0;
    int                 pending_break = 0;
    int                 status;
    char                nfq_buf[1500];
    int                 chk_rm_all = 0;

    /* Netfilter-related handles
    */
    int                  nfq_fd;
    struct nfq_handle   *nfq_h;
    struct nfq_q_handle *nfq_qh;
    struct nfnl_handle  *nfq_nh;

    nfq_h = nfq_open();
    if (!nfq_h) {
        log_msg(LOG_ERR, "[*] nfq_open error\n");
        clean_exit(opts, FW_CLEANUP, EXIT_FAILURE);
    }

    /* Unbind existing nf_queue handler for AF_INET (if any)
    */
    res = nfq_unbind_pf(nfq_h, AF_INET);
    if (res < 0)  {
        log_msg(LOG_WARNING, "[*] Error during nfq_unbind_pf() error: %d\n", res);
    }

    /* Bind the given queue connection handle to process packets.
    */
    res =  nfq_bind_pf(nfq_h, AF_INET);
    if ( res < 0) {
        log_msg(LOG_ERR, "Error during nfq_bind_pf(), error: %d\n", res);
        clean_exit(opts, FW_CLEANUP, EXIT_FAILURE);
    }

    /* Create queue
    */
    nfq_qh = nfq_create_queue(nfq_h,  atoi(opts->config[CONF_NFQ_QUEUE_NUMBER]), &process_nfq_packet, opts);
    if (!nfq_qh) {
        log_msg(LOG_ERR, "Error during nfq_create_queue()\n");
        clean_exit(opts, FW_CLEANUP, EXIT_FAILURE);
    }

    /* Set the amount of data to be copied to userspace for each packet
     * queued to the given queue.
    */
    if (nfq_set_mode(nfq_qh, NFQNL_COPY_PACKET, 0xffff) < 0) {
        log_msg(LOG_ERR, "Can't set packet_copy mode\n");
        clean_exit(opts, FW_CLEANUP, EXIT_FAILURE);
    }

    /* Get the netlink handle associated with the given queue connection
     * handle. Then use it to get the file descriptor we will use for
     * receiving the queued packets
    */
    nfq_nh = nfq_nfnlh(nfq_h);
    nfq_fd = nfnl_fd(nfq_nh);

    /* Set our nfq handle nonblocking mode.
     *
    */
    if((fd_flags = fcntl(nfq_fd, F_GETFL, 0)) < 0)
    {
        log_msg(LOG_ERR, "nfq_capture: fcntl F_GETFL error: %s",
            strerror(errno));
        clean_exit(opts, FW_CLEANUP, EXIT_FAILURE);
    }

    fd_flags |= O_NONBLOCK;

    if(fcntl(nfq_fd, F_SETFL, fd_flags) < 0)
    {
        log_msg(LOG_ERR, "nfq_capture: fcntl F_SETFL error setting O_NONBLOCK: %s",
            strerror(errno));
        exit(EXIT_FAILURE);
    }

    /* Initialize our signal handlers. You can check the return value for
     * the number of signals that were *not* set.  Those that were not set
     * will be listed in the log/stderr output.
    */
    if(set_sig_handlers() > 0)
        log_msg(LOG_ERR, "Errors encountered when setting signal handlers.");

    log_msg(LOG_INFO, "Starting fwknopd main event loop.");

    /* Jump into our home-grown packet cature loop.
    */
    while(1)
    {
        /* If we got a SIGCHLD and it was the tcp server, then handle it here.
        ** XXX: --DSS Do we need this here?  I'm guessing we would not be using
        **            the TCP server in NF_QUEUE capture mode.
        */
        if(got_sigchld)
        {
            if(opts->tcp_server_pid > 0)
            {
                child_pid = waitpid(0, &status, WNOHANG);

                if(child_pid == opts->tcp_server_pid)
                {
                    if(WIFSIGNALED(status))
                        log_msg(LOG_WARNING, "TCP server got signal: %i",  WTERMSIG(status));

                    log_msg(LOG_WARNING,
                        "TCP server exited with status of %i. Attempting restart.",
                        WEXITSTATUS(status)
                    );

                    opts->tcp_server_pid = 0;

                    /* Attempt to restart tcp server ? */
                    usleep(1000000);
                    run_tcp_server(opts);
                }
            }

            got_sigchld = 0;
        }

        /* Any signal except USR1, USR2, and SIGCHLD mean break the loop.
        */
        if(got_signal != 0)
        {
            if(got_sigint || got_sigterm || got_sighup)
            {
                pending_break = 1;
            }
            else if(got_sigusr1 || got_sigusr2)
            {
                /* Not doing anything with these yet.
                */
                got_sigusr1 = got_sigusr2 = 0;
                got_signal = 0;
            }
            else
                got_signal = 0;
        }

        res = recv(nfq_fd, nfq_buf, sizeof(nfq_buf), 0);

        /* Count processed packets
        */
        if(res > 0)
        {
            nfq_handle_packet(nfq_h, nfq_buf, res);

            /* Count the set of processed packets (nfq_dispatch() return
             * value) - we use this as a comparison for --packet-limit regardless
             * of SPA packet validity at this point.
            */
            opts->packet_ctr += res;
            if (opts->packet_ctr_limit && opts->packet_ctr >= opts->packet_ctr_limit)
            {
                log_msg(LOG_WARNING,
                    "* Incoming packet count limit of %i reached",
                    opts->packet_ctr_limit
                );

                pending_break = 1;
            }
        }
        /* If there was an error, complain and go on (to an extent before
         * giving up).
        */
        else if(res < 0 && errno != EAGAIN)
        {

            log_msg(LOG_ERR, "[*] Error reading from  nfq descriptor: %s", strerror);

            if(nfq_errcnt++ > MAX_NFQ_ERRORS_BEFORE_BAIL)
            {
                log_msg(LOG_ERR, "[*] %i consecutive nfq errors.  Giving up",
                    nfq_errcnt
                );
                clean_exit(opts, FW_CLEANUP, EXIT_FAILURE);
            }

        }
        else if(pending_break == 1 || res == -2)
        {
            log_msg(LOG_INFO, "Gracefully leaving the fwknopd event loop.");
            break;
        }
        else
            nfq_errcnt = 0;

        /* Check for any expired firewall rules and deal with them.
        */
        check_firewall_rules(opts, chk_rm_all);

        usleep(atoi(opts->config[CONF_NFQ_LOOP_SLEEP]));
    }

    nfq_destroy_queue(nfq_qh);
    nfq_close(nfq_h);

    return(0);
}
Esempio n. 3
0
int
main(int argc, char **argv)
{
    int                 res, last_sig, rp_cache_count;
    char               *locale;
    pid_t               old_pid;

    fko_srv_options_t   opts;

    while(1)
    {
        /* Handle command line
        */
        config_init(&opts, argc, argv);

        /* Process any options that do their thing and exit. */

        /* Kill the currently running fwknopd?
        */
        if(opts.kill == 1)
        {
            old_pid = get_running_pid(&opts);

            if(old_pid > 0)
            {
                res = kill(old_pid, SIGTERM);
                if(res == 0)
                {
                    fprintf(stderr, "Killed fwknopd (pid=%i)\n", old_pid);
                    exit(EXIT_SUCCESS);
                }
                else
                {
                    perror("Unable to kill fwknop: ");
                    exit(EXIT_FAILURE);
                }
            }
            else
            {
                fprintf(stderr, "No running fwknopd detected.\n");
                exit(EXIT_FAILURE);
            }
        }

        /* Status of the currently running fwknopd?
        */
        if(opts.status == 1)
        {
            old_pid = write_pid_file(&opts);

            if(old_pid > 0)
                fprintf(stderr, "Detected fwknopd is running (pid=%i).\n", old_pid);
            else
                fprintf(stderr, "No running fwknopd detected.\n");

            exit(EXIT_SUCCESS);
        }

        /* Restart the currently running fwknopd?
        */
        if(opts.restart == 1 || opts.status == 1)
        {
            old_pid = get_running_pid(&opts);

            if(old_pid > 0)
            {
                res = kill(old_pid, SIGHUP);
                if(res == 0)
                {
                    fprintf(stderr, "Sent restart signal to fwknopd (pid=%i)\n", old_pid);
                    exit(EXIT_SUCCESS);
                }
                else
                {
                    perror("Unable to send signal to fwknop: ");
                    exit(EXIT_FAILURE);
                }
            }
            else
            {
                fprintf(stderr, "No running fwknopd detected.\n");
                exit(EXIT_FAILURE);
            }
        }

        /* Initialize logging.
        */
        init_logging(&opts);

#if HAVE_LOCALE_H 
        /* Set the locale if specified. 
        */ 
        if(opts.config[CONF_LOCALE] != NULL
          && strncasecmp(opts.config[CONF_LOCALE], "NONE", 4) != 0) 
        { 
            locale = setlocale(LC_ALL, opts.config[CONF_LOCALE]); 
 
            if(locale == NULL) 
            { 
                log_msg(LOG_ERR, 
                    "WARNING: Unable to set locale to '%s'.", 
                    opts.config[CONF_LOCALE] 
                ); 
            } 
            else 
            { 
                if(opts.verbose) 
                    log_msg(LOG_INFO, 
                        "Locale set to '%s'.", opts.config[CONF_LOCALE] 
                    ); 
            } 
        } 
#endif 

        /* Make sure we have a valid run dir and path leading to digest file
         * in case it configured to be somewhere other than the run dir.
        */
        check_dir_path((const char *)opts.config[CONF_FWKNOP_RUN_DIR], "Run", 0);
#if USE_FILE_CACHE
        check_dir_path((const char *)opts.config[CONF_DIGEST_FILE], "Run", 1);
#else
        check_dir_path((const char *)opts.config[CONF_DIGEST_DB_FILE], "Run", 1);
#endif

        /* Process the access.conf file.
        */
        parse_access_file(&opts);

        /* Show config (including access.conf vars) and exit dump config was
         * wanted.
        */
        if(opts.dump_config == 1)
        {
            dump_config(&opts);
            dump_access_list(&opts);
            exit(EXIT_SUCCESS);
        }

        /* Initialize the firewall rules handler based on the fwknopd.conf
         * file, but (for iptables firewalls) don't flush any rules or create
         * any chains yet.  This allows us to dump the current firewall rules
         * via fw_rules_dump() in --fw-list mode before changing around any rules
         * of an existing fwknopd process.
        */
        fw_config_init(&opts);

        if(opts.fw_list == 1)
        {
            fw_dump_rules(&opts);
            exit(EXIT_SUCCESS);
        }

        /* If we are a new process (just being started), proceed with normal
         * start-up.  Otherwise, we are here as a result of a signal sent to an
         * existing process and we want to restart.
        */
        if(get_running_pid(&opts) != getpid())
        {
            /* If foreground mode is not set, the fork off and become a daemon.
            * Otherwise, attempt to get the pid file lock and go on.
            */
            if(opts.foreground == 0)
            {
                daemonize_process(&opts);
            }
            else
            {
                old_pid = write_pid_file(&opts);
                if(old_pid > 0)
                {
                    fprintf(stderr,
                        "* An instance of fwknopd is already running: (PID=%i).\n", old_pid
                    );

                    exit(EXIT_FAILURE);
                }
                else if(old_pid < 0)
                {
                    fprintf(stderr, "* PID file error. The lock may not be effective.\n");
                }
            }

            log_msg(LOG_INFO, "Starting %s", MY_NAME);
        }
        else
        {
            log_msg(LOG_INFO, "Re-starting %s", MY_NAME);
        }

        if(opts.verbose > 1 && opts.foreground)
        {
            dump_config(&opts);
            dump_access_list(&opts);
        }

        /* Initialize the digest cache for replay attack detection (either
         * with dbm support or with the default simple cache file strategy)
         * if so configured.
        */
        if(strncasecmp(opts.config[CONF_ENABLE_DIGEST_PERSISTENCE], "Y", 1) == 0)
        {
            rp_cache_count = replay_cache_init(&opts);

            if(rp_cache_count < 0)
            {
                log_msg(LOG_WARNING,
                    "Error opening digest cache file. Incoming digests will not be remembered."
                );
                strlcpy(opts.config[CONF_ENABLE_DIGEST_PERSISTENCE], "N", 2);
            }

            if(opts.verbose)
                log_msg(LOG_ERR,
                    "Using Digest Cache: '%s' (entry count = %i)",
#if USE_FILE_CACHE
                    opts.config[CONF_DIGEST_FILE], rp_cache_count
#else
                    opts.config[CONF_DIGEST_DB_FILE], rp_cache_count
#endif
                );
        }

        /* Prepare the firewall - i.e. flush any old rules and (for iptables)
         * create fwknop chains.
        */
        fw_initialize(&opts);

        /* If the TCP server option was set, fire it up here.
        */
        if(strncasecmp(opts.config[CONF_ENABLE_TCP_SERVER], "Y", 1) == 0)
        {
            if(atoi(opts.config[CONF_TCPSERV_PORT]) <= 0
              || atoi(opts.config[CONF_TCPSERV_PORT]) >  65535)
            {
                log_msg(LOG_WARNING,
                    "WARNING: ENABLE_TCP_SERVER is set, but TCPSERV_PORT is not valid. TCP server not started!"
                );
            }
            else
            {
                run_tcp_server(&opts);
            }
        }

        /* Intiate pcap capture mode...
        */
        pcap_capture(&opts);

        if(got_signal) {
            last_sig   = got_signal;
            got_signal = 0;

            if(got_sighup)
            {
                log_msg(LOG_WARNING, "Got SIGHUP.  Re-reading configs.");
                free_configs(&opts);
                kill(opts.tcp_server_pid, SIGTERM);
                usleep(1000000);
                got_sighup = 0;
            }
            else if(got_sigint)
            {
                log_msg(LOG_WARNING, "Got SIGINT.  Exiting...");
                got_sigint = 0;
                break;
            }
            else if(got_sigterm)
            {
                log_msg(LOG_WARNING, "Got SIGTERM.  Exiting...");
                got_sigterm = 0;
                break;
            }
            else
            {
                log_msg(LOG_WARNING,
                    "Got signal %i. No defined action but to exit.", last_sig);
                break;
            }
        }
        else if (opts.packet_ctr_limit > 0
            && opts.packet_ctr >= opts.packet_ctr_limit)
        {
            log_msg(LOG_INFO,
                "Packet count limit (%d) reached.  Exiting...",
                opts.packet_ctr_limit);
            break;
        }
        else    /* got_signal was not set (should be if we are here) */
        {
            log_msg(LOG_WARNING,
                "Capture ended without signal.  Exiting...");
            break;
        }
    }

    log_msg(LOG_INFO, "Shutting Down fwknopd.");

    /* Kill the TCP server (if we have one running).
    */
    if(opts.tcp_server_pid > 0)
    {
        log_msg(LOG_INFO, "Killing the TCP server (pid=%i)",
            opts.tcp_server_pid);

        kill(opts.tcp_server_pid, SIGTERM);

        /* --DSS XXX: This seems to be necessary if the tcp server
         *            was restarted by this program.  We need to
         *            investigate and fix this. For now, this works
         *            (it is kludgy, but does no harm afaik).
        */
        kill(opts.tcp_server_pid, SIGKILL);
    }

    /* Other cleanup.
    */
    fw_cleanup();
    free_logging();

#if USE_FILE_CACHE
    free_replay_list(&opts);
#endif

    free_configs(&opts);

    return(0);
}
Esempio n. 4
0
/* The pcap capture routine.
*/
int
pcap_capture(fko_srv_options_t *opts)
{
    pcap_t              *pcap;
    char                errstr[PCAP_ERRBUF_SIZE] = {0};
    struct bpf_program  fp;
    int                 res;
    int                 pcap_errcnt = 0;
    int                 pending_break = 0;
    int                 promisc = 0;
    int                 set_direction = 1;
    int                 pcap_file_mode = 0;
    int                 status;
    int                 useconds;
    int                 pcap_dispatch_count;
    int                 max_sniff_bytes;
    int                 is_err;
    pid_t               child_pid;

#if FIREWALL_IPFW
    time_t              now;
#endif

    useconds = strtol_wrapper(opts->config[CONF_PCAP_LOOP_SLEEP],
            0, RCHK_MAX_PCAP_LOOP_SLEEP, NO_EXIT_UPON_ERR, &is_err);
    if(is_err != FKO_SUCCESS)
    {
        log_msg(LOG_ERR, "[*] invalid PCAP_LOOP_SLEEP_value");
        clean_exit(opts, FW_CLEANUP, EXIT_FAILURE);
    }

    max_sniff_bytes = strtol_wrapper(opts->config[CONF_MAX_SNIFF_BYTES],
            0, RCHK_MAX_SNIFF_BYTES, NO_EXIT_UPON_ERR, &is_err);
    if(is_err != FKO_SUCCESS)
    {
        log_msg(LOG_ERR, "[*] invalid MAX_SNIFF_BYTES");
        clean_exit(opts, FW_CLEANUP, EXIT_FAILURE);
    }

    /* Set promiscuous mode if ENABLE_PCAP_PROMISC is set to 'Y'.
    */
    if(strncasecmp(opts->config[CONF_ENABLE_PCAP_PROMISC], "Y", 1) == 0)
        promisc = 1;

    if(opts->config[CONF_PCAP_FILE] != NULL
            && opts->config[CONF_PCAP_FILE][0] != '\0')
        pcap_file_mode = 1;

    if(pcap_file_mode == 1) {
        log_msg(LOG_INFO, "Reading pcap file: %s",
            opts->config[CONF_PCAP_FILE]);

        pcap = pcap_open_offline(opts->config[CONF_PCAP_FILE], errstr);

        if(pcap == NULL)
        {
            log_msg(LOG_ERR, "[*] pcap_open_offline() error: %s",
                    errstr);
            clean_exit(opts, FW_CLEANUP, EXIT_FAILURE);
        }
    }
    else
    {
        log_msg(LOG_INFO, "Sniffing interface: %s",
            opts->config[CONF_PCAP_INTF]);

        pcap = pcap_open_live(opts->config[CONF_PCAP_INTF],
            max_sniff_bytes, promisc, 100, errstr
        );

        if(pcap == NULL)
        {
            log_msg(LOG_ERR, "[*] pcap_open_live() error: %s", errstr);
            clean_exit(opts, FW_CLEANUP, EXIT_FAILURE);
        }
    }

    /* Set pcap filters, if any.
    */
    if (opts->config[CONF_PCAP_FILTER][0] != '\0')
    {
        if(pcap_compile(pcap, &fp, opts->config[CONF_PCAP_FILTER], 1, 0) == -1)
        {
            log_msg(LOG_ERR, "[*] Error compiling pcap filter: %s",
                pcap_geterr(pcap)
            );
            clean_exit(opts, FW_CLEANUP, EXIT_FAILURE);
        }

        if(pcap_setfilter(pcap, &fp) == -1)
        {
            log_msg(LOG_ERR, "[*] Error setting pcap filter: %s",
                pcap_geterr(pcap)
            );
            clean_exit(opts, FW_CLEANUP, EXIT_FAILURE);
        }

        log_msg(LOG_INFO, "PCAP filter is: '%s'", opts->config[CONF_PCAP_FILTER]);

        pcap_freecode(&fp);
    }

    /* Determine and set the data link encapsulation offset.
    */
    switch(pcap_datalink(pcap)) {
        case DLT_EN10MB:
            opts->data_link_offset = 14;
            break;
#if defined(__linux__)
        case DLT_LINUX_SLL:
            opts->data_link_offset = 16;
            break;
#elif defined(__OpenBSD__)
        case DLT_LOOP:
            set_direction = 0;
            opts->data_link_offset = 4;
            break;
#endif
        case DLT_NULL:
            set_direction = 0;
            opts->data_link_offset = 4;
            break;
        default:
            opts->data_link_offset = 0;
            break;
    }

    /* We are only interested on seeing packets coming into the interface.
    */
    if ((opts->pcap_any_direction == 0)
            && (set_direction == 1) && (pcap_file_mode == 0)
            && (pcap_setdirection(pcap, PCAP_D_IN) < 0))
        if(opts->verbose)
            log_msg(LOG_WARNING, "[*] Warning: pcap error on setdirection: %s.",
                pcap_geterr(pcap));

    /* Set our pcap handle nonblocking mode.
     *
     * NOTE: This is simply set to 0 for now until we find a need
     *       to actually use this mode (which when set on a FreeBSD
     *       system, it silently breaks the packet capture).
    */
    if((pcap_file_mode == 0)
            && (pcap_setnonblock(pcap, DEF_PCAP_NONBLOCK, errstr)) == -1)
    {
        log_msg(LOG_ERR, "[*] Error setting pcap nonblocking to %i: %s",
            0, errstr
        );
        clean_exit(opts, FW_CLEANUP, EXIT_FAILURE);
    }

    pcap_dispatch_count = strtol_wrapper(opts->config[CONF_PCAP_DISPATCH_COUNT],
            0, RCHK_MAX_PCAP_DISPATCH_COUNT, NO_EXIT_UPON_ERR, &is_err);
    if(is_err != FKO_SUCCESS)
    {
        log_msg(LOG_ERR, "[*] invalid PCAP_DISPATCH_COUNT");
        clean_exit(opts, FW_CLEANUP, EXIT_FAILURE);
    }

    /* Initialize our signal handlers. You can check the return value for
     * the number of signals that were *not* set.  Those that were not set
     * will be listed in the log/stderr output.
    */
    if(set_sig_handlers() > 0)
        log_msg(LOG_ERR, "Errors encountered when setting signal handlers.");

    log_msg(LOG_INFO, "Starting fwknopd main event loop.");

    /* Jump into our home-grown packet cature loop.
    */
    while(1)
    {
        /* If we got a SIGCHLD and it was the tcp server, then handle it here.
        */
        if(got_sigchld)
        {
            if(opts->tcp_server_pid > 0)
            {
                child_pid = waitpid(0, &status, WNOHANG);

                if(child_pid == opts->tcp_server_pid)
                {
                    if(WIFSIGNALED(status))
                        log_msg(LOG_WARNING, "TCP server got signal: %i",  WTERMSIG(status));

                    log_msg(LOG_WARNING,
                        "TCP server exited with status of %i. Attempting restart.",
                        WEXITSTATUS(status)
                    );

                    opts->tcp_server_pid = 0;

                    /* Attempt to restart tcp server ? */
                    usleep(1000000);
                    run_tcp_server(opts);
                }
            }

            got_sigchld = 0;
        }

        /* Any signal except USR1, USR2, and SIGCHLD mean break the loop.
        */
        if(got_signal != 0)
        {
            if(got_sigint || got_sigterm || got_sighup)
            {
                pcap_breakloop(pcap);
                pending_break = 1;
            }
            else if(got_sigusr1 || got_sigusr2)
            {
                /* Not doing anything with these yet.
                */
                got_sigusr1 = got_sigusr2 = 0;
                got_signal = 0;
            }
            else
                got_signal = 0;
        }

        res = pcap_dispatch(pcap, pcap_dispatch_count,
            (pcap_handler)&process_packet, (unsigned char *)opts);

        /* Count processed packets
        */
        if(res > 0)
        {
            if(opts->foreground == 1 && opts->verbose > 2)
                log_msg(LOG_DEBUG, "pcap_dispatch() processed: %d packets", res);

            /* Count the set of processed packets (pcap_dispatch() return
             * value) - we use this as a comparison for --packet-limit regardless
             * of SPA packet validity at this point.
            */
            opts->packet_ctr += res;
            if (opts->packet_ctr_limit && opts->packet_ctr >= opts->packet_ctr_limit)
            {
                log_msg(LOG_WARNING,
                    "* Incoming packet count limit of %i reached",
                    opts->packet_ctr_limit
                );

                pcap_breakloop(pcap);
                pending_break = 1;
            }
        }
        /* If there was an error, complain and go on (to an extent before
         * giving up).
        */
        else if(res == -1)
        {
            log_msg(LOG_ERR, "[*] Error from pcap_dispatch: %s",
                pcap_geterr(pcap)
            );

            if(pcap_errcnt++ > MAX_PCAP_ERRORS_BEFORE_BAIL)
            {
                log_msg(LOG_ERR, "[*] %i consecutive pcap errors.  Giving up",
                    pcap_errcnt
                );
                clean_exit(opts, FW_CLEANUP, EXIT_FAILURE);
            }
        }
        else if(pending_break == 1 || res == -2)
        {
            /* pcap_breakloop was called, so we bail. */
            log_msg(LOG_INFO, "Gracefully leaving the fwknopd event loop.");
            break;
        }
        else
            pcap_errcnt = 0;

        /* Check for any expired firewall rules and deal with them.
        */
        check_firewall_rules(opts);

#if FIREWALL_IPFW
        /* Purge expired rules that no longer have any corresponding
         * dynamic rules.
        */
        if(opts->fw_config->total_rules > 0)
        {
            time(&now);
            if(opts->fw_config->last_purge < (now - opts->fw_config->purge_interval))
            {
                ipfw_purge_expired_rules(opts);
                opts->fw_config->last_purge = now;
            }
        }
#endif

        usleep(useconds);
    }

    pcap_close(pcap);

    return(0);
}
Esempio n. 5
0
int
main(int argc, char **argv)
{
    fko_srv_options_t   opts;
    int depth = 0;

    while(1)
    {
        /* Handle command line
        */
        //处理启动参数。
        config_init(&opts, argc, argv);

#if HAVE_LIBFIU
        /* Set any fault injection points early
        */
        enable_fault_injections(&opts);
#endif

        /* Process any options that do their thing and exit.
        */

        /* Kill the currently running fwknopd process?
        */
        if(opts.kill == 1)
            clean_exit(&opts, NO_FW_CLEANUP, stop_fwknopd(&opts));

        /* Status of the currently running fwknopd process?
        */
        if(opts.status == 1)
            clean_exit(&opts, NO_FW_CLEANUP, status_fwknopd(&opts));

        /* Restart the currently running fwknopd process?
        */
        if(opts.restart == 1)
            clean_exit(&opts, NO_FW_CLEANUP, restart_fwknopd(&opts));

        /* Initialize logging.
        */
        init_logging(&opts);

        /* Update the verbosity level for the log module */
        log_set_verbosity(LOG_DEFAULT_VERBOSITY + opts.verbose);

#if HAVE_LOCALE_H
        /* Set the locale if specified.
        */
        set_locale(&opts);
#endif

        /* Make sure we have a valid run dir and path leading to digest file
         * in case it configured to be somewhere other than the run dir.
        */
        if(!opts.afl_fuzzing
                && ! check_dir_path((const char *)opts.config[CONF_FWKNOP_RUN_DIR], "Run", 0))
            clean_exit(&opts, NO_FW_CLEANUP, EXIT_FAILURE);

        /* Initialize the firewall rules handler based on the fwknopd.conf
         * file, but (for iptables firewalls) don't flush any rules or create
         * any chains yet. This allows us to dump the current firewall rules
         * via fw_rules_dump() in --fw-list mode before changing around any rules
         * of an existing fwknopd process.
        */
        if(fw_config_init(&opts) != 1)
            clean_exit(&opts, NO_FW_CLEANUP, EXIT_FAILURE);

        if(opts.fw_list == 1 || opts.fw_list_all == 1)
        {
            fw_dump_rules(&opts);
            clean_exit(&opts, NO_FW_CLEANUP, EXIT_SUCCESS);
        }

        if(opts.fw_flush == 1)
        {
            fprintf(stdout, "Deleting any existing firewall rules...\n");
            clean_exit(&opts, FW_CLEANUP, EXIT_SUCCESS);
        }

        if (opts.config[CONF_ACCESS_FOLDER] != NULL) //If we have an access folder, process it
        {
            if (parse_access_folder(&opts, opts.config[CONF_ACCESS_FOLDER], &depth) != EXIT_SUCCESS)
            {
                clean_exit(&opts, NO_FW_CLEANUP, EXIT_FAILURE);
            }
        }
        /* Process the access.conf file, but only if no access.conf folder was specified.
        */
        //读入access.conf中的数据。
        else if (parse_access_file(&opts, opts.config[CONF_ACCESS_FILE], &depth) != EXIT_SUCCESS)
        {
            clean_exit(&opts, NO_FW_CLEANUP, EXIT_FAILURE);
        }

        /* We must have at least one valid access stanza at this point
        */
        //检查有没有合法的stanza。
        if(! valid_access_stanzas(opts.acc_stanzas))
        {
            log_msg(LOG_ERR, "Fatal, could not find any valid access.conf stanzas");
            clean_exit(&opts, NO_FW_CLEANUP, EXIT_FAILURE);
        }

        /* Show config (including access.conf vars) and exit dump config was
         * wanted.
        */
        if(opts.dump_config == 1)
        {
            dump_config(&opts);
            dump_access_list(&opts);
            clean_exit(&opts, NO_FW_CLEANUP, EXIT_SUCCESS);
        }

        /* Now is the right time to bail if we're just parsing the configs
        */
        if(opts.exit_after_parse_config)
        {
            log_msg(LOG_INFO, "Configs parsed, exiting.");
            clean_exit(&opts, NO_FW_CLEANUP, EXIT_SUCCESS);
        }

        /* Acquire pid, become a daemon or run in the foreground, write pid
         * to pid file.
        */
        if(! opts.exit_parse_digest_cache)
            setup_pid(&opts);

        if(opts.verbose > 1 && opts.foreground)
        {
            dump_config(&opts);
            dump_access_list(&opts);
        }

        /* Initialize the digest cache for replay attack detection (either
         * with dbm support or with the default simple cache file strategy)
         * if so configured.
        */
        init_digest_cache(&opts);

        if(opts.exit_parse_digest_cache)
        {
            log_msg(LOG_INFO, "Digest cache parsed, exiting.");
            clean_exit(&opts, NO_FW_CLEANUP, EXIT_SUCCESS);
        }

#if AFL_FUZZING
        /* SPA data from STDIN. */
        if(opts.afl_fuzzing)
        {
            if(opts.config[CONF_AFL_PKT_FILE] != 0x0)
            {
                afl_enc_pkt_from_file(&opts);
            }
            else
            {
                afl_pkt_from_stdin(&opts);
            }
        }
#endif

        /* Prepare the firewall - i.e. flush any old rules and (for iptables)
         * create fwknop chains.
        */
        if(!opts.test && opts.enable_fw && (fw_initialize(&opts) != 1))
            clean_exit(&opts, FW_CLEANUP, EXIT_FAILURE);

        /* If we are to acquire SPA data via a UDP socket, start it up here.
        */
        //启动UDP监听。
        if(opts.enable_udp_server ||
                strncasecmp(opts.config[CONF_ENABLE_UDP_SERVER], "Y", 1) == 0)
        {
            if(run_udp_server(&opts) < 0)
            {
                log_msg(LOG_ERR, "Fatal run_udp_server() error");
                clean_exit(&opts, FW_CLEANUP, EXIT_FAILURE);
            }
            else
            {
                break;
            }
        }

        /* If the TCP server option was set, fire it up here. Note that in
         * this mode, fwknopd still acquires SPA packets via libpcap. If you
         * want to use UDP only without the libpcap dependency, then fwknop
         * needs to be compiled with --enable-udp-server. Note that the UDP
         * server can be run even when fwknopd links against libpcap as well,
         * but there is no reason to link against it if SPA packets are
         * always going to be acquired via a UDP socket.
        */
        if(strncasecmp(opts.config[CONF_ENABLE_TCP_SERVER], "Y", 1) == 0)
        {
            if(run_tcp_server(&opts) < 0)
            {
                log_msg(LOG_ERR, "Fatal run_tcp_server() error");
                clean_exit(&opts, FW_CLEANUP, EXIT_FAILURE);
            }
        }

#if USE_LIBPCAP
        /* Intiate pcap capture mode...
        */
        if(!opts.enable_udp_server
                && strncasecmp(opts.config[CONF_ENABLE_UDP_SERVER], "N", 1) == 0)
        {
            pcap_capture(&opts);
        }
#endif

        /* Deal with any signals that we've received and break out
         * of the loop for any terminating signals
        */
        if(handle_signals(&opts) == 1)
            break;
    }

    log_msg(LOG_INFO, "Shutting Down fwknopd.");

    /* Kill the TCP server (if we have one running).
    */
    if(opts.tcp_server_pid > 0)
    {
        log_msg(LOG_INFO, "Killing the TCP server (pid=%i)",
            opts.tcp_server_pid);

        kill(opts.tcp_server_pid, SIGTERM);

        /* --DSS XXX: This seems to be necessary if the tcp server
         *            was restarted by this program. We need to
         *            investigate and fix this. For now, this works
         *            (it is kludgy, but does no harm afaik).
        */
        kill(opts.tcp_server_pid, SIGKILL);
    }

    clean_exit(&opts, FW_CLEANUP, EXIT_SUCCESS);

    return(EXIT_SUCCESS);  /* This never gets called */
}