xref: /netbsd-src/external/bsd/tcpdump/dist/print-nflog.c (revision cc576e1d8e4f4078fd4e81238abca9fca216f6ec)
1 /*
2  * Copyright (c) 2013, Petar Alilovic,
3  * Faculty of Electrical Engineering and Computing, University of Zagreb
4  * All rights reserved
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * * Redistributions of source code must retain the above copyright notice,
10  *	 this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright
12  *	 notice, this list of conditions and the following disclaimer in the
13  *	 documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
25  * DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 #ifndef lint
30 __RCSID("$NetBSD: print-nflog.c,v 1.2 2017/01/24 23:29:14 christos Exp $");
31 #endif
32 
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36 
37 #include <netdissect-stdinc.h>
38 
39 #include "netdissect.h"
40 
41 #if defined(DLT_NFLOG) && defined(HAVE_PCAP_NFLOG_H)
42 #include <pcap/nflog.h>
43 
44 static const struct tok nflog_values[] = {
45 	{ AF_INET,		"IPv4" },
46 #ifdef AF_INET6
47 	{ AF_INET6,		"IPv6" },
48 #endif /*AF_INET6*/
49 	{ 0,			NULL }
50 };
51 
52 static inline void
53 nflog_hdr_print(netdissect_options *ndo, const nflog_hdr_t *hdr, u_int length)
54 {
55 	ND_PRINT((ndo, "version %d, resource ID %d", hdr->nflog_version, ntohs(hdr->nflog_rid)));
56 
57 	if (!ndo->ndo_qflag) {
58 		ND_PRINT((ndo,", family %s (%d)",
59 						  tok2str(nflog_values, "Unknown",
60 								  hdr->nflog_family),
61 						  hdr->nflog_family));
62 		} else {
63 		ND_PRINT((ndo,", %s",
64 						  tok2str(nflog_values,
65 								  "Unknown NFLOG (0x%02x)",
66 								  hdr->nflog_family)));
67 		}
68 
69 	ND_PRINT((ndo, ", length %u: ", length));
70 }
71 
72 u_int
73 nflog_if_print(netdissect_options *ndo,
74 			   const struct pcap_pkthdr *h, const u_char *p)
75 {
76 	const nflog_hdr_t *hdr = (const nflog_hdr_t *)p;
77 	const nflog_tlv_t *tlv;
78 	uint16_t size;
79 	uint16_t h_size = sizeof(nflog_hdr_t);
80 	u_int caplen = h->caplen;
81 	u_int length = h->len;
82 
83 	if (caplen < (int) sizeof(nflog_hdr_t) || length < (int) sizeof(nflog_hdr_t)) {
84 		ND_PRINT((ndo, "[|nflog]"));
85 		return h_size;
86 	}
87 
88 	if (hdr->nflog_version != 0) {
89 		ND_PRINT((ndo, "version %u (unknown)", hdr->nflog_version));
90 		return h_size;
91 	}
92 
93 	if (ndo->ndo_eflag)
94 		nflog_hdr_print(ndo, hdr, length);
95 
96 	p += sizeof(nflog_hdr_t);
97 	length -= sizeof(nflog_hdr_t);
98 	caplen -= sizeof(nflog_hdr_t);
99 
100 	while (length > 0) {
101 		/* We have some data.  Do we have enough for the TLV header? */
102 		if (caplen < sizeof(nflog_tlv_t) || length < sizeof(nflog_tlv_t)) {
103 			/* No. */
104 			ND_PRINT((ndo, "[|nflog]"));
105 			return h_size;
106 		}
107 
108 		tlv = (const nflog_tlv_t *) p;
109 		size = tlv->tlv_length;
110 		if (size % 4 != 0)
111 			size += 4 - size % 4;
112 
113 		/* Is the TLV's length less than the minimum? */
114 		if (size < sizeof(nflog_tlv_t)) {
115 			/* Yes. Give up now. */
116 			ND_PRINT((ndo, "[|nflog]"));
117 			return h_size;
118 		}
119 
120 		/* Do we have enough data for the full TLV? */
121 		if (caplen < size || length < size) {
122 			/* No. */
123 			ND_PRINT((ndo, "[|nflog]"));
124 			return h_size;
125 		}
126 
127 		if (tlv->tlv_type == NFULA_PAYLOAD) {
128 			/*
129 			 * This TLV's data is the packet payload.
130 			 * Skip past the TLV header, and break out
131 			 * of the loop so we print the packet data.
132 			 */
133 			p += sizeof(nflog_tlv_t);
134 			h_size += sizeof(nflog_tlv_t);
135 			length -= sizeof(nflog_tlv_t);
136 			caplen -= sizeof(nflog_tlv_t);
137 			break;
138 		}
139 
140 		p += size;
141 		h_size += size;
142 		length -= size;
143 		caplen -= size;
144 	}
145 
146 	switch (hdr->nflog_family) {
147 
148 	case AF_INET:
149 		ip_print(ndo, p, length);
150 		break;
151 
152 #ifdef AF_INET6
153 	case AF_INET6:
154 		ip6_print(ndo, p, length);
155 		break;
156 #endif /* AF_INET6 */
157 
158 	default:
159 		if (!ndo->ndo_eflag)
160 			nflog_hdr_print(ndo, hdr,
161 				length + sizeof(nflog_hdr_t));
162 
163 		if (!ndo->ndo_suppress_default_print)
164 			ND_DEFAULTPRINT(p, caplen);
165 		break;
166 	}
167 
168 	return h_size;
169 }
170 
171 #endif /* defined(DLT_NFLOG) && defined(HAVE_PCAP_NFLOG_H) */
172