1276761Sdelphij/*
2276761Sdelphij * Copyright (c) 2013, Petar Alilovic,
3276761Sdelphij * Faculty of Electrical Engineering and Computing, University of Zagreb
4276761Sdelphij * All rights reserved
5276761Sdelphij *
6276761Sdelphij * Redistribution and use in source and binary forms, with or without
7276761Sdelphij * modification, are permitted provided that the following conditions are met:
8276761Sdelphij *
9276761Sdelphij * * Redistributions of source code must retain the above copyright notice,
10276761Sdelphij *	 this list of conditions and the following disclaimer.
11276761Sdelphij * * Redistributions in binary form must reproduce the above copyright
12276761Sdelphij *	 notice, this list of conditions and the following disclaimer in the
13276761Sdelphij *	 documentation and/or other materials provided with the distribution.
14276761Sdelphij *
15276761Sdelphij * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
16276761Sdelphij * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17276761Sdelphij * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18276761Sdelphij * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
19276761Sdelphij * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20276761Sdelphij * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21276761Sdelphij * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22276761Sdelphij * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23276761Sdelphij * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24276761Sdelphij * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
25276761Sdelphij * DAMAGE.
26276761Sdelphij */
27276761Sdelphij
28313537Sglebius/* \summary: DLT_NFLOG printer */
29313537Sglebius
30276761Sdelphij#ifdef HAVE_CONFIG_H
31276761Sdelphij#include "config.h"
32276761Sdelphij#endif
33276761Sdelphij
34313537Sglebius#include <netdissect-stdinc.h>
35276761Sdelphij
36313537Sglebius#include "netdissect.h"
37276761Sdelphij
38276761Sdelphij#if defined(DLT_NFLOG) && defined(HAVE_PCAP_NFLOG_H)
39276761Sdelphij#include <pcap/nflog.h>
40276761Sdelphij
41276761Sdelphijstatic const struct tok nflog_values[] = {
42276761Sdelphij	{ AF_INET,		"IPv4" },
43313537Sglebius#ifdef AF_INET6
44276761Sdelphij	{ AF_INET6,		"IPv6" },
45313537Sglebius#endif /*AF_INET6*/
46276761Sdelphij	{ 0,			NULL }
47276761Sdelphij};
48276761Sdelphij
49276761Sdelphijstatic inline void
50276761Sdelphijnflog_hdr_print(netdissect_options *ndo, const nflog_hdr_t *hdr, u_int length)
51276761Sdelphij{
52276761Sdelphij	ND_PRINT((ndo, "version %d, resource ID %d", hdr->nflog_version, ntohs(hdr->nflog_rid)));
53276761Sdelphij
54276761Sdelphij	if (!ndo->ndo_qflag) {
55276761Sdelphij		ND_PRINT((ndo,", family %s (%d)",
56276761Sdelphij						  tok2str(nflog_values, "Unknown",
57276761Sdelphij								  hdr->nflog_family),
58276761Sdelphij						  hdr->nflog_family));
59276761Sdelphij		} else {
60276761Sdelphij		ND_PRINT((ndo,", %s",
61276761Sdelphij						  tok2str(nflog_values,
62276761Sdelphij								  "Unknown NFLOG (0x%02x)",
63276761Sdelphij								  hdr->nflog_family)));
64276761Sdelphij		}
65276761Sdelphij
66276761Sdelphij	ND_PRINT((ndo, ", length %u: ", length));
67276761Sdelphij}
68276761Sdelphij
69276761Sdelphiju_int
70276761Sdelphijnflog_if_print(netdissect_options *ndo,
71276761Sdelphij			   const struct pcap_pkthdr *h, const u_char *p)
72276761Sdelphij{
73276761Sdelphij	const nflog_hdr_t *hdr = (const nflog_hdr_t *)p;
74276761Sdelphij	const nflog_tlv_t *tlv;
75276761Sdelphij	uint16_t size;
76276761Sdelphij	uint16_t h_size = sizeof(nflog_hdr_t);
77276761Sdelphij	u_int caplen = h->caplen;
78276761Sdelphij	u_int length = h->len;
79276761Sdelphij
80276761Sdelphij	if (caplen < (int) sizeof(nflog_hdr_t) || length < (int) sizeof(nflog_hdr_t)) {
81276761Sdelphij		ND_PRINT((ndo, "[|nflog]"));
82276761Sdelphij		return h_size;
83276761Sdelphij	}
84276761Sdelphij
85313537Sglebius	if (hdr->nflog_version != 0) {
86276761Sdelphij		ND_PRINT((ndo, "version %u (unknown)", hdr->nflog_version));
87276761Sdelphij		return h_size;
88276761Sdelphij	}
89276761Sdelphij
90276761Sdelphij	if (ndo->ndo_eflag)
91276761Sdelphij		nflog_hdr_print(ndo, hdr, length);
92276761Sdelphij
93276761Sdelphij	p += sizeof(nflog_hdr_t);
94276761Sdelphij	length -= sizeof(nflog_hdr_t);
95276761Sdelphij	caplen -= sizeof(nflog_hdr_t);
96276761Sdelphij
97276761Sdelphij	while (length > 0) {
98276761Sdelphij		/* We have some data.  Do we have enough for the TLV header? */
99276761Sdelphij		if (caplen < sizeof(nflog_tlv_t) || length < sizeof(nflog_tlv_t)) {
100276761Sdelphij			/* No. */
101276761Sdelphij			ND_PRINT((ndo, "[|nflog]"));
102276761Sdelphij			return h_size;
103276761Sdelphij		}
104276761Sdelphij
105276761Sdelphij		tlv = (const nflog_tlv_t *) p;
106276761Sdelphij		size = tlv->tlv_length;
107276761Sdelphij		if (size % 4 != 0)
108276761Sdelphij			size += 4 - size % 4;
109276761Sdelphij
110276761Sdelphij		/* Is the TLV's length less than the minimum? */
111276761Sdelphij		if (size < sizeof(nflog_tlv_t)) {
112276761Sdelphij			/* Yes. Give up now. */
113276761Sdelphij			ND_PRINT((ndo, "[|nflog]"));
114276761Sdelphij			return h_size;
115276761Sdelphij		}
116276761Sdelphij
117276761Sdelphij		/* Do we have enough data for the full TLV? */
118276761Sdelphij		if (caplen < size || length < size) {
119276761Sdelphij			/* No. */
120276761Sdelphij			ND_PRINT((ndo, "[|nflog]"));
121276761Sdelphij			return h_size;
122276761Sdelphij		}
123276761Sdelphij
124276761Sdelphij		if (tlv->tlv_type == NFULA_PAYLOAD) {
125276761Sdelphij			/*
126276761Sdelphij			 * This TLV's data is the packet payload.
127276761Sdelphij			 * Skip past the TLV header, and break out
128276761Sdelphij			 * of the loop so we print the packet data.
129276761Sdelphij			 */
130276761Sdelphij			p += sizeof(nflog_tlv_t);
131276761Sdelphij			h_size += sizeof(nflog_tlv_t);
132276761Sdelphij			length -= sizeof(nflog_tlv_t);
133276761Sdelphij			caplen -= sizeof(nflog_tlv_t);
134276761Sdelphij			break;
135276761Sdelphij		}
136276761Sdelphij
137276761Sdelphij		p += size;
138276761Sdelphij		h_size += size;
139276761Sdelphij		length -= size;
140276761Sdelphij		caplen -= size;
141276761Sdelphij	}
142276761Sdelphij
143276761Sdelphij	switch (hdr->nflog_family) {
144276761Sdelphij
145276761Sdelphij	case AF_INET:
146276761Sdelphij		ip_print(ndo, p, length);
147276761Sdelphij		break;
148276761Sdelphij
149285275Spkelsey#ifdef AF_INET6
150276761Sdelphij	case AF_INET6:
151276761Sdelphij		ip6_print(ndo, p, length);
152276761Sdelphij		break;
153285275Spkelsey#endif /* AF_INET6 */
154276761Sdelphij
155276761Sdelphij	default:
156276761Sdelphij		if (!ndo->ndo_eflag)
157276761Sdelphij			nflog_hdr_print(ndo, hdr,
158276761Sdelphij				length + sizeof(nflog_hdr_t));
159276761Sdelphij
160276761Sdelphij		if (!ndo->ndo_suppress_default_print)
161276761Sdelphij			ND_DEFAULTPRINT(p, caplen);
162276761Sdelphij		break;
163276761Sdelphij	}
164276761Sdelphij
165276761Sdelphij	return h_size;
166276761Sdelphij}
167276761Sdelphij
168276761Sdelphij#endif /* defined(DLT_NFLOG) && defined(HAVE_PCAP_NFLOG_H) */
169