Logo Search packages:      
Sourcecode: libnetfilter-queue version File versions  Download package

libnetfilter_queue.c

/* libnetfilter_queue.c: generic library for access to nf_queue
 *
 * (C) 2005 by Harald Welte <laforge@gnumonks.org>
 *
 *  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
 *
 *  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 <andreas@florath.net>
 *    Fix __set_verdict() that it can now handle payload.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>

#include <libnfnetlink/libnfnetlink.h>
#include <libnetfilter_queue/libnetfilter_queue.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
 * 
 * \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 nfqnl_test.c source file.
 * 
 */

00069 struct nfq_handle
{
      struct nfnl_handle *nfnlh;
      struct nfnl_subsys_handle *nfnlssh;
      struct nfq_q_handle *qh_list;
};

00076 struct nfq_q_handle
{
      struct nfq_q_handle *next;
      struct nfq_handle *h;
      u_int16_t id;

      nfq_callback *cb;
      void *data;
};

00086 struct nfq_data {
      struct nfattr **data;
};

int 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, u_int16_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, u_int8_t command,
            u_int16_t queuenum, u_int16_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.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;
      u_int16_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);
}

static struct nfnl_callback pkt_cb = {
      .call       = &__nfq_rcv_pkt,
      .attr_count = NFQA_MAX,
};

/* public interface */

struct nfnl_handle *nfq_nfnlh(struct nfq_handle *h)
{
      return h->nfnlh;
}

/**
 *
 * \defgroup Queue Queue handling
 *
 * 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_STOLEN gone away
 *   - 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
 *
 * 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.
 */
00248 int nfq_fd(struct nfq_handle *h)
{
      return nfnl_fd(nfq_nfnlh(h));
}

/**
 * @}
 */

/**
 * \defgroup LibrarySetup Library setup
 *
 * 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.
 */
00303 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;
}

/**
 * @}
 */

/**
 * 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 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;
}

/**
 * \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. 
 */
00386 int nfq_close(struct nfq_handle *h)
{
      int ret;
      
      ret = nfnl_close(h->nfnlh);
      if (ret == 0)
            free(h);
      return ret;
}

/**
 * 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).
 *
 * \return integer inferior to 0 in case of failure
 */
00406 int nfq_bind_pf(struct nfq_handle *h, u_int16_t pf)
{
      return __build_send_cfg_msg(h, NFQNL_CFG_CMD_PF_BIND, 0, 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.
 */
00419 int nfq_unbind_pf(struct nfq_handle *h, u_int16_t pf)
{
      return __build_send_cfg_msg(h, NFQNL_CFG_CMD_PF_UNBIND, 0, 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.
 */

00467 struct nfq_q_handle *nfq_create_queue(struct nfq_handle *h, 
            u_int16_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));

      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;
}

/**
 * @}
 */

/**
 * \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.
 */
00513 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;
}

/**
 * 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.
 */
00536 int nfq_handle_packet(struct nfq_handle *h, char *buf, int len)
{
      return nfnl_handle_packet(h->nfnlh, buf, len);
}

/**
 * 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 - do not copy any data
 * - NFQNL_COPY_META - copy only packet metadata
 * - NFQNL_COPY_PACKET - copy entire packet
 *
 * \return -1 on error; >=0 otherwise.
 */
00556 int nfq_set_mode(struct nfq_q_handle *qh,
            u_int8_t mode, u_int32_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, &params,
                  sizeof(params));

      return nfnl_query(qh->h->nfnlh, &u.nmh);
}

/**
 * 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.
 */
00588 int nfq_set_queue_maxlen(struct nfq_q_handle *qh,
                        u_int32_t queuelen)
{
      union {
            char buf[NFNL_HEADER_LEN
                  +NFA_LENGTH(sizeof(struct nfqnl_msg_config_params))];
            struct nlmsghdr nmh;
      } u;
      u_int32_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);
}

/**
 * @}
 */

