1*05b00f60SXin Li /*
2*05b00f60SXin Li * Copyright (c) 2013, Petar Alilovic,
3*05b00f60SXin Li * Faculty of Electrical Engineering and Computing, University of Zagreb
4*05b00f60SXin Li * All rights reserved
5*05b00f60SXin Li *
6*05b00f60SXin Li * Redistribution and use in source and binary forms, with or without
7*05b00f60SXin Li * modification, are permitted provided that the following conditions are met:
8*05b00f60SXin Li *
9*05b00f60SXin Li * * Redistributions of source code must retain the above copyright notice,
10*05b00f60SXin Li * this list of conditions and the following disclaimer.
11*05b00f60SXin Li * * Redistributions in binary form must reproduce the above copyright
12*05b00f60SXin Li * notice, this list of conditions and the following disclaimer in the
13*05b00f60SXin Li * documentation and/or other materials provided with the distribution.
14*05b00f60SXin Li *
15*05b00f60SXin Li * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
16*05b00f60SXin Li * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17*05b00f60SXin Li * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18*05b00f60SXin Li * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
19*05b00f60SXin Li * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20*05b00f60SXin Li * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21*05b00f60SXin Li * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22*05b00f60SXin Li * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*05b00f60SXin Li * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*05b00f60SXin Li * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
25*05b00f60SXin Li * DAMAGE.
26*05b00f60SXin Li */
27*05b00f60SXin Li
28*05b00f60SXin Li /* \summary: DLT_NFLOG printer */
29*05b00f60SXin Li
30*05b00f60SXin Li #ifdef HAVE_CONFIG_H
31*05b00f60SXin Li #include <config.h>
32*05b00f60SXin Li #endif
33*05b00f60SXin Li
34*05b00f60SXin Li #include "netdissect-stdinc.h"
35*05b00f60SXin Li
36*05b00f60SXin Li #include "netdissect.h"
37*05b00f60SXin Li #include "extract.h"
38*05b00f60SXin Li
39*05b00f60SXin Li #ifdef DLT_NFLOG
40*05b00f60SXin Li
41*05b00f60SXin Li /*
42*05b00f60SXin Li * Structure of an NFLOG header and TLV parts, as described at
43*05b00f60SXin Li * https://www.tcpdump.org/linktypes/LINKTYPE_NFLOG.html
44*05b00f60SXin Li *
45*05b00f60SXin Li * The NFLOG header is big-endian.
46*05b00f60SXin Li *
47*05b00f60SXin Li * The TLV length and type are in host byte order. The value is either
48*05b00f60SXin Li * big-endian or is an array of bytes in some externally-specified byte
49*05b00f60SXin Li * order (text string, link-layer address, link-layer header, packet
50*05b00f60SXin Li * data, etc.).
51*05b00f60SXin Li */
52*05b00f60SXin Li typedef struct nflog_hdr {
53*05b00f60SXin Li nd_uint8_t nflog_family; /* address family */
54*05b00f60SXin Li nd_uint8_t nflog_version; /* version */
55*05b00f60SXin Li nd_uint16_t nflog_rid; /* resource ID */
56*05b00f60SXin Li } nflog_hdr_t;
57*05b00f60SXin Li
58*05b00f60SXin Li #define NFLOG_HDR_LEN sizeof(nflog_hdr_t)
59*05b00f60SXin Li
60*05b00f60SXin Li typedef struct nflog_tlv {
61*05b00f60SXin Li nd_uint16_t tlv_length; /* tlv length */
62*05b00f60SXin Li nd_uint16_t tlv_type; /* tlv type */
63*05b00f60SXin Li /* value follows this */
64*05b00f60SXin Li } nflog_tlv_t;
65*05b00f60SXin Li
66*05b00f60SXin Li #define NFLOG_TLV_LEN sizeof(nflog_tlv_t)
67*05b00f60SXin Li
68*05b00f60SXin Li typedef struct nflog_packet_hdr {
69*05b00f60SXin Li nd_uint16_t hw_protocol; /* hw protocol */
70*05b00f60SXin Li nd_uint8_t hook; /* netfilter hook */
71*05b00f60SXin Li nd_byte pad[1]; /* padding to 32 bits */
72*05b00f60SXin Li } nflog_packet_hdr_t;
73*05b00f60SXin Li
74*05b00f60SXin Li typedef struct nflog_hwaddr {
75*05b00f60SXin Li nd_uint16_t hw_addrlen; /* address length */
76*05b00f60SXin Li nd_byte pad[2]; /* padding to 32-bit boundary */
77*05b00f60SXin Li nd_byte hw_addr[8]; /* address, up to 8 bytes */
78*05b00f60SXin Li } nflog_hwaddr_t;
79*05b00f60SXin Li
80*05b00f60SXin Li typedef struct nflog_timestamp {
81*05b00f60SXin Li nd_uint64_t sec;
82*05b00f60SXin Li nd_uint64_t usec;
83*05b00f60SXin Li } nflog_timestamp_t;
84*05b00f60SXin Li
85*05b00f60SXin Li /*
86*05b00f60SXin Li * TLV types.
87*05b00f60SXin Li */
88*05b00f60SXin Li #define NFULA_PACKET_HDR 1 /* nflog_packet_hdr_t */
89*05b00f60SXin Li #define NFULA_MARK 2 /* packet mark from skbuff */
90*05b00f60SXin Li #define NFULA_TIMESTAMP 3 /* nflog_timestamp_t for skbuff's time stamp */
91*05b00f60SXin Li #define NFULA_IFINDEX_INDEV 4 /* ifindex of device on which packet received (possibly bridge group) */
92*05b00f60SXin Li #define NFULA_IFINDEX_OUTDEV 5 /* ifindex of device on which packet transmitted (possibly bridge group) */
93*05b00f60SXin Li #define NFULA_IFINDEX_PHYSINDEV 6 /* ifindex of physical device on which packet received (not bridge group) */
94*05b00f60SXin Li #define NFULA_IFINDEX_PHYSOUTDEV 7 /* ifindex of physical device on which packet transmitted (not bridge group) */
95*05b00f60SXin Li #define NFULA_HWADDR 8 /* nflog_hwaddr_t for hardware address */
96*05b00f60SXin Li #define NFULA_PAYLOAD 9 /* packet payload */
97*05b00f60SXin Li #define NFULA_PREFIX 10 /* text string - null-terminated, count includes NUL */
98*05b00f60SXin Li #define NFULA_UID 11 /* UID owning socket on which packet was sent/received */
99*05b00f60SXin Li #define NFULA_SEQ 12 /* sequence number of packets on this NFLOG socket */
100*05b00f60SXin Li #define NFULA_SEQ_GLOBAL 13 /* sequence number of pakets on all NFLOG sockets */
101*05b00f60SXin Li #define NFULA_GID 14 /* GID owning socket on which packet was sent/received */
102*05b00f60SXin Li #define NFULA_HWTYPE 15 /* ARPHRD_ type of skbuff's device */
103*05b00f60SXin Li #define NFULA_HWHEADER 16 /* skbuff's MAC-layer header */
104*05b00f60SXin Li #define NFULA_HWLEN 17 /* length of skbuff's MAC-layer header */
105*05b00f60SXin Li
106*05b00f60SXin Li static const struct tok nflog_values[] = {
107*05b00f60SXin Li { AF_INET, "IPv4" },
108*05b00f60SXin Li { AF_INET6, "IPv6" },
109*05b00f60SXin Li { 0, NULL }
110*05b00f60SXin Li };
111*05b00f60SXin Li
112*05b00f60SXin Li static void
nflog_hdr_print(netdissect_options * ndo,const nflog_hdr_t * hdr,u_int length)113*05b00f60SXin Li nflog_hdr_print(netdissect_options *ndo, const nflog_hdr_t *hdr, u_int length)
114*05b00f60SXin Li {
115*05b00f60SXin Li ND_PRINT("version %u, resource ID %u",
116*05b00f60SXin Li GET_U_1(hdr->nflog_version), GET_BE_U_2(hdr->nflog_rid));
117*05b00f60SXin Li
118*05b00f60SXin Li if (!ndo->ndo_qflag) {
119*05b00f60SXin Li ND_PRINT(", family %s (%u)",
120*05b00f60SXin Li tok2str(nflog_values, "Unknown",
121*05b00f60SXin Li GET_U_1(hdr->nflog_family)),
122*05b00f60SXin Li GET_U_1(hdr->nflog_family));
123*05b00f60SXin Li } else {
124*05b00f60SXin Li ND_PRINT(", %s",
125*05b00f60SXin Li tok2str(nflog_values,
126*05b00f60SXin Li "Unknown NFLOG (0x%02x)",
127*05b00f60SXin Li GET_U_1(hdr->nflog_family)));
128*05b00f60SXin Li }
129*05b00f60SXin Li
130*05b00f60SXin Li ND_PRINT(", length %u: ", length);
131*05b00f60SXin Li }
132*05b00f60SXin Li
133*05b00f60SXin Li void
nflog_if_print(netdissect_options * ndo,const struct pcap_pkthdr * h,const u_char * p)134*05b00f60SXin Li nflog_if_print(netdissect_options *ndo,
135*05b00f60SXin Li const struct pcap_pkthdr *h, const u_char *p)
136*05b00f60SXin Li {
137*05b00f60SXin Li const nflog_hdr_t *hdr = (const nflog_hdr_t *)p;
138*05b00f60SXin Li uint16_t size;
139*05b00f60SXin Li uint16_t h_size = NFLOG_HDR_LEN;
140*05b00f60SXin Li u_int caplen = h->caplen;
141*05b00f60SXin Li u_int length = h->len;
142*05b00f60SXin Li
143*05b00f60SXin Li ndo->ndo_protocol = "nflog";
144*05b00f60SXin Li if (caplen < NFLOG_HDR_LEN) {
145*05b00f60SXin Li nd_print_trunc(ndo);
146*05b00f60SXin Li ndo->ndo_ll_hdr_len += caplen;
147*05b00f60SXin Li return;
148*05b00f60SXin Li }
149*05b00f60SXin Li ndo->ndo_ll_hdr_len += NFLOG_HDR_LEN;
150*05b00f60SXin Li
151*05b00f60SXin Li ND_TCHECK_SIZE(hdr);
152*05b00f60SXin Li if (GET_U_1(hdr->nflog_version) != 0) {
153*05b00f60SXin Li ND_PRINT("version %u (unknown)", GET_U_1(hdr->nflog_version));
154*05b00f60SXin Li return;
155*05b00f60SXin Li }
156*05b00f60SXin Li
157*05b00f60SXin Li if (ndo->ndo_eflag)
158*05b00f60SXin Li nflog_hdr_print(ndo, hdr, length);
159*05b00f60SXin Li
160*05b00f60SXin Li p += NFLOG_HDR_LEN;
161*05b00f60SXin Li length -= NFLOG_HDR_LEN;
162*05b00f60SXin Li caplen -= NFLOG_HDR_LEN;
163*05b00f60SXin Li
164*05b00f60SXin Li while (length > 0) {
165*05b00f60SXin Li const nflog_tlv_t *tlv;
166*05b00f60SXin Li
167*05b00f60SXin Li /* We have some data. Do we have enough for the TLV header? */
168*05b00f60SXin Li if (caplen < NFLOG_TLV_LEN)
169*05b00f60SXin Li goto trunc; /* No. */
170*05b00f60SXin Li
171*05b00f60SXin Li tlv = (const nflog_tlv_t *) p;
172*05b00f60SXin Li ND_TCHECK_SIZE(tlv);
173*05b00f60SXin Li size = GET_HE_U_2(tlv->tlv_length);
174*05b00f60SXin Li if (size % 4 != 0)
175*05b00f60SXin Li size += 4 - size % 4;
176*05b00f60SXin Li
177*05b00f60SXin Li /* Is the TLV's length less than the minimum? */
178*05b00f60SXin Li if (size < NFLOG_TLV_LEN)
179*05b00f60SXin Li goto trunc; /* Yes. Give up now. */
180*05b00f60SXin Li
181*05b00f60SXin Li /* Do we have enough data for the full TLV? */
182*05b00f60SXin Li if (caplen < size)
183*05b00f60SXin Li goto trunc; /* No. */
184*05b00f60SXin Li
185*05b00f60SXin Li if (GET_HE_U_2(tlv->tlv_type) == NFULA_PAYLOAD) {
186*05b00f60SXin Li /*
187*05b00f60SXin Li * This TLV's data is the packet payload.
188*05b00f60SXin Li * Skip past the TLV header, and break out
189*05b00f60SXin Li * of the loop so we print the packet data.
190*05b00f60SXin Li */
191*05b00f60SXin Li p += NFLOG_TLV_LEN;
192*05b00f60SXin Li h_size += NFLOG_TLV_LEN;
193*05b00f60SXin Li length -= NFLOG_TLV_LEN;
194*05b00f60SXin Li caplen -= NFLOG_TLV_LEN;
195*05b00f60SXin Li break;
196*05b00f60SXin Li }
197*05b00f60SXin Li
198*05b00f60SXin Li p += size;
199*05b00f60SXin Li h_size += size;
200*05b00f60SXin Li length -= size;
201*05b00f60SXin Li caplen -= size;
202*05b00f60SXin Li }
203*05b00f60SXin Li
204*05b00f60SXin Li switch (GET_U_1(hdr->nflog_family)) {
205*05b00f60SXin Li
206*05b00f60SXin Li case AF_INET:
207*05b00f60SXin Li ip_print(ndo, p, length);
208*05b00f60SXin Li break;
209*05b00f60SXin Li
210*05b00f60SXin Li case AF_INET6:
211*05b00f60SXin Li ip6_print(ndo, p, length);
212*05b00f60SXin Li break;
213*05b00f60SXin Li
214*05b00f60SXin Li default:
215*05b00f60SXin Li if (!ndo->ndo_eflag)
216*05b00f60SXin Li nflog_hdr_print(ndo, hdr,
217*05b00f60SXin Li length + NFLOG_HDR_LEN);
218*05b00f60SXin Li
219*05b00f60SXin Li if (!ndo->ndo_suppress_default_print)
220*05b00f60SXin Li ND_DEFAULTPRINT(p, caplen);
221*05b00f60SXin Li break;
222*05b00f60SXin Li }
223*05b00f60SXin Li
224*05b00f60SXin Li ndo->ndo_ll_hdr_len += h_size - NFLOG_HDR_LEN;
225*05b00f60SXin Li return;
226*05b00f60SXin Li trunc:
227*05b00f60SXin Li nd_print_trunc(ndo);
228*05b00f60SXin Li ndo->ndo_ll_hdr_len += h_size - NFLOG_HDR_LEN;
229*05b00f60SXin Li }
230*05b00f60SXin Li
231*05b00f60SXin Li #endif /* DLT_NFLOG */
232