From 42a449b85917e5be92a17312999e77d82b0f82f3 Mon Sep 17 00:00:00 2001 From: "/C=DE/ST=Berlin/L=Berlin/O=Netfilter Project/OU=Development/CN=laforge/emailAddress=laforge@netfilter.org" Date: Wed, 27 Jul 2005 19:35:41 +0000 Subject: add (incomplete) support for libipq emulation API --- _queue/Makefile.am | 8 +- _queue/libipq_compat.c | 351 ++++++++++++++++++++++++++++++++++++++++++++ _queue/libnfnetlink_queue.c | 41 +++--- _queue/libnfnetlink_queue.h | 26 ++-- 4 files changed, 392 insertions(+), 34 deletions(-) create mode 100644 _queue/libipq_compat.c diff --git a/_queue/Makefile.am b/_queue/Makefile.am index e4631a0..6b15391 100644 --- a/_queue/Makefile.am +++ b/_queue/Makefile.am @@ -6,12 +6,12 @@ INCLUDES=-I../include -I/lib/modules/$(shell (uname -r))/build/include CFLAGS=-fPIC -Wall LIBS= -lib_LTLIBRARIES = libnfnetlink_queue +lib_LTLIBRARIES = libnfnetlink_queue.la -libnfqnetlink_la_LDFLAGS = -Wc,-nostartfiles -libnfqnetlink_la_SOURCES = libnfnetlink_queue.c +libnfnetlink_queue_la_LDFLAGS = -Wc,-nostartfiles +libnfnetlink_queue_la_SOURCES = libnfnetlink_queue.c libipq_compat.c -include_HEADERS = libnfnetlink_queue.h +include_HEADERS = libnfnetlink_queue.h libipq.h man_MANS = #nfnetlink_queue.3 nfnetlink_queue.7 diff --git a/_queue/libipq_compat.c b/_queue/libipq_compat.c new file mode 100644 index 0000000..9e99674 --- /dev/null +++ b/_queue/libipq_compat.c @@ -0,0 +1,351 @@ +/* + * libipq - backwards compatibility library for libnfnetlink_queue + * + * (C) 2005 by Harald Welte + * + * Based on original libipq.c, + * Author: James Morris + * 07-11-2001 Modified by Fernando Anton to add support for IPv6. + * Copyright (c) 2000-2001 Netfilter Core Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This 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. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "libnfnetlink_queue.h" +#include "libipq.h" + +/**************************************************************************** + * + * Private interface + * + ****************************************************************************/ + +enum { + IPQ_ERR_NONE = 0, + IPQ_ERR_IMPL, + IPQ_ERR_HANDLE, + IPQ_ERR_SOCKET, + IPQ_ERR_BIND, + IPQ_ERR_BUFFER, + IPQ_ERR_RECV, + IPQ_ERR_NLEOF, + IPQ_ERR_ADDRLEN, + IPQ_ERR_STRUNC, + IPQ_ERR_RTRUNC, + IPQ_ERR_NLRECV, + IPQ_ERR_SEND, + IPQ_ERR_SUPP, + IPQ_ERR_RECVBUF, + IPQ_ERR_TIMEOUT, + IPQ_ERR_PROTOCOL +}; +#define IPQ_MAXERR IPQ_ERR_PROTOCOL + +struct ipq_errmap_t { + int errcode; + char *message; +} ipq_errmap[] = { + { IPQ_ERR_NONE, "Unknown error" }, + { IPQ_ERR_IMPL, "Implementation error" }, + { IPQ_ERR_HANDLE, "Unable to create netlink handle" }, + { IPQ_ERR_SOCKET, "Unable to create netlink socket" }, + { IPQ_ERR_BIND, "Unable to bind netlink socket" }, + { IPQ_ERR_BUFFER, "Unable to allocate buffer" }, + { IPQ_ERR_RECV, "Failed to receive netlink message" }, + { IPQ_ERR_NLEOF, "Received EOF on netlink socket" }, + { IPQ_ERR_ADDRLEN, "Invalid peer address length" }, + { IPQ_ERR_STRUNC, "Sent message truncated" }, + { IPQ_ERR_RTRUNC, "Received message truncated" }, + { IPQ_ERR_NLRECV, "Received error from netlink" }, + { IPQ_ERR_SEND, "Failed to send netlink message" }, + { IPQ_ERR_SUPP, "Operation not supported" }, + { IPQ_ERR_RECVBUF, "Receive buffer size invalid" }, + { IPQ_ERR_TIMEOUT, "Timeout"}, + { IPQ_ERR_PROTOCOL, "Invalid protocol specified" } +}; + +static int ipq_errno = IPQ_ERR_NONE; + +#if 0 +static ssize_t ipq_netlink_sendto(const struct ipq_handle *h, + const void *msg, size_t len); + +static ssize_t ipq_netlink_recvfrom(const struct ipq_handle *h, + unsigned char *buf, size_t len, + int timeout); + +static ssize_t ipq_netlink_sendmsg(const struct ipq_handle *h, + const struct msghdr *msg, + unsigned int flags); + +static char *ipq_strerror(int errcode); + +static ssize_t ipq_netlink_sendto(const struct ipq_handle *h, + const void *msg, size_t len) +{ + int status = sendto(h->fd, msg, len, 0, + (struct sockaddr *)&h->peer, sizeof(h->peer)); + if (status < 0) + ipq_errno = IPQ_ERR_SEND; + return status; +} + +static ssize_t ipq_netlink_sendmsg(const struct ipq_handle *h, + const struct msghdr *msg, + unsigned int flags) +{ + int status = sendmsg(h->fd, msg, flags); + if (status < 0) + ipq_errno = IPQ_ERR_SEND; + return status; +} + +static ssize_t ipq_netlink_recvfrom(const struct ipq_handle *h, + unsigned char *buf, size_t len, + int timeout) +{ + unsigned int addrlen; + int status; + struct nlmsghdr *nlh; + + if (len < sizeof(struct nlmsgerr)) { + ipq_errno = IPQ_ERR_RECVBUF; + return -1; + } + addrlen = sizeof(h->peer); + + if (timeout != 0) { + int ret; + struct timeval tv; + fd_set read_fds; + + if (timeout < 0) { + /* non-block non-timeout */ + tv.tv_sec = 0; + tv.tv_usec = 0; + } else { + tv.tv_sec = timeout / 1000000; + tv.tv_usec = timeout % 1000000; + } + + FD_ZERO(&read_fds); + FD_SET(h->fd, &read_fds); + ret = select(h->fd+1, &read_fds, NULL, NULL, &tv); + if (ret < 0) { + if (errno == EINTR) { + return 0; + } else { + ipq_errno = IPQ_ERR_RECV; + return -1; + } + } + if (!FD_ISSET(h->fd, &read_fds)) { + ipq_errno = IPQ_ERR_TIMEOUT; + return 0; + } + } + status = recvfrom(h->fd, buf, len, 0, + (struct sockaddr *)&h->peer, &addrlen); + if (status < 0) { + ipq_errno = IPQ_ERR_RECV; + return status; + } + if (addrlen != sizeof(h->peer)) { + ipq_errno = IPQ_ERR_RECV; + return -1; + } + if (h->peer.nl_pid != 0) { + ipq_errno = IPQ_ERR_RECV; + return -1; + } + if (status == 0) { + ipq_errno = IPQ_ERR_NLEOF; + return -1; + } + nlh = (struct nlmsghdr *)buf; + if (nlh->nlmsg_flags & MSG_TRUNC || nlh->nlmsg_len > status) { + ipq_errno = IPQ_ERR_RTRUNC; + return -1; + } + return status; +} +#endif + +static char *ipq_strerror(int errcode) +{ + if (errcode < 0 || errcode > IPQ_MAXERR) + errcode = IPQ_ERR_IMPL; + return ipq_errmap[errcode].message; +} + +/**************************************************************************** + * + * Public interface + * + ****************************************************************************/ + +/* + * Create and initialise an ipq handle. + */ +struct ipq_handle *ipq_create_handle(u_int32_t flags, u_int32_t protocol) +{ + int status; + struct ipq_handle *h; + + h = (struct ipq_handle *)malloc(sizeof(struct ipq_handle)); + if (h == NULL) { + ipq_errno = IPQ_ERR_HANDLE; + return NULL; + } + + memset(h, 0, sizeof(struct ipq_handle)); + + status = nfqnl_open(&h->nfqnlh); + if (status < 0) { + ipq_errno = IPQ_ERR_SOCKET; + goto err_free; + } + + if (protocol == PF_INET) + status = nfqnl_bind_pf(&h->nfqnlh, PF_INET); + else if (protocol == PF_INET6) + status = nfqnl_bind_pf(&h->nfqnlh, PF_INET6); + else { + ipq_errno = IPQ_ERR_PROTOCOL; + goto err_close; + } + h->family = protocol; + if (status < 0) { + ipq_errno = IPQ_ERR_BIND; + goto err_close; + } + + status = nfqnl_create_queue(&h->nfqnlh, &h->qh, 0); + if (status < 0) { + ipq_errno = IPQ_ERR_BIND; + goto err_close; + } + + return h; + +err_close: + nfqnl_close(&h->nfqnlh); +err_free: + free(h); + return NULL; +} + +/* + * No error condition is checked here at this stage, but it may happen + * if/when reliable messaging is implemented. + */ +int ipq_destroy_handle(struct ipq_handle *h) +{ + if (h) { + nfqnl_close(&h->nfqnlh); + free(h); + } + return 0; +} + +int ipq_set_mode(const struct ipq_handle *h, + u_int8_t mode, size_t range) +{ + return nfqnl_set_mode(&h->qh, mode, range); +} + +/* + * timeout is in microseconds (1 second is 1000000 (1 million) microseconds) + * + */ +ssize_t ipq_read(const struct ipq_handle *h, + unsigned char *buf, size_t len, int timeout) +{ + struct nfattr *tb[NFQA_MAX]; + struct nlmsghdr *nlh = (struct nlmsghdr *)buf; + struct nfgenmsg *msg = NULL; + struct nfattr *nfa; + + //return ipq_netlink_recvfrom(h, buf, len, timeout); + + /* This really sucks. We have to copy the whole packet + * in order to build a data structure that is compatible to + * the old ipq interface... */ + + nfa = nfnl_parse_hdr(&h->nfqnlh.nfnlh, nlh, &msg); + if (!msg || !nfa) + return 0; + + if (msg->nfgen_family != h->family) + return 0; + + nfnl_parse_attr(tb, NFQA_MAX, nfa, 0xffff); + + +} + +int ipq_message_type(const unsigned char *buf) +{ + return ((struct nlmsghdr*)buf)->nlmsg_type; +} + +int ipq_get_msgerr(const unsigned char *buf) +{ + struct nlmsghdr *h = (struct nlmsghdr *)buf; + struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); + return -err->error; +} + +ipq_packet_msg_t *ipq_get_packet(const unsigned char *buf) +{ + return NLMSG_DATA((struct nlmsghdr *)(buf)); +} + +int ipq_set_verdict(const struct ipq_handle *h, + ipq_id_t id, + unsigned int verdict, + size_t data_len, + unsigned char *buf) +{ + return nfqnl_set_verdict(&h->qh, id, verdict, data_len, buf); +} + +/* Not implemented yet */ +int ipq_ctl(const struct ipq_handle *h, int request, ...) +{ + return 1; +} + +char *ipq_errstr(void) +{ + return ipq_strerror(ipq_errno); +} + +void ipq_perror(const char *s) +{ + if (s) + fputs(s, stderr); + else + fputs("ERROR", stderr); + if (ipq_errno) + fprintf(stderr, ": %s", ipq_errstr()); + if (errno) + fprintf(stderr, ": %s", strerror(errno)); + fputc('\n', stderr); +} diff --git a/_queue/libnfnetlink_queue.c b/_queue/libnfnetlink_queue.c index a3c58b7..389e945 100644 --- a/_queue/libnfnetlink_queue.c +++ b/_queue/libnfnetlink_queue.c @@ -28,7 +28,7 @@ #include #include #include -#include "libnfqnetlink.h" +#include "libnfnetlink_queue.h" /*********************************************************************** * low level stuff @@ -40,7 +40,7 @@ int nfqnl_open(struct nfqnl_handle *h) memset(h, 0, sizeof(*h)); - err = nfnl_open(&h->nfnlh, NFNL_SUBSYS_QUEUE, subscriptions); + err = nfnl_open(&h->nfnlh, NFNL_SUBSYS_QUEUE, 0); if (err < 0) return err; @@ -54,7 +54,7 @@ int nfqnl_close(struct nfqnl_handle *h) /* build a NFQNL_MSG_CONFIG message */ static int -__build_send_cfg_msg(const struct nfqnl_handle *h, u_int8_t command, +__build_send_cfg_msg(struct nfqnl_handle *h, u_int8_t command, u_int16_t queuenum, u_int16_t pf) { char buf[NLMSG_LENGTH(sizeof(struct nlmsghdr)) @@ -74,23 +74,23 @@ __build_send_cfg_msg(const struct nfqnl_handle *h, u_int8_t command, } /* bind nf_queue from a specific protocol family */ -int nfqnl_bind_pf(const struct nfqnl_handle *h, u_int16_t pf) +int nfqnl_bind_pf(struct nfqnl_handle *h, u_int16_t pf) { return __build_send_cfg_msg(h, NFQNL_CFG_CMD_PF_BIND, 0, pf); } /* unbind nf_queue from a specific protocol family */ -int nfqnl_unbind_pf(const struct nfqnl_handle *h, u_int16_t pf) +int nfqnl_unbind_pf(struct nfqnl_handle *h, u_int16_t pf) { return __build_send_cfg_msg(h, NFQNL_CFG_CMD_PF_UNBIND, 0, pf); } /* bind this socket to a specific queue number */ -int nfqnl_create_queue(const struct nfqnl_handle *h, +int nfqnl_create_queue(struct nfqnl_handle *h, struct nfqnl_q_handle *qh, u_int16_t num) { - qh->queue = h; - qh->id = qh; + qh->h = h; + qh->id = num; return __build_send_cfg_msg(h, NFQNL_CFG_CMD_BIND, num, 0); } @@ -98,14 +98,14 @@ int nfqnl_create_queue(const struct nfqnl_handle *h, /* unbind this socket from a specific queue number */ int nfqnl_destroy_queue(struct nfqnl_q_handle *qh) { - int ret = __build_send_cfg_msg(h, NFQNL_CFG_CMD_UNBIND, num, 0); + int ret = __build_send_cfg_msg(qh->h, NFQNL_CFG_CMD_UNBIND, qh->id, 0); if (ret == 0) qh->h = NULL; return ret; } -int nfqnl_set_mode(const struct nfqnl_q_handle *qh +int nfqnl_set_mode(struct nfqnl_q_handle *qh, u_int8_t mode, u_int32_t range) { char buf[NLMSG_LENGTH(sizeof(struct nlmsghdr)) @@ -114,7 +114,7 @@ int nfqnl_set_mode(const struct nfqnl_q_handle *qh struct nfqnl_msg_config_params params; struct nlmsghdr *nmh = (struct nlmsghdr *) buf; - nfnl_fill_hdr(&qh->h->nfnlh, nmh, 0, AF_UNSPEC, queuenum, + nfnl_fill_hdr(&qh->h->nfnlh, nmh, 0, AF_UNSPEC, qh->id, NFQNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK); params.copy_range = htonl(range); @@ -125,9 +125,9 @@ int nfqnl_set_mode(const struct nfqnl_q_handle *qh return nfnl_send(&qh->h->nfnlh, nmh); } -static int __set_verdict(const struct nfqnl_q_handle *qh, u_int32_t id, +static int __set_verdict(struct nfqnl_q_handle *qh, u_int32_t id, u_int32_t verdict, u_int32_t mark, int set_mark, - u_int32_t data_len, unsigned char *buf) + u_int32_t data_len, unsigned char *data) { struct nfqnl_msg_verdict_hdr vh; char buf[NLMSG_LENGTH(sizeof(struct nlmsghdr)) @@ -137,13 +137,12 @@ static int __set_verdict(const struct nfqnl_q_handle *qh, u_int32_t id, struct nlmsghdr *nmh = (struct nlmsghdr *) buf; struct iovec iov[3]; - struct msghdr msg; int nvecs; vh.verdict = htonl(verdict); vh.id = htonl(id); - nfnl_fill_hdr(&qh->h->nfnlh, nmh, 0, AF_UNSPEC, queuenum, + nfnl_fill_hdr(&qh->h->nfnlh, nmh, 0, AF_UNSPEC, qh->id, NFQNL_MSG_VERDICT, NLM_F_REQUEST); /* add verdict header */ @@ -153,28 +152,28 @@ static int __set_verdict(const struct nfqnl_q_handle *qh, u_int32_t id, nfnl_addattr32(nmh, sizeof(buf), NFQA_MARK, mark); iov[0].iov_base = nmh; - iov[0].iov_len = FIXME; + iov[0].iov_len = NLMSG_TAIL(nmh) - (void *)nmh; nvecs = 1; if (data_len) { struct nfattr data_attr; nfnl_build_nfa_iovec(&iov[1], &data_attr, NFQA_PAYLOAD, - data_len, buf); + data_len, data); nvecs += 2; } - return nfnl_sendiov(&qh->h->nfnlh, &iov, nvecs, 0); + return nfnl_sendiov(&qh->h->nfnlh, iov, nvecs, 0); } -int nfqnl_set_verdict(const struct nfqnl_q_handle *qh, u_int32_t id, +int nfqnl_set_verdict(struct nfqnl_q_handle *qh, u_int32_t id, u_int32_t verdict, u_int32_t data_len, unsigned char *buf) { - return __set_verdict(qh, id, verdict, 0, 0, datalen, buf); + return __set_verdict(qh, id, verdict, 0, 0, data_len, buf); } -int nfqnl_set_verdict_mark(const struct nfqnl_q_handle *qh, u_int32_t id, +int nfqnl_set_verdict_mark(struct nfqnl_q_handle *qh, u_int32_t id, u_int32_t verdict, u_int32_t mark, u_int32_t datalen, unsigned char *buf) { diff --git a/_queue/libnfnetlink_queue.h b/_queue/libnfnetlink_queue.h index bab7893..1b807a7 100644 --- a/_queue/libnfnetlink_queue.h +++ b/_queue/libnfnetlink_queue.h @@ -12,7 +12,6 @@ #include #include #include -#include "libnfqnetlink.h" #define NFQN @@ -21,6 +20,12 @@ struct nfqnl_handle struct nfnl_handle nfnlh; }; +struct nfqnl_q_handle +{ + struct nfqnl_handle *h; + u_int16_t id; +}; + struct ctnl_msg_handler { int type; int (*handler)(struct sockaddr_nl *, struct nlmsghdr *, void *arg); @@ -31,23 +36,26 @@ struct ctnl_handle { struct ctnl_msg_handler *handler[NFQNL_MSG_MAX]; }; -extern int nfqnl_open(struct nfqnl_handle *, unsigned int ); +extern int nfqnl_open(struct nfqnl_handle *h); extern int nfqnl_close(struct nfqnl_handle *h); -extern int nfqnl_bind_pf(const struct nfqnl_handle *h, u_int16_t pf); -extern int nfqnl_unbind_pf(const struct nfqnl_handle *h, u_int16_t pf); +extern int nfqnl_bind_pf(struct nfqnl_handle *h, u_int16_t pf); +extern int nfqnl_unbind_pf(struct nfqnl_handle *h, u_int16_t pf); -extern int nfqnl_bind(const struct nfqnl_handle *h, u_int16_t num); -extern int nfqnl_unbind(const struct nfqnl_handle *h, u_int16_t num); +extern int nfqnl_create_queue(struct nfqnl_handle *h, + struct nfqnl_q_handle *qh, u_int16_t num); +extern int nfqnl_destroy_queue(struct nfqnl_q_handle *qh); -extern int nfqnl_set_mode(const struct nfqnl_handle *h, u_int16_t num, +extern int nfqnl_set_mode(struct nfqnl_q_handle *qh, u_int8_t mode, unsigned int len); -extern int nfqnl_set_verdict(const struct nfqnl_handle *h, +extern int nfqnl_set_verdict(struct nfqnl_q_handle *qh, u_int32_t id, u_int32_t verdict, - u_int32_t mark, u_int32_t data_len, unsigned char *buf); +extern int nfqnl_set_verdict_mark(struct nfqnl_q_handle *qh, u_int32_t id, + u_int32_t verdict, u_int32_t mark, + u_int32_t datalen, unsigned char *buf); #endif /* __LIBNFQNETLINK_H */ -- cgit v1.2.3