static int __set_verdict(struct nfq_q_handle *qh, u_int32_t id,
            u_int32_t verdict, u_int32_t mark, int set_mark,
            u_int32_t data_len, const unsigned char *data)
{
      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,
                  NFQNL_MSG_VERDICT, 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, or by calling the nfq_set_verdict2() function.
 *
 * \return -1 on error; >= 0 otherwise.
 */
00690 int nfq_set_verdict(struct nfq_q_handle *qh, u_int32_t id,
            u_int32_t verdict, u_int32_t data_len, 
            const unsigned char *buf)
{
      return __set_verdict(qh, id, verdict, 0, 0, data_len, buf);
}     

/**
 * 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
 */
00706 int nfq_set_verdict2(struct nfq_q_handle *qh, u_int32_t id,
                 u_int32_t verdict, u_int32_t mark,
                 u_int32_t data_len, const unsigned char *buf)
{
      return __set_verdict(qh, id, verdict, htonl(mark), 1, data_len, buf);
}

/**
 * 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.
 */
00727 int nfq_set_verdict_mark(struct nfq_q_handle *qh, u_int32_t id,
            u_int32_t verdict, u_int32_t mark,
            u_int32_t data_len, const unsigned char *buf)
{
      return __set_verdict(qh, id, verdict, mark, 1, data_len, buf);
}

/**
 * @}
 */



/*************************************************************
 * Message parsing functions 
 *************************************************************/

/**
 * \defgroup Parsing Message parsing functions
 * @{
 */

/**
 * 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 {
            u_int32_t   packet_id;  // unique ID of packet in queue
            u_int16_t   hw_protocol;      // hw protocol (network order)
            u_int8_t    hook;       // netfilter hook
      } __attribute__ ((packed));
\endverbatim
 */
00767 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);
}

/**
 * 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.
 */
00779 uint32_t nfq_get_nfmark(struct nfq_data *nfad)
{
      return ntohl(nfnl_get_data(nfad->data, NFQA_MARK, u_int32_t));
}

/**
 * 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.
 */
00793 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;
}

/**
 * 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)
 */
00818 u_int32_t nfq_get_indev(struct nfq_data *nfad)
{
      return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_INDEV, u_int32_t));
}

/**
 * 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?).
 */
00831 u_int32_t nfq_get_physindev(struct nfq_data *nfad)
{
      return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_PHYSINDEV, u_int32_t));
}

/**
 * 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?).
 */
00844 u_int32_t nfq_get_outdev(struct nfq_data *nfad)
{
      return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_OUTDEV, u_int32_t));
}

/**
 * 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.
 */
00859 u_int32_t nfq_get_physoutdev(struct nfq_data *nfad)
{
      return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_PHYSOUTDEV, u_int32_t));
}

/**
 * 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
 *
 */
