aboutsummaryrefslogtreecommitdiff
path: root/pcap-netfilter-linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'pcap-netfilter-linux.c')
-rw-r--r--pcap-netfilter-linux.c108
1 files changed, 57 insertions, 51 deletions
diff --git a/pcap-netfilter-linux.c b/pcap-netfilter-linux.c
index 2a5812b273af..bde648f3ea59 100644
--- a/pcap-netfilter-linux.c
+++ b/pcap-netfilter-linux.c
@@ -11,8 +11,8 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote
- * products derived from this software without specific prior written
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
@@ -57,14 +57,14 @@
#include <linux/netfilter/nfnetlink_queue.h>
/* NOTE: if your program drops privilages after pcap_activate() it WON'T work with nfqueue.
- * It took me quite some time to debug ;/
+ * It took me quite some time to debug ;/
*
* Sending any data to nfnetlink socket requires CAP_NET_ADMIN privilages,
* and in nfqueue we need to send verdict reply after recving packet.
*
* In tcpdump you can disable dropping privilages with -Z root
*/
-
+
#include "pcap-netfilter-linux.h"
#define HDR_LENGTH (NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct nfgenmsg))))
@@ -79,10 +79,12 @@ typedef enum { OTHER = -1, NFLOG, NFQUEUE } nftype_t;
*/
struct pcap_netfilter {
u_int packets_read; /* count of packets read with recvfrom() */
+ u_int packets_nobufs; /* ENOBUFS counter */
};
static int nfqueue_send_verdict(const pcap_t *handle, u_int16_t group_id, u_int32_t id, u_int32_t verdict);
+
static int
netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user)
{
@@ -98,28 +100,29 @@ netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_c
handle->break_loop = 0;
return -2;
}
- } while ((len == -1) && (errno == EINTR));
+ if(errno == ENOBUFS) handlep->packets_nobufs++;
+ } while ((len == -1) && (errno == EINTR || errno == ENOBUFS));
if (len < 0) {
- snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't receive packet %d:%s", errno, pcap_strerror(errno));
+ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't receive packet %d:%s", errno, pcap_strerror(errno));
return -1;
}
- buf = handle->buffer;
- while (len >= NLMSG_SPACE(0)) {
+ buf = (unsigned char *)handle->buffer;
+ while ((u_int)len >= NLMSG_SPACE(0)) {
const struct nlmsghdr *nlh = (const struct nlmsghdr *) buf;
u_int32_t msg_len;
nftype_t type = OTHER;
- if (nlh->nlmsg_len < sizeof(struct nlmsghdr) || len < nlh->nlmsg_len) {
- snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Message truncated: (got: %d) (nlmsg_len: %u)", len, nlh->nlmsg_len);
+ if (nlh->nlmsg_len < sizeof(struct nlmsghdr) || (u_int)len < nlh->nlmsg_len) {
+ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Message truncated: (got: %d) (nlmsg_len: %u)", len, nlh->nlmsg_len);
return -1;
}
- if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_ULOG &&
- NFNL_MSG_TYPE(nlh->nlmsg_type) == NFULNL_MSG_PACKET)
+ if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_ULOG &&
+ NFNL_MSG_TYPE(nlh->nlmsg_type) == NFULNL_MSG_PACKET)
type = NFLOG;
- else if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_QUEUE &&
+ else if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_QUEUE &&
NFNL_MSG_TYPE(nlh->nlmsg_type) == NFQNL_MSG_PACKET)
type = NFQUEUE;
@@ -127,14 +130,14 @@ netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_c
const unsigned char *payload = NULL;
struct pcap_pkthdr pkth;
- const struct nfgenmsg *nfg;
+ const struct nfgenmsg *nfg = NULL;
int id = 0;
if (handle->linktype != DLT_NFLOG) {
const struct nfattr *payload_attr = NULL;
if (nlh->nlmsg_len < HDR_LENGTH) {
- snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Malformed message: (nlmsg_len: %u)", nlh->nlmsg_len);
+ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Malformed message: (nlmsg_len: %u)", nlh->nlmsg_len);
return -1;
}
@@ -184,7 +187,7 @@ netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_c
gettimeofday(&pkth.ts, NULL);
if (handle->fcode.bf_insns == NULL ||
- bpf_filter(handle->fcode.bf_insns, payload, pkth.len, pkth.caplen))
+ bpf_filter(handle->fcode.bf_insns, payload, pkth.len, pkth.caplen))
{
handlep->packets_read++;
callback(user, &pkth, payload);
@@ -194,13 +197,16 @@ netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_c
if (type == NFQUEUE) {
/* XXX, possible responses: NF_DROP, NF_ACCEPT, NF_STOLEN, NF_QUEUE, NF_REPEAT, NF_STOP */
- nfqueue_send_verdict(handle, ntohs(nfg->res_id), id, NF_ACCEPT);
+ /* if type == NFQUEUE, handle->linktype is always != DLT_NFLOG,
+ so nfg is always initialized to NLMSG_DATA(nlh). */
+ if (nfg != NULL)
+ nfqueue_send_verdict(handle, ntohs(nfg->res_id), id, NF_ACCEPT);
}
}
msg_len = NLMSG_ALIGN(nlh->nlmsg_len);
- if (msg_len > len)
- msg_len = len;
+ if (msg_len > (u_int)len)
+ msg_len = (u_int)len;
len -= msg_len;
buf += msg_len;
@@ -221,7 +227,7 @@ netfilter_stats_linux(pcap_t *handle, struct pcap_stat *stats)
struct pcap_netfilter *handlep = handle->priv;
stats->ps_recv = handlep->packets_read;
- stats->ps_drop = 0;
+ stats->ps_drop = handlep->packets_nobufs;
stats->ps_ifdrop = 0;
return 0;
}
@@ -229,9 +235,9 @@ netfilter_stats_linux(pcap_t *handle, struct pcap_stat *stats)
static int
netfilter_inject_linux(pcap_t *handle, const void *buf, size_t size)
{
- snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on netfilter devices");
+ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "inject not supported on netfilter devices");
return (-1);
-}
+}
struct my_nfattr {
u_int16_t nfa_len;
@@ -249,7 +255,7 @@ netfilter_send_config_msg(const pcap_t *handle, u_int16_t msg_type, int ack, u_i
struct sockaddr_nl snl;
static unsigned int seq_id;
-
+
if (!seq_id)
seq_id = time(NULL);
++seq_id;
@@ -304,7 +310,7 @@ netfilter_send_config_msg(const pcap_t *handle, u_int16_t msg_type, int ack, u_i
if (snl.nl_pid != 0 || seq_id != nlh->nlmsg_seq) /* if not from kernel or wrong sequence skip */
continue;
- while (len >= NLMSG_SPACE(0) && NLMSG_OK(nlh, len)) {
+ while ((u_int)len >= NLMSG_SPACE(0) && NLMSG_OK(nlh, len)) {
if (nlh->nlmsg_type == NLMSG_ERROR || (nlh->nlmsg_type == NLMSG_DONE && nlh->nlmsg_flags & NLM_F_MULTI)) {
if (nlh->nlmsg_len < NLMSG_ALIGN(sizeof(struct nlmsgerr))) {
errno = EBADMSG;
@@ -341,7 +347,7 @@ nflog_send_config_cmd(const pcap_t *handle, u_int16_t group_id, u_int8_t cmd, u_
return nflog_send_config_msg(handle, family, group_id, &nfa);
}
-static int
+static int
nflog_send_config_mode(const pcap_t *handle, u_int16_t group_id, u_int8_t copy_mode, u_int32_t copy_range)
{
struct nfulnl_msg_config_mode msg;
@@ -395,7 +401,7 @@ nfqueue_send_config_cmd(const pcap_t *handle, u_int16_t group_id, u_int8_t cmd,
return nfqueue_send_config_msg(handle, AF_UNSPEC, group_id, &nfa);
}
-static int
+static int
nfqueue_send_config_mode(const pcap_t *handle, u_int16_t group_id, u_int8_t copy_mode, u_int32_t copy_range)
{
struct nfqnl_msg_config_params msg;
@@ -414,7 +420,7 @@ nfqueue_send_config_mode(const pcap_t *handle, u_int16_t group_id, u_int8_t copy
static int
netfilter_activate(pcap_t* handle)
{
- const char *dev = handle->opt.source;
+ const char *dev = handle->opt.device;
unsigned short groups[32];
int group_count = 0;
nftype_t type = OTHER;
@@ -428,7 +434,7 @@ netfilter_activate(pcap_t* handle)
dev += strlen(NFQUEUE_IFACE);
type = NFQUEUE;
}
-
+
if (type != OTHER && *dev == ':') {
dev++;
while (*dev) {
@@ -436,16 +442,16 @@ netfilter_activate(pcap_t* handle)
char *end_dev;
if (group_count == 32) {
- snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
- "Maximum 32 netfilter groups! dev: %s",
- handle->opt.source);
+ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "Maximum 32 netfilter groups! dev: %s",
+ handle->opt.device);
return PCAP_ERROR;
}
group_id = strtol(dev, &end_dev, 0);
if (end_dev != dev) {
if (group_id < 0 || group_id > 65535) {
- snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Netfilter group range from 0 to 65535 (got %ld)",
group_id);
return PCAP_ERROR;
@@ -461,9 +467,9 @@ netfilter_activate(pcap_t* handle)
}
if (type == OTHER || *dev) {
- snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
- "Can't get netfilter group(s) index from %s",
- handle->opt.source);
+ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
+ "Can't get netfilter group(s) index from %s",
+ handle->opt.device);
return PCAP_ERROR;
}
@@ -488,7 +494,7 @@ netfilter_activate(pcap_t* handle)
/* Create netlink socket */
handle->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER);
if (handle->fd < 0) {
- snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't create raw socket %d:%s", errno, pcap_strerror(errno));
+ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't create raw socket %d:%s", errno, pcap_strerror(errno));
return PCAP_ERROR;
}
@@ -506,54 +512,54 @@ netfilter_activate(pcap_t* handle)
handle->buffer = malloc(handle->bufsize);
if (!handle->buffer) {
- snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate dump buffer: %s", pcap_strerror(errno));
+ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't allocate dump buffer: %s", pcap_strerror(errno));
goto close_fail;
}
if (type == NFLOG) {
if (nflog_send_config_cmd(handle, 0, NFULNL_CFG_CMD_PF_UNBIND, AF_INET) < 0) {
- snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFULNL_CFG_CMD_PF_UNBIND: %s", pcap_strerror(errno));
+ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFULNL_CFG_CMD_PF_UNBIND: %s", pcap_strerror(errno));
goto close_fail;
}
if (nflog_send_config_cmd(handle, 0, NFULNL_CFG_CMD_PF_BIND, AF_INET) < 0) {
- snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFULNL_CFG_CMD_PF_BIND: %s", pcap_strerror(errno));
+ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFULNL_CFG_CMD_PF_BIND: %s", pcap_strerror(errno));
goto close_fail;
}
/* Bind socket to the nflog groups */
for (i = 0; i < group_count; i++) {
if (nflog_send_config_cmd(handle, groups[i], NFULNL_CFG_CMD_BIND, AF_UNSPEC) < 0) {
- snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't listen on group group index: %s", pcap_strerror(errno));
+ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't listen on group group index: %s", pcap_strerror(errno));
goto close_fail;
}
if (nflog_send_config_mode(handle, groups[i], NFULNL_COPY_PACKET, handle->snapshot) < 0) {
- snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFULNL_COPY_PACKET: %s", pcap_strerror(errno));
+ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFULNL_COPY_PACKET: %s", pcap_strerror(errno));
goto close_fail;
}
}
} else {
if (nfqueue_send_config_cmd(handle, 0, NFQNL_CFG_CMD_PF_UNBIND, AF_INET) < 0) {
- snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFQNL_CFG_CMD_PF_UNBIND: %s", pcap_strerror(errno));
+ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFQNL_CFG_CMD_PF_UNBIND: %s", pcap_strerror(errno));
goto close_fail;
}
if (nfqueue_send_config_cmd(handle, 0, NFQNL_CFG_CMD_PF_BIND, AF_INET) < 0) {
- snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFQNL_CFG_CMD_PF_BIND: %s", pcap_strerror(errno));
+ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFQNL_CFG_CMD_PF_BIND: %s", pcap_strerror(errno));
goto close_fail;
}
/* Bind socket to the nfqueue groups */
for (i = 0; i < group_count; i++) {
if (nfqueue_send_config_cmd(handle, groups[i], NFQNL_CFG_CMD_BIND, AF_UNSPEC) < 0) {
- snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't listen on group group index: %s", pcap_strerror(errno));
+ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Can't listen on group group index: %s", pcap_strerror(errno));
goto close_fail;
}
if (nfqueue_send_config_mode(handle, groups[i], NFQNL_COPY_PACKET, handle->snapshot) < 0) {
- snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFQNL_COPY_PACKET: %s", pcap_strerror(errno));
+ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "NFQNL_COPY_PACKET: %s", pcap_strerror(errno));
goto close_fail;
}
}
@@ -572,7 +578,7 @@ netfilter_activate(pcap_t* handle)
* Set the socket buffer size to the specified value.
*/
if (setsockopt(handle->fd, SOL_SOCKET, SO_RCVBUF, &handle->opt.buffer_size, sizeof(handle->opt.buffer_size)) == -1) {
- snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "SO_RCVBUF: %s", pcap_strerror(errno));
+ pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "SO_RCVBUF: %s", pcap_strerror(errno));
goto close_fail;
}
}
@@ -599,7 +605,7 @@ netfilter_create(const char *device, char *ebuf, int *is_ours)
/* Does it begin with NFLOG_IFACE or NFQUEUE_IFACE? */
if (strncmp(cp, NFLOG_IFACE, sizeof NFLOG_IFACE - 1) == 0)
cp += sizeof NFLOG_IFACE - 1;
- else if (strncmp(cp, NFQUEUE_IFACE, sizeof NFQUEUE_IFACE - 1) == 0)
+ else if (strncmp(cp, NFQUEUE_IFACE, sizeof NFQUEUE_IFACE - 1) == 0)
cp += sizeof NFQUEUE_IFACE - 1;
else {
/* Nope, doesn't begin with NFLOG_IFACE nor NFQUEUE_IFACE */
@@ -620,7 +626,7 @@ netfilter_create(const char *device, char *ebuf, int *is_ours)
/* OK, it's probably ours. */
*is_ours = 1;
- p = pcap_create_common(device, ebuf, sizeof (struct pcap_netfilter));
+ p = pcap_create_common(ebuf, sizeof (struct pcap_netfilter));
if (p == NULL)
return (NULL);
@@ -628,17 +634,17 @@ netfilter_create(const char *device, char *ebuf, int *is_ours)
return (p);
}
-int
+int
netfilter_findalldevs(pcap_if_t **alldevsp, char *err_str)
{
int sock;
-
+
sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER);
if (sock < 0) {
/* if netlink is not supported this is not fatal */
if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT)
return 0;
- snprintf(err_str, PCAP_ERRBUF_SIZE, "Can't open netlink socket %d:%s",
+ pcap_snprintf(err_str, PCAP_ERRBUF_SIZE, "Can't open netlink socket %d:%s",
errno, pcap_strerror(errno));
return -1;
}