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