Ejemplo n.º 1
0
int nfnl_check_attributes(const struct nfnl_handle *h,
			 const struct nlmsghdr *nlh,
			 struct nfattr *nfa[])
{
	assert(h);
	assert(nlh);
	assert(nfa);

	int min_len;
	uint8_t type = NFNL_MSG_TYPE(nlh->nlmsg_type);
	uint8_t subsys_id = NFNL_SUBSYS_ID(nlh->nlmsg_type);
	const struct nfnl_subsys_handle *ssh;
	struct nfnl_callback *cb;

	if (subsys_id > NFNL_MAX_SUBSYS)
		return -EINVAL;

	ssh = &h->subsys[subsys_id];
 	cb = &ssh->cb[type];

#if 1
	/* checks need to be enabled as soon as this is called from
	 * somebody else than __nfnl_handle_msg */
	if (type >= ssh->cb_count)
		return -EINVAL;

	min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
	if (nlh->nlmsg_len < min_len)
		return -EINVAL;
#endif
	memset(nfa, 0, sizeof(struct nfattr *) * cb->attr_count);

	if (nlh->nlmsg_len > min_len) {
		struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh));
		int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);

		while (NFA_OK(attr, attrlen)) {
			unsigned int flavor = NFA_TYPE(attr);
			if (flavor) {
				if (flavor > cb->attr_count) {
					/* we have received an attribute from
					 * the kernel which we don't understand
					 * yet. We have to silently ignore this
					 * for the sake of future compatibility */
					attr = NFA_NEXT(attr, attrlen);
					continue;
				}
				nfa[flavor - 1] = attr;
			}
			attr = NFA_NEXT(attr, attrlen);
		}
	}

	return 0;
}
Ejemplo n.º 2
0
/**
 * nfnetlink_check_attributes - check and parse nfnetlink attributes
 *
 * subsys: nfnl subsystem for which this message is to be parsed
 * nlmsghdr: netlink message to be checked/parsed
 * cda: array of pointers, needs to be at least subsys->attr_count big
 *
 */
static int
nfnetlink_check_attributes(struct nfnetlink_subsystem *subsys,
			   struct nlmsghdr *nlh, struct nfattr *cda[])
{
	int min_len;
	u_int16_t attr_count;
	u_int8_t cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);

	if (unlikely(cb_id >= subsys->cb_count)) {
		DEBUGP("msgtype %u >= %u, returning\n",
			cb_id, subsys->cb_count);
		return -EINVAL;
	}

	min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
	if (unlikely(nlh->nlmsg_len < min_len))
		return -EINVAL;

	attr_count = subsys->cb[cb_id].attr_count;
	memset(cda, 0, sizeof(struct nfattr *) * attr_count);

	/* check attribute lengths. */
	if (likely(nlh->nlmsg_len > min_len)) {
		struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh));
		int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);

		while (NFA_OK(attr, attrlen)) {
			unsigned flavor = NFA_TYPE(attr);
			if (flavor) {
				if (flavor > attr_count)
					return -EINVAL;
				cda[flavor - 1] = attr;
			}
			attr = NFA_NEXT(attr, attrlen);
		}
	}

	/* implicit: if nlmsg_len == min_len, we return 0, and an empty
	 * (zeroed) cda[] array. The message is valid, but empty. */

        return 0;
}
Ejemplo n.º 3
0
/**
 * nfnetlink_check_attributes - check and parse nfnetlink attributes
 *
 * subsys: nfnl subsystem for which this message is to be parsed
 * nlmsghdr: netlink message to be checked/parsed
 * cda: array of pointers, needs to be at least subsys->attr_count big
 *
 */
static int
nfnetlink_check_attributes(struct nfnetlink_subsystem *subsys,
			   struct nlmsghdr *nlh, struct nfattr *cda[])
{
	int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
	u_int8_t cb_id = NFNL_MSG_TYPE(nlh->nlmsg_type);
	u_int16_t attr_count = subsys->cb[cb_id].attr_count;