00902 int nfq_get_indev_name(struct nlif_handle *nlif_handle,
                  struct nfq_data *nfad, char *name)
{
      u_int32_t ifindex = nfq_get_indev(nfad);
      return nlif_index2name(nlif_handle, ifindex, 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. 
 */
00921 int nfq_get_physindev_name(struct nlif_handle *nlif_handle,
                     struct nfq_data *nfad, char *name)
{
      u_int32_t ifindex = nfq_get_physindev(nfad);
      return nlif_index2name(nlif_handle, ifindex, 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. 
 */
00940 int nfq_get_outdev_name(struct nlif_handle *nlif_handle,
                  struct nfq_data *nfad, char *name)
{
      u_int32_t ifindex = nfq_get_outdev(nfad);
      return nlif_index2name(nlif_handle, ifindex, 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. 
 */

00960 int nfq_get_physoutdev_name(struct nlif_handle *nlif_handle,
                      struct nfq_data *nfad, char *name)
{
      u_int32_t ifindex = nfq_get_physoutdev(nfad);
      return nlif_index2name(nlif_handle, ifindex, 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 {
            u_int16_t   hw_addrlen;
            u_int16_t   _pad;
            u_int8_t    hw_addr[8];
      } __attribute__ ((packed));
\endverbatim
 */
00989 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);
}

/**
 * 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.
 */
01006 int nfq_get_payload(struct nfq_data *nfad, unsigned char **data)
{
      *data = nfnl_get_pointer_to_data(nfad->data, NFQA_PAYLOAD, char);
      if (*data)
            return NFA_PAYLOAD(nfad->data[NFQA_PAYLOAD-1]);

      return -1;
}

#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)

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;
      u_int32_t mark, ifi;
      int size, offset = 0, len = 0, ret;
      unsigned char *data;

      size = snprintf(buf + offset, rem, "<pkt>");
      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, "<when>");
            SNPRINTF_FAILURE(size, rem, offset, len);

            size = snprintf(buf + offset, rem,
                        "<hour>%d</hour>", tm.tm_hour);
            SNPRINTF_FAILURE(size, rem, offset, len);

            size = snprintf(buf + offset,
                        rem, "<min>%02d</min>", tm.tm_min);
            SNPRINTF_FAILURE(size, rem, offset, len);

            size = snprintf(buf + offset,
                        rem, "<sec>%02d</sec>", tm.tm_sec);
            SNPRINTF_FAILURE(size, rem, offset, len);

            size = snprintf(buf + offset, rem, "<wday>%d</wday>",
                        tm.tm_wday + 1);
            SNPRINTF_FAILURE(size, rem, offset, len);

            size = snprintf(buf + offset, rem, "<day>%d</day>", tm.tm_mday);
            SNPRINTF_FAILURE(size, rem, offset, len);

            size = snprintf(buf + offset, rem, "<month>%d</month>",
                        tm.tm_mon + 1);
            SNPRINTF_FAILURE(size, rem, offset, len);

            size = snprintf(buf + offset, rem, "<year>%d</year>",
                        1900 + tm.tm_year);
            SNPRINTF_FAILURE(size, rem, offset, len);

            size = snprintf(buf + offset, rem, "</when>");
            SNPRINTF_FAILURE(size, rem, offset, len);
      }

      ph = nfq_get_msg_packet_hdr(tb);
      if (ph) {
            size = snprintf(buf + offset, rem,
                        "<hook>%u</hook><id>%u</id>",
                        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, "<hw><proto>%04x"
                                             "</proto>",
                              ntohs(ph->hw_protocol));
                  SNPRINTF_FAILURE(size, rem, offset, len);

                  size = snprintf(buf + offset, rem, "<src>");
                  SNPRINTF_FAILURE(size, rem, offset, len);

                  for (i=0; i<hlen; i++) {
                        size = snprintf(buf + offset, rem, "%02x",
                                    hwph->hw_addr[i]);
                        SNPRINTF_FAILURE(size, rem, offset, len);
                  }

                  size = snprintf(buf + offset, rem, "</src></hw>");
                  SNPRINTF_FAILURE(size, rem, offset, len);
            } else if (flags & NFQ_XML_HW) {
                  size = snprintf(buf + offset, rem, "<hw><proto>%04x"
                                        "</proto></hw>",
                         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, "<mark>%u</mark>", mark);
            SNPRINTF_FAILURE(size, rem, offset, len);
      }

      ifi = nfq_get_indev(tb);
      if (ifi && (flags & NFQ_XML_DEV)) {
            size = snprintf(buf + offset, rem, "<indev>%u</indev>", ifi);
            SNPRINTF_FAILURE(size, rem, offset, len);
      }

      ifi = nfq_get_outdev(tb);
      if (ifi && (flags & NFQ_XML_DEV)) {
            size = snprintf(buf + offset, rem, "<outdev>%u</outdev>", ifi);
            SNPRINTF_FAILURE(size, rem, offset, len);
      }

      ifi = nfq_get_physindev(tb);
      if (ifi && (flags & NFQ_XML_PHYSDEV)) {
            size = snprintf(buf + offset, rem,
                        "<physindev>%u</physindev>", ifi);
            SNPRINTF_FAILURE(size, rem, offset, len);
      }

      ifi = nfq_get_physoutdev(tb);
      if (ifi && (flags & NFQ_XML_PHYSDEV)) {
            size = snprintf(buf + offset, rem,
                        "<physoutdev>%u</physoutdev>", ifi);
            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, "<payload>");
            SNPRINTF_FAILURE(size, rem, offset, len);

            for (i=0; i<ret; i++) {
                  size = snprintf(buf + offset, rem, "%02x",
                              data[i] & 0xff);
                  SNPRINTF_FAILURE(size, rem, offset, len);
            }

            size = snprintf(buf + offset, rem, "</payload>");
            SNPRINTF_FAILURE(size, rem, offset, len);
      }

      size = snprintf(buf + offset, rem, "</pkt>");
      SNPRINTF_FAILURE(size, rem, offset, len);

      return len;
}

/**
 * @}
 */

Generated by  Doxygen 1.6.0   Back to index