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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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