libnetfilter_conntrack 1.1.0
conntrack/snprintf_default.c
1/*
2 * (C) 2005-2011 by Pablo Neira Ayuso <pablo@netfilter.org>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 */
9
10#include "internal/internal.h"
11
12static int __snprintf_l3protocol(char *buf,
13 unsigned int len,
14 const struct nf_conntrack *ct)
15{
16 uint8_t num = ct->head.orig.l3protonum;
17
18 if (!test_bit(ATTR_ORIG_L3PROTO, ct->head.set))
19 return -1;
20
21 return snprintf(buf, len, "%-8s %u ", __l3proto2str(num), num);
22}
23
24int __snprintf_protocol(char *buf,
25 unsigned int len,
26 const struct nf_conntrack *ct)
27{
28 uint8_t num = ct->head.orig.protonum;
29
30 if (!test_bit(ATTR_ORIG_L4PROTO, ct->head.set))
31 return -1;
32
33 return snprintf(buf, len, "%-8s %u ", __proto2str(num), num);
34}
35
36static int __snprintf_timeout(char *buf,
37 unsigned int len,
38 const struct nf_conntrack *ct)
39{
40 return snprintf(buf, len, "%u ", ct->timeout);
41}
42
43static int __snprintf_protoinfo(char *buf,
44 unsigned int len,
45 const struct nf_conntrack *ct)
46{
47 uint8_t state = ct->protoinfo.tcp.state;
48 const char *str = NULL;
49
50 if (state < ARRAY_SIZE(states))
51 str = states[state];
52
53 if (str == NULL)
54 str = states[TCP_CONNTRACK_NONE];
55
56 return snprintf(buf, len, "%s ", str);
57}
58
59static int __snprintf_protoinfo_sctp(char *buf,
60 unsigned int len,
61 const struct nf_conntrack *ct)
62{
63 uint8_t state = ct->protoinfo.sctp.state;
64 const char *str = NULL;
65
66 if (state < ARRAY_SIZE(sctp_states))
67 str = sctp_states[state];
68
69 if (str == NULL)
70 str = sctp_states[SCTP_CONNTRACK_NONE];
71
72 return snprintf(buf, len, "%s ", str);
73}
74
75static int __snprintf_protoinfo_dccp(char *buf,
76 unsigned int len,
77 const struct nf_conntrack *ct)
78{
79 const char *str = NULL;
80 uint8_t state = ct->protoinfo.dccp.state;
81
82 if (state < ARRAY_SIZE(dccp_states))
83 str = dccp_states[state];
84
85 if (str == NULL)
86 str = dccp_states[DCCP_CONNTRACK_NONE];
87
88 return snprintf(buf, len, "%s ", str);
89}
90
91static int __snprintf_address_ipv4(char *buf,
92 unsigned int len,
93 const struct __nfct_tuple *tuple,
94 const char *src_tag,
95 const char *dst_tag)
96{
97 int ret, size = 0, offset = 0;
98 struct in_addr src = { .s_addr = tuple->src.v4 };
99 struct in_addr dst = { .s_addr = tuple->dst.v4 };
100
101 ret = snprintf(buf, len, "%s=%s ", src_tag, inet_ntoa(src));
102 BUFFER_SIZE(ret, size, len, offset);
103
104 ret = snprintf(buf+offset, len, "%s=%s ", dst_tag, inet_ntoa(dst));
105 BUFFER_SIZE(ret, size, len, offset);
106
107 return size;
108}
109
110static int __snprintf_address_ipv6(char *buf,
111 unsigned int len,
112 const struct __nfct_tuple *tuple,
113 const char *src_tag,
114 const char *dst_tag)
115{
116 int ret, size = 0, offset = 0;
117 struct in6_addr src;
118 struct in6_addr dst;
119 char tmp[INET6_ADDRSTRLEN];
120
121 memcpy(&src, &tuple->src.v6, sizeof(struct in6_addr));
122 memcpy(&dst, &tuple->dst.v6, sizeof(struct in6_addr));
123
124 if (!inet_ntop(AF_INET6, &src, tmp, sizeof(tmp)))
125 return -1;
126
127 ret = snprintf(buf, len, "%s=%s ", src_tag, tmp);
128 BUFFER_SIZE(ret, size, len, offset);
129
130 if (!inet_ntop(AF_INET6, &dst, tmp, sizeof(tmp)))
131 return -1;
132
133 ret = snprintf(buf + offset, len, "%s=%s ", dst_tag, tmp);
134 BUFFER_SIZE(ret, size, len, offset);
135
136 return size;
137}
138
139int __snprintf_address(char *buf,
140 unsigned int len,
141 const struct __nfct_tuple *tuple,
142 const char *src_tag,
143 const char *dst_tag)
144{
145 int size = 0;
146
147 switch (tuple->l3protonum) {
148 case AF_INET:
149 size = __snprintf_address_ipv4(buf, len, tuple,
150 src_tag, dst_tag);
151 break;
152 case AF_INET6:
153 size = __snprintf_address_ipv6(buf, len, tuple,
154 src_tag, dst_tag);
155 break;
156 }
157
158 return size;
159}
160
161int __snprintf_proto(char *buf,
162 unsigned int len,
163 const struct __nfct_tuple *tuple)
164{
165 int size = 0;
166
167 switch(tuple->protonum) {
168 case IPPROTO_TCP:
169 case IPPROTO_UDP:
170 case IPPROTO_UDPLITE:
171 case IPPROTO_SCTP:
172 case IPPROTO_DCCP:
173 return snprintf(buf, len, "sport=%u dport=%u ",
174 ntohs(tuple->l4src.tcp.port),
175 ntohs(tuple->l4dst.tcp.port));
176 break;
177 case IPPROTO_GRE:
178 return snprintf(buf, len, "srckey=0x%x dstkey=0x%x ",
179 ntohs(tuple->l4src.all),
180 ntohs(tuple->l4dst.all));
181 break;
182 case IPPROTO_ICMP:
183 case IPPROTO_ICMPV6:
184 /* The ID only makes sense some ICMP messages but we want to
185 * display the same output that /proc/net/ip_conntrack does */
186 return (snprintf(buf, len, "type=%d code=%d id=%d ",
187 tuple->l4dst.icmp.type,
188 tuple->l4dst.icmp.code,
189 ntohs(tuple->l4src.icmp.id)));
190 break;
191 }
192
193 return size;
194}
195
196static int
197__snprintf_tuple_zone(char *buf, unsigned int len, const char *pfx,
198 const struct __nfct_tuple *tuple)
199{
200 return (snprintf(buf, len, "zone-%s=%u ", pfx, tuple->zone));
201}
202
203static int __snprintf_status_assured(char *buf,
204 unsigned int len,
205 const struct nf_conntrack *ct)
206{
207 int size = 0;
208
209 if (ct->status & IPS_HW_OFFLOAD)
210 size = snprintf(buf, len, "[HW_OFFLOAD] ");
211 else if (ct->status & IPS_OFFLOAD)
212 size = snprintf(buf, len, "[OFFLOAD] ");
213 else if (ct->status & IPS_ASSURED)
214 size = snprintf(buf, len, "[ASSURED] ");
215
216 return size;
217}
218
219static int __snprintf_status_not_seen_reply(char *buf,
220 unsigned int len,
221 const struct nf_conntrack *ct)
222{
223 int size = 0;
224
225 if (!(ct->status & IPS_SEEN_REPLY))
226 size = snprintf(buf, len, "[UNREPLIED] ");
227
228 return size;
229}
230
231static int __snprintf_counters(char *buf,
232 unsigned int len,
233 const struct nf_conntrack *ct,
234 int dir)
235{
236 return (snprintf(buf, len, "packets=%llu bytes=%llu ",
237 (unsigned long long) ct->counters[dir].packets,
238 (unsigned long long) ct->counters[dir].bytes));
239}
240
241static int
242__snprintf_mark(char *buf, unsigned int len, const struct nf_conntrack *ct)
243{
244 return (snprintf(buf, len, "mark=%u ", ct->mark));
245}
246
247static int
248__snprintf_secmark(char *buf, unsigned int len, const struct nf_conntrack *ct)
249{
250 return (snprintf(buf, len, "secmark=%u ", ct->secmark));
251}
252
253static int
254__snprintf_use(char *buf, unsigned int len, const struct nf_conntrack *ct)
255{
256 return (snprintf(buf, len, "use=%u ", ct->use));
257}
258
259static int
260__snprintf_id(char *buf, unsigned int len, const struct nf_conntrack *ct)
261{
262 return (snprintf(buf, len, "id=%u ", ct->id));
263}
264
265static int
266__snprintf_zone(char *buf, unsigned int len, const struct nf_conntrack *ct)
267{
268 return (snprintf(buf, len, "zone=%u ", ct->zone));
269}
270
271static int
272__snprintf_secctx(char *buf, unsigned int len, const struct nf_conntrack *ct)
273{
274 return (snprintf(buf, len, "secctx=%s ", ct->secctx));
275}
276
277static int
278__snprintf_timestamp_start(char *buf, unsigned int len,
279 const struct nf_conntrack *ct)
280{
281 time_t start = (time_t)(ct->timestamp.start / NSEC_PER_SEC);
282 char *tmp = ctime(&start);
283
284 /* overwrite \n in the ctime() output. */
285 tmp[strlen(tmp)-1] = '\0';
286 return (snprintf(buf, len, "[start=%s] ", tmp));
287}
288
289static int
290__snprintf_timestamp_stop(char *buf, unsigned int len,
291 const struct nf_conntrack *ct)
292{
293 time_t stop = (time_t)(ct->timestamp.stop / NSEC_PER_SEC);
294 char *tmp = ctime(&stop);
295
296 /* overwrite \n in the ctime() output. */
297 tmp[strlen(tmp)-1] = '\0';
298 return (snprintf(buf, len, "[stop=%s] ", tmp));
299}
300
301static int
302__snprintf_timestamp_delta(char *buf, unsigned int len,
303 const struct nf_conntrack *ct)
304{
305 time_t delta_time, stop;
306
307 if (ct->timestamp.stop == 0)
308 time(&stop);
309 else
310 stop = (time_t)(ct->timestamp.stop / NSEC_PER_SEC);
311
312 delta_time = stop - (time_t)(ct->timestamp.start / NSEC_PER_SEC);
313
314 return (snprintf(buf, len, "delta-time=%llu ",
315 (unsigned long long)delta_time));
316}
317
318static int
319__snprintf_helper_name(char *buf, unsigned int len, const struct nf_conntrack *ct)
320{
321 return (snprintf(buf, len, "helper=%s ", ct->helper_name));
322}
323
324int
325__snprintf_connlabels(char *buf, unsigned int len,
326 struct nfct_labelmap *map,
327 const struct nfct_bitmask *b, const char *fmt)
328{
329 unsigned int i, max;
330 int ret, size = 0, offset = 0;
331
332 max = nfct_bitmask_maxbit(b);
333 for (i = 0; i <= max && len; i++) {
334 const char *name;
335 if (!nfct_bitmask_test_bit(b, i))
336 continue;
337 name = nfct_labelmap_get_name(map, i);
338 if (!name || strcmp(name, "") == 0)
339 continue;
340
341 ret = snprintf(buf + offset, len, fmt, name);
342 BUFFER_SIZE(ret, size, len, offset);
343 }
344 return size;
345}
346
347static int
348__snprintf_clabels(char *buf, unsigned int len,
349 const struct nf_conntrack *ct, struct nfct_labelmap *map)
350{
351 const struct nfct_bitmask *b = nfct_get_attr(ct, ATTR_CONNLABELS);
352 int ret, size = 0, offset = 0;
353
354 if (!b)
355 return 0;
356
357 ret = snprintf(buf, len, "labels=");
358 BUFFER_SIZE(ret, size, len, offset);
359
360 ret = __snprintf_connlabels(buf + offset, len, map, b, "%s,");
361
362 BUFFER_SIZE(ret, size, len, offset);
363
364 offset--; /* remove last , */
365 size--;
366 ret = snprintf(buf + offset, len, " ");
367 BUFFER_SIZE(ret, size, len, offset);
368
369 return size;
370}
371
372int __snprintf_conntrack_default(char *buf,
373 unsigned int len,
374 const struct nf_conntrack *ct,
375 unsigned int msg_type,
376 unsigned int flags,
377 struct nfct_labelmap *map)
378{
379 int ret = 0, size = 0, offset = 0;
380
381 switch(msg_type) {
382 case NFCT_T_NEW:
383 ret = snprintf(buf, len, "%9s ", "[NEW]");
384 break;
385 case NFCT_T_UPDATE:
386 ret = snprintf(buf, len, "%9s ", "[UPDATE]");
387 break;
388 case NFCT_T_DESTROY:
389 ret = snprintf(buf, len, "%9s ", "[DESTROY]");
390 break;
391 default:
392 break;
393 }
394
395 BUFFER_SIZE(ret, size, len, offset);
396
397 if (flags & NFCT_OF_SHOW_LAYER3) {
398 ret = __snprintf_l3protocol(buf+offset, len, ct);
399 BUFFER_SIZE(ret, size, len, offset);
400 }
401
402 ret = __snprintf_protocol(buf+offset, len, ct);
403 BUFFER_SIZE(ret, size, len, offset);
404
405 if (test_bit(ATTR_TIMEOUT, ct->head.set)) {
406 ret = __snprintf_timeout(buf+offset, len, ct);
407 BUFFER_SIZE(ret, size, len, offset);
408 }
409
410 if (test_bit(ATTR_TCP_STATE, ct->head.set)) {
411 ret = __snprintf_protoinfo(buf+offset, len, ct);
412 BUFFER_SIZE(ret, size, len, offset);
413 }
414
415 if (test_bit(ATTR_SCTP_STATE, ct->head.set)) {
416 ret = __snprintf_protoinfo_sctp(buf+offset, len, ct);
417 BUFFER_SIZE(ret, size, len, offset);
418 }
419
420 if (test_bit(ATTR_DCCP_STATE, ct->head.set)) {
421 ret = __snprintf_protoinfo_dccp(buf+offset, len, ct);
422 BUFFER_SIZE(ret, size, len, offset);
423 }
424
425 ret = __snprintf_address(buf+offset, len, &ct->head.orig,
426 "src", "dst");
427 BUFFER_SIZE(ret, size, len, offset);
428
429 ret = __snprintf_proto(buf+offset, len, &ct->head.orig);
430 BUFFER_SIZE(ret, size, len, offset);
431
432 if (test_bit(ATTR_ORIG_ZONE, ct->head.set)) {
433 ret = __snprintf_tuple_zone(buf+offset, len, "orig", &ct->head.orig);
434 BUFFER_SIZE(ret, size, len, offset);
435 }
436
437 if (test_bit(ATTR_ORIG_COUNTER_PACKETS, ct->head.set) &&
438 test_bit(ATTR_ORIG_COUNTER_BYTES, ct->head.set)) {
439 ret = __snprintf_counters(buf+offset, len, ct, __DIR_ORIG);
440 BUFFER_SIZE(ret, size, len, offset);
441 }
442
443 if (test_bit(ATTR_STATUS, ct->head.set)) {
444 ret = __snprintf_status_not_seen_reply(buf+offset, len, ct);
445 BUFFER_SIZE(ret, size, len, offset);
446 }
447
448 ret = __snprintf_address(buf+offset, len, &ct->repl,
449 "src", "dst");
450 BUFFER_SIZE(ret, size, len, offset);
451
452 ret = __snprintf_proto(buf+offset, len, &ct->repl);
453 BUFFER_SIZE(ret, size, len, offset);
454
455 if (test_bit(ATTR_REPL_ZONE, ct->head.set)) {
456 ret = __snprintf_tuple_zone(buf+offset, len, "reply", &ct->repl);
457 BUFFER_SIZE(ret, size, len, offset);
458 }
459
460 if (test_bit(ATTR_REPL_COUNTER_PACKETS, ct->head.set) &&
461 test_bit(ATTR_REPL_COUNTER_BYTES, ct->head.set)) {
462 ret = __snprintf_counters(buf+offset, len, ct, __DIR_REPL);
463 BUFFER_SIZE(ret, size, len, offset);
464 }
465
466 if (test_bit(ATTR_STATUS, ct->head.set)) {
467 ret = __snprintf_status_assured(buf+offset, len, ct);
468 BUFFER_SIZE(ret, size, len, offset);
469 }
470
471 if (test_bit(ATTR_MARK, ct->head.set)) {
472 ret = __snprintf_mark(buf+offset, len, ct);
473 BUFFER_SIZE(ret, size, len, offset);
474 }
475
476 if (test_bit(ATTR_SECMARK, ct->head.set)) {
477 ret = __snprintf_secmark(buf+offset, len, ct);
478 BUFFER_SIZE(ret, size, len, offset);
479 }
480
481 if (test_bit(ATTR_SECCTX, ct->head.set)) {
482 ret = __snprintf_secctx(buf+offset, len, ct);
483 BUFFER_SIZE(ret, size, len, offset);
484 }
485
486 if (test_bit(ATTR_ZONE, ct->head.set)) {
487 ret = __snprintf_zone(buf+offset, len, ct);
488 BUFFER_SIZE(ret, size, len, offset);
489 }
490
491 if (test_bit(ATTR_TIMESTAMP_START, ct->head.set)) {
492 ret = __snprintf_timestamp_delta(buf+offset, len, ct);
493 BUFFER_SIZE(ret, size, len, offset);
494 }
495 if (flags & NFCT_OF_TIMESTAMP) {
496 if (test_bit(ATTR_TIMESTAMP_START, ct->head.set)) {
497 ret = __snprintf_timestamp_start(buf+offset, len, ct);
498 BUFFER_SIZE(ret, size, len, offset);
499 }
500 if (test_bit(ATTR_TIMESTAMP_STOP, ct->head.set)) {
501 ret = __snprintf_timestamp_stop(buf+offset, len, ct);
502 BUFFER_SIZE(ret, size, len, offset);
503 }
504 }
505
506 if (test_bit(ATTR_HELPER_NAME, ct->head.set)) {
507 ret = __snprintf_helper_name(buf+offset, len, ct);
508 BUFFER_SIZE(ret, size, len, offset);
509 }
510
511 if (test_bit(ATTR_USE, ct->head.set)) {
512 ret = __snprintf_use(buf+offset, len, ct);
513 BUFFER_SIZE(ret, size, len, offset);
514 }
515
516 if (flags & NFCT_OF_ID && test_bit(ATTR_ID, ct->head.set)) {
517 ret = __snprintf_id(buf+offset, len, ct);
518 BUFFER_SIZE(ret, size, len, offset);
519 }
520
521 if (map && test_bit(ATTR_CONNLABELS, ct->head.set)) {
522 ret = __snprintf_clabels(buf+offset, len, ct, map);
523 BUFFER_SIZE(ret, size, len, offset);
524 }
525
526 /* Delete the last blank space */
527 size--;
528
529 return size;
530}
const void * nfct_get_attr(const struct nf_conntrack *ct, const enum nf_conntrack_attr type)
const char * nfct_labelmap_get_name(struct nfct_labelmap *m, unsigned int bit)