libnetfilter_conntrack  1.0.9
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  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 
69 const 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 
82 static 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 
94 static 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 
111 int __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 
139 int __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 
178 static 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 
197 static 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 
211 static 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 
225 static 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 
243 static 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 
258 static 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 
270 int
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 
300 static 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 
372 static 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 
395 int __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  }
595 err_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)