/* nfq initialize */ void fwnfq_init(void) { g_message("Opening library handle"); h = nfq_open(); if (!h) g_error("Error during nfq_open()"); g_message("unbinding existing nf_queue handler for AF_INET (if any)"); if (nfq_unbind_pf(h, AF_INET) < 0) g_warning("Error during nfq_unbind_pf()"); g_message("Binding nfnetlink_queue as nf_queue handler for AF_INET"); if (nfq_bind_pf(h, AF_INET) < 0) g_error("Error during nfq_bind_pf()"); g_message("Binding this socket to queue '0'"); qh = nfq_create_queue(h, 0, &fwnfq_callback, NULL); if (!qh) g_error("Error during nfq_create_queue()\n"); g_message("Setting copy_packet mode"); if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) g_error("Can't set packet_copy mode"); nh = nfq_nfnlh(h); fd = nfnl_fd(nh); }
QHandler::QHandler(unsigned short qid) : qid(qid) { // Default these to 0, so we won't handle anything. lowerHashLimit = 0; upperHashLimit = 0; std::cout << "Opening library..." << std::endl; h = nfq_open(); if (h == 0) { throw std::runtime_error("Cannot open lib"); } // Unbind existing handler if (nfq_unbind_pf(h, AF_INET) < 0) { std::cerr << "error during nfq_unbind_pf() - maybe this is ok\n"; } // Bind new handler if (nfq_bind_pf(h, AF_INET) < 0) { throw std::runtime_error("nfq_bind_pf failed"); } qh = nfq_create_queue(h, QueueId, &packet_callback, this); if (qh == 0) { throw std::runtime_error("Cannot create queue"); } // Set packet copy mode... if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) { throw std::runtime_error("nfq_set_mode failed"); } // Get the nl handle and file descriptor... nh = nfq_nfnlh(h); sock = nfnl_fd(nh); // So far so good. // Set our socket non blocking. SetNonBlocking(sock); }
/* * Initialize stdin and nfq hook, then loop forever. Callback() does all the real work. */ int main(int argc, char **argv) { int fd; int rv; char buf[4096] __attribute__ ((aligned)); if(getuid() != 0) { fail("Only root can use me."); } /* make stdin non-blocking, i.e. optional */ int flags = fcntl(0, F_GETFL, 0); flags |= O_NONBLOCK; fcntl(0, F_SETFL, flags); /* signal handler will close nfq hooks on exit */ if(signal(SIGINT, sig_handler) == SIG_IGN) signal(SIGINT, SIG_IGN); if(signal(SIGHUP, sig_handler) == SIG_IGN) signal(SIGINT, SIG_IGN); if(signal(SIGTERM, sig_handler) == SIG_IGN) signal(SIGINT, SIG_IGN); /* hook callback() into userspace netlink queue */ if (!(nfqh = nfq_open())) fail("nfq_open() failed"); if (0 > nfq_unbind_pf(nfqh, AF_INET)) fail("nfq_unbind_pf failed"); if (0 > nfq_bind_pf(nfqh, AF_INET)) fail("nfq_bind_pf failed"); if (!(qh = nfq_create_queue(nfqh, 0, &callback, NULL))) fail("nfq_create_queue failed"); if (0 > nfq_set_mode(qh, NFQNL_COPY_META, 0xffff)) fail("nfq_set_mode failed"); nh = nfq_nfnlh(nfqh); fd = nfnl_fd(nh); printf("Commencing packet mangling..\n"); clock_gettime(CLOCK_REALTIME, &last_time); while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) nfq_handle_packet(nfqh, buf, rv); printf("Exiting..\n"); return 0; }
/* * Open a netlink connection and returns file descriptor */ int netlink_open_connection(void *data) { struct nfnl_handle *nh; #ifdef UFD_DEBUG printf("opening library handle\n"); #endif h = nfq_open(); if (!h) { fprintf(stderr, "error during nfq_open()\n"); exit(1); } #ifdef UFD_DEBUG printf("unbinding existing nf_queue handler for AF_INET (if any)\n"); #endif if (nfq_unbind_pf(h, AF_INET) < 0) { fprintf(stderr, "error during nfq_unbind_pf()\n"); exit(1); } #ifdef UFD_DEBUG printf("binding nfnetlink_queue as nf_queue handler for AF_INET\n"); #endif if (nfq_bind_pf(h, AF_INET) < 0) { fprintf(stderr, "error during nfq_bind_pf()\n"); exit(1); } #ifdef UFD_DEBUG printf("binding this socket to queue '0'\n"); #endif qh = nfq_create_queue(h, 0, &cb, NULL); if (!qh) { fprintf(stderr, "error during nfq_create_queue()\n"); exit(1); } #ifdef UFD_DEBUG printf("setting copy_packet mode\n"); #endif if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) { fprintf(stderr, "can't set packet_copy mode\n"); exit(1); } nh = nfq_nfnlh(h); return nfnl_fd(nh); }
static int OpenAndConfNFqueue(){ struct nfq_q_handle *myQueue; struct nfnl_handle *netlinkHandle; int fd = 0, e = 0; inet_pton(AF_INET, "239.255.255.250", &(ssdp.sin_addr)); /* Get a queue connection handle from the module */ if (!(nfqHandle = nfq_open())) { syslog(LOG_ERR, "Error in nfq_open(): %m"); return -1; } /* Unbind the handler from processing any IP packets Not totally sure why this is done, or if it's necessary... */ if ((e = nfq_unbind_pf(nfqHandle, AF_INET)) < 0) { syslog(LOG_ERR, "Error in nfq_unbind_pf(): %m"); return -1; } /* Bind this handler to process IP packets... */ if (nfq_bind_pf(nfqHandle, AF_INET) < 0) { syslog(LOG_ERR, "Error in nfq_bind_pf(): %m"); return -1; } /* Install a callback on queue -Q */ if (!(myQueue = nfq_create_queue(nfqHandle, nfqueue, &nfqueue_cb, NULL))) { syslog(LOG_ERR, "Error in nfq_create_queue(): %m"); return -1; } /* Turn on packet copy mode */ if (nfq_set_mode(myQueue, NFQNL_COPY_PACKET, 0xffff) < 0) { syslog(LOG_ERR, "Error setting packet copy mode (): %m"); return -1; } netlinkHandle = nfq_nfnlh(nfqHandle); fd = nfnl_fd(netlinkHandle); return fd; }
int main(int argc, char **argv) { struct nfq_handle *nfqHandle; struct nfq_q_handle *myQueue; struct nfnl_handle *netlinkHandle; int fd, res; char buf[BUFF_SIZE]; if (argc!=4) { fprintf(stderr,"Error in number of arguments\n"); exit(-1); } // get the public IP address. And the public IP address is host byte order. publicIP = inet_network(argv[1]); if (publicIP == 0) { fprintf(stderr,"Error in public IP\n"); exit(-1); } fprintf(stdout,"publicIP: %u\n",publicIP); // get the subnet IP address. And the subnet IP address is host byte order. internalIP = inet_network(argv[2]); if (internalIP == 0) { fprintf(stderr,"Error in internal IP\n"); exit(-1); } fprintf(stdout,"internalIP: %u\n",internalIP); mask = mask << (32-atoi(argv[3])); subnetIP = internalIP & mask; fprintf(stdout,"subnetIP: %u\n",subnetIP); initUdp( &udpHead ); initTcp( &tcpHead ); if ( !(nfqHandle = nfq_open())) { fprintf(stderr, "Error in nfq_open()\n"); exit(-1); } if ( nfq_unbind_pf(nfqHandle, AF_INET) < 0 ) { fprintf(stderr, "Error in nfq_unbind_pf()\n"); exit(-1); } if ( nfq_bind_pf(nfqHandle, AF_INET) < 0) { fprintf(stderr, "Error in nfq_bind_pf()\n"); exit(-1); } if ( !(myQueue = nfq_create_queue(nfqHandle, 0, &Callback123, NULL)) ) { fprintf(stderr, "Error in nfq_create_queue()\n"); exit(1); } if ( nfq_set_mode(myQueue, NFQNL_COPY_PACKET, 0xffff) <0 ) { fprintf(stderr, "Could not set packet copy mode\n"); exit(1); } netlinkHandle = nfq_nfnlh(nfqHandle); fd = nfnl_fd(netlinkHandle); fprintf(stdout,"ready to receive packets\n"); //Start to process the packet we receive. while ( (res = recv(fd, buf , sizeof(buf), 0)) && res>=0 ) { printf("\n\n\n*******NEW ONE*******\n"); fprintf(stdout,"in the loop\n"); nfq_handle_packet(nfqHandle, buf , res); } //End the process nfq_destroy_queue(myQueue); nfq_close(nfqHandle); return 0; }
TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen) { #ifndef OS_WIN32 struct timeval tv; int opt; #endif NFQQueueVars *nfq_q = NFQGetQueue(nfq_t->nfq_index); if (nfq_q == NULL) { SCLogError(SC_ERR_NFQ_OPEN, "no queue for given index"); return TM_ECODE_FAILED; } SCLogDebug("opening library handle"); nfq_q->h = nfq_open(); if (!nfq_q->h) { SCLogError(SC_ERR_NFQ_OPEN, "nfq_open() failed"); return TM_ECODE_FAILED; } if (nfq_g.unbind == 0) { /* VJ: on my Ubuntu Hardy system this fails the first time it's * run. Ignoring the error seems to have no bad effects. */ SCLogDebug("unbinding existing nf_queue handler for AF_INET (if any)"); if (nfq_unbind_pf(nfq_q->h, AF_INET) < 0) { SCLogError(SC_ERR_NFQ_UNBIND, "nfq_unbind_pf() for AF_INET failed"); exit(EXIT_FAILURE); } if (nfq_unbind_pf(nfq_q->h, AF_INET6) < 0) { SCLogError(SC_ERR_NFQ_UNBIND, "nfq_unbind_pf() for AF_INET6 failed"); exit(EXIT_FAILURE); } nfq_g.unbind = 1; SCLogDebug("binding nfnetlink_queue as nf_queue handler for AF_INET and AF_INET6"); if (nfq_bind_pf(nfq_q->h, AF_INET) < 0) { SCLogError(SC_ERR_NFQ_BIND, "nfq_bind_pf() for AF_INET failed"); exit(EXIT_FAILURE); } if (nfq_bind_pf(nfq_q->h, AF_INET6) < 0) { SCLogError(SC_ERR_NFQ_BIND, "nfq_bind_pf() for AF_INET6 failed"); exit(EXIT_FAILURE); } } SCLogInfo("binding this thread %d to queue '%" PRIu32 "'", nfq_t->nfq_index, nfq_q->queue_num); /* pass the thread memory as a void ptr so the * callback function has access to it. */ nfq_q->qh = nfq_create_queue(nfq_q->h, nfq_q->queue_num, &NFQCallBack, (void *)nfq_t); if (nfq_q->qh == NULL) { SCLogError(SC_ERR_NFQ_CREATE_QUEUE, "nfq_create_queue failed"); return TM_ECODE_FAILED; } SCLogDebug("setting copy_packet mode"); /* 05DC = 1500 */ //if (nfq_set_mode(nfq_t->qh, NFQNL_COPY_PACKET, 0x05DC) < 0) { if (nfq_set_mode(nfq_q->qh, NFQNL_COPY_PACKET, 0xFFFF) < 0) { SCLogError(SC_ERR_NFQ_SET_MODE, "can't set packet_copy mode"); return TM_ECODE_FAILED; } #ifdef HAVE_NFQ_MAXLEN if (queue_maxlen > 0) { SCLogInfo("setting queue length to %" PRId32 "", queue_maxlen); /* non-fatal if it fails */ if (nfq_set_queue_maxlen(nfq_q->qh, queue_maxlen) < 0) { SCLogWarning(SC_ERR_NFQ_MAXLEN, "can't set queue maxlen: your kernel probably " "doesn't support setting the queue length"); } } #endif /* HAVE_NFQ_MAXLEN */ #ifndef OS_WIN32 /* set netlink buffer size to a decent value */ nfnl_rcvbufsiz(nfq_nfnlh(nfq_q->h), queue_maxlen * 1500); SCLogInfo("setting nfnl bufsize to %" PRId32 "", queue_maxlen * 1500); nfq_q->nh = nfq_nfnlh(nfq_q->h); nfq_q->fd = nfnl_fd(nfq_q->nh); NFQMutexInit(nfq_q); /* Set some netlink specific option on the socket to increase performance */ opt = 1; #ifdef NETLINK_BROADCAST_SEND_ERROR setsockopt(nfq_q->fd, SOL_NETLINK, NETLINK_BROADCAST_SEND_ERROR, &opt, sizeof(int)); #endif /* Don't send error about no buffer space available but drop the packets instead */ #ifdef NETLINK_NO_ENOBUFS setsockopt(nfq_q->fd, SOL_NETLINK, NETLINK_NO_ENOBUFS, &opt, sizeof(int)); #endif #ifdef HAVE_NFQ_SET_QUEUE_FLAGS if (nfq_config.flags & NFQ_FLAG_FAIL_OPEN) { uint32_t flags = NFQA_CFG_F_FAIL_OPEN; uint32_t mask = NFQA_CFG_F_FAIL_OPEN; int r = nfq_set_queue_flags(nfq_q->qh, mask, flags); if (r == -1) { SCLogWarning(SC_ERR_NFQ_SET_MODE, "can't set fail-open mode: %s", strerror(errno)); } else { SCLogInfo("fail-open mode should be set on queue"); } } #endif /* set a timeout to the socket so we can check for a signal * in case we don't get packets for a longer period. */ tv.tv_sec = 1; tv.tv_usec = 0; if(setsockopt(nfq_q->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) { SCLogWarning(SC_ERR_NFQ_SETSOCKOPT, "can't set socket timeout: %s", strerror(errno)); } SCLogDebug("nfq_q->h %p, nfq_q->nh %p, nfq_q->qh %p, nfq_q->fd %" PRId32 "", nfq_q->h, nfq_q->nh, nfq_q->qh, nfq_q->fd); #else /* OS_WIN32 */ NFQMutexInit(nfq_q); nfq_q->ovr.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); nfq_q->fd = nfq_fd(nfq_q->h); SCLogDebug("nfq_q->h %p, nfq_q->qh %p, nfq_q->fd %p", nfq_q->h, nfq_q->qh, nfq_q->fd); #endif /* OS_WIN32 */ return TM_ECODE_OK; }
/* 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); }
/** * nflog_fd - get the file descriptor associated with the nflog handler * \param log handler obtained via call to nflog_open() * * \return a file descriptor for the netlink connection associated with the * given log connection handle. The file descriptor can then be used for * receiving the logged packets for processing. * * This function returns a file descriptor that can be used for communication * over the netlink connection associated with the given log connection * handle. */ int nflog_fd(struct nflog_handle *h) { return nfnl_fd(nflog_nfnlh(h)); }
int main(int argc, char **argv) { struct nfq_handle *h; struct nfq_q_handle *qh; struct nfnl_handle *nh; int fd; int rv; char buf[4096]; printf("opening library handle\n"); h = nfq_open(); if (!h) { fprintf(stderr, "error during nfq_open()\n"); exit(1); } printf("unbinding existing nf_queue handler for AF_INET (if any)\n"); if (nfq_unbind_pf(h, AF_INET) < 0) { fprintf(stderr, "error during nfq_unbind_pf()\n"); exit(1); } printf("binding nfnetlink_queue as nf_queue handler for AF_INET\n"); if (nfq_bind_pf(h, AF_INET) < 0) { fprintf(stderr, "error during nfq_bind_pf()\n"); exit(1); } printf("binding this socket to queue '0'\n"); qh = nfq_create_queue(h, 0, &cb, NULL); if (!qh) { fprintf(stderr, "error during nfq_create_queue()\n"); exit(1); } printf("setting copy_packet mode\n"); if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) { fprintf(stderr, "can't set packet_copy mode\n"); exit(1); } nh = nfq_nfnlh(h); fd = nfnl_fd(nh); while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) { printf("pkt received\n"); nfq_handle_packet(h, buf, rv); } printf("unbinding from queue 0\n"); nfq_destroy_queue(qh); #ifdef INSANE /* normally, applications SHOULD NOT issue this command, since * it detaches other programs/sockets from AF_INET, too ! */ printf("unbinding from AF_INET\n"); nfq_unbind_pf(h, AF_INET); #endif printf("closing library handle\n"); nfq_close(h); exit(0); }
int nfct_fd(struct nfct_handle *cth) { return nfnl_fd(cth->nfnlh); }
int main(int argc, char **argv) { struct nfq_handle *h; struct nfq_q_handle *qh; struct nfnl_handle *nh; int fd; int rv; int argument; char buf[BUFSIZE]; char *pcap_destination; pcap_t *pd; /*! process arguments */ while ( -1 != (argument = getopt (argc, argv, "o:h"))) { switch (argument) { case 'o' : pcap_destination = (char *) malloc(strlen(optarg) * sizeof(char)); memcpy(pcap_destination,optarg,strlen(optarg)); fprintf(stdout,"pcap recording into %s\n",pcap_destination); use_pcap = 1; break; case 'h': fprintf(stdout,"nfqueue_recorder: record/display traffic passing through a netfilter queue\n\n" "-h: this help\n" "-o <file> : record in pcap <file>\n" "\nroute traffic to it using the NFQUEUE target\n" "\tiptables -I INPUT -p tcp --dport 443 -j NFQUEUE\n" "\tiptables -I FORWARD -j NFQUEUE\n" "\nex: ./nfqueue_recorder -o traffic.pcap\n"); return 0; default: fprintf(stdout,"use -h for help\n"); return -1; } } /*! open dump file * using DLT_RAW because iptables does not give us datalink layer */ if(use_pcap == 1){ fprintf(stdout,"opening pcap file at %s\n",pcap_destination); pd = pcap_open_dead(DLT_RAW, BUFSIZE); p_output = pcap_dump_open(pd,pcap_destination); if (!p_output){ fprintf(stderr, "error while opening pcap file\n"); exit(1); } } printf("opening library handle\n"); h = nfq_open(); if (!h) { fprintf(stderr, "error during nfq_open()\n"); exit(1); } printf("unbinding existing nf_queue handler for AF_INET (if any)\n"); if (nfq_unbind_pf(h, AF_INET) < 0) { fprintf(stderr, "error during nfq_unbind_pf()\n"); exit(1); } printf("binding nfnetlink_queue as nf_queue handler for AF_INET\n"); if (nfq_bind_pf(h, AF_INET) < 0) { fprintf(stderr, "error during nfq_bind_pf()\n"); exit(1); } printf("binding this socket to queue '0'\n"); qh = nfq_create_queue(h, 0, &cb, NULL); if (!qh) { fprintf(stderr, "error during nfq_create_queue()\n"); exit(1); } printf("setting copy_packet mode\n"); if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) { fprintf(stderr, "can't set packet_copy mode\n"); exit(1); } nh = nfq_nfnlh(h); fd = nfnl_fd(nh); while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) { printf("-- New packet received --\n"); nfq_handle_packet(h, buf, rv); } printf("unbinding from queue 0\n"); nfq_destroy_queue(qh); #ifdef INSANE /* normally, applications SHOULD NOT issue this command, since * it detaches other programs/sockets from AF_INET, too ! */ printf("unbinding from AF_INET\n"); nfq_unbind_pf(h, AF_INET); #endif printf("closing library handle\n"); nfq_close(h); exit(0); }
int main(int argc, char* argv[]) { struct nfq_handle *handle = NULL; struct nfq_q_handle *queue = NULL; struct nfnl_handle *netlink_handle = NULL; struct sigaction action; uint32_t nfqueue_fd = 0; int err = 0; const char* traffic_tap_cat = sff-tap.log"; /* * ----------------------------------------------------------- * Daemonize so that we run in the background * ----------------------------------------------------------- */ int pid; if(getppid() == 1) { printf("No parent PID already a daemon"); exit(0); } pid = fork(); if(pid < 0) { printf("Fork failed"); exit(-1); } if(pid > 0) { /* The parent */ exit(0); } err = init_log4c(); if(err) { return err; } log4c_cat = log4c_category_get(traffic_tap_cat); if (!log4c_cat) { printf("Failed to get log4c category: %s\n", traffic_tap_cat); uninit_log4c(); return TRAFFIC_TAP_INIT_ERROR; } /* Set up handler for SIGTERM for graceful shutdown */ memset(&action, 0, sizeof(struct sigaction)); action.sa_handler = sig_handler; sigaction(SIGTERM, &action, NULL); /* Initialize NF_QUEUE stuff */ handle = nfq_open(); if(!handle) { log4c_category_log(log4c_cat, LOG4C_PRIORITY_ERROR, "Error initializing sff-tap: during nfq_open()"); uninit_log4c(); return SFF_TAP_INIT_ERROR; } if(nfq_unbind_pf(handle, AF_INET) < 0) { log4c_category_log(log4c_cat, LOG4C_PRIORITY_ERROR, "Error initializing sff-tap: during nfq_unbind_pf()"); uninit_log4c(); return SFF_TAP_INIT_ERROR; } if(nfq_bind_pf(handle, AF_INET) < 0) { log4c_category_log(log4c_cat, LOG4C_PRIORITY_ERROR, "Error initializing sff-tap: during nfq_bind_pf()"); uninit_log4c(); return SFF_TAP_INIT_ERROR; } queue = nfq_create_queue(handle, 0, &manage_packet, NULL); if(!queue) { log4c_category_log(log4c_cat, LOG4C_PRIORITY_ERROR, "Error initializing traffic-tap: during nfq_create_queue()"); uninit_log4c(); return SFF_TAP_INIT_ERROR; } if(nfq_set_mode(queue, NFQNL_COPY_PACKET, 0xffff) < 0) { log4c_category_log(log4c_cat, LOG4C_PRIORITY_ERROR, "Error initializing traffic-tap: can't set packet_copy mode"); uninit_log4c(); return SFF_TAP_INIT_ERROR; } netlink_handle = nfq_nfnlh(handle); nfqueue_fd = nfnl_fd(netlink_handle); log4c_category_log(log4c_cat, LOG4C_PRIORITY_NOTICE, "Tap initialized successfully."); while(!exit_flag) { char rcv_buf[RCV_BUF_SIZE]; int received; if((received = recv(nfqueue_fd, rcv_buf, sizeof(rcv_buf), 0)) >= 0 ) { // Call the handle nfq_handle_packet(handle, rcv_buf, received); } } log4c_category_log(log4c_cat, LOG4C_PRIORITY_NOTICE, "SIGTERM caught in tap; exiting."); if(queue != NULL) { nfq_destroy_queue(queue); } if(handle != NULL) { nfq_close(handle); } err = uninit_log4c(); return err; }
// loop to process a received packet at the queue // ---------------------------------------------- short int netlink_loop(unsigned short int queuenum) { int fd, rv; char buf[MAX_PKTSIZE]; struct queues_t *queue; pthread_mutex_lock(&mutexusock); queue = malloc(sizeof(struct queues_t)); // opening library handle queue->nfqh = nfq_open(); if (!queue->nfqh) error(ERR, 0, "Error during nfq_open()\n"); // unbinding existing nf_queue handler for AF_INET (if any) // an error with Kernel 2.6.23 or above --> commented 2 lines if (nfq_unbind_pf(queue->nfqh, AF_INET) < 0) error(ERR, 0, "Error during nfq_unbind_pf()\n"); // binds the given queue connection handle to process packets. if (nfq_bind_pf(queue->nfqh, AF_INET) < 0) error(ERR, 0, "Error during nfq_bind_pf()\n"); printf("NFQUEUE: binding to queue '%hd'\n", queuenum); // create queue queue->qh = nfq_create_queue(queue->nfqh, queuenum, &nfqueue_cb, NULL); if (!queue->qh) error(ERR, 0, "Error during nfq_create_queue()\n"); // sets the amount of data to be copied to userspace for each packet queued // to the given queue. if (nfq_set_mode(queue->qh, NFQNL_COPY_PACKET, MAX_PKTSIZE) < 0) error(ERR, 0, "Can't set packet_copy mode\n"); // Set kernel queue maximum length parameter if (nfq_set_queue_maxlen(queue->qh, MAX_QUEUE_LEN) < 0) error(ERR, 0, "Can't set max len of queue\n"); // returns the netlink handle associated with the given queue connection handle. // Possibly useful if you wish to perform other netlink communication // directly after opening a queue without opening a new netlink connection to do so queue->nh = nfq_nfnlh(queue->nfqh); queue->next = queues; queues = queue; pthread_mutex_unlock(&mutexusock); // returns a file descriptor for the netlink connection associated with the // given queue connection handle. The file descriptor can then be used for // receiving the queued packets for processing. fd = nfnl_fd(queue->nh); while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) { // triggers an associated callback for the given packet received from the queue. // Packets can be read from the queue using nfq_fd() and recv(). nfq_handle_packet(queue->nfqh, buf, rv); memset(buf, 0x0, sizeof(buf)); for (;;) { if ((rv = recv(fd, buf, sizeof(buf), 0)) >= 0) { nfq_handle_packet(queue->nfqh, buf, rv); memset(buf, 0x0, sizeof(buf)); continue; } /* if the computer is slower than the network the buffer * may fill up. Depending on the application, this error * may be ignored */ if (errno == ENOBUFS) { printf("packet lost!!\n"); continue; } printf("NFQUEUE: recv failed: errno=%d (%s)\n", errno, strerror(errno)); } } // unbinding before exit printf("NFQUEUE: unbinding from queue '%hd'\n", queuenum); nfq_destroy_queue(queue->qh); nfq_close(queue->nfqh); return OK; }