	/* check attribute lengths. */
	if (likely(nlh->nlmsg_len > min_len)) {
		struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh));
		int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
		nfattr_parse(cda, attr_count, attr, attrlen);
	}

	/* implicit: if nlmsg_len == min_len, we return 0, and an empty
	 * (zeroed) cda[] array. The message is valid, but empty. */

	return 0;
}
Ejemplo n.º 4
0
void nfnl_dump_packet(struct nlmsghdr *nlh, int received_len, char *desc)
{
	void *nlmsg_data = NLMSG_DATA(nlh);
	struct nfattr *nfa = NFM_NFA(NLMSG_DATA(nlh));
	int len = NFM_PAYLOAD(nlh);

	printf("%s called from %s\n", __FUNCTION__, desc);
	printf("  nlmsghdr = %p, received_len = %u\n", nlh, received_len);
	printf("  NLMSG_DATA(nlh) = %p (+%td bytes)\n", nlmsg_data,
	       (nlmsg_data - (void *)nlh));
	printf("  NFM_NFA(NLMSG_DATA(nlh)) = %p (+%td bytes)\n",
		nfa, ((void *)nfa - (void *)nlh));
	printf("  NFM_PAYLOAD(nlh) = %u\n", len);
	printf("  nlmsg_type = %u, nlmsg_len = %u, nlmsg_seq = %u "
		"nlmsg_flags = 0x%x\n", nlh->nlmsg_type, nlh->nlmsg_len,
		nlh->nlmsg_seq, nlh->nlmsg_flags);

	while (NFA_OK(nfa, len)) {
		printf("    nfa@%p: nfa_type=%u, nfa_len=%u\n",
			nfa, NFA_TYPE(nfa), nfa->nfa_len);
		nfa = NFA_NEXT(nfa,len);
	}
}
Ejemplo n.º 5
0
static int
netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user)
{
	struct pcap_netfilter *handlep = handle->priv;
	const unsigned char *buf;
	int count = 0;
	int len;

	/* ignore interrupt system call error */
	do {
		len = recv(handle->fd, handle->buffer, handle->bufsize, 0);
		if (handle->break_loop) {
			handle->break_loop = 0;
			return -2;
		}
	} while ((len == -1) && (errno == EINTR));

	if (len < 0) {
		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)) {
		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);
			return -1;
		}

		if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_ULOG && 
			NFNL_MSG_TYPE(nlh->nlmsg_type) == NFULNL_MSG_PACKET) 
				type = NFLOG;

		if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_QUEUE && 
			NFNL_MSG_TYPE(nlh->nlmsg_type) == NFQNL_MSG_PACKET)
				type = NFQUEUE;

		if (type != OTHER) {
			const unsigned char *payload = NULL;
			struct pcap_pkthdr pkth;

			const struct nfgenmsg *nfg;
			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);
					return -1;
				}

				nfg = NLMSG_DATA(nlh);
				if (nlh->nlmsg_len > HDR_LENGTH) {
					struct nfattr *attr = NFM_NFA(nfg);
					int attr_len = nlh->nlmsg_len - NLMSG_ALIGN(HDR_LENGTH);

					while (NFA_OK(attr, attr_len)) {
						if (type == NFQUEUE) {
							switch (NFA_TYPE(attr)) {
								case NFQA_PACKET_HDR:
									{
										const struct nfqnl_msg_packet_hdr *pkt_hdr = (const struct nfqnl_msg_packet_hdr *) NFA_DATA(attr);

										id = ntohl(pkt_hdr->packet_id);
										break;
									}
								case NFQA_PAYLOAD:
									payload_attr = attr;
									break;
							}

						} else if (type == NFLOG) {
							switch (NFA_TYPE(attr)) {
								case NFULA_PAYLOAD:
									payload_attr = attr;
									break;
							}
						}
						attr = NFA_NEXT(attr, attr_len);
					}
				}

				if (payload_attr) {
					payload = NFA_DATA(payload_attr);
					pkth.len = pkth.caplen = NFA_PAYLOAD(payload_attr);
				}

			} else {
				payload = NLMSG_DATA(nlh);
				pkth.caplen = pkth.len = nlh->nlmsg_len-NLMSG_ALIGN(sizeof(struct nlmsghdr));
			}

			if (payload) {
				/* pkth.caplen = min (payload_len, handle->snapshot); */

				gettimeofday(&pkth.ts, NULL);
				if (handle->fcode.bf_insns == NULL ||
						bpf_filter(handle->fcode.bf_insns, payload, pkth.len, pkth.caplen)) 
				{
					handlep->packets_read++;
					callback(user, &pkth, payload);
					count++;
				}
			}

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

		msg_len = NLMSG_ALIGN(nlh->nlmsg_len);
		if (msg_len > len)
			msg_len = len;

		len -= msg_len;
		buf += msg_len;
	}
	return count;
}
Ejemplo n.º 6
0
/* On error, -1 is returned and errno is set appropiately. On success, 
 * 0 is returned if there is no more data to process, >0 if there is
 * more data to process */
