1d1e87331SXin LI /*
2d1e87331SXin LI * Copyright (c) 2011 Jakub Zawadzki
3d1e87331SXin LI * All rights reserved.
4d1e87331SXin LI *
5d1e87331SXin LI * Redistribution and use in source and binary forms, with or without
6d1e87331SXin LI * modification, are permitted provided that the following conditions
7d1e87331SXin LI * are met:
8d1e87331SXin LI *
9d1e87331SXin LI * 1. Redistributions of source code must retain the above copyright
10d1e87331SXin LI * notice, this list of conditions and the following disclaimer.
11d1e87331SXin LI * 2. Redistributions in binary form must reproduce the above copyright
12d1e87331SXin LI * notice, this list of conditions and the following disclaimer in the
13d1e87331SXin LI * documentation and/or other materials provided with the distribution.
14d1e87331SXin LI * 3. The name of the author may not be used to endorse or promote
15d1e87331SXin LI * products derived from this software without specific prior written
16d1e87331SXin LI * permission.
17d1e87331SXin LI *
18d1e87331SXin LI * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19d1e87331SXin LI * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20d1e87331SXin LI * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21d1e87331SXin LI * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22d1e87331SXin LI * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23d1e87331SXin LI * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24d1e87331SXin LI * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25d1e87331SXin LI * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26d1e87331SXin LI * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27d1e87331SXin LI * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28d1e87331SXin LI * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29d1e87331SXin LI */
30d1e87331SXin LI
31b00ab754SHans Petter Selasky #include <config.h>
32d1e87331SXin LI
33d1e87331SXin LI #include "pcap-int.h"
346f9cba8fSJoseph Mingrone #include "diag-control.h"
35d1e87331SXin LI
36d1e87331SXin LI #ifdef NEED_STRERROR_H
37d1e87331SXin LI #include "strerror.h"
38d1e87331SXin LI #endif
39d1e87331SXin LI
40d1e87331SXin LI #include <errno.h>
41d1e87331SXin LI #include <stdlib.h>
42d1e87331SXin LI #include <unistd.h>
43d1e87331SXin LI #include <string.h>
44d1e87331SXin LI #include <sys/socket.h>
45d1e87331SXin LI #include <arpa/inet.h>
46d1e87331SXin LI
47d1e87331SXin LI #include <time.h>
48d1e87331SXin LI #include <sys/time.h>
49d1e87331SXin LI #include <netinet/in.h>
50d1e87331SXin LI #include <linux/types.h>
51d1e87331SXin LI
52d1e87331SXin LI #include <linux/netlink.h>
53edc89b24SXin LI #include <linux/netfilter.h>
54d1e87331SXin LI #include <linux/netfilter/nfnetlink.h>
55d1e87331SXin LI #include <linux/netfilter/nfnetlink_log.h>
56edc89b24SXin LI #include <linux/netfilter/nfnetlink_queue.h>
57edc89b24SXin LI
586f9cba8fSJoseph Mingrone /* NOTE: if your program drops privileges after pcap_activate() it WON'T work with nfqueue.
59edc89b24SXin LI * It took me quite some time to debug ;/
60edc89b24SXin LI *
616f9cba8fSJoseph Mingrone * Sending any data to nfnetlink socket requires CAP_NET_ADMIN privileges,
62*afdbf109SJoseph Mingrone * and in nfqueue we need to send verdict reply after receiving packet.
63edc89b24SXin LI *
646f9cba8fSJoseph Mingrone * In tcpdump you can disable dropping privileges with -Z root
65edc89b24SXin LI */
66d1e87331SXin LI
67d1e87331SXin LI #include "pcap-netfilter-linux.h"
68d1e87331SXin LI
69d1e87331SXin LI #define HDR_LENGTH (NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct nfgenmsg))))
70d1e87331SXin LI
71d1e87331SXin LI #define NFLOG_IFACE "nflog"
72edc89b24SXin LI #define NFQUEUE_IFACE "nfqueue"
73edc89b24SXin LI
74edc89b24SXin LI typedef enum { OTHER = -1, NFLOG, NFQUEUE } nftype_t;
75edc89b24SXin LI
76681ed54cSXin LI /*
77681ed54cSXin LI * Private data for capturing on Linux netfilter sockets.
78681ed54cSXin LI */
79681ed54cSXin LI struct pcap_netfilter {
80681ed54cSXin LI u_int packets_read; /* count of packets read with recvfrom() */
81ada6f083SXin LI u_int packets_nobufs; /* ENOBUFS counter */
82681ed54cSXin LI };
83681ed54cSXin LI
84b00ab754SHans Petter Selasky static int nfqueue_send_verdict(const pcap_t *handle, uint16_t group_id, u_int32_t id, u_int32_t verdict);
85d1e87331SXin LI
86ada6f083SXin LI
87d1e87331SXin LI static int
netfilter_read_linux(pcap_t * handle,int max_packets,pcap_handler callback,u_char * user)88edc89b24SXin LI netfilter_read_linux(pcap_t *handle, int max_packets, pcap_handler callback, u_char *user)
89d1e87331SXin LI {
90681ed54cSXin LI struct pcap_netfilter *handlep = handle->priv;
91b00ab754SHans Petter Selasky register u_char *bp, *ep;
92d1e87331SXin LI int count = 0;
936f9cba8fSJoseph Mingrone ssize_t len;
94d1e87331SXin LI
95b00ab754SHans Petter Selasky /*
96b00ab754SHans Petter Selasky * Has "pcap_breakloop()" been called?
97b00ab754SHans Petter Selasky */
98b00ab754SHans Petter Selasky if (handle->break_loop) {
99b00ab754SHans Petter Selasky /*
100b00ab754SHans Petter Selasky * Yes - clear the flag that indicates that it
101b00ab754SHans Petter Selasky * has, and return PCAP_ERROR_BREAK to indicate
102b00ab754SHans Petter Selasky * that we were told to break out of the loop.
103b00ab754SHans Petter Selasky */
104b00ab754SHans Petter Selasky handle->break_loop = 0;
105b00ab754SHans Petter Selasky return PCAP_ERROR_BREAK;
106b00ab754SHans Petter Selasky }
107b00ab754SHans Petter Selasky len = handle->cc;
108b00ab754SHans Petter Selasky if (len == 0) {
109b00ab754SHans Petter Selasky /*
110b00ab754SHans Petter Selasky * The buffer is empty; refill it.
111b00ab754SHans Petter Selasky *
112b00ab754SHans Petter Selasky * We ignore EINTR, as that might just be due to a signal
113b00ab754SHans Petter Selasky * being delivered - if the signal should interrupt the
114b00ab754SHans Petter Selasky * loop, the signal handler should call pcap_breakloop()
115b00ab754SHans Petter Selasky * to set handle->break_loop (we ignore it on other
116b00ab754SHans Petter Selasky * platforms as well).
117b00ab754SHans Petter Selasky */
118d1e87331SXin LI do {
119d1e87331SXin LI len = recv(handle->fd, handle->buffer, handle->bufsize, 0);
120d1e87331SXin LI if (handle->break_loop) {
121d1e87331SXin LI handle->break_loop = 0;
122b00ab754SHans Petter Selasky return PCAP_ERROR_BREAK;
123d1e87331SXin LI }
124*afdbf109SJoseph Mingrone if (len == -1 && errno == ENOBUFS)
125b00ab754SHans Petter Selasky handlep->packets_nobufs++;
126ada6f083SXin LI } while ((len == -1) && (errno == EINTR || errno == ENOBUFS));
127d1e87331SXin LI
128d1e87331SXin LI if (len < 0) {
129*afdbf109SJoseph Mingrone pcapint_fmt_errmsg_for_errno(handle->errbuf,
130b00ab754SHans Petter Selasky PCAP_ERRBUF_SIZE, errno, "Can't receive packet");
131b00ab754SHans Petter Selasky return PCAP_ERROR;
132d1e87331SXin LI }
133d1e87331SXin LI
134b00ab754SHans Petter Selasky bp = (unsigned char *)handle->buffer;
135b00ab754SHans Petter Selasky } else
136b00ab754SHans Petter Selasky bp = handle->bp;
1376f9cba8fSJoseph Mingrone
1386f9cba8fSJoseph Mingrone /*
1396f9cba8fSJoseph Mingrone * Loop through each message.
1406f9cba8fSJoseph Mingrone *
1416f9cba8fSJoseph Mingrone * This assumes that a single buffer of message will have
1426f9cba8fSJoseph Mingrone * <= INT_MAX packets, so the message count doesn't overflow.
1436f9cba8fSJoseph Mingrone */
144b00ab754SHans Petter Selasky ep = bp + len;
145b00ab754SHans Petter Selasky while (bp < ep) {
146b00ab754SHans Petter Selasky const struct nlmsghdr *nlh = (const struct nlmsghdr *) bp;
147b00ab754SHans Petter Selasky uint32_t msg_len;
148edc89b24SXin LI nftype_t type = OTHER;
149b00ab754SHans Petter Selasky /*
150b00ab754SHans Petter Selasky * Has "pcap_breakloop()" been called?
151b00ab754SHans Petter Selasky * If so, return immediately - if we haven't read any
152b00ab754SHans Petter Selasky * packets, clear the flag and return PCAP_ERROR_BREAK
153b00ab754SHans Petter Selasky * to indicate that we were told to break out of the loop,
154b00ab754SHans Petter Selasky * otherwise leave the flag set, so that the *next* call
155b00ab754SHans Petter Selasky * will break out of the loop without having read any
156b00ab754SHans Petter Selasky * packets, and return the number of packets we've
157b00ab754SHans Petter Selasky * processed so far.
158b00ab754SHans Petter Selasky */
159b00ab754SHans Petter Selasky if (handle->break_loop) {
160b00ab754SHans Petter Selasky handle->bp = bp;
1616f9cba8fSJoseph Mingrone handle->cc = (int)(ep - bp);
162b00ab754SHans Petter Selasky if (count == 0) {
163b00ab754SHans Petter Selasky handle->break_loop = 0;
164b00ab754SHans Petter Selasky return PCAP_ERROR_BREAK;
165b00ab754SHans Petter Selasky } else
166b00ab754SHans Petter Selasky return count;
167b00ab754SHans Petter Selasky }
1686f9cba8fSJoseph Mingrone /*
1696f9cba8fSJoseph Mingrone * NLMSG_SPACE(0) might be signed or might be unsigned,
1706f9cba8fSJoseph Mingrone * depending on whether the kernel defines NLMSG_ALIGNTO
1716f9cba8fSJoseph Mingrone * as 4, which older kernels do, or as 4U, which newer
1726f9cba8fSJoseph Mingrone * kernels do.
1736f9cba8fSJoseph Mingrone *
1746f9cba8fSJoseph Mingrone * ep - bp is of type ptrdiff_t, which is signed.
1756f9cba8fSJoseph Mingrone *
1766f9cba8fSJoseph Mingrone * To squelch warnings, we cast both to size_t, which
1776f9cba8fSJoseph Mingrone * is unsigned; ep >= bp, so the cast is safe.
1786f9cba8fSJoseph Mingrone */
1796f9cba8fSJoseph Mingrone if ((size_t)(ep - bp) < (size_t)NLMSG_SPACE(0)) {
180b00ab754SHans Petter Selasky /*
181b00ab754SHans Petter Selasky * There's less than one netlink message left
182b00ab754SHans Petter Selasky * in the buffer. Give up.
183b00ab754SHans Petter Selasky */
184b00ab754SHans Petter Selasky break;
185b00ab754SHans Petter Selasky }
186d1e87331SXin LI
187ada6f083SXin LI if (nlh->nlmsg_len < sizeof(struct nlmsghdr) || (u_int)len < nlh->nlmsg_len) {
1886f9cba8fSJoseph Mingrone snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Message truncated: (got: %zd) (nlmsg_len: %u)", len, nlh->nlmsg_len);
189d1e87331SXin LI return -1;
190d1e87331SXin LI }
191d1e87331SXin LI
192d1e87331SXin LI if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_ULOG &&
193d1e87331SXin LI NFNL_MSG_TYPE(nlh->nlmsg_type) == NFULNL_MSG_PACKET)
194edc89b24SXin LI type = NFLOG;
195681ed54cSXin LI else if (NFNL_SUBSYS_ID(nlh->nlmsg_type) == NFNL_SUBSYS_QUEUE &&
196edc89b24SXin LI NFNL_MSG_TYPE(nlh->nlmsg_type) == NFQNL_MSG_PACKET)
197edc89b24SXin LI type = NFQUEUE;
198edc89b24SXin LI
199edc89b24SXin LI if (type != OTHER) {
200d1e87331SXin LI const unsigned char *payload = NULL;
201d1e87331SXin LI struct pcap_pkthdr pkth;
202d1e87331SXin LI
203ada6f083SXin LI const struct nfgenmsg *nfg = NULL;
204edc89b24SXin LI int id = 0;
205edc89b24SXin LI
206d1e87331SXin LI if (handle->linktype != DLT_NFLOG) {
207d1e87331SXin LI const struct nfattr *payload_attr = NULL;
208d1e87331SXin LI
209d1e87331SXin LI if (nlh->nlmsg_len < HDR_LENGTH) {
2106f9cba8fSJoseph Mingrone snprintf(handle->errbuf, PCAP_ERRBUF_SIZE, "Malformed message: (nlmsg_len: %u)", nlh->nlmsg_len);
211d1e87331SXin LI return -1;
212d1e87331SXin LI }
213d1e87331SXin LI
214edc89b24SXin LI nfg = NLMSG_DATA(nlh);
215d1e87331SXin LI if (nlh->nlmsg_len > HDR_LENGTH) {
216edc89b24SXin LI struct nfattr *attr = NFM_NFA(nfg);
217d1e87331SXin LI int attr_len = nlh->nlmsg_len - NLMSG_ALIGN(HDR_LENGTH);
218d1e87331SXin LI
219d1e87331SXin LI while (NFA_OK(attr, attr_len)) {
220edc89b24SXin LI if (type == NFQUEUE) {
221edc89b24SXin LI switch (NFA_TYPE(attr)) {
222edc89b24SXin LI case NFQA_PACKET_HDR:
223edc89b24SXin LI {
224edc89b24SXin LI const struct nfqnl_msg_packet_hdr *pkt_hdr = (const struct nfqnl_msg_packet_hdr *) NFA_DATA(attr);
225edc89b24SXin LI
226edc89b24SXin LI id = ntohl(pkt_hdr->packet_id);
227edc89b24SXin LI break;
228edc89b24SXin LI }
229edc89b24SXin LI case NFQA_PAYLOAD:
230edc89b24SXin LI payload_attr = attr;
231edc89b24SXin LI break;
232edc89b24SXin LI }
233edc89b24SXin LI
234edc89b24SXin LI } else if (type == NFLOG) {
235d1e87331SXin LI switch (NFA_TYPE(attr)) {
236d1e87331SXin LI case NFULA_PAYLOAD:
237d1e87331SXin LI payload_attr = attr;
238d1e87331SXin LI break;
239d1e87331SXin LI }
240edc89b24SXin LI }
241d1e87331SXin LI attr = NFA_NEXT(attr, attr_len);
242d1e87331SXin LI }
243d1e87331SXin LI }
244d1e87331SXin LI
245d1e87331SXin LI if (payload_attr) {
246d1e87331SXin LI payload = NFA_DATA(payload_attr);
247d1e87331SXin LI pkth.len = pkth.caplen = NFA_PAYLOAD(payload_attr);
248d1e87331SXin LI }
249d1e87331SXin LI
250d1e87331SXin LI } else {
251d1e87331SXin LI payload = NLMSG_DATA(nlh);
252d1e87331SXin LI pkth.caplen = pkth.len = nlh->nlmsg_len-NLMSG_ALIGN(sizeof(struct nlmsghdr));
253d1e87331SXin LI }
254d1e87331SXin LI
255d1e87331SXin LI if (payload) {
256d1e87331SXin LI /* pkth.caplen = min (payload_len, handle->snapshot); */
257d1e87331SXin LI
258d1e87331SXin LI gettimeofday(&pkth.ts, NULL);
259d1e87331SXin LI if (handle->fcode.bf_insns == NULL ||
260*afdbf109SJoseph Mingrone pcapint_filter(handle->fcode.bf_insns, payload, pkth.len, pkth.caplen))
261d1e87331SXin LI {
262681ed54cSXin LI handlep->packets_read++;
263d1e87331SXin LI callback(user, &pkth, payload);
264d1e87331SXin LI count++;
265d1e87331SXin LI }
266d1e87331SXin LI }
267edc89b24SXin LI
268edc89b24SXin LI if (type == NFQUEUE) {
269edc89b24SXin LI /* XXX, possible responses: NF_DROP, NF_ACCEPT, NF_STOLEN, NF_QUEUE, NF_REPEAT, NF_STOP */
270ada6f083SXin LI /* if type == NFQUEUE, handle->linktype is always != DLT_NFLOG,
271ada6f083SXin LI so nfg is always initialized to NLMSG_DATA(nlh). */
272ada6f083SXin LI if (nfg != NULL)
273edc89b24SXin LI nfqueue_send_verdict(handle, ntohs(nfg->res_id), id, NF_ACCEPT);
274edc89b24SXin LI }
275d1e87331SXin LI }
276d1e87331SXin LI
277d1e87331SXin LI msg_len = NLMSG_ALIGN(nlh->nlmsg_len);
278b00ab754SHans Petter Selasky /*
279b00ab754SHans Petter Selasky * If the message length would run past the end of the
280b00ab754SHans Petter Selasky * buffer, truncate it to the remaining space in the
281b00ab754SHans Petter Selasky * buffer.
2826f9cba8fSJoseph Mingrone *
2836f9cba8fSJoseph Mingrone * To squelch warnings, we cast ep - bp to uint32_t, which
2846f9cba8fSJoseph Mingrone * is unsigned and is the type of msg_len; ep >= bp, and
2856f9cba8fSJoseph Mingrone * len should fit in 32 bits (either it's set from an int
2866f9cba8fSJoseph Mingrone * or it's set from a recv() call with a buffer size that's
2876f9cba8fSJoseph Mingrone * an int, and we're assuming either ILP32 or LP64), so
2886f9cba8fSJoseph Mingrone * the cast is safe.
289b00ab754SHans Petter Selasky */
2906f9cba8fSJoseph Mingrone if (msg_len > (uint32_t)(ep - bp))
2916f9cba8fSJoseph Mingrone msg_len = (uint32_t)(ep - bp);
292d1e87331SXin LI
293b00ab754SHans Petter Selasky bp += msg_len;
294b00ab754SHans Petter Selasky if (count >= max_packets && !PACKET_COUNT_IS_UNLIMITED(max_packets)) {
295b00ab754SHans Petter Selasky handle->bp = bp;
2966f9cba8fSJoseph Mingrone handle->cc = (int)(ep - bp);
297b00ab754SHans Petter Selasky if (handle->cc < 0)
298b00ab754SHans Petter Selasky handle->cc = 0;
299b00ab754SHans Petter Selasky return count;
300d1e87331SXin LI }
301b00ab754SHans Petter Selasky }
302b00ab754SHans Petter Selasky
303b00ab754SHans Petter Selasky handle->cc = 0;
304d1e87331SXin LI return count;
305d1e87331SXin LI }
306d1e87331SXin LI
307d1e87331SXin LI static int
netfilter_set_datalink(pcap_t * handle,int dlt)308d1e87331SXin LI netfilter_set_datalink(pcap_t *handle, int dlt)
309d1e87331SXin LI {
310d1e87331SXin LI handle->linktype = dlt;
311d1e87331SXin LI return 0;
312d1e87331SXin LI }
313d1e87331SXin LI
314d1e87331SXin LI static int
netfilter_stats_linux(pcap_t * handle,struct pcap_stat * stats)315d1e87331SXin LI netfilter_stats_linux(pcap_t *handle, struct pcap_stat *stats)
316d1e87331SXin LI {
317681ed54cSXin LI struct pcap_netfilter *handlep = handle->priv;
318681ed54cSXin LI
319681ed54cSXin LI stats->ps_recv = handlep->packets_read;
320ada6f083SXin LI stats->ps_drop = handlep->packets_nobufs;
321d1e87331SXin LI stats->ps_ifdrop = 0;
322d1e87331SXin LI return 0;
323d1e87331SXin LI }
324d1e87331SXin LI
325d1e87331SXin LI static int
netfilter_inject_linux(pcap_t * handle,const void * buf _U_,int size _U_)3266f9cba8fSJoseph Mingrone netfilter_inject_linux(pcap_t *handle, const void *buf _U_, int size _U_)
327d1e87331SXin LI {
3286f9cba8fSJoseph Mingrone snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
32957e22627SCy Schubert "Packet injection is not supported on netfilter devices");
330d1e87331SXin LI return (-1);
331d1e87331SXin LI }
332d1e87331SXin LI
333d1e87331SXin LI struct my_nfattr {
334b00ab754SHans Petter Selasky uint16_t nfa_len;
335b00ab754SHans Petter Selasky uint16_t nfa_type;
336d1e87331SXin LI void *data;
337d1e87331SXin LI };
338d1e87331SXin LI
339d1e87331SXin LI static int
netfilter_send_config_msg(const pcap_t * handle,uint16_t msg_type,int ack,u_int8_t family,u_int16_t res_id,const struct my_nfattr * mynfa)340b00ab754SHans Petter Selasky netfilter_send_config_msg(const pcap_t *handle, uint16_t msg_type, int ack, u_int8_t family, u_int16_t res_id, const struct my_nfattr *mynfa)
341d1e87331SXin LI {
342d1e87331SXin LI char buf[1024] __attribute__ ((aligned));
34357e22627SCy Schubert memset(buf, 0, sizeof(buf));
344d1e87331SXin LI
345d1e87331SXin LI struct nlmsghdr *nlh = (struct nlmsghdr *) buf;
346d1e87331SXin LI struct nfgenmsg *nfg = (struct nfgenmsg *) (buf + sizeof(struct nlmsghdr));
347d1e87331SXin LI
348d1e87331SXin LI struct sockaddr_nl snl;
349d1e87331SXin LI static unsigned int seq_id;
350d1e87331SXin LI
351d1e87331SXin LI if (!seq_id)
3526f9cba8fSJoseph Mingrone DIAG_OFF_NARROWING
353d1e87331SXin LI seq_id = time(NULL);
3546f9cba8fSJoseph Mingrone DIAG_ON_NARROWING
355d1e87331SXin LI ++seq_id;
356d1e87331SXin LI
357d1e87331SXin LI nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nfgenmsg));
358edc89b24SXin LI nlh->nlmsg_type = msg_type;
359edc89b24SXin LI nlh->nlmsg_flags = NLM_F_REQUEST | (ack ? NLM_F_ACK : 0);
360d1e87331SXin LI nlh->nlmsg_pid = 0; /* to kernel */
361d1e87331SXin LI nlh->nlmsg_seq = seq_id;
362d1e87331SXin LI
363d1e87331SXin LI nfg->nfgen_family = family;
364d1e87331SXin LI nfg->version = NFNETLINK_V0;
365d1e87331SXin LI nfg->res_id = htons(res_id);
366d1e87331SXin LI
367d1e87331SXin LI if (mynfa) {
368d1e87331SXin LI struct nfattr *nfa = (struct nfattr *) (buf + NLMSG_ALIGN(nlh->nlmsg_len));
369d1e87331SXin LI
370d1e87331SXin LI nfa->nfa_type = mynfa->nfa_type;
371d1e87331SXin LI nfa->nfa_len = NFA_LENGTH(mynfa->nfa_len);
372d1e87331SXin LI memcpy(NFA_DATA(nfa), mynfa->data, mynfa->nfa_len);
373d1e87331SXin LI nlh->nlmsg_len = NLMSG_ALIGN(nlh->nlmsg_len) + NFA_ALIGN(nfa->nfa_len);
374d1e87331SXin LI }
375d1e87331SXin LI
376d1e87331SXin LI memset(&snl, 0, sizeof(snl));
377d1e87331SXin LI snl.nl_family = AF_NETLINK;
378d1e87331SXin LI
379d1e87331SXin LI if (sendto(handle->fd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *) &snl, sizeof(snl)) == -1)
380d1e87331SXin LI return -1;
381d1e87331SXin LI
382edc89b24SXin LI if (!ack)
383edc89b24SXin LI return 0;
384edc89b24SXin LI
385d1e87331SXin LI /* waiting for reply loop */
386d1e87331SXin LI do {
387d1e87331SXin LI socklen_t addrlen = sizeof(snl);
388d1e87331SXin LI int len;
389d1e87331SXin LI
390d1e87331SXin LI /* ignore interrupt system call error */
391d1e87331SXin LI do {
3926f9cba8fSJoseph Mingrone /*
3936f9cba8fSJoseph Mingrone * The buffer is not so big that its size won't
3946f9cba8fSJoseph Mingrone * fit into an int.
3956f9cba8fSJoseph Mingrone */
3966f9cba8fSJoseph Mingrone len = (int)recvfrom(handle->fd, buf, sizeof(buf), 0, (struct sockaddr *) &snl, &addrlen);
397d1e87331SXin LI } while ((len == -1) && (errno == EINTR));
398d1e87331SXin LI
399d1e87331SXin LI if (len <= 0)
400d1e87331SXin LI return len;
401d1e87331SXin LI
402d1e87331SXin LI if (addrlen != sizeof(snl) || snl.nl_family != AF_NETLINK) {
403d1e87331SXin LI errno = EINVAL;
404d1e87331SXin LI return -1;
405d1e87331SXin LI }
406d1e87331SXin LI
407d1e87331SXin LI nlh = (struct nlmsghdr *) buf;
408d1e87331SXin LI if (snl.nl_pid != 0 || seq_id != nlh->nlmsg_seq) /* if not from kernel or wrong sequence skip */
409d1e87331SXin LI continue;
410d1e87331SXin LI
411b00ab754SHans Petter Selasky while ((u_int)len >= NLMSG_SPACE(0) && NLMSG_OK(nlh, (u_int)len)) {
412d1e87331SXin LI if (nlh->nlmsg_type == NLMSG_ERROR || (nlh->nlmsg_type == NLMSG_DONE && nlh->nlmsg_flags & NLM_F_MULTI)) {
413d1e87331SXin LI if (nlh->nlmsg_len < NLMSG_ALIGN(sizeof(struct nlmsgerr))) {
414d1e87331SXin LI errno = EBADMSG;
415d1e87331SXin LI return -1;
416d1e87331SXin LI }
417d1e87331SXin LI errno = -(*((int *)NLMSG_DATA(nlh)));
418d1e87331SXin LI return (errno == 0) ? 0 : -1;
419d1e87331SXin LI }
420d1e87331SXin LI nlh = NLMSG_NEXT(nlh, len);
421d1e87331SXin LI }
422d1e87331SXin LI } while (1);
423d1e87331SXin LI
424d1e87331SXin LI return -1; /* never here */
425d1e87331SXin LI }
426d1e87331SXin LI
427d1e87331SXin LI static int
nflog_send_config_msg(const pcap_t * handle,uint8_t family,u_int16_t group_id,const struct my_nfattr * mynfa)428b00ab754SHans Petter Selasky nflog_send_config_msg(const pcap_t *handle, uint8_t family, u_int16_t group_id, const struct my_nfattr *mynfa)
429edc89b24SXin LI {
430edc89b24SXin LI return netfilter_send_config_msg(handle, (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG, 1, family, group_id, mynfa);
431edc89b24SXin LI }
432edc89b24SXin LI
433edc89b24SXin LI static int
nflog_send_config_cmd(const pcap_t * handle,uint16_t group_id,u_int8_t cmd,u_int8_t family)434b00ab754SHans Petter Selasky nflog_send_config_cmd(const pcap_t *handle, uint16_t group_id, u_int8_t cmd, u_int8_t family)
435d1e87331SXin LI {
436d1e87331SXin LI struct nfulnl_msg_config_cmd msg;
437d1e87331SXin LI struct my_nfattr nfa;
438d1e87331SXin LI
439d1e87331SXin LI msg.command = cmd;
440d1e87331SXin LI
441d1e87331SXin LI nfa.data = &msg;
442d1e87331SXin LI nfa.nfa_type = NFULA_CFG_CMD;
443d1e87331SXin LI nfa.nfa_len = sizeof(msg);
444d1e87331SXin LI
445d1e87331SXin LI return nflog_send_config_msg(handle, family, group_id, &nfa);
446d1e87331SXin LI }
447d1e87331SXin LI
448d1e87331SXin LI static int
nflog_send_config_mode(const pcap_t * handle,uint16_t group_id,u_int8_t copy_mode,u_int32_t copy_range)449b00ab754SHans Petter Selasky nflog_send_config_mode(const pcap_t *handle, uint16_t group_id, u_int8_t copy_mode, u_int32_t copy_range)
450d1e87331SXin LI {
451d1e87331SXin LI struct nfulnl_msg_config_mode msg;
452d1e87331SXin LI struct my_nfattr nfa;
453d1e87331SXin LI
454d1e87331SXin LI msg.copy_range = htonl(copy_range);
455d1e87331SXin LI msg.copy_mode = copy_mode;
456d1e87331SXin LI
457d1e87331SXin LI nfa.data = &msg;
458d1e87331SXin LI nfa.nfa_type = NFULA_CFG_MODE;
459d1e87331SXin LI nfa.nfa_len = sizeof(msg);
460d1e87331SXin LI
461d1e87331SXin LI return nflog_send_config_msg(handle, AF_UNSPEC, group_id, &nfa);
462d1e87331SXin LI }
463d1e87331SXin LI
464d1e87331SXin LI static int
nfqueue_send_verdict(const pcap_t * handle,uint16_t group_id,u_int32_t id,u_int32_t verdict)465b00ab754SHans Petter Selasky nfqueue_send_verdict(const pcap_t *handle, uint16_t group_id, u_int32_t id, u_int32_t verdict)
466edc89b24SXin LI {
467edc89b24SXin LI struct nfqnl_msg_verdict_hdr msg;
468edc89b24SXin LI struct my_nfattr nfa;
469edc89b24SXin LI
470edc89b24SXin LI msg.id = htonl(id);
471edc89b24SXin LI msg.verdict = htonl(verdict);
472edc89b24SXin LI
473edc89b24SXin LI nfa.data = &msg;
474edc89b24SXin LI nfa.nfa_type = NFQA_VERDICT_HDR;
475edc89b24SXin LI nfa.nfa_len = sizeof(msg);
476edc89b24SXin LI
477edc89b24SXin LI return netfilter_send_config_msg(handle, (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_VERDICT, 0, AF_UNSPEC, group_id, &nfa);
478edc89b24SXin LI }
479edc89b24SXin LI
480edc89b24SXin LI static int
nfqueue_send_config_msg(const pcap_t * handle,uint8_t family,u_int16_t group_id,const struct my_nfattr * mynfa)481b00ab754SHans Petter Selasky nfqueue_send_config_msg(const pcap_t *handle, uint8_t family, u_int16_t group_id, const struct my_nfattr *mynfa)
482edc89b24SXin LI {
483edc89b24SXin LI return netfilter_send_config_msg(handle, (NFNL_SUBSYS_QUEUE << 8) | NFQNL_MSG_CONFIG, 1, family, group_id, mynfa);
484edc89b24SXin LI }
485edc89b24SXin LI
486edc89b24SXin LI static int
nfqueue_send_config_cmd(const pcap_t * handle,uint16_t group_id,u_int8_t cmd,u_int16_t pf)487b00ab754SHans Petter Selasky nfqueue_send_config_cmd(const pcap_t *handle, uint16_t group_id, u_int8_t cmd, u_int16_t pf)
488edc89b24SXin LI {
489edc89b24SXin LI struct nfqnl_msg_config_cmd msg;
490edc89b24SXin LI struct my_nfattr nfa;
491edc89b24SXin LI
492edc89b24SXin LI msg.command = cmd;
493edc89b24SXin LI msg.pf = htons(pf);
494edc89b24SXin LI
495edc89b24SXin LI nfa.data = &msg;
496edc89b24SXin LI nfa.nfa_type = NFQA_CFG_CMD;
497edc89b24SXin LI nfa.nfa_len = sizeof(msg);
498edc89b24SXin LI
499edc89b24SXin LI return nfqueue_send_config_msg(handle, AF_UNSPEC, group_id, &nfa);
500edc89b24SXin LI }
501edc89b24SXin LI
502edc89b24SXin LI static int
nfqueue_send_config_mode(const pcap_t * handle,uint16_t group_id,u_int8_t copy_mode,u_int32_t copy_range)503b00ab754SHans Petter Selasky nfqueue_send_config_mode(const pcap_t *handle, uint16_t group_id, u_int8_t copy_mode, u_int32_t copy_range)
504edc89b24SXin LI {
505edc89b24SXin LI struct nfqnl_msg_config_params msg;
506edc89b24SXin LI struct my_nfattr nfa;
507edc89b24SXin LI
508edc89b24SXin LI msg.copy_range = htonl(copy_range);
509edc89b24SXin LI msg.copy_mode = copy_mode;
510edc89b24SXin LI
511edc89b24SXin LI nfa.data = &msg;
512edc89b24SXin LI nfa.nfa_type = NFQA_CFG_PARAMS;
513edc89b24SXin LI nfa.nfa_len = sizeof(msg);
514edc89b24SXin LI
515edc89b24SXin LI return nfqueue_send_config_msg(handle, AF_UNSPEC, group_id, &nfa);
516edc89b24SXin LI }
517edc89b24SXin LI
518edc89b24SXin LI static int
netfilter_activate(pcap_t * handle)519edc89b24SXin LI netfilter_activate(pcap_t* handle)
520d1e87331SXin LI {
521ada6f083SXin LI const char *dev = handle->opt.device;
522d1e87331SXin LI unsigned short groups[32];
523d1e87331SXin LI int group_count = 0;
524edc89b24SXin LI nftype_t type = OTHER;
525d1e87331SXin LI int i;
526d1e87331SXin LI
527d1e87331SXin LI if (strncmp(dev, NFLOG_IFACE, strlen(NFLOG_IFACE)) == 0) {
528d1e87331SXin LI dev += strlen(NFLOG_IFACE);
529edc89b24SXin LI type = NFLOG;
530d1e87331SXin LI
531edc89b24SXin LI } else if (strncmp(dev, NFQUEUE_IFACE, strlen(NFQUEUE_IFACE)) == 0) {
532edc89b24SXin LI dev += strlen(NFQUEUE_IFACE);
533edc89b24SXin LI type = NFQUEUE;
534edc89b24SXin LI }
535edc89b24SXin LI
536edc89b24SXin LI if (type != OTHER && *dev == ':') {
537d1e87331SXin LI dev++;
538d1e87331SXin LI while (*dev) {
539d1e87331SXin LI long int group_id;
540d1e87331SXin LI char *end_dev;
541d1e87331SXin LI
542d1e87331SXin LI if (group_count == 32) {
5436f9cba8fSJoseph Mingrone snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
544d1e87331SXin LI "Maximum 32 netfilter groups! dev: %s",
545ada6f083SXin LI handle->opt.device);
546d1e87331SXin LI return PCAP_ERROR;
547d1e87331SXin LI }
548d1e87331SXin LI
549d1e87331SXin LI group_id = strtol(dev, &end_dev, 0);
550d1e87331SXin LI if (end_dev != dev) {
551d1e87331SXin LI if (group_id < 0 || group_id > 65535) {
5526f9cba8fSJoseph Mingrone snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
553d1e87331SXin LI "Netfilter group range from 0 to 65535 (got %ld)",
554d1e87331SXin LI group_id);
555d1e87331SXin LI return PCAP_ERROR;
556d1e87331SXin LI }
557d1e87331SXin LI
558d1e87331SXin LI groups[group_count++] = (unsigned short) group_id;
559d1e87331SXin LI dev = end_dev;
560d1e87331SXin LI }
561d1e87331SXin LI if (*dev != ',')
562d1e87331SXin LI break;
563d1e87331SXin LI dev++;
564d1e87331SXin LI }
565d1e87331SXin LI }
566d1e87331SXin LI
567edc89b24SXin LI if (type == OTHER || *dev) {
5686f9cba8fSJoseph Mingrone snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
569d1e87331SXin LI "Can't get netfilter group(s) index from %s",
570ada6f083SXin LI handle->opt.device);
571d1e87331SXin LI return PCAP_ERROR;
572d1e87331SXin LI }
573d1e87331SXin LI
574d1e87331SXin LI /* if no groups, add default: 0 */
575d1e87331SXin LI if (!group_count) {
576d1e87331SXin LI groups[0] = 0;
577d1e87331SXin LI group_count = 1;
578d1e87331SXin LI }
579d1e87331SXin LI
580b00ab754SHans Petter Selasky /*
581b00ab754SHans Petter Selasky * Turn a negative snapshot value (invalid), a snapshot value of
582b00ab754SHans Petter Selasky * 0 (unspecified), or a value bigger than the normal maximum
583b00ab754SHans Petter Selasky * value, into the maximum allowed value.
584b00ab754SHans Petter Selasky *
585b00ab754SHans Petter Selasky * If some application really *needs* a bigger snapshot
586b00ab754SHans Petter Selasky * length, we should just increase MAXIMUM_SNAPLEN.
587b00ab754SHans Petter Selasky */
588b00ab754SHans Petter Selasky if (handle->snapshot <= 0 || handle->snapshot > MAXIMUM_SNAPLEN)
589b00ab754SHans Petter Selasky handle->snapshot = MAXIMUM_SNAPLEN;
590b00ab754SHans Petter Selasky
591d1e87331SXin LI /* Initialize some components of the pcap structure. */
592d1e87331SXin LI handle->bufsize = 128 + handle->snapshot;
593d1e87331SXin LI handle->offset = 0;
594edc89b24SXin LI handle->read_op = netfilter_read_linux;
595d1e87331SXin LI handle->inject_op = netfilter_inject_linux;
596*afdbf109SJoseph Mingrone handle->setfilter_op = pcapint_install_bpf_program; /* no kernel filtering */
597d1e87331SXin LI handle->setdirection_op = NULL;
598d1e87331SXin LI handle->set_datalink_op = netfilter_set_datalink;
599*afdbf109SJoseph Mingrone handle->getnonblock_op = pcapint_getnonblock_fd;
600*afdbf109SJoseph Mingrone handle->setnonblock_op = pcapint_setnonblock_fd;
601d1e87331SXin LI handle->stats_op = netfilter_stats_linux;
602d1e87331SXin LI
603d1e87331SXin LI /* Create netlink socket */
604d1e87331SXin LI handle->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER);
605d1e87331SXin LI if (handle->fd < 0) {
606*afdbf109SJoseph Mingrone pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
607b00ab754SHans Petter Selasky errno, "Can't create raw socket");
608d1e87331SXin LI return PCAP_ERROR;
609d1e87331SXin LI }
610d1e87331SXin LI
611edc89b24SXin LI if (type == NFLOG) {
612edc89b24SXin LI handle->linktype = DLT_NFLOG;
613d1e87331SXin LI handle->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);
614*afdbf109SJoseph Mingrone if (handle->dlt_list == NULL) {
615*afdbf109SJoseph Mingrone pcapint_fmt_errmsg_for_errno(handle->errbuf,
616*afdbf109SJoseph Mingrone PCAP_ERRBUF_SIZE, errno,
617*afdbf109SJoseph Mingrone "Can't allocate DLT list");
618*afdbf109SJoseph Mingrone goto close_fail;
619*afdbf109SJoseph Mingrone }
620d1e87331SXin LI handle->dlt_list[0] = DLT_NFLOG;
621d1e87331SXin LI handle->dlt_list[1] = DLT_IPV4;
622d1e87331SXin LI handle->dlt_count = 2;
623edc89b24SXin LI } else
624edc89b24SXin LI handle->linktype = DLT_IPV4;
625edc89b24SXin LI
626d1e87331SXin LI handle->buffer = malloc(handle->bufsize);
627d1e87331SXin LI if (!handle->buffer) {
628*afdbf109SJoseph Mingrone pcapint_fmt_errmsg_for_errno(handle->errbuf, PCAP_ERRBUF_SIZE,
629b00ab754SHans Petter Selasky errno, "Can't allocate dump buffer");
630d1e87331SXin LI goto close_fail;
631d1e87331SXin LI }
632d1e87331SXin LI
633edc89b24SXin LI if (type == NFLOG) {
634d1e87331SXin LI if (nflog_send_config_cmd(handle, 0, NFULNL_CFG_CMD_PF_UNBIND, AF_INET) < 0) {
635*afdbf109SJoseph Mingrone pcapint_fmt_errmsg_for_errno(handle->errbuf,
636b00ab754SHans Petter Selasky PCAP_ERRBUF_SIZE, errno,
637b00ab754SHans Petter Selasky "NFULNL_CFG_CMD_PF_UNBIND");
638d1e87331SXin LI goto close_fail;
639d1e87331SXin LI }
640d1e87331SXin LI
641d1e87331SXin LI if (nflog_send_config_cmd(handle, 0, NFULNL_CFG_CMD_PF_BIND, AF_INET) < 0) {
642*afdbf109SJoseph Mingrone pcapint_fmt_errmsg_for_errno(handle->errbuf,
643b00ab754SHans Petter Selasky PCAP_ERRBUF_SIZE, errno, "NFULNL_CFG_CMD_PF_BIND");
644d1e87331SXin LI goto close_fail;
645d1e87331SXin LI }
646d1e87331SXin LI
647d1e87331SXin LI /* Bind socket to the nflog groups */
648d1e87331SXin LI for (i = 0; i < group_count; i++) {
649d1e87331SXin LI if (nflog_send_config_cmd(handle, groups[i], NFULNL_CFG_CMD_BIND, AF_UNSPEC) < 0) {
650*afdbf109SJoseph Mingrone pcapint_fmt_errmsg_for_errno(handle->errbuf,
651b00ab754SHans Petter Selasky PCAP_ERRBUF_SIZE, errno,
6526f9cba8fSJoseph Mingrone "Can't listen on group index");
653d1e87331SXin LI goto close_fail;
654d1e87331SXin LI }
655d1e87331SXin LI
656d1e87331SXin LI if (nflog_send_config_mode(handle, groups[i], NFULNL_COPY_PACKET, handle->snapshot) < 0) {
657*afdbf109SJoseph Mingrone pcapint_fmt_errmsg_for_errno(handle->errbuf,
658b00ab754SHans Petter Selasky PCAP_ERRBUF_SIZE, errno,
659b00ab754SHans Petter Selasky "NFULNL_COPY_PACKET");
660d1e87331SXin LI goto close_fail;
661d1e87331SXin LI }
662d1e87331SXin LI }
663d1e87331SXin LI
664edc89b24SXin LI } else {
665edc89b24SXin LI if (nfqueue_send_config_cmd(handle, 0, NFQNL_CFG_CMD_PF_UNBIND, AF_INET) < 0) {
666*afdbf109SJoseph Mingrone pcapint_fmt_errmsg_for_errno(handle->errbuf,
667b00ab754SHans Petter Selasky PCAP_ERRBUF_SIZE, errno, "NFQNL_CFG_CMD_PF_UNBIND");
668edc89b24SXin LI goto close_fail;
669edc89b24SXin LI }
670edc89b24SXin LI
671edc89b24SXin LI if (nfqueue_send_config_cmd(handle, 0, NFQNL_CFG_CMD_PF_BIND, AF_INET) < 0) {
672*afdbf109SJoseph Mingrone pcapint_fmt_errmsg_for_errno(handle->errbuf,
673b00ab754SHans Petter Selasky PCAP_ERRBUF_SIZE, errno, "NFQNL_CFG_CMD_PF_BIND");
674edc89b24SXin LI goto close_fail;
675edc89b24SXin LI }
676edc89b24SXin LI
677edc89b24SXin LI /* Bind socket to the nfqueue groups */
678edc89b24SXin LI for (i = 0; i < group_count; i++) {
679edc89b24SXin LI if (nfqueue_send_config_cmd(handle, groups[i], NFQNL_CFG_CMD_BIND, AF_UNSPEC) < 0) {
680*afdbf109SJoseph Mingrone pcapint_fmt_errmsg_for_errno(handle->errbuf,
681b00ab754SHans Petter Selasky PCAP_ERRBUF_SIZE, errno,
6826f9cba8fSJoseph Mingrone "Can't listen on group index");
683edc89b24SXin LI goto close_fail;
684edc89b24SXin LI }
685edc89b24SXin LI
686edc89b24SXin LI if (nfqueue_send_config_mode(handle, groups[i], NFQNL_COPY_PACKET, handle->snapshot) < 0) {
687*afdbf109SJoseph Mingrone pcapint_fmt_errmsg_for_errno(handle->errbuf,
688b00ab754SHans Petter Selasky PCAP_ERRBUF_SIZE, errno,
689b00ab754SHans Petter Selasky "NFQNL_COPY_PACKET");
690edc89b24SXin LI goto close_fail;
691edc89b24SXin LI }
692edc89b24SXin LI }
693edc89b24SXin LI }
694edc89b24SXin LI
695d1e87331SXin LI if (handle->opt.rfmon) {
696d1e87331SXin LI /*
697d1e87331SXin LI * Monitor mode doesn't apply to netfilter devices.
698d1e87331SXin LI */
699*afdbf109SJoseph Mingrone pcapint_cleanup_live_common(handle);
700d1e87331SXin LI return PCAP_ERROR_RFMON_NOTSUP;
701d1e87331SXin LI }
702d1e87331SXin LI
703d1e87331SXin LI if (handle->opt.buffer_size != 0) {
704d1e87331SXin LI /*
705d1e87331SXin LI * Set the socket buffer size to the specified value.
706d1e87331SXin LI */
707d1e87331SXin LI if (setsockopt(handle->fd, SOL_SOCKET, SO_RCVBUF, &handle->opt.buffer_size, sizeof(handle->opt.buffer_size)) == -1) {
708*afdbf109SJoseph Mingrone pcapint_fmt_errmsg_for_errno(handle->errbuf,
709b00ab754SHans Petter Selasky PCAP_ERRBUF_SIZE, errno, "SO_RCVBUF");
710d1e87331SXin LI goto close_fail;
711d1e87331SXin LI }
712d1e87331SXin LI }
713d1e87331SXin LI
714d1e87331SXin LI handle->selectable_fd = handle->fd;
715d1e87331SXin LI return 0;
716d1e87331SXin LI
717d1e87331SXin LI close_fail:
718*afdbf109SJoseph Mingrone pcapint_cleanup_live_common(handle);
719d1e87331SXin LI return PCAP_ERROR;
720d1e87331SXin LI }
721d1e87331SXin LI
722d1e87331SXin LI pcap_t *
netfilter_create(const char * device,char * ebuf,int * is_ours)723edc89b24SXin LI netfilter_create(const char *device, char *ebuf, int *is_ours)
724d1e87331SXin LI {
725edc89b24SXin LI const char *cp;
726d1e87331SXin LI pcap_t *p;
727d1e87331SXin LI
728edc89b24SXin LI /* Does this look like an netfilter device? */
729edc89b24SXin LI cp = strrchr(device, '/');
730edc89b24SXin LI if (cp == NULL)
731edc89b24SXin LI cp = device;
732edc89b24SXin LI
733edc89b24SXin LI /* Does it begin with NFLOG_IFACE or NFQUEUE_IFACE? */
734edc89b24SXin LI if (strncmp(cp, NFLOG_IFACE, sizeof NFLOG_IFACE - 1) == 0)
735edc89b24SXin LI cp += sizeof NFLOG_IFACE - 1;
736edc89b24SXin LI else if (strncmp(cp, NFQUEUE_IFACE, sizeof NFQUEUE_IFACE - 1) == 0)
737edc89b24SXin LI cp += sizeof NFQUEUE_IFACE - 1;
738edc89b24SXin LI else {
739edc89b24SXin LI /* Nope, doesn't begin with NFLOG_IFACE nor NFQUEUE_IFACE */
740edc89b24SXin LI *is_ours = 0;
741edc89b24SXin LI return NULL;
742edc89b24SXin LI }
743edc89b24SXin LI
744edc89b24SXin LI /*
745edc89b24SXin LI * Yes - is that either the end of the name, or is it followed
746edc89b24SXin LI * by a colon?
747edc89b24SXin LI */
748edc89b24SXin LI if (*cp != ':' && *cp != '\0') {
749edc89b24SXin LI /* Nope */
750edc89b24SXin LI *is_ours = 0;
751edc89b24SXin LI return NULL;
752edc89b24SXin LI }
753edc89b24SXin LI
754edc89b24SXin LI /* OK, it's probably ours. */
755edc89b24SXin LI *is_ours = 1;
756edc89b24SXin LI
7576f9cba8fSJoseph Mingrone p = PCAP_CREATE_COMMON(ebuf, struct pcap_netfilter);
758d1e87331SXin LI if (p == NULL)
759d1e87331SXin LI return (NULL);
760d1e87331SXin LI
761edc89b24SXin LI p->activate_op = netfilter_activate;
762d1e87331SXin LI return (p);
763d1e87331SXin LI }
764d1e87331SXin LI
765d1e87331SXin LI int
netfilter_findalldevs(pcap_if_list_t * devlistp,char * err_str)766b00ab754SHans Petter Selasky netfilter_findalldevs(pcap_if_list_t *devlistp, char *err_str)
767d1e87331SXin LI {
768d1e87331SXin LI int sock;
769d1e87331SXin LI
770d1e87331SXin LI sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER);
771d1e87331SXin LI if (sock < 0) {
77215752fa8SXin LI /* if netlink is not supported this is not fatal */
77315752fa8SXin LI if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT)
774d1e87331SXin LI return 0;
775*afdbf109SJoseph Mingrone pcapint_fmt_errmsg_for_errno(err_str, PCAP_ERRBUF_SIZE,
776b00ab754SHans Petter Selasky errno, "Can't open netlink socket");
777d1e87331SXin LI return -1;
778d1e87331SXin LI }
779d1e87331SXin LI close(sock);
780d1e87331SXin LI
781b00ab754SHans Petter Selasky /*
782b00ab754SHans Petter Selasky * The notion of "connected" vs. "disconnected" doesn't apply.
783b00ab754SHans Petter Selasky * XXX - what about "up" and "running"?
784b00ab754SHans Petter Selasky */
785*afdbf109SJoseph Mingrone if (pcapint_add_dev(devlistp, NFLOG_IFACE,
786b00ab754SHans Petter Selasky PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE,
787b00ab754SHans Petter Selasky "Linux netfilter log (NFLOG) interface", err_str) == NULL)
788d1e87331SXin LI return -1;
789*afdbf109SJoseph Mingrone if (pcapint_add_dev(devlistp, NFQUEUE_IFACE,
790b00ab754SHans Petter Selasky PCAP_IF_CONNECTION_STATUS_NOT_APPLICABLE,
791b00ab754SHans Petter Selasky "Linux netfilter queue (NFQUEUE) interface", err_str) == NULL)
792edc89b24SXin LI return -1;
793d1e87331SXin LI return 0;
794d1e87331SXin LI }
795