]> The Tcpdump Group git mirrors - tcpdump/blob - print-nflog.c
Print decoded attributes from NFLOG message
[tcpdump] / print-nflog.c
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 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include <netdissect-stdinc.h>
33
34 #include "netdissect.h"
35
36 #if defined(DLT_NFLOG) && defined(HAVE_PCAP_NFLOG_H)
37 #include <pcap/nflog.h>
38
39 static const struct tok nflog_values[] = {
40 { AF_INET, "IPv4" },
41 #ifdef AF_INET6
42 { AF_INET6, "IPv6" },
43 #endif /*AF_INET6*/
44 { 0, NULL }
45 };
46
47 static inline void
48 nflog_hdr_print(netdissect_options *ndo, const nflog_hdr_t *hdr, u_int length)
49 {
50 ND_PRINT((ndo, "version %d, resource ID %d", hdr->nflog_version, ntohs(hdr->nflog_rid)));
51
52 if (!ndo->ndo_qflag) {
53 ND_PRINT((ndo,", family %s (%d)",
54 tok2str(nflog_values, "Unknown",
55 hdr->nflog_family),
56 hdr->nflog_family));
57 } else {
58 ND_PRINT((ndo,", %s",
59 tok2str(nflog_values,
60 "Unknown NFLOG (0x%02x)",
61 hdr->nflog_family)));
62 }
63
64 ND_PRINT((ndo, ", length %u: ", length));
65 }
66
67 static char *hook_names[] = { "PRE","IN","FWD","OUT","POST" };
68
69 static const char *hook2txt(int hook) {
70 if(hook >= sizeof(hook_names)/sizeof(hook_names[0])) return "UNK";
71 return hook_names[hook];
72 }
73
74 u_int
75 nflog_if_print(netdissect_options *ndo,
76 const struct pcap_pkthdr *h, const u_char *p)
77 {
78 const nflog_hdr_t *hdr = (const nflog_hdr_t *)p;
79 const nflog_tlv_t *tlv;
80 uint16_t size;
81 uint16_t hw_hdrlen = 0;
82 uint16_t hw_addrlen = 0;
83 uint16_t h_size = sizeof(nflog_hdr_t);
84 u_int caplen = h->caplen;
85 u_int length = h->len;
86
87 if (caplen < (int) sizeof(nflog_hdr_t) || length < (int) sizeof(nflog_hdr_t)) {
88 ND_PRINT((ndo, "[|nflog]"));
89 return h_size;
90 }
91
92 if (!(hdr->nflog_version) == 0) {
93 ND_PRINT((ndo, "version %u (unknown)", hdr->nflog_version));
94 return h_size;
95 }
96
97 if (ndo->ndo_eflag)
98 nflog_hdr_print(ndo, hdr, length);
99
100 p += sizeof(nflog_hdr_t);
101 length -= sizeof(nflog_hdr_t);
102 caplen -= sizeof(nflog_hdr_t);
103
104 while (length > 0) {
105 /* We have some data. Do we have enough for the TLV header? */
106 if (caplen < sizeof(nflog_tlv_t) || length < sizeof(nflog_tlv_t)) {
107 /* No. */
108 ND_PRINT((ndo, "[|nflog]"));
109 return h_size;
110 }
111
112 tlv = (const nflog_tlv_t *) p;
113 size = tlv->tlv_length;
114 if (size % 4 != 0)
115 size += 4 - size % 4;
116
117 /* Is the TLV's length less than the minimum? */
118 if (size < sizeof(nflog_tlv_t)) {
119 /* Yes. Give up now. */
120 ND_PRINT((ndo, "[|nflog]"));
121 return h_size;
122 }
123
124 /* Do we have enough data for the full TLV? */
125 if (caplen < size || length < size) {
126 /* No. */
127 ND_PRINT((ndo, "[|nflog]"));
128 return h_size;
129 }
130
131 if (tlv->tlv_type == NFULA_PAYLOAD) {
132 /*
133 * This TLV's data is the packet payload.
134 * Skip past the TLV header, and break out
135 * of the loop so we print the packet data.
136 */
137 p += sizeof(nflog_tlv_t);
138 h_size += sizeof(nflog_tlv_t);
139 length -= sizeof(nflog_tlv_t);
140 caplen -= sizeof(nflog_tlv_t);
141 break;
142 }
143 {
144 const u_char *adata = p+sizeof(nflog_tlv_t);
145 switch(tlv->tlv_type) {
146 case NFULA_TIMESTAMP:
147 case NFULA_HWTYPE:
148 break;
149 case NFULA_PACKET_HDR:
150 if(ndo->ndo_vflag)
151 ND_PRINT((ndo, "HOOK:%s ",
152 hook2txt(((nflog_packet_hdr_t *)adata)->hook)));
153 break;
154 case NFULA_MARK:
155 ND_PRINT((ndo, "MARK:0x%x ",
156 htonl(*(u_int32_t *)adata)));
157 break;
158 case NFULA_UID:
159 if(ndo->ndo_vflag)
160 ND_PRINT((ndo, "UID:%u ",
161 htonl(*(u_int32_t *)adata)));
162 break;
163 case NFULA_GID:
164 if(ndo->ndo_vflag)
165 ND_PRINT((ndo, "GID:%u ",
166 htonl(*(u_int32_t *)adata)));
167 break;
168 case NFULA_PREFIX:
169 if(p[sizeof(nflog_tlv_t)])
170 ND_PRINT((ndo, "Prefix:%.*s ",
171 size-sizeof(nflog_tlv_t), adata));
172 break;
173 case NFULA_IFINDEX_INDEV:
174 if(ndo->ndo_vflag > 1)
175 ND_PRINT((ndo, "iif:%u ",
176 htonl(*(u_int32_t *)adata)));
177 break;
178 case NFULA_IFINDEX_OUTDEV:
179 if(ndo->ndo_vflag > 1)
180 ND_PRINT((ndo, "oif:%u ",
181 htonl(*(u_int32_t *)adata)));
182 break;
183 case NFULA_IFINDEX_PHYSINDEV:
184 if(ndo->ndo_vflag > 1)
185 ND_PRINT((ndo, "phyiif:%u ",
186 htonl(*(u_int32_t *)adata)));
187 break;
188 case NFULA_IFINDEX_PHYSOUTDEV:
189 if(ndo->ndo_vflag > 1)
190 ND_PRINT((ndo, "phyoif:%u ",
191 htonl(*(u_int32_t *)adata)));
192 break;
193 case NFULA_HWADDR:
194 hw_addrlen = htons(((nflog_hwaddr_t *)adata)->hw_addrlen);
195 break;
196 case NFULA_HWLEN:
197 hw_hdrlen = htons((*(u_int16_t *)adata));
198 break;
199 case NFULA_HWHEADER:
200 if (!hw_hdrlen || ndo->ndo_vflag < 2) break;
201 {
202 char attr_buf[128];
203 int n,l;
204 memset(attr_buf,0,sizeof(attr_buf));
205 for(n=0,l=0; n < hw_hdrlen && l < sizeof(attr_buf)-3; n++) {
206 if(hw_addrlen &&
207 (n == hw_addrlen || n == hw_addrlen*2))
208 attr_buf[l++] = ':';
209 l += snprintf(&attr_buf[l],3,"%02x",adata[n]);
210 }
211 ND_PRINT((ndo, "HWHDR=%s ",attr_buf));
212 }
213 break;
214 default:
215 if (ndo->ndo_vflag < 3) break;
216 ND_PRINT((ndo, "ATTR%d/%d ",tlv->tlv_type,size));
217 }
218 }
219
220 p += size;
221 h_size += size;
222 length -= size;
223 caplen -= size;
224 }
225
226 switch (hdr->nflog_family) {
227
228 case AF_INET:
229 ip_print(ndo, p, length);
230 break;
231
232 #ifdef AF_INET6
233 case AF_INET6:
234 ip6_print(ndo, p, length);
235 break;
236 #endif /* AF_INET6 */
237
238 default:
239 if (!ndo->ndo_eflag)
240 nflog_hdr_print(ndo, hdr,
241 length + sizeof(nflog_hdr_t));
242
243 if (!ndo->ndo_suppress_default_print)
244 ND_DEFAULTPRINT(p, caplen);
245 break;
246 }
247
248 return h_size;
249 }
250
251 #endif /* defined(DLT_NFLOG) && defined(HAVE_PCAP_NFLOG_H) */