static int nfnl_step(struct nfnl_handle *h, struct nlmsghdr *nlh)
{
	struct nfnl_subsys_handle *ssh;
	uint8_t type = NFNL_MSG_TYPE(nlh->nlmsg_type);
	uint8_t subsys_id = NFNL_SUBSYS_ID(nlh->nlmsg_type);

	/* Is this an error message? */
	if (nfnl_is_error(h, nlh)) {
		/* This is an ACK */
		if (errno == 0)
			return 0;
		/* This an error message */
		return -1;
	}
	
	/* nfnetlink sanity checks: check for nfgenmsg size */
	if (nlh->nlmsg_len < NLMSG_SPACE(sizeof(struct nfgenmsg))) {
		errno = ENOSPC;
		return -1;
	}

	if (subsys_id > NFNL_MAX_SUBSYS) {
		errno = ENOENT;
		return -1;
	}

	ssh = &h->subsys[subsys_id];
	if (!ssh) {
		errno = ENOENT;
		return -1;
	}

	if (type >= ssh->cb_count) {
		errno = ENOENT;
		return -1;
	}

	if (ssh->cb[type].attr_count) {
		int err;
		struct nfattr *tb[ssh->cb[type].attr_count];
		struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh));
		int min_len = NLMSG_SPACE(sizeof(struct nfgenmsg));
		int len = nlh->nlmsg_len - NLMSG_ALIGN(min_len);

		err = nfnl_parse_attr(tb, ssh->cb[type].attr_count, attr, len);
		if (err == -1)
			return -1;

		if (ssh->cb[type].call) {
			/*
			 * On error, the callback returns NFNL_CB_FAILURE and
			 * errno must be explicitely set. On success, 
			 * NFNL_CB_STOP is returned and we're done, otherwise 
			 * NFNL_CB_CONTINUE means that we want to continue 
			 * data processing.
			 */
			return ssh->cb[type].call(nlh,
						  tb,
						  ssh->cb[type].data);
		}
	}
	/* no callback set, continue data processing */
	return 1;
}
ulog_packet_msg_t *ipulog_get_packet(struct ipulog_handle *h,
				     const unsigned char *buf,
				     size_t len)
{
	struct nlmsghdr *nlh;
	struct nfattr *tb[NFULA_MAX];
	struct nfulnl_msg_packet_hdr *hdr;

	if (!h->last_nlh) {
		printf("first\n");
		nlh = nfnl_get_msg_first(nflog_nfnlh(h->nfulh), buf, len);
	}else {
next_msg:	printf("next\n");
		nlh = nfnl_get_msg_next(nflog_nfnlh(h->nfulh), buf, len);
	}
	h->last_nlh = nlh;

	if (!nlh)
		return NULL;

	nfnl_parse_attr(tb, NFULA_MAX, NFM_NFA(NLMSG_DATA(nlh)),
			NFM_PAYLOAD(nlh));
	
	if (!tb[NFULA_PACKET_HDR-1])
		goto next_msg;

	/* now build the fake ulog_packet_msg */
	hdr = NFA_DATA(tb[NFULA_PACKET_HDR-1]);
	h->upmsg.hook = hdr->hook;

	if (tb[NFULA_MARK-1])
		h->upmsg.mark = ntohl(*(u_int32_t *)NFA_DATA(tb[NFULA_MARK-1]));
	else
		h->upmsg.mark = 0;

	if (tb[NFULA_TIMESTAMP]) {
		/* FIXME: 64bit network-to-host */
		h->upmsg.timestamp_sec = h->upmsg.timestamp_usec = 0;
	} else
		h->upmsg.timestamp_sec = h->upmsg.timestamp_usec = 0;

	if (tb[NFULA_IFINDEX_INDEV-1]) {
		/* FIXME: ifindex lookup */	
		h->upmsg.indev_name[0] = '\0';
	} else
		h->upmsg.indev_name[0] = '\0';

	if (tb[NFULA_IFINDEX_OUTDEV-1]) {
		/* FIXME: ifindex lookup */	
		h->upmsg.outdev_name[0] = '\0';
	} else
		h->upmsg.outdev_name[0] = '\0';

	if (tb[NFULA_HWADDR-1]) {
		struct nfulnl_msg_packet_hw *phw = NFA_DATA(tb[NFULA_HWADDR-1]);
		h->upmsg.mac_len = ntohs(phw->hw_addrlen);
		memcpy(h->upmsg.mac, phw->hw_addr, 8);
	} else
		h->upmsg.mac_len = 0;

	if (tb[NFULA_PREFIX-1]) {
		int plen = NFA_PAYLOAD(tb[NFULA_PREFIX-1]);
		if (ULOG_PREFIX_LEN < plen)
			plen = ULOG_PREFIX_LEN;
		memcpy(h->upmsg.prefix, NFA_DATA(tb[NFULA_PREFIX-1]), plen);
		h->upmsg.prefix[ULOG_PREFIX_LEN-1] = '\0';
	}

	if (tb[NFULA_PAYLOAD-1]) {
		memcpy(h->upmsg.payload, NFA_DATA(tb[NFULA_PAYLOAD-1]),
			NFA_PAYLOAD(tb[NFULA_PAYLOAD-1]));
		h->upmsg.data_len = NFA_PAYLOAD(tb[NFULA_PAYLOAD-1]);
	} else
		h->upmsg.data_len = 0;
	
	return &h->upmsg;
}
Ejemplo n.º 8
0
static int
nflog_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user)
{
	const unsigned char *buf;
	int count = 0;
	int len;

	/* ignore interrupt system call error */
	do {
		len = recv(handle->fd, handle->buffer, handle->bufsize, 0);
		if (handle->break_loop) {
			handle->break_loop = 0;
			return -2;
		}
	} while ((len == -1) && (errno == EINTR));

	if (len < 0) {
		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)) {
		const struct nlmsghdr *nlh = (const struct nlmsghdr *) buf;
		u_int32_t msg_len;

		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);
			return -1;
		}

		if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_ULOG &&
			NFNL_MSG_TYPE(nlh->nlmsg_type) == NFULNL_MSG_PACKET)
		{
			const unsigned char *payload = NULL;
			struct pcap_pkthdr pkth;

			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);
					return -1;
				}

				if (nlh->nlmsg_len > HDR_LENGTH) {
					struct nfattr *attr = NFM_NFA(NLMSG_DATA(nlh));
					int attr_len = nlh->nlmsg_len - NLMSG_ALIGN(HDR_LENGTH);

					while (NFA_OK(attr, attr_len)) {
						switch (NFA_TYPE(attr)) {
							case NFULA_PAYLOAD:
								payload_attr = attr;
								break;
						}
						attr = NFA_NEXT(attr, attr_len);
					}
				}

				if (payload_attr) {
					payload = NFA_DATA(payload_attr);
					pkth.len = pkth.caplen = NFA_PAYLOAD(payload_attr);
				}

			} else {
				payload = NLMSG_DATA(nlh);
				pkth.caplen = pkth.len = nlh->nlmsg_len-NLMSG_ALIGN(sizeof(struct nlmsghdr));
			}

			if (payload) {
				/* pkth.caplen = min (payload_len, handle->snapshot); */

				gettimeofday(&pkth.ts, NULL);
				if (handle->fcode.bf_insns == NULL ||
						bpf_filter(handle->fcode.bf_insns, payload, pkth.len, pkth.caplen))
				{
					handle->md.packets_read++;
					callback(user, &pkth, payload);
					count++;
				}
			}
		}

		msg_len = NLMSG_ALIGN(nlh->nlmsg_len);
		if (msg_len > len)
			msg_len = len;

		len -= msg_len;
		buf += msg_len;
	}
	return count;
}
Ejemplo n.º 9
0
static int
netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user)
{
	struct pcap_netfilter *handlep = handle->priv;
	register u_char *bp, *ep;
	int count = 0;
	ssize_t len;

	/*
	 * Has "pcap_breakloop()" been called?
	 */
	if (handle->break_loop) {
		/*
		 * Yes - clear the flag that indicates that it
		 * has, and return PCAP_ERROR_BREAK to indicate
		 * that we were told to break out of the loop.
		 */
		handle->break_loop = 0;
		return PCAP_ERROR_BREAK;
	}
	len = handle->cc;
	if (len == 0) {
		/*
		 * The buffer is empty; refill it.
		 *
		 * We ignore EINTR, as that might just be due to a signal
		 * being delivered - if the signal should interrupt the
		 * loop, the signal handler should call pcap_breakloop()
		 * to set handle->break_loop (we ignore it on other
		 * platforms as well).
		 */
		do {
			len = recv(handle->fd, handle->buffer, handle->bufsize, 0);
			if (handle->break_loop) {
				handle->break_loop = 0;
				return PCAP_ERROR_BREAK;
			}
			if (errno == ENOBUFS)
				handlep->packets_nobufs++;
		} while ((len == -1) && (errno == EINTR || errno == ENOBUFS));

		if (len < 0) {
			pcap_fmt_errmsg_for_errno(handle->errbuf,
			    PCAP_ERRBUF_SIZE, errno, "Can't receive packet");
			return PCAP_ERROR;
		}

		bp = (unsigned char *)handle->buffer;
	} else
		bp = handle->bp;
	ep = bp + len;
	while (bp < ep) {
		const struct nlmsghdr *nlh = (const struct nlmsghdr *) bp;
		uint32_t msg_len;
		nftype_t type = OTHER;
		/*
		 * Has "pcap_breakloop()" been called?
		 * If so, return immediately - if we haven't read any
		 * packets, clear the flag and return PCAP_ERROR_BREAK
		 * to indicate that we were told to break out of the loop,
		 * otherwise leave the flag set, so that the *next* call
		 * will break out of the loop without having read any
		 * packets, and return the number of packets we've
		 * processed so far.
		 */
		if (handle->break_loop) {
			handle->bp = bp;
			handle->cc = (int)(ep - bp);
			if (count == 0) {
				handle->break_loop = 0;
				return PCAP_ERROR_BREAK;
			} else
				return count;
		}
		if (ep - bp < NLMSG_SPACE(0)) {
			/*
			 * There's less than one netlink message left
			 * in the buffer.  Give up.
			 */
			break;
		}

		if (nlh->nlmsg_len < sizeof(struct nlmsghdr) || (u_int)len < nlh->nlmsg_len) {
			pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Message truncated: (got: %zd) (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)
			type = NFLOG;
		else if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_QUEUE &&
		         NFNL_MSG_TYPE(nlh->nlmsg_type) == NFQNL_MSG_PACKET)
			type = NFQUEUE;

		if (type != OTHER) {
			const unsigned char *payload = NULL;
			struct pcap_pkthdr pkth;

			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) {
					pcap_snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Malformed message: (nlmsg_len: %u)", nlh->nlmsg_len);
					return -1;
				}

				nfg = NLMSG_DATA(nlh);
				if (nlh->nlmsg_len > HDR_LENGTH) {
					struct nfattr *attr = NFM_NFA(nfg);
					int attr_len = nlh->nlmsg_len - NLMSG_ALIGN(HDR_LENGTH);

					while (NFA_OK(attr, attr_len)) {
						if (type == NFQUEUE) {
							switch (NFA_TYPE(attr)) {
								case NFQA_PACKET_HDR:
									{
										const struct nfqnl_msg_packet_hdr *pkt_hdr = (const struct nfqnl_msg_packet_hdr *) NFA_DATA(attr);

										id = ntohl(pkt_hdr->packet_id);
										break;
									}
								case NFQA_PAYLOAD:
									payload_attr = attr;
									break;
							}

						} else if (type == NFLOG) {
							switch (NFA_TYPE(attr)) {
								case NFULA_PAYLOAD:
									payload_attr = attr;
									break;
							}
						}
						attr = NFA_NEXT(attr, attr_len);
					}
				}

				if (payload_attr) {
					payload = NFA_DATA(payload_attr);
					pkth.len = pkth.caplen = NFA_PAYLOAD(payload_attr);
				}

			} else {
				payload = NLMSG_DATA(nlh);
				pkth.caplen = pkth.len = nlh->nlmsg_len-NLMSG_ALIGN(sizeof(struct nlmsghdr));
			}

			if (payload) {
				/* pkth.caplen = min (payload_len, handle->snapshot); */

				gettimeofday(&pkth.ts, NULL);
				if (handle->fcode.bf_insns == NULL ||
						pcap_filter(handle->fcode.bf_insns, payload, pkth.len, pkth.caplen))
				{
					handlep->packets_read++;
					callback(user, &pkth, payload);
					count++;
				}
			}

			if (type == NFQUEUE) {
				/* XXX, possible responses: NF_DROP, NF_ACCEPT, NF_STOLEN, NF_QUEUE, NF_REPEAT, NF_STOP */
				/* 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 the message length would run past the end of the
		 * buffer, truncate it to the remaining space in the
		 * buffer.
		 */
		if (msg_len > ep - bp)
			msg_len = (uint32_t)(ep - bp);

		bp += msg_len;
		if (count >= max_packets && !PACKET_COUNT_IS_UNLIMITED(max_packets)) {
			handle->bp = bp;
			handle->cc = (int)(ep - bp);
			if (handle->cc < 0)
				handle->cc = 0;
			return count;
		}
	}

	handle->cc = 0;
	return count;
}