/* libnetfilter_queue.c: generic library for access to nf_queue * * (C) 2005 by Harald Welte * (C) 2005, 2008-2010 by Pablo Neira Ayuso * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation (or any later at your option) * * This program 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. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * 2006-01-23 Andreas Florath * Fix __set_verdict() that it can now handle payload. */ #include #include #include #include #include #include #include #include #include #include #include #include "internal.h" /** * \mainpage * * libnetfilter_queue is a userspace library providing an API to packets that * have been queued by the kernel packet filter. It is is part of a system that * deprecates the old ip_queue / libipq mechanism. * * libnetfilter_queue homepage is: * http://netfilter.org/projects/libnetfilter_queue/ * * \section Dependencies * libnetfilter_queue requires libnfnetlink and a kernel that includes the * nfnetlink_queue subsystem (i.e. 2.6.14 or later). * * \section Main Features * - receiving queued packets from the kernel nfnetlink_queue subsystem * - issuing verdicts and/or reinjecting altered packets to the kernel * nfnetlink_queue subsystem * * The cinematic is the following: When an iptables rules with target NFQUEUE * matches, the kernel en-queued the packet in a chained list. It then format * a nfnetlink message and sends the information (packet data , packet id and * metadata) via a socket to the software connected to the queue. The software * can then read the message. * * To remove the packet from the queue, the userspace software must issue a * verdict asking kernel to accept or drop the packet. Userspace can also alter * the packet. Verdict can be done in asynchronous manner, as the only needed * information is the packet id. * * When a queue is full, packets that should have been en-queued are dropped by * kernel instead of being en-queued. * * \section Git Tree * The current development version of libnetfilter_queue can be accessed * at https://git.netfilter.org/cgi-bin/gitweb.cgi?p=libnetfilter_queue.git;a=summary. * * \section Privileges * You need the CAP_NET_ADMIN capability in order to allow your application * to receive from and to send packets to kernel-space. * * \section Using libnetfilter_queue * * To write your own program using libnetfilter_queue, you should start by reading * the doxygen documentation (start by \link LibrarySetup \endlink page) and * nf-queue.c source file. * * Another source of information on libnetfilter_queue usage is the following * article: * https://home.regit.org/netfilter-en/using-nfqueue-and-libnetfilter_queue/ * * \section errors ENOBUFS errors in recv() * * recv() may return -1 and errno is set to ENOBUFS in case that your * application is not fast enough to retrieve the packets from the kernel. * In that case, you can increase the socket buffer size by means of * nfnl_rcvbufsiz(). Although this delays the appearance of ENOBUFS errors, * you may hit it again sooner or later. The next section provides some hints * on how to obtain the best performance for your application. * * \section perf Performance * To improve your libnetfilter_queue application in terms of performance, * you may consider the following tweaks: * * - increase the default socket buffer size by means of nfnl_rcvbufsiz(). * - set nice value of your process to -20 (maximum priority). * - set the CPU affinity of your process to a spare core that is not used * to handle NIC interruptions. * - set NETLINK_NO_ENOBUFS socket option to avoid receiving ENOBUFS errors * (requires Linux kernel >= 2.6.30). * - see --queue-balance option in NFQUEUE target for multi-threaded apps * (it requires Linux kernel >= 2.6.31). * - consider using fail-open option see nfq_set_queue_flags() (it requires * Linux kernel >= 3.6) * - increase queue max length with nfq_set_queue_maxlen() to resist to packets * burst */ struct nfq_handle { struct nfnl_handle *nfnlh; struct nfnl_subsys_handle *nfnlssh; struct nfq_q_handle *qh_list; }; struct nfq_q_handle { struct nfq_q_handle *next; struct nfq_handle *h; uint16_t id; nfq_callback *cb; void *data; }; struct nfq_data { struct nfattr **data; }; int nfq_errno; EXPORT_SYMBOL(nfq_errno); /*********************************************************************** * low level stuff ***********************************************************************/ static void del_qh(struct nfq_q_handle *qh) { struct nfq_q_handle *cur_qh, *prev_qh = NULL; for (cur_qh = qh->h->qh_list; cur_qh; cur_qh = cur_qh->next) { if (cur_qh == qh) { if (prev_qh) prev_qh->next = qh->next; else qh->h->qh_list = qh->next; return; } prev_qh = cur_qh; } } static void add_qh(struct nfq_q_handle *qh) { qh->next = qh->h->qh_list; qh->h->qh_list = qh; } static struct nfq_q_handle *find_qh(struct nfq_handle *h, uint16_t id) { struct nfq_q_handle *qh; for (qh = h->qh_list; qh; qh = qh->next) { if (qh->id == id) return qh; } return NULL; } /* build a NFQNL_MSG_CONFIG message */ static int __build_send_cfg_msg(struct nfq_handle *h, uint8_t command, uint16_t queuenum, uint16_t pf) { union { char buf[NFNL_HEADER_LEN +NFA_LENGTH(sizeof(struct nfqnl_msg_config_cmd))]; struct nlmsghdr nmh; } u; struct nfqnl_msg_config_cmd cmd; nfnl_fill_hdr(h->nfnlssh, &u.nmh, 0, AF_UNSPEC, queuenum, NFQNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK); cmd._pad = 0; cmd.command = command; cmd.pf = htons(pf); nfnl_addattr_l(&u.nmh, sizeof(u), NFQA_CFG_CMD, &cmd, sizeof(cmd)); return nfnl_query(h->nfnlh, &u.nmh); } static int __nfq_rcv_pkt(struct nlmsghdr *nlh, struct nfattr *nfa[], void *data) { struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); struct nfq_handle *h = data; uint16_t queue_num = ntohs(nfmsg->res_id); struct nfq_q_handle *qh = find_qh(h, queue_num); struct nfq_data nfqa; if (!qh) return -ENODEV; if (!qh->cb) return -ENODEV; nfqa.data = nfa; return qh->cb(qh, nfmsg, &nfqa, qh->data); } /* public interface */ struct nfnl_handle *nfq_nfnlh(struct nfq_handle *h) { return h->nfnlh; } EXPORT_SYMBOL(nfq_nfnlh); /** * * \defgroup Queue Queue handling [DEPRECATED] * * Once libnetfilter_queue library has been initialised (See * \link LibrarySetup \endlink), it is possible to bind the program to a * specific queue. This can be done by using nfq_create_queue(). * * The queue can then be tuned via nfq_set_mode() or nfq_set_queue_maxlen(). * * Here's a little code snippet that create queue numbered 0: * \verbatim 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); } \endverbatim * * Next step is the handling of incoming packets which can be done via a loop: * * \verbatim fd = nfq_fd(h); while ((rv = recv(fd, buf, sizeof(buf), 0)) >= 0) { printf("pkt received\n"); nfq_handle_packet(h, buf, rv); } \endverbatim * When the decision on a packet has been choosed, the verdict has to be given * by calling nfq_set_verdict() or nfq_set_verdict2(). The verdict * determines the destiny of the packet as follows: * * - NF_DROP discarded the packet * - NF_ACCEPT the packet passes, continue iterations * - NF_QUEUE inject the packet into a different queue * (the target queue number is in the high 16 bits of the verdict) * - NF_REPEAT iterate the same cycle once more * - NF_STOP accept, but don't continue iterations * * The verdict NF_STOLEN must not be used, as it has special meaning in the * kernel. * When using NF_REPEAT, one way to prevent re-queueing of the same packet * is to also set an nfmark using nfq_set_verdict2, and set up the nefilter * rules to only queue a packet when the mark is not (yet) set. * * Data and information about the packet can be fetch by using message parsing * functions (See \link Parsing \endlink). * @{ */ /** * nfq_fd - get the file descriptor associated with the nfqueue handler * \param h Netfilter queue connection handle obtained via call to nfq_open() * * \return 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. * * This function returns a file descriptor that can be used for communication * over the netlink connection associated with the given queue connection * handle. */ int nfq_fd(struct nfq_handle *h) { return nfnl_fd(nfq_nfnlh(h)); } EXPORT_SYMBOL(nfq_fd); /** * @} */ /** * \defgroup LibrarySetup Library setup [DEPRECATED] * * Library initialisation is made in two steps. * * First step is to call nfq_open() to open a NFQUEUE handler. * * Second step is to tell the kernel that userspace queueing is handle by * NFQUEUE for the selected protocol. This is made by calling nfq_unbind_pf() * and nfq_bind_pf() with protocol information. The idea behind this is to * enable simultaneously loaded modules to be used for queuing. * * Here's a little code snippet that bind with AF_INET: * \verbatim 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); } \endverbatim * Once this is done, you can setup and use a \link Queue \endlink. * @{ */ /** * nfq_open - open a nfqueue handler * * This function obtains a netfilter queue connection handle. When you are * finished with the handle returned by this function, you should destroy * it by calling nfq_close(). A new netlink connection is obtained internally * and associated with the queue connection handle returned. * * \return a pointer to a new queue handle or NULL on failure. */ struct nfq_handle *nfq_open(void) { struct nfnl_handle *nfnlh = nfnl_open(); struct nfq_handle *qh; if (!nfnlh) return NULL; /* unset netlink sequence tracking by default */ nfnl_unset_sequence_tracking(nfnlh); qh = nfq_open_nfnl(nfnlh); if (!qh) nfnl_close(nfnlh); return qh; } EXPORT_SYMBOL(nfq_open); /** * @} */ /** * nfq_open_nfnl - open a nfqueue handler from a existing nfnetlink handler * \param nfnlh Netfilter netlink connection handle obtained by calling nfnl_open() * * This function obtains a netfilter queue connection handle using an existing * netlink connection. This function is used internally to implement * nfq_open(), and should typically not be called directly. * * \return a pointer to a new queue handle or NULL on failure. */ struct nfq_handle *nfq_open_nfnl(struct nfnl_handle *nfnlh) { struct nfnl_callback pkt_cb = { .call = __nfq_rcv_pkt, .attr_count = NFQA_MAX, }; struct nfq_handle *h; int err; h = malloc(sizeof(*h)); if (!h) return NULL; memset(h, 0, sizeof(*h)); h->nfnlh = nfnlh; h->nfnlssh = nfnl_subsys_open(h->nfnlh, NFNL_SUBSYS_QUEUE, NFQNL_MSG_MAX, 0); if (!h->nfnlssh) { /* FIXME: nfq_errno */ goto out_free; } pkt_cb.data = h; err = nfnl_callback_register(h->nfnlssh, NFQNL_MSG_PACKET, &pkt_cb); if (err < 0) { nfq_errno = err; goto out_close; } return h; out_close: nfnl_subsys_close(h->nfnlssh); out_free: free(h); return NULL; } EXPORT_SYMBOL(nfq_open_nfnl); /** * \addtogroup LibrarySetup * * When the program has finished with libnetfilter_queue, it has to call * the nfq_close() function to free all associated resources. * * @{ */ /** * nfq_close - close a nfqueue handler * \param h Netfilter queue connection handle obtained via call to nfq_open() * * This function closes the nfqueue handler and free associated resources. * * \return 0 on success, non-zero on failure. */ int nfq_close(struct nfq_handle *h) { int ret; ret = nfnl_close(h->nfnlh); if (ret == 0) free(h); return ret; } EXPORT_SYMBOL(nfq_close); /** * nfq_bind_pf - bind a nfqueue handler to a given protocol family * \param h Netfilter queue connection handle obtained via call to nfq_open() * \param pf protocol family to bind to nfqueue handler obtained from nfq_open() * * Binds the given queue connection handle to process packets belonging to * the given protocol family (ie. PF_INET, PF_INET6, etc). * This call is obsolete, Linux kernels from 3.8 onwards ignore it. * * \return integer inferior to 0 in case of failure */ int nfq_bind_pf(struct nfq_handle *h, uint16_t pf) { return __build_send_cfg_msg(h, NFQNL_CFG_CMD_PF_BIND, 0, pf); } EXPORT_SYMBOL(nfq_bind_pf); /** * nfq_unbind_pf - unbind nfqueue handler from a protocol family * \param h Netfilter queue connection handle obtained via call to nfq_open() * \param pf protocol family to unbind family from * * Unbinds the given queue connection handle from processing packets belonging * to the given protocol family. * * This call is obsolete, Linux kernels from 3.8 onwards ignore it. */ int nfq_unbind_pf(struct nfq_handle *h, uint16_t pf) { return __build_send_cfg_msg(h, NFQNL_CFG_CMD_PF_UNBIND, 0, pf); } EXPORT_SYMBOL(nfq_unbind_pf); /** * @} */ /** * \addtogroup Queue * @{ */ /** * nfq_create_queue - create a new queue handle and return it. * * \param h Netfilter queue connection handle obtained via call to nfq_open() * \param num the number of the queue to bind to * \param cb callback function to call for each queued packet * \param data custom data to pass to the callback function * * \return a nfq_q_handle pointing to the newly created queue * * Creates a new queue handle, and returns it. The new queue is identified by * #num, and the callback specified by #cb will be called for each enqueued * packet. The #data argument will be passed unchanged to the callback. If * a queue entry with id #num already exists, this function will return failure * and the existing entry is unchanged. * * The nfq_callback type is defined in libnetfilter_queue.h as: * \verbatim typedef int nfq_callback(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfad, void *data); \endverbatim * * Parameters: * - qh The queue handle returned by nfq_create_queue * - nfmsg message objetc that contains the packet * - nfad Netlink packet data handle * - data the value passed to the data parameter of nfq_create_queue * * The callback should return < 0 to stop processing. */ struct nfq_q_handle *nfq_create_queue(struct nfq_handle *h, uint16_t num, nfq_callback *cb, void *data) { int ret; struct nfq_q_handle *qh; if (find_qh(h, num)) return NULL; qh = malloc(sizeof(*qh)); if (!qh) return NULL; memset(qh, 0, sizeof(*qh)); qh->h = h; qh->id = num; qh->cb = cb; qh->data = data; ret = __build_send_cfg_msg(h, NFQNL_CFG_CMD_BIND, num, 0); if (ret < 0) { nfq_errno = ret; free(qh); return NULL; } add_qh(qh); return qh; } EXPORT_SYMBOL(nfq_create_queue); /** * @} */ /** * \addtogroup Queue * @{ */ /** * nfq_destroy_queue - destroy a queue handle * \param qh queue handle that we want to destroy created via nfq_create_queue * * Removes the binding for the specified queue handle. This call also unbind * from the nfqueue handler, so you don't have to call nfq_unbind_pf. */ int nfq_destroy_queue(struct nfq_q_handle *qh) { int ret = __build_send_cfg_msg(qh->h, NFQNL_CFG_CMD_UNBIND, qh->id, 0); if (ret == 0) { del_qh(qh); free(qh); } return ret; } EXPORT_SYMBOL(nfq_destroy_queue); /** * nfq_handle_packet - handle a packet received from the nfqueue subsystem * \param h Netfilter queue connection handle obtained via call to nfq_open() * \param buf data to pass to the callback * \param len length of packet data in buffer * * Triggers an associated callback for the given packet received from the * queue. Packets can be read from the queue using nfq_fd() and recv(). See * example code for nfq_fd(). * * \return 0 on success, non-zero on failure. */ int nfq_handle_packet(struct nfq_handle *h, char *buf, int len) { return nfnl_handle_packet(h->nfnlh, buf, len); } EXPORT_SYMBOL(nfq_handle_packet); /** * nfq_set_mode - set the amount of packet data that nfqueue copies to userspace * \param qh Netfilter queue handle obtained by call to nfq_create_queue(). * \param mode the part of the packet that we are interested in * \param range size of the packet that we want to get * * Sets the amount of data to be copied to userspace for each packet queued * to the given queue. * * - NFQNL_COPY_NONE - noop, do not use it * - NFQNL_COPY_META - copy only packet metadata * - NFQNL_COPY_PACKET - copy entire packet * * \return -1 on error; >=0 otherwise. */ int nfq_set_mode(struct nfq_q_handle *qh, uint8_t mode, uint32_t range) { union { char buf[NFNL_HEADER_LEN +NFA_LENGTH(sizeof(struct nfqnl_msg_config_params))]; struct nlmsghdr nmh; } u; struct nfqnl_msg_config_params params; nfnl_fill_hdr(qh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, qh->id, NFQNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK); params.copy_range = htonl(range); params.copy_mode = mode; nfnl_addattr_l(&u.nmh, sizeof(u), NFQA_CFG_PARAMS, ¶ms, sizeof(params)); return nfnl_query(qh->h->nfnlh, &u.nmh); } EXPORT_SYMBOL(nfq_set_mode); /** * nfq_set_queue_flags - set flags (options) for the kernel queue * \param qh Netfilter queue handle obtained by call to nfq_create_queue(). * \param mask specifies which flag bits to modify * \param flag bitmask of flags * * Existing flags, that you may want to combine, are: * * - NFQA_CFG_F_FAIL_OPEN (requires Linux kernel >= 3.6): the kernel will * accept the packets if the kernel queue gets full. If this flag is not * set, the default action in this case is to drop packets. * * - NFQA_CFG_F_CONNTRACK (requires Linux kernel >= 3.6): the kernel will * include the Connection Tracking system information. * * - NFQA_CFG_F_GSO (requires Linux kernel >= 3.10): the kernel will * not normalize offload packets, i.e. your application will need to * be able to handle packets larger than the mtu. * * Normalization is expensive, so this flag should always be set. * Because attributes in netlink messages are limited to 65531 bytes, * you also need to check the NFQA_CAP_LEN attribute, it contains the * original size of the captured packet on the kernel side. * If it is set and differs from the payload length, the packet was * truncated. This also happens when limiting capture size * with the NFQNL_COPY_PACKET setting, or when e.g. a local user * sends a very large packet. * * If your application validates checksums (e.g., tcp checksum), * then you must also check if the NFQA_SKB_INFO attribute is present. * If it is, you need to test the NFQA_SKB_CSUMNOTREADY bit: * \verbatim if (attr[NFQA_SKB_INFO]) { uint32_t info = ntohl(mnl_attr_get_u32(attr[NFQA_SKB_INFO])); if (info & NFQA_SKB_CSUMNOTREADY) validate_checksums = false; } \endverbatim * if this bit is set, the layer 3/4 checksums of the packet appear incorrect, * but are not (because they will be corrected later by the kernel). * Please see example/nf-queue.c in the libnetfilter_queue source for more * details. * * - NFQA_CFG_F_UID_GID: the kernel will dump UID and GID of the socket to * which each packet belongs. * * Here's a little code snippet to show how to use this API: * \verbatim uint32_t flags = NFQA_CFG_F_FAIL_OPEN; uint32_t mask = NFQA_CFG_F_FAIL_OPEN; printf("Enabling fail-open on this q\n"); err = nfq_set_queue_flags(qh, mask, flags); printf("Disabling fail-open on this q\n"); flags &= ~NFQA_CFG_F_FAIL_OPEN; err = nfq_set_queue_flags(qh, mask, flags); \endverbatim * - NFQA_CFG_F_SECCTX: the kernel will dump security context of the socket to * which each packet belongs. * * \warning * When fragmentation occurs and NFQA_CFG_F_GSO is NOT set then the kernel * dumps UID/GID and security context fields only for one fragment. To deal * with this limitation always set NFQA_CFG_F_GSO. * * \return -1 on error with errno set appropriately; =0 otherwise. */ int nfq_set_queue_flags(struct nfq_q_handle *qh, uint32_t mask, uint32_t flags) { union { char buf[NFNL_HEADER_LEN +NFA_LENGTH(sizeof(mask) +NFA_LENGTH(sizeof(flags)))]; struct nlmsghdr nmh; } u; mask = htonl(mask); flags = htonl(flags); nfnl_fill_hdr(qh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, qh->id, NFQNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK); nfnl_addattr32(&u.nmh, sizeof(u), NFQA_CFG_FLAGS, flags); nfnl_addattr32(&u.nmh, sizeof(u), NFQA_CFG_MASK, mask); return nfnl_query(qh->h->nfnlh, &u.nmh); } EXPORT_SYMBOL(nfq_set_queue_flags); /** * nfq_set_queue_maxlen - Set kernel queue maximum length parameter * \param qh Netfilter queue handle obtained by call to nfq_create_queue(). * \param queuelen the length of the queue * * Sets the size of the queue in kernel. This fixes the maximum number * of packets the kernel will store before internally before dropping * upcoming packets. * * \return -1 on error; >=0 otherwise. */ int nfq_set_queue_maxlen(struct nfq_q_handle *qh, uint32_t queuelen) { union { char buf[NFNL_HEADER_LEN +NFA_LENGTH(sizeof(struct nfqnl_msg_config_params))]; struct nlmsghdr nmh; } u; uint32_t queue_maxlen = htonl(queuelen); nfnl_fill_hdr(qh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, qh->id, NFQNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK); nfnl_addattr_l(&u.nmh, sizeof(u), NFQA_CFG_QUEUE_MAXLEN, &queue_maxlen, sizeof(queue_maxlen)); return nfnl_query(qh->h->nfnlh, &u.nmh); } EXPORT_SYMBOL(nfq_set_queue_maxlen); /** * @} */ static int __set_verdict(struct nfq_q_handle *qh, uint32_t id, uint32_t verdict, uint32_t mark, int set_mark, uint32_t data_len, const unsigned char *data, enum nfqnl_msg_types type) { struct nfqnl_msg_verdict_hdr vh; union { char buf[NFNL_HEADER_LEN +NFA_LENGTH(sizeof(mark)) +NFA_LENGTH(sizeof(vh))]; struct nlmsghdr nmh; } u; struct iovec iov[3]; int nvecs; /* This must be declared here (and not inside the data * handling block) because the iovec points to this. */ struct nfattr data_attr; memset(iov, 0, sizeof(iov)); vh.verdict = htonl(verdict); vh.id = htonl(id); nfnl_fill_hdr(qh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, qh->id, type, NLM_F_REQUEST); /* add verdict header */ nfnl_addattr_l(&u.nmh, sizeof(u), NFQA_VERDICT_HDR, &vh, sizeof(vh)); if (set_mark) nfnl_addattr32(&u.nmh, sizeof(u), NFQA_MARK, mark); iov[0].iov_base = &u.nmh; iov[0].iov_len = NLMSG_TAIL(&u.nmh) - (void *)&u.nmh; nvecs = 1; if (data_len) { /* The typecast here is to cast away data's const-ness: */ nfnl_build_nfa_iovec(&iov[1], &data_attr, NFQA_PAYLOAD, data_len, (unsigned char *) data); nvecs += 2; /* Add the length of the appended data to the message * header. The size of the attribute is given in the * nfa_len field and is set in the nfnl_build_nfa_iovec() * function. */ u.nmh.nlmsg_len += data_attr.nfa_len; } return nfnl_sendiov(qh->h->nfnlh, iov, nvecs, 0); } /** * \addtogroup Queue * @{ */ /** * nfq_set_verdict - issue a verdict on a packet * \param qh Netfilter queue handle obtained by call to nfq_create_queue(). * \param id ID assigned to packet by netfilter. * \param verdict verdict to return to netfilter (NF_ACCEPT, NF_DROP) * \param data_len number of bytes of data pointed to by #buf * \param buf the buffer that contains the packet data * * Can be obtained by: * \verbatim int id; struct nfqnl_msg_packet_hdr *ph = nfq_get_msg_packet_hdr(tb); if (ph) id = ntohl(ph->packet_id); \endverbatim * * Notifies netfilter of the userspace verdict for the given packet. Every * queued packet _must_ have a verdict specified by userspace, either by * calling this function, the nfq_set_verdict2() function, or the _batch * versions of these functions. * * \return -1 on error; >= 0 otherwise. */ int nfq_set_verdict(struct nfq_q_handle *qh, uint32_t id, uint32_t verdict, uint32_t data_len, const unsigned char *buf) { return __set_verdict(qh, id, verdict, 0, 0, data_len, buf, NFQNL_MSG_VERDICT); } EXPORT_SYMBOL(nfq_set_verdict); /** * nfq_set_verdict2 - like nfq_set_verdict, but you can set the mark. * \param qh Netfilter queue handle obtained by call to nfq_create_queue(). * \param id ID assigned to packet by netfilter. * \param verdict verdict to return to netfilter (NF_ACCEPT, NF_DROP) * \param mark mark to put on packet * \param data_len number of bytes of data pointed to by #buf * \param buf the buffer that contains the packet data */ int nfq_set_verdict2(struct nfq_q_handle *qh, uint32_t id, uint32_t verdict, uint32_t mark, uint32_t data_len, const unsigned char *buf) { return __set_verdict(qh, id, verdict, htonl(mark), 1, data_len, buf, NFQNL_MSG_VERDICT); } EXPORT_SYMBOL(nfq_set_verdict2); /** * nfq_set_verdict_batch - issue verdicts on several packets at once * \param qh Netfilter queue handle obtained by call to nfq_create_queue(). * \param id maximum ID of the packets that the verdict should be applied to. * \param verdict verdict to return to netfilter (NF_ACCEPT, NF_DROP) * * Unlike nfq_set_verdict, the verdict is applied to all queued packets * whose packet id is smaller or equal to #id. * * batch support was added in Linux 3.1. * These functions will fail silently on older kernels. */ int nfq_set_verdict_batch(struct nfq_q_handle *qh, uint32_t id, uint32_t verdict) { return __set_verdict(qh, id, verdict, 0, 0, 0, NULL, NFQNL_MSG_VERDICT_BATCH); } EXPORT_SYMBOL(nfq_set_verdict_batch); /** * nfq_set_verdict_batch2 - like nfq_set_verdict_batch, but you can set a mark. * \param qh Netfilter queue handle obtained by call to nfq_create_queue(). * \param id maximum ID of the packets that the verdict should be applied to. * \param verdict verdict to return to netfilter (NF_ACCEPT, NF_DROP) * \param mark mark to put on packet */ int nfq_set_verdict_batch2(struct nfq_q_handle *qh, uint32_t id, uint32_t verdict, uint32_t mark) { return __set_verdict(qh, id, verdict, htonl(mark), 1, 0, NULL, NFQNL_MSG_VERDICT_BATCH); } EXPORT_SYMBOL(nfq_set_verdict_batch2); /** * nfq_set_verdict_mark - like nfq_set_verdict, but you can set the mark. * \param qh Netfilter queue handle obtained by call to nfq_create_queue(). * \param id ID assigned to packet by netfilter. * \param verdict verdict to return to netfilter (NF_ACCEPT, NF_DROP) * \param mark the mark to put on the packet, in network byte order. * \param data_len number of bytes of data pointed to by #buf * \param buf the buffer that contains the packet data * * \return -1 on error; >= 0 otherwise. * * This function is deprecated since it is broken, its use is highly * discouraged. Please, use nfq_set_verdict2 instead. */ int nfq_set_verdict_mark(struct nfq_q_handle *qh, uint32_t id, uint32_t verdict, uint32_t mark, uint32_t data_len, const unsigned char *buf) { return __set_verdict(qh, id, verdict, mark, 1, data_len, buf, NFQNL_MSG_VERDICT); } EXPORT_SYMBOL(nfq_set_verdict_mark); /** * @} */ /************************************************************* * Message parsing functions *************************************************************/ /** * \defgroup Parsing Message parsing functions [DEPRECATED] * @{ */ /** * nfqnl_msg_packet_hdr - return the metaheader that wraps the packet * \param nfad Netlink packet data handle passed to callback function * * \return the netfilter queue netlink packet header for the given * nfq_data argument. Typically, the nfq_data value is passed as the 3rd * parameter to the callback function set by a call to nfq_create_queue(). * * The nfqnl_msg_packet_hdr structure is defined in libnetfilter_queue.h as: * * \verbatim struct nfqnl_msg_packet_hdr { uint32_t packet_id; // unique ID of packet in queue uint16_t hw_protocol; // hw protocol (network order) uint8_t hook; // netfilter hook } __attribute__ ((packed)); \endverbatim */ struct nfqnl_msg_packet_hdr *nfq_get_msg_packet_hdr(struct nfq_data *nfad) { return nfnl_get_pointer_to_data(nfad->data, NFQA_PACKET_HDR, struct nfqnl_msg_packet_hdr); } EXPORT_SYMBOL(nfq_get_msg_packet_hdr); /** * nfq_get_nfmark - get the packet mark * \param nfad Netlink packet data handle passed to callback function * * \return the netfilter mark currently assigned to the given queued packet. */ uint32_t nfq_get_nfmark(struct nfq_data *nfad) { return ntohl(nfnl_get_data(nfad->data, NFQA_MARK, uint32_t)); } EXPORT_SYMBOL(nfq_get_nfmark); /** * nfq_get_timestamp - get the packet timestamp * \param nfad Netlink packet data handle passed to callback function * \param tv structure to fill with timestamp info * * Retrieves the received timestamp when the given queued packet. * * \return 0 on success, non-zero on failure. */ int nfq_get_timestamp(struct nfq_data *nfad, struct timeval *tv) { struct nfqnl_msg_packet_timestamp *qpt; qpt = nfnl_get_pointer_to_data(nfad->data, NFQA_TIMESTAMP, struct nfqnl_msg_packet_timestamp); if (!qpt) return -1; tv->tv_sec = __be64_to_cpu(qpt->sec); tv->tv_usec = __be64_to_cpu(qpt->usec); return 0; } EXPORT_SYMBOL(nfq_get_timestamp); /** * nfq_get_indev - get the interface that the packet was received through * \param nfad Netlink packet data handle passed to callback function * * \return The index of the device the queued packet was received via. If the * returned index is 0, the packet was locally generated or the input * interface is not known (ie. POSTROUTING?). * * \warning all nfq_get_dev() functions return 0 if not set, since linux * only allows ifindex >= 1, see net/core/dev.c:2600 (in 2.6.13.1) */ uint32_t nfq_get_indev(struct nfq_data *nfad) { return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_INDEV, uint32_t)); } EXPORT_SYMBOL(nfq_get_indev); /** * nfq_get_physindev - get the physical interface that the packet was received * \param nfad Netlink packet data handle passed to callback function * * \return The index of the physical device the queued packet was received via. * If the returned index is 0, the packet was locally generated or the * physical input interface is no longer known (ie. POSTROUTING?). */ uint32_t nfq_get_physindev(struct nfq_data *nfad) { return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_PHYSINDEV, uint32_t)); } EXPORT_SYMBOL(nfq_get_physindev); /** * nfq_get_outdev - gets the interface that the packet will be routed out * \param nfad Netlink packet data handle passed to callback function * * \return The index of the device the queued packet will be sent out. If the * returned index is 0, the packet is destined for localhost or the output * interface is not yet known (ie. PREROUTING?). */ uint32_t nfq_get_outdev(struct nfq_data *nfad) { return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_OUTDEV, uint32_t)); } EXPORT_SYMBOL(nfq_get_outdev); /** * nfq_get_physoutdev - get the physical interface that the packet output * \param nfad Netlink packet data handle passed to callback function * * The index of the physical device the queued packet will be sent out. * If the returned index is 0, the packet is destined for localhost or the * physical output interface is not yet known (ie. PREROUTING?). * * \return The index of physical interface that the packet output will be routed out. */ uint32_t nfq_get_physoutdev(struct nfq_data *nfad) { return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_PHYSOUTDEV, uint32_t)); } EXPORT_SYMBOL(nfq_get_physoutdev); /** * nfq_get_indev_name - get the name of the interface the packet * was received through * \param nlif_handle pointer to a nlif interface resolving handle * \param nfad Netlink packet data handle passed to callback function * \param name pointer to the buffer to receive the interface name; * not more than \c IFNAMSIZ bytes will be copied to it. * \return -1 in case of error, >0 if it succeed. * * To use a nlif_handle, You need first to call nlif_open() and to open * an handler. Don't forget to store the result as it will be used * during all your program life: * \verbatim h = nlif_open(); if (h == NULL) { perror("nlif_open"); exit(EXIT_FAILURE); } \endverbatim * Once the handler is open, you need to fetch the interface table at a * whole via a call to nlif_query. * \verbatim nlif_query(h); \endverbatim * libnfnetlink is able to update the interface mapping when a new interface * appears. To do so, you need to call nlif_catch() on the handler after each * interface related event. The simplest way to get and treat event is to run * a select() or poll() against the nlif file descriptor. To get this file * descriptor, you need to use nlif_fd: * \verbatim if_fd = nlif_fd(h); \endverbatim * Don't forget to close the handler when you don't need the feature anymore: * \verbatim nlif_close(h); \endverbatim * */ int nfq_get_indev_name(struct nlif_handle *nlif_handle, struct nfq_data *nfad, char *name) { uint32_t ifindex = nfq_get_indev(nfad); return nlif_index2name(nlif_handle, ifindex, name); } EXPORT_SYMBOL(nfq_get_indev_name); /** * nfq_get_physindev_name - get the name of the physical interface the * packet was received through * \param nlif_handle pointer to a nlif interface resolving handle * \param nfad Netlink packet data handle passed to callback function * \param name pointer to the buffer to receive the interface name; * not more than \c IFNAMSIZ bytes will be copied to it. * * See nfq_get_indev_name() documentation for nlif_handle usage. * * \return -1 in case of error, > 0 if it succeed. */ int nfq_get_physindev_name(struct nlif_handle *nlif_handle, struct nfq_data *nfad, char *name) { uint32_t ifindex = nfq_get_physindev(nfad); return nlif_index2name(nlif_handle, ifindex, name); } EXPORT_SYMBOL(nfq_get_physindev_name); /** * nfq_get_outdev_name - get the name of the physical interface the * packet will be sent to * \param nlif_handle pointer to a nlif interface resolving handle * \param nfad Netlink packet data handle passed to callback function * \param name pointer to the buffer to receive the interface name; * not more than \c IFNAMSIZ bytes will be copied to it. * * See nfq_get_indev_name() documentation for nlif_handle usage. * * \return -1 in case of error, > 0 if it succeed. */ int nfq_get_outdev_name(struct nlif_handle *nlif_handle, struct nfq_data *nfad, char *name) { uint32_t ifindex = nfq_get_outdev(nfad); return nlif_index2name(nlif_handle, ifindex, name); } EXPORT_SYMBOL(nfq_get_outdev_name); /** * nfq_get_physoutdev_name - get the name of the interface the * packet will be sent to * \param nlif_handle pointer to a nlif interface resolving handle * \param nfad Netlink packet data handle passed to callback function * \param name pointer to the buffer to receive the interface name; * not more than \c IFNAMSIZ bytes will be copied to it. * * See nfq_get_indev_name() documentation for nlif_handle usage. * * \return -1 in case of error, > 0 if it succeed. */ int nfq_get_physoutdev_name(struct nlif_handle *nlif_handle, struct nfq_data *nfad, char *name) { uint32_t ifindex = nfq_get_physoutdev(nfad); return nlif_index2name(nlif_handle, ifindex, name); } EXPORT_SYMBOL(nfq_get_physoutdev_name); /** * nfq_get_packet_hw * * get hardware address * * \param nfad Netlink packet data handle passed to callback function * * Retrieves the hardware address associated with the given queued packet. * For ethernet packets, the hardware address returned (if any) will be the * MAC address of the packet source host. The destination MAC address is not * known until after POSTROUTING and a successful ARP request, so cannot * currently be retrieved. * * The nfqnl_msg_packet_hw structure is defined in libnetfilter_queue.h as: * \verbatim struct nfqnl_msg_packet_hw { uint16_t hw_addrlen; uint16_t _pad; uint8_t hw_addr[8]; } __attribute__ ((packed)); \endverbatim */ struct nfqnl_msg_packet_hw *nfq_get_packet_hw(struct nfq_data *nfad) { return nfnl_get_pointer_to_data(nfad->data, NFQA_HWADDR, struct nfqnl_msg_packet_hw); } EXPORT_SYMBOL(nfq_get_packet_hw); /** * nfq_get_uid - get the UID of the user the packet belongs to * \param nfad Netlink packet data handle passed to callback function * * \warning If the NFQA_CFG_F_GSO flag is not set, then fragmented packets * may be pushed into the queue. In this case, only one fragment will have the * UID field set. To deal with this issue always set NFQA_CFG_F_GSO. * * \return 1 if there is a UID available, 0 otherwise. */ int nfq_get_uid(struct nfq_data *nfad, uint32_t *uid) { if (!nfnl_attr_present(nfad->data, NFQA_UID)) return 0; *uid = ntohl(nfnl_get_data(nfad->data, NFQA_UID, uint32_t)); return 1; } EXPORT_SYMBOL(nfq_get_uid); /** * nfq_get_gid - get the GID of the user the packet belongs to * \param nfad Netlink packet data handle passed to callback function * * \warning If the NFQA_CFG_F_GSO flag is not set, then fragmented packets * may be pushed into the queue. In this case, only one fragment will have the * GID field set. To deal with this issue always set NFQA_CFG_F_GSO. * * \return 1 if there is a GID available, 0 otherwise. */ int nfq_get_gid(struct nfq_data *nfad, uint32_t *gid) { if (!nfnl_attr_present(nfad->data, NFQA_GID)) return 0; *gid = ntohl(nfnl_get_data(nfad->data, NFQA_GID, uint32_t)); return 1; } EXPORT_SYMBOL(nfq_get_gid); /** * nfq_get_secctx - get the security context for this packet * \param nfad Netlink packet data handle passed to callback function * \param secdata data to write the security context to * * \warning If the NFQA_CFG_F_GSO flag is not set, then fragmented packets * may be pushed into the queue. In this case, only one fragment will have the * SECCTX field set. To deal with this issue always set NFQA_CFG_F_GSO. * * \return -1 on error, otherwise > 0 */ int nfq_get_secctx(struct nfq_data *nfad, unsigned char **secdata) { if (!nfnl_attr_present(nfad->data, NFQA_SECCTX)) return -1; *secdata = (unsigned char *)nfnl_get_pointer_to_data(nfad->data, NFQA_SECCTX, char); if (*secdata) return NFA_PAYLOAD(nfad->data[NFQA_SECCTX-1]); return 0; } EXPORT_SYMBOL(nfq_get_secctx); /** * nfq_get_payload - get payload * \param nfad Netlink packet data handle passed to callback function * \param data Pointer of pointer that will be pointed to the payload * * Retrieve the payload for a queued packet. The actual amount and type of * data retrieved by this function will depend on the mode set with the * nfq_set_mode() function. * * \return -1 on error, otherwise > 0. */ int nfq_get_payload(struct nfq_data *nfad, unsigned char **data) { *data = (unsigned char *) nfnl_get_pointer_to_data(nfad->data, NFQA_PAYLOAD, char); if (*data) return NFA_PAYLOAD(nfad->data[NFQA_PAYLOAD-1]); return -1; } EXPORT_SYMBOL(nfq_get_payload); /** * @} */ #define SNPRINTF_FAILURE(ret, rem, offset, len) \ do { \ if (ret < 0) \ return ret; \ len += ret; \ if (ret > rem) \ ret = rem; \ offset += ret; \ rem -= ret; \ } while (0) /** * \defgroup Printing Printing [DEPRECATED] * @{ */ /** * nfq_snprintf_xml - print the enqueued packet in XML format into a buffer * \param buf The buffer that you want to use to print the logged packet * \param rem The size of the buffer that you have passed * \param tb Netlink packet data handle passed to callback function * \param flags The flag that tell what to print into the buffer * * This function supports the following flags: * * - NFQ_XML_HW: include the hardware link layer address * - NFQ_XML_MARK: include the packet mark * - NFQ_XML_DEV: include the device information * - NFQ_XML_PHYSDEV: include the physical device information * - NFQ_XML_PAYLOAD: include the payload (in hexadecimal) * - NFQ_XML_TIME: include the timestamp * - NFQ_XML_ALL: include all the logging information (all flags set) * * You can combine this flags with an binary OR. * * \return -1 in case of failure, otherwise the length of the string that * would have been printed into the buffer (in case that there is enough * room in it). See snprintf() return value for more information. */ int nfq_snprintf_xml(char *buf, size_t rem, struct nfq_data *tb, int flags) { struct nfqnl_msg_packet_hdr *ph; struct nfqnl_msg_packet_hw *hwph; uint32_t mark, ifi; uint32_t uid, gid; int size, offset = 0, len = 0, ret; unsigned char *data; size = snprintf(buf + offset, rem, ""); SNPRINTF_FAILURE(size, rem, offset, len); if (flags & NFQ_XML_TIME) { time_t t; struct tm tm; t = time(NULL); if (localtime_r(&t, &tm) == NULL) return -1; size = snprintf(buf + offset, rem, ""); SNPRINTF_FAILURE(size, rem, offset, len); size = snprintf(buf + offset, rem, "%d", tm.tm_hour); SNPRINTF_FAILURE(size, rem, offset, len); size = snprintf(buf + offset, rem, "%02d", tm.tm_min); SNPRINTF_FAILURE(size, rem, offset, len); size = snprintf(buf + offset, rem, "%02d", tm.tm_sec); SNPRINTF_FAILURE(size, rem, offset, len); size = snprintf(buf + offset, rem, "%d", tm.tm_wday + 1); SNPRINTF_FAILURE(size, rem, offset, len); size = snprintf(buf + offset, rem, "%d", tm.tm_mday); SNPRINTF_FAILURE(size, rem, offset, len); size = snprintf(buf + offset, rem, "%d", tm.tm_mon + 1); SNPRINTF_FAILURE(size, rem, offset, len); size = snprintf(buf + offset, rem, "%d", 1900 + tm.tm_year); SNPRINTF_FAILURE(size, rem, offset, len); size = snprintf(buf + offset, rem, ""); SNPRINTF_FAILURE(size, rem, offset, len); } ph = nfq_get_msg_packet_hdr(tb); if (ph) { size = snprintf(buf + offset, rem, "%u%u", ph->hook, ntohl(ph->packet_id)); SNPRINTF_FAILURE(size, rem, offset, len); hwph = nfq_get_packet_hw(tb); if (hwph && (flags & NFQ_XML_HW)) { int i, hlen = ntohs(hwph->hw_addrlen); size = snprintf(buf + offset, rem, "%04x" "", ntohs(ph->hw_protocol)); SNPRINTF_FAILURE(size, rem, offset, len); size = snprintf(buf + offset, rem, ""); SNPRINTF_FAILURE(size, rem, offset, len); for (i=0; ihw_addr[i]); SNPRINTF_FAILURE(size, rem, offset, len); } size = snprintf(buf + offset, rem, ""); SNPRINTF_FAILURE(size, rem, offset, len); } else if (flags & NFQ_XML_HW) { size = snprintf(buf + offset, rem, "%04x" "", ntohs(ph->hw_protocol)); SNPRINTF_FAILURE(size, rem, offset, len); } } mark = nfq_get_nfmark(tb); if (mark && (flags & NFQ_XML_MARK)) { size = snprintf(buf + offset, rem, "%u", mark); SNPRINTF_FAILURE(size, rem, offset, len); } ifi = nfq_get_indev(tb); if (ifi && (flags & NFQ_XML_DEV)) { size = snprintf(buf + offset, rem, "%u", ifi); SNPRINTF_FAILURE(size, rem, offset, len); } ifi = nfq_get_outdev(tb); if (ifi && (flags & NFQ_XML_DEV)) { size = snprintf(buf + offset, rem, "%u", ifi); SNPRINTF_FAILURE(size, rem, offset, len); } ifi = nfq_get_physindev(tb); if (ifi && (flags & NFQ_XML_PHYSDEV)) { size = snprintf(buf + offset, rem, "%u", ifi); SNPRINTF_FAILURE(size, rem, offset, len); } ifi = nfq_get_physoutdev(tb); if (ifi && (flags & NFQ_XML_PHYSDEV)) { size = snprintf(buf + offset, rem, "%u", ifi); SNPRINTF_FAILURE(size, rem, offset, len); } if (nfq_get_uid(tb, &uid) && (flags & NFQ_XML_UID)) { size = snprintf(buf + offset, rem, "%u", uid); SNPRINTF_FAILURE(size, rem, offset, len); } if (nfq_get_gid(tb, &gid) && (flags & NFQ_XML_GID)) { size = snprintf(buf + offset, rem, "%u", gid); SNPRINTF_FAILURE(size, rem, offset, len); } ret = nfq_get_payload(tb, &data); if (ret >= 0 && (flags & NFQ_XML_PAYLOAD)) { int i; size = snprintf(buf + offset, rem, ""); SNPRINTF_FAILURE(size, rem, offset, len); for (i=0; i"); SNPRINTF_FAILURE(size, rem, offset, len); } size = snprintf(buf + offset, rem, ""); SNPRINTF_FAILURE(size, rem, offset, len); return len; } EXPORT_SYMBOL(nfq_snprintf_xml); /** * @} */