libnetfilter_conntrack 1.1.0
conntrack/snprintf_xml.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
12/*
13 * XML output sample:
14 *
15 * <flow>
16 * <meta direction="original">
17 * <layer3 protonum="2" protoname="IPv4">
18 * <src>192.168.0.1</src>
19 * <dst>192.168.0.2</dst>
20 * </layer3>
21 * <layer4 protonum="16" protoname"udp">
22 * <sport>80</sport>
23 * <dport>56665</dport>
24 * </layer4>
25 * <counters>
26 * <bytes>10</bytes>
27 * <packets>1</packets>
28 * </counters>
29 * </meta>
30 * <meta direction="reply">
31 * <layer3 protonum="2" protoname="IPv4">
32 * <src>192.168.0.2</src>
33 * <dst>192.168.0.1</dst>
34 * </layer3>
35 * <layer4 protonum="16" protoname="udp">
36 * <sport>80</sport>
37 * <dport>56665</dport>
38 * </layer4>
39 * <counters>
40 * <bytes>5029</bytes>
41 * <packets>12</packets>
42 * </counters>
43 * </meta>
44 * <meta direction="independent">
45 * <state>ESTABLISHED</state>
46 * <timeout>100</timeout>
47 * <mark>1</mark>
48 * <secmark>0</secmark>
49 * <id>453281439</id>
50 * <use>1</use>
51 * <assured/>
52 * </meta>
53 * </flow>
54 */
55
56const char *__proto2str(uint8_t protonum)
57{
58 const char *str = NULL;
59
60 if (protonum < ARRAY_SIZE(proto2str))
61 str = proto2str[protonum];
62
63 if (str == NULL)
64 str = "unknown";
65
66 return str;
67}
68
69const char *__l3proto2str(uint8_t protonum)
70{
71 const char *str = NULL;
72
73 if (protonum < ARRAY_SIZE(l3proto2str))
74 str = l3proto2str[protonum];
75
76 if (str == NULL)
77 str = "unknown";
78
79 return str;
80}
81
82static int __snprintf_ipv4_xml(char *buf,
83 unsigned int len,
84 const struct __nfct_tuple *tuple,
85 unsigned int type)
86{
87 struct in_addr addr = {
88 .s_addr = (type == __ADDR_SRC) ? tuple->src.v4 : tuple->dst.v4,
89 };
90
91 return snprintf(buf, len, "%s", inet_ntoa(addr));
92}
93
94static int __snprintf_ipv6_xml(char *buf,
95 unsigned int len,
96 const struct __nfct_tuple *tuple,
97 unsigned int type)
98{
99 struct in6_addr addr;
100 static char tmp[INET6_ADDRSTRLEN];
101 const void *p = (type == __ADDR_SRC) ? &tuple->src.v6 : &tuple->dst.v6;
102
103 memcpy(&addr, p, sizeof(struct in6_addr));
104
105 if (!inet_ntop(AF_INET6, &addr, tmp, sizeof(tmp)))
106 return -1;
107
108 return snprintf(buf, len, "%s", tmp);
109}
110
111int __snprintf_addr_xml(char *buf, unsigned int len,
112 const struct __nfct_tuple *tuple,
113 enum __nfct_addr type)
114{
115 int ret;
116 unsigned int size = 0, offset = 0;
117 const char *tag = (type == __ADDR_SRC) ? "src" : "dst";
118
119 ret = snprintf(buf, len, "<%s>", tag);
120 BUFFER_SIZE(ret, size, len, offset);
121
122 switch (tuple->l3protonum) {
123 case AF_INET:
124 ret = __snprintf_ipv4_xml(buf+offset, len, tuple, type);
125 BUFFER_SIZE(ret, size, len, offset);
126 break;
127 case AF_INET6:
128 ret = __snprintf_ipv6_xml(buf+offset, len, tuple, type);
129 BUFFER_SIZE(ret, size, len, offset);
130 break;
131 }
132
133 ret = snprintf(buf+offset, len, "</%s>", tag);
134 BUFFER_SIZE(ret, size, len, offset);
135
136 return size;
137}
138
139int __snprintf_proto_xml(char *buf, unsigned int len,
140 const struct __nfct_tuple *tuple,
141 enum __nfct_addr type)
142{
143 int ret = 0;
144 unsigned int size = 0, offset = 0;
145
146 switch(tuple->protonum) {
147 case IPPROTO_TCP:
148 case IPPROTO_UDP:
149 case IPPROTO_UDPLITE:
150 case IPPROTO_SCTP:
151 case IPPROTO_DCCP:
152 if (type == __ADDR_SRC) {
153 ret = snprintf(buf, len, "<sport>%u</sport>",
154 ntohs(tuple->l4src.tcp.port));
155 BUFFER_SIZE(ret, size, len, offset);
156 } else {
157 ret = snprintf(buf, len, "<dport>%u</dport>",
158 ntohs(tuple->l4dst.tcp.port));
159 BUFFER_SIZE(ret, size, len, offset);
160 }
161 break;
162 case IPPROTO_GRE:
163 if (type == __ADDR_SRC) {
164 ret = snprintf(buf, len, "<srckey>0x%x</srckey>",
165 ntohs(tuple->l4src.all));
166 BUFFER_SIZE(ret, size, len, offset);
167 } else {
168 ret = snprintf(buf, len, "<dstkey>0x%x</dstkey>",
169 ntohs(tuple->l4dst.all));
170 BUFFER_SIZE(ret, size, len, offset);
171 }
172 break;
173 }
174
175 return ret;
176}
177
178static int __snprintf_counters_xml(char *buf,
179 unsigned int len,
180 const struct nf_conntrack *ct,
181 unsigned int type)
182{
183 int ret;
184 unsigned int size = 0, offset = 0;
185
186 ret = snprintf(buf, len, "<packets>%llu</packets>",
187 (unsigned long long)ct->counters[type].packets);
188 BUFFER_SIZE(ret, size, len, offset);
189
190 ret = snprintf(buf+offset, len, "<bytes>%llu</bytes>",
191 (unsigned long long)ct->counters[type].bytes);
192 BUFFER_SIZE(ret, size, len, offset);
193
194 return size;
195}
196
197static int
198__snprintf_timestamp_start(char *buf, unsigned int len,
199 const struct nf_conntrack *ct)
200{
201 int ret;
202 unsigned int size = 0, offset = 0;
203
204 ret = snprintf(buf, len, "<start>%llu</start>",
205 (unsigned long long)ct->timestamp.start);
206 BUFFER_SIZE(ret, size, len, offset);
207
208 return size;
209}
210
211static int
212__snprintf_timestamp_stop(char *buf, unsigned int len,
213 const struct nf_conntrack *ct)
214{
215 int ret;
216 unsigned int size = 0, offset = 0;
217
218 ret = snprintf(buf, len, "<stop>%llu</stop>",
219 (unsigned long long)ct->timestamp.stop);
220 BUFFER_SIZE(ret, size, len, offset);
221
222 return size;
223}
224
225static int
226__snprintf_deltatime_now(char *buf, unsigned int len,
227 const struct nf_conntrack *ct)
228{
229 int ret;
230 unsigned int size = 0, offset = 0;
231 time_t now, delta_time;
232
233 time(&now);
234 delta_time = now - (time_t)(ct->timestamp.start / NSEC_PER_SEC);
235
236 ret = snprintf(buf+offset, len, "<deltatime>%llu</deltatime>",
237 (unsigned long long)delta_time);
238 BUFFER_SIZE(ret, size, len, offset);
239
240 return size;
241}
242
243static int
244__snprintf_deltatime(char *buf, unsigned int len, const struct nf_conntrack *ct)
245{
246 int ret;
247 unsigned int size = 0, offset = 0;
248 time_t delta_time = (time_t)((ct->timestamp.stop -
249 ct->timestamp.start) / NSEC_PER_SEC);
250
251 ret = snprintf(buf+offset, len, "<deltatime>%llu</deltatime>",
252 (unsigned long long)delta_time);
253 BUFFER_SIZE(ret, size, len, offset);
254
255 return size;
256}
257
258static int
259__snprintf_helper_name(char *buf, unsigned int len, const struct nf_conntrack *ct)
260{
261 int ret;
262 unsigned int size = 0, offset = 0;
263
264 ret = snprintf(buf+offset, len, "<helper>%s</helper>", ct->helper_name);
265 BUFFER_SIZE(ret, size, len, offset);
266
267 return size;
268}
269
270int
271__snprintf_localtime_xml(char *buf, unsigned int len, const struct tm *tm)
272{
273 int ret = 0;
274 unsigned int size = 0, offset = 0;
275
276 ret = snprintf(buf+offset, len, "<hour>%d</hour>", tm->tm_hour);
277 BUFFER_SIZE(ret, size, len, offset);
278
279 ret = snprintf(buf+offset, len, "<min>%02d</min>", tm->tm_min);
280 BUFFER_SIZE(ret, size, len, offset);
281
282 ret = snprintf(buf+offset, len, "<sec>%02d</sec>", tm->tm_sec);
283 BUFFER_SIZE(ret, size, len, offset);
284
285 ret = snprintf(buf+offset, len, "<wday>%d</wday>", tm->tm_wday + 1);
286 BUFFER_SIZE(ret, size, len, offset);
287
288 ret = snprintf(buf+offset, len, "<day>%d</day>", tm->tm_mday);
289 BUFFER_SIZE(ret, size, len, offset);
290
291 ret = snprintf(buf+offset, len, "<month>%d</month>", tm->tm_mon + 1);
292 BUFFER_SIZE(ret, size, len, offset);
293
294 ret = snprintf(buf+offset, len, "<year>%d</year>", 1900 + tm->tm_year);
295 BUFFER_SIZE(ret, size, len, offset);
296
297 return size;
298}
299
300static int __snprintf_tuple_xml(char *buf,
301 unsigned int len,
302 const struct nf_conntrack *ct,
303 unsigned int dir, bool zone_incl)
304{
305 int ret;
306 unsigned int size = 0, offset = 0;
307 const struct __nfct_tuple *tuple = NULL;
308
309 switch(dir) {
310 case __DIR_ORIG:
311 tuple = &ct->head.orig;
312 break;
313 case __DIR_REPL:
314 tuple = &ct->repl;
315 break;
316 }
317 ret = snprintf(buf, len, "<meta direction=\"%s\">",
318 dir == __DIR_ORIG ? "original" : "reply");
319 BUFFER_SIZE(ret, size, len, offset);
320
321 ret = snprintf(buf+offset, len,
322 "<layer3 protonum=\"%d\" protoname=\"%s\">",
323 tuple->l3protonum, __l3proto2str(tuple->l3protonum));
324 BUFFER_SIZE(ret, size, len, offset);
325
326 ret = __snprintf_addr_xml(buf+offset, len, tuple, __ADDR_SRC);
327 BUFFER_SIZE(ret, size, len, offset);
328
329 ret = __snprintf_addr_xml(buf+offset, len, tuple, __ADDR_DST);
330 BUFFER_SIZE(ret, size, len, offset);
331
332 ret = snprintf(buf+offset, len, "</layer3>");
333 BUFFER_SIZE(ret, size, len, offset);
334
335 ret = snprintf(buf+offset, len,
336 "<layer4 protonum=\"%d\" protoname=\"%s\">",
337 tuple->protonum, __proto2str(tuple->protonum));
338 BUFFER_SIZE(ret, size, len, offset);
339
340 ret = __snprintf_proto_xml(buf+offset, len, tuple, __DIR_ORIG);
341 BUFFER_SIZE(ret, size, len, offset);
342
343 ret = __snprintf_proto_xml(buf+offset, len, tuple, __DIR_REPL);
344 BUFFER_SIZE(ret, size, len, offset);
345
346 ret = snprintf(buf+offset, len, "</layer4>");
347 BUFFER_SIZE(ret, size, len, offset);
348
349 if (zone_incl) {
350 ret = snprintf(buf+offset, len, "<zone>%u</zone>", tuple->zone);
351 BUFFER_SIZE(ret, size, len, offset);
352 }
353
354 if (test_bit(ATTR_ORIG_COUNTER_PACKETS, ct->head.set) &&
355 test_bit(ATTR_ORIG_COUNTER_BYTES, ct->head.set)) {
356 ret = snprintf(buf+offset, len, "<counters>");
357 BUFFER_SIZE(ret, size, len, offset);
358
359 ret = __snprintf_counters_xml(buf+offset, len, ct, dir);
360 BUFFER_SIZE(ret, size, len, offset);
361
362 ret = snprintf(buf+offset, len, "</counters>");
363 BUFFER_SIZE(ret, size, len, offset);
364 }
365
366 ret = snprintf(buf+offset, len, "</meta>");
367 BUFFER_SIZE(ret, size, len, offset);
368
369 return size;
370}
371
372static int
373__snprintf_clabels_xml(char *buf, unsigned int len,
374 const struct nf_conntrack *ct, struct nfct_labelmap *map)
375{
376 const struct nfct_bitmask *b = nfct_get_attr(ct, ATTR_CONNLABELS);
377 int ret, size = 0, offset = 0;
378
379 if (!b)
380 return 0;
381
382 ret = snprintf(buf, len, "<labels>");
383 BUFFER_SIZE(ret, size, len, offset);
384
385 ret = __snprintf_connlabels(buf + offset, len, map, b, "<label>%s</label>");
386
387 BUFFER_SIZE(ret, size, len, offset);
388
389 ret = snprintf(buf + offset, len, "</labels>");
390 BUFFER_SIZE(ret, size, len, offset);
391
392 return size;
393}
394
395int __snprintf_conntrack_xml(char *buf,
396 unsigned int len,
397 const struct nf_conntrack *ct,
398 const unsigned int msg_type,
399 const unsigned int flags,
400 struct nfct_labelmap *map)
401{
402 int ret = 0;
403 unsigned int size = 0, offset = 0;
404
405 switch(msg_type) {
406 case NFCT_T_NEW:
407 ret = snprintf(buf, len, "<flow type=\"new\">");
408 break;
409 case NFCT_T_UPDATE:
410 ret = snprintf(buf, len, "<flow type=\"update\">");
411 break;
412 case NFCT_T_DESTROY:
413 ret = snprintf(buf, len, "<flow type=\"destroy\">");
414 break;
415 default:
416 ret = snprintf(buf, len, "<flow>");
417 break;
418 }
419
420 BUFFER_SIZE(ret, size, len, offset);
421
422 ret = __snprintf_tuple_xml(buf+offset, len, ct, __DIR_ORIG,
423 test_bit(ATTR_ORIG_ZONE, ct->head.set));
424 BUFFER_SIZE(ret, size, len, offset);
425
426 ret = __snprintf_tuple_xml(buf+offset, len, ct, __DIR_REPL,
427 test_bit(ATTR_REPL_ZONE, ct->head.set));
428 BUFFER_SIZE(ret, size, len, offset);
429
430 if (test_bit(ATTR_TCP_STATE, ct->head.set) ||
431 test_bit(ATTR_SCTP_STATE, ct->head.set) ||
432 test_bit(ATTR_DCCP_STATE, ct->head.set) ||
433 test_bit(ATTR_TIMEOUT, ct->head.set) ||
434 test_bit(ATTR_MARK, ct->head.set) ||
435 test_bit(ATTR_SECMARK, ct->head.set) ||
436 test_bit(ATTR_ZONE, ct->head.set) ||
437 test_bit(ATTR_USE, ct->head.set) ||
438 test_bit(ATTR_STATUS, ct->head.set) ||
439 test_bit(ATTR_ID, ct->head.set) ||
440 test_bit(ATTR_CONNLABELS, ct->head.set) ||
441 test_bit(ATTR_TIMESTAMP_START, ct->head.set) ||
442 test_bit(ATTR_TIMESTAMP_STOP, ct->head.set)) {
443 ret = snprintf(buf+offset, len,
444 "<meta direction=\"independent\">");
445 BUFFER_SIZE(ret, size, len, offset);
446 }
447
448 if (test_bit(ATTR_TCP_STATE, ct->head.set)) {
449 ret = snprintf(buf+offset, len, "<state>%s</state>",
450 ct->protoinfo.tcp.state < TCP_CONNTRACK_MAX ?
451 states[ct->protoinfo.tcp.state] :
452 states[TCP_CONNTRACK_NONE]);
453 BUFFER_SIZE(ret, size, len, offset);
454 }
455
456 if (test_bit(ATTR_SCTP_STATE, ct->head.set)) {
457 ret = snprintf(buf+offset, len, "<state>%s</state>",
458 ct->protoinfo.sctp.state < SCTP_CONNTRACK_MAX ?
459 states[ct->protoinfo.sctp.state] :
460 states[SCTP_CONNTRACK_NONE]);
461 BUFFER_SIZE(ret, size, len, offset);
462 }
463
464 if (test_bit(ATTR_DCCP_STATE, ct->head.set)) {
465 ret = snprintf(buf+offset, len, "<state>%s</state>",
466 ct->protoinfo.sctp.state < DCCP_CONNTRACK_MAX ?
467 states[ct->protoinfo.dccp.state] :
468 states[DCCP_CONNTRACK_NONE]);
469 BUFFER_SIZE(ret, size, len, offset);
470 }
471
472 if (test_bit(ATTR_TIMEOUT, ct->head.set)) {
473 ret = snprintf(buf+offset, len,
474 "<timeout>%u</timeout>", ct->timeout);
475 BUFFER_SIZE(ret, size, len, offset);
476 }
477
478 if (test_bit(ATTR_MARK, ct->head.set)) {
479 ret = snprintf(buf+offset, len, "<mark>%u</mark>", ct->mark);
480 BUFFER_SIZE(ret, size, len, offset);
481 }
482
483 if (map && test_bit(ATTR_CONNLABELS, ct->head.set)) {
484 ret = __snprintf_clabels_xml(buf+offset, len, ct, map);
485 BUFFER_SIZE(ret, size, len, offset);
486 }
487
488 if (test_bit(ATTR_SECMARK, ct->head.set)) {
489 ret = snprintf(buf+offset, len,
490 "<secmark>%u</secmark>", ct->secmark);
491 BUFFER_SIZE(ret, size, len, offset);
492 }
493
494 if (test_bit(ATTR_SECCTX, ct->head.set)) {
495 ret = snprintf(buf+offset, len,
496 "<secctx>%s</secctx>", ct->secctx);
497 BUFFER_SIZE(ret, size, len, offset);
498 }
499
500 if (test_bit(ATTR_ZONE, ct->head.set)) {
501 ret = snprintf(buf+offset, len, "<zone>%u</zone>", ct->zone);
502 BUFFER_SIZE(ret, size, len, offset);
503 }
504
505 if (test_bit(ATTR_USE, ct->head.set)) {
506 ret = snprintf(buf+offset, len, "<use>%u</use>", ct->use);
507 BUFFER_SIZE(ret, size, len, offset);
508 }
509
510 if (test_bit(ATTR_ID, ct->head.set)) {
511 ret = snprintf(buf+offset, len, "<id>%u</id>", ct->id);
512 BUFFER_SIZE(ret, size, len, offset);
513 }
514
515 if (test_bit(ATTR_STATUS, ct->head.set)
516 && ct->status & IPS_ASSURED) {
517 ret = snprintf(buf+offset, len, "<assured/>");
518 BUFFER_SIZE(ret, size, len, offset);
519 }
520
521 if (test_bit(ATTR_STATUS, ct->head.set)
522 && !(ct->status & IPS_SEEN_REPLY)) {
523 ret = snprintf(buf+offset, len, "<unreplied/>");
524 BUFFER_SIZE(ret, size, len, offset);
525 }
526
527 if (flags & NFCT_OF_TIMESTAMP) {
528 if (test_bit(ATTR_TIMESTAMP_START, ct->head.set) ||
529 test_bit(ATTR_TIMESTAMP_STOP, ct->head.set)) {
530 ret = snprintf(buf+offset, len, "<timestamp>");
531 BUFFER_SIZE(ret, size, len, offset);
532 }
533 if (test_bit(ATTR_TIMESTAMP_START, ct->head.set)) {
534 ret = __snprintf_timestamp_start(buf+offset, len, ct);
535 BUFFER_SIZE(ret, size, len, offset);
536 }
537 if (test_bit(ATTR_TIMESTAMP_STOP, ct->head.set)) {
538 ret = __snprintf_timestamp_stop(buf+offset, len, ct);
539 BUFFER_SIZE(ret, size, len, offset);
540 }
541 if (test_bit(ATTR_TIMESTAMP_START, ct->head.set) ||
542 test_bit(ATTR_TIMESTAMP_STOP, ct->head.set)) {
543 ret = snprintf(buf+offset, len, "</timestamp>");
544 BUFFER_SIZE(ret, size, len, offset);
545 }
546 }
547 if (test_bit(ATTR_TIMESTAMP_START, ct->head.set) &&
548 test_bit(ATTR_TIMESTAMP_STOP, ct->head.set)) {
549 ret = __snprintf_deltatime(buf+offset, len, ct);
550 BUFFER_SIZE(ret, size, len, offset);
551 } else if (test_bit(ATTR_TIMESTAMP_START, ct->head.set)) {
552 ret = __snprintf_deltatime_now(buf+offset, len, ct);
553 BUFFER_SIZE(ret, size, len, offset);
554 }
555
556 if (test_bit(ATTR_TCP_STATE, ct->head.set) ||
557 test_bit(ATTR_SCTP_STATE, ct->head.set) ||
558 test_bit(ATTR_DCCP_STATE, ct->head.set) ||
559 test_bit(ATTR_TIMEOUT, ct->head.set) ||
560 test_bit(ATTR_MARK, ct->head.set) ||
561 test_bit(ATTR_SECMARK, ct->head.set) ||
562 test_bit(ATTR_ZONE, ct->head.set) ||
563 test_bit(ATTR_USE, ct->head.set) ||
564 test_bit(ATTR_STATUS, ct->head.set) ||
565 test_bit(ATTR_ID, ct->head.set) ||
566 test_bit(ATTR_CONNLABELS, ct->head.set) ||
567 test_bit(ATTR_TIMESTAMP_START, ct->head.set) ||
568 test_bit(ATTR_TIMESTAMP_STOP, ct->head.set)) {
569 ret = snprintf(buf+offset, len, "</meta>");
570 BUFFER_SIZE(ret, size, len, offset);
571 }
572
573 if (flags & NFCT_OF_TIME) {
574 time_t t;
575 struct tm tm;
576
577 t = time(NULL);
578 if (localtime_r(&t, &tm) == NULL)
579 goto err_out;
580
581 ret = snprintf(buf+offset, len, "<when>");
582 BUFFER_SIZE(ret, size, len, offset);
583
584 ret = __snprintf_localtime_xml(buf+offset, len, &tm);
585 BUFFER_SIZE(ret, size, len, offset);
586
587 ret = snprintf(buf+offset, len, "</when>");
588 BUFFER_SIZE(ret, size, len, offset);
589 }
590
591 if (test_bit(ATTR_HELPER_NAME, ct->head.set)) {
592 ret = __snprintf_helper_name(buf+offset, len, ct);
593 BUFFER_SIZE(ret, size, len, offset);
594 }
595err_out:
596 ret = snprintf(buf+offset, len, "</flow>");
597 BUFFER_SIZE(ret, size, len, offset);
598
599 return size;
600}
const void * nfct_get_attr(const struct nf_conntrack *ct, const enum nf_conntrack_attr type)