xref: /netbsd-src/external/bsd/tcpdump/dist/print-nflog.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
1026d7285Schristos /*
2026d7285Schristos  * Copyright (c) 2013, Petar Alilovic,
3026d7285Schristos  * Faculty of Electrical Engineering and Computing, University of Zagreb
4026d7285Schristos  * All rights reserved
5026d7285Schristos  *
6026d7285Schristos  * Redistribution and use in source and binary forms, with or without
7026d7285Schristos  * modification, are permitted provided that the following conditions are met:
8026d7285Schristos  *
9026d7285Schristos  * * Redistributions of source code must retain the above copyright notice,
10026d7285Schristos  *	 this list of conditions and the following disclaimer.
11026d7285Schristos  * * Redistributions in binary form must reproduce the above copyright
12026d7285Schristos  *	 notice, this list of conditions and the following disclaimer in the
13026d7285Schristos  *	 documentation and/or other materials provided with the distribution.
14026d7285Schristos  *
15026d7285Schristos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
16026d7285Schristos  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17026d7285Schristos  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18026d7285Schristos  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
19026d7285Schristos  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20026d7285Schristos  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21026d7285Schristos  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22026d7285Schristos  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23026d7285Schristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24026d7285Schristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
25026d7285Schristos  * DAMAGE.
26026d7285Schristos  */
27026d7285Schristos 
28fdccd7e4Schristos #include <sys/cdefs.h>
29fdccd7e4Schristos #ifndef lint
30*26ba0b50Schristos __RCSID("$NetBSD: print-nflog.c,v 1.5 2024/09/02 16:15:32 christos Exp $");
31fdccd7e4Schristos #endif
32fdccd7e4Schristos 
33dc860a36Sspz /* \summary: DLT_NFLOG printer */
34dc860a36Sspz 
35c74ad251Schristos #include <config.h>
36026d7285Schristos 
37c74ad251Schristos #include "netdissect-stdinc.h"
38026d7285Schristos 
39784088dfSchristos #include "netdissect.h"
40c74ad251Schristos #include "extract.h"
41026d7285Schristos 
42c74ad251Schristos #ifdef DLT_NFLOG
43c74ad251Schristos 
44c74ad251Schristos /*
45c74ad251Schristos  * Structure of an NFLOG header and TLV parts, as described at
46c74ad251Schristos  * https://www.tcpdump.org/linktypes/LINKTYPE_NFLOG.html
47c74ad251Schristos  *
48c74ad251Schristos  * The NFLOG header is big-endian.
49c74ad251Schristos  *
50c74ad251Schristos  * The TLV length and type are in host byte order.  The value is either
51c74ad251Schristos  * big-endian or is an array of bytes in some externally-specified byte
52c74ad251Schristos  * order (text string, link-layer address, link-layer header, packet
53c74ad251Schristos  * data, etc.).
54c74ad251Schristos  */
55c74ad251Schristos typedef struct nflog_hdr {
56c74ad251Schristos 	nd_uint8_t	nflog_family;		/* address family */
57c74ad251Schristos 	nd_uint8_t	nflog_version;		/* version */
58c74ad251Schristos 	nd_uint16_t	nflog_rid;		/* resource ID */
59c74ad251Schristos } nflog_hdr_t;
60c74ad251Schristos 
61c74ad251Schristos #define NFLOG_HDR_LEN sizeof(nflog_hdr_t)
62c74ad251Schristos 
63c74ad251Schristos typedef struct nflog_tlv {
64c74ad251Schristos 	nd_uint16_t	tlv_length;		/* tlv length */
65c74ad251Schristos 	nd_uint16_t	tlv_type;		/* tlv type */
66c74ad251Schristos 	/* value follows this */
67c74ad251Schristos } nflog_tlv_t;
68c74ad251Schristos 
69c74ad251Schristos #define NFLOG_TLV_LEN sizeof(nflog_tlv_t)
70c74ad251Schristos 
71c74ad251Schristos typedef struct nflog_packet_hdr {
72c74ad251Schristos 	nd_uint16_t	hw_protocol;	/* hw protocol */
73c74ad251Schristos 	nd_uint8_t	hook;		/* netfilter hook */
74c74ad251Schristos 	nd_byte		pad[1];		/* padding to 32 bits */
75c74ad251Schristos } nflog_packet_hdr_t;
76c74ad251Schristos 
77c74ad251Schristos typedef struct nflog_hwaddr {
78c74ad251Schristos 	nd_uint16_t	hw_addrlen;	/* address length */
79c74ad251Schristos 	nd_byte		pad[2];		/* padding to 32-bit boundary */
80c74ad251Schristos 	nd_byte		hw_addr[8];	/* address, up to 8 bytes */
81c74ad251Schristos } nflog_hwaddr_t;
82c74ad251Schristos 
83c74ad251Schristos typedef struct nflog_timestamp {
84c74ad251Schristos 	nd_uint64_t	sec;
85c74ad251Schristos 	nd_uint64_t	usec;
86c74ad251Schristos } nflog_timestamp_t;
87c74ad251Schristos 
88c74ad251Schristos /*
89c74ad251Schristos  * TLV types.
90c74ad251Schristos  */
91c74ad251Schristos #define NFULA_PACKET_HDR		1	/* nflog_packet_hdr_t */
92c74ad251Schristos #define NFULA_MARK			2	/* packet mark from skbuff */
93c74ad251Schristos #define NFULA_TIMESTAMP			3	/* nflog_timestamp_t for skbuff's time stamp */
94c74ad251Schristos #define NFULA_IFINDEX_INDEV		4	/* ifindex of device on which packet received (possibly bridge group) */
95c74ad251Schristos #define NFULA_IFINDEX_OUTDEV		5	/* ifindex of device on which packet transmitted (possibly bridge group) */
96c74ad251Schristos #define NFULA_IFINDEX_PHYSINDEV		6	/* ifindex of physical device on which packet received (not bridge group) */
97c74ad251Schristos #define NFULA_IFINDEX_PHYSOUTDEV	7	/* ifindex of physical device on which packet transmitted (not bridge group) */
98c74ad251Schristos #define NFULA_HWADDR			8	/* nflog_hwaddr_t for hardware address */
99c74ad251Schristos #define NFULA_PAYLOAD			9	/* packet payload */
100c74ad251Schristos #define NFULA_PREFIX			10	/* text string - null-terminated, count includes NUL */
101c74ad251Schristos #define NFULA_UID			11	/* UID owning socket on which packet was sent/received */
102c74ad251Schristos #define NFULA_SEQ			12	/* sequence number of packets on this NFLOG socket */
103*26ba0b50Schristos #define NFULA_SEQ_GLOBAL		13	/* sequence number of packets on all NFLOG sockets */
104c74ad251Schristos #define NFULA_GID			14	/* GID owning socket on which packet was sent/received */
105c74ad251Schristos #define NFULA_HWTYPE			15	/* ARPHRD_ type of skbuff's device */
106c74ad251Schristos #define NFULA_HWHEADER			16	/* skbuff's MAC-layer header */
107c74ad251Schristos #define NFULA_HWLEN			17	/* length of skbuff's MAC-layer header */
108026d7285Schristos 
109*26ba0b50Schristos /*
110*26ba0b50Schristos  * Define two constants specifically for the two AF code points from the
111*26ba0b50Schristos  * LINKTYPE_NFLOG specification above and use these constants instead of
112*26ba0b50Schristos  * AF_INET and AF_INET6.  This is the only way to dissect the "wire" encoding
113*26ba0b50Schristos  * correctly because some BSD systems define AF_INET6 differently from Linux
114*26ba0b50Schristos  * (see af.h) and Haiku defines both AF_INET and AF_INET6 differently from
115*26ba0b50Schristos  * Linux.
116*26ba0b50Schristos  */
117*26ba0b50Schristos #define NFLOG_AF_INET   2
118*26ba0b50Schristos #define NFLOG_AF_INET6 10
119026d7285Schristos static const struct tok nflog_values[] = {
120*26ba0b50Schristos 	{ NFLOG_AF_INET,	"IPv4" },
121*26ba0b50Schristos 	{ NFLOG_AF_INET6,	"IPv6" },
122026d7285Schristos 	{ 0,			NULL }
123026d7285Schristos };
124026d7285Schristos 
125c74ad251Schristos static void
126c47fd378Schristos nflog_hdr_print(netdissect_options *ndo, const nflog_hdr_t *hdr, u_int length)
127026d7285Schristos {
128c74ad251Schristos 	ND_PRINT("version %u, resource ID %u",
129c74ad251Schristos 	    GET_U_1(hdr->nflog_version), GET_BE_U_2(hdr->nflog_rid));
130026d7285Schristos 
131026d7285Schristos 	if (!ndo->ndo_qflag) {
132c74ad251Schristos 		ND_PRINT(", family %s (%u)",
133026d7285Schristos 			 tok2str(nflog_values, "Unknown",
134c74ad251Schristos 				 GET_U_1(hdr->nflog_family)),
135c74ad251Schristos 			 GET_U_1(hdr->nflog_family));
136026d7285Schristos 		} else {
137c74ad251Schristos 		ND_PRINT(", %s",
138026d7285Schristos 			 tok2str(nflog_values,
139026d7285Schristos 				 "Unknown NFLOG (0x%02x)",
140c74ad251Schristos 			 GET_U_1(hdr->nflog_family)));
141026d7285Schristos 		}
142026d7285Schristos 
143c74ad251Schristos 	ND_PRINT(", length %u: ", length);
144026d7285Schristos }
145026d7285Schristos 
146c74ad251Schristos void
147c47fd378Schristos nflog_if_print(netdissect_options *ndo,
148026d7285Schristos 	       const struct pcap_pkthdr *h, const u_char *p)
149026d7285Schristos {
150026d7285Schristos 	const nflog_hdr_t *hdr = (const nflog_hdr_t *)p;
151c47fd378Schristos 	uint16_t size;
152c74ad251Schristos 	uint16_t h_size = NFLOG_HDR_LEN;
153026d7285Schristos 	u_int caplen = h->caplen;
154026d7285Schristos 	u_int length = h->len;
155026d7285Schristos 
156c74ad251Schristos 	ndo->ndo_protocol = "nflog";
157c74ad251Schristos 	if (caplen < NFLOG_HDR_LEN) {
158c74ad251Schristos 		nd_print_trunc(ndo);
159c74ad251Schristos 		ndo->ndo_ll_hdr_len += caplen;
160c74ad251Schristos 		return;
161026d7285Schristos 	}
162c74ad251Schristos 	ndo->ndo_ll_hdr_len += NFLOG_HDR_LEN;
163026d7285Schristos 
164c74ad251Schristos 	ND_TCHECK_SIZE(hdr);
165c74ad251Schristos 	if (GET_U_1(hdr->nflog_version) != 0) {
166c74ad251Schristos 		ND_PRINT("version %u (unknown)", GET_U_1(hdr->nflog_version));
167c74ad251Schristos 		return;
168026d7285Schristos 	}
169026d7285Schristos 
170026d7285Schristos 	if (ndo->ndo_eflag)
171026d7285Schristos 		nflog_hdr_print(ndo, hdr, length);
172026d7285Schristos 
173c74ad251Schristos 	p += NFLOG_HDR_LEN;
174c74ad251Schristos 	length -= NFLOG_HDR_LEN;
175c74ad251Schristos 	caplen -= NFLOG_HDR_LEN;
176026d7285Schristos 
177c47fd378Schristos 	while (length > 0) {
178c74ad251Schristos 		const nflog_tlv_t *tlv;
179c74ad251Schristos 
180c47fd378Schristos 		/* We have some data.  Do we have enough for the TLV header? */
181c74ad251Schristos 		if (caplen < NFLOG_TLV_LEN)
182c74ad251Schristos 			goto trunc;	/* No. */
183c47fd378Schristos 
184026d7285Schristos 		tlv = (const nflog_tlv_t *) p;
185c74ad251Schristos 		ND_TCHECK_SIZE(tlv);
186c74ad251Schristos 		size = GET_HE_U_2(tlv->tlv_length);
187026d7285Schristos 		if (size % 4 != 0)
188026d7285Schristos 			size += 4 - size % 4;
189026d7285Schristos 
190c47fd378Schristos 		/* Is the TLV's length less than the minimum? */
191c74ad251Schristos 		if (size < NFLOG_TLV_LEN)
192c74ad251Schristos 			goto trunc;	/* Yes. Give up now. */
193c47fd378Schristos 
194c47fd378Schristos 		/* Do we have enough data for the full TLV? */
195c74ad251Schristos 		if (caplen < size)
196c74ad251Schristos 			goto trunc;	/* No. */
197c47fd378Schristos 
198c74ad251Schristos 		if (GET_HE_U_2(tlv->tlv_type) == NFULA_PAYLOAD) {
199c47fd378Schristos 			/*
200c47fd378Schristos 			 * This TLV's data is the packet payload.
201c47fd378Schristos 			 * Skip past the TLV header, and break out
202c47fd378Schristos 			 * of the loop so we print the packet data.
203c47fd378Schristos 			 */
204c74ad251Schristos 			p += NFLOG_TLV_LEN;
205c74ad251Schristos 			h_size += NFLOG_TLV_LEN;
206c74ad251Schristos 			length -= NFLOG_TLV_LEN;
207c74ad251Schristos 			caplen -= NFLOG_TLV_LEN;
208c47fd378Schristos 			break;
209c47fd378Schristos 		}
210026d7285Schristos 
211026d7285Schristos 		p += size;
212c47fd378Schristos 		h_size += size;
213c47fd378Schristos 		length -= size;
214c47fd378Schristos 		caplen -= size;
215c47fd378Schristos 	}
216026d7285Schristos 
217c74ad251Schristos 	switch (GET_U_1(hdr->nflog_family)) {
218026d7285Schristos 
219*26ba0b50Schristos 	case NFLOG_AF_INET:
220026d7285Schristos 		ip_print(ndo, p, length);
221026d7285Schristos 		break;
222026d7285Schristos 
223*26ba0b50Schristos 	case NFLOG_AF_INET6:
224026d7285Schristos 		ip6_print(ndo, p, length);
225026d7285Schristos 		break;
226026d7285Schristos 
227026d7285Schristos 	default:
228026d7285Schristos 		if (!ndo->ndo_eflag)
229026d7285Schristos 			nflog_hdr_print(ndo, hdr,
230c74ad251Schristos 					length + NFLOG_HDR_LEN);
231026d7285Schristos 
232026d7285Schristos 		if (!ndo->ndo_suppress_default_print)
233c47fd378Schristos 			ND_DEFAULTPRINT(p, caplen);
234026d7285Schristos 		break;
235026d7285Schristos 	}
236026d7285Schristos 
237c74ad251Schristos 	ndo->ndo_ll_hdr_len += h_size - NFLOG_HDR_LEN;
238c74ad251Schristos 	return;
239c74ad251Schristos trunc:
240c74ad251Schristos 	nd_print_trunc(ndo);
241c74ad251Schristos 	ndo->ndo_ll_hdr_len += h_size - NFLOG_HDR_LEN;
242026d7285Schristos }
243026d7285Schristos 
244c74ad251Schristos #endif /* DLT_NFLOG */
245