libnetfilter_conntrack  1.0.9
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 
12 static 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 
24 int __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 
36 static 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 
43 static 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 
59 static 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 
75 static 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 
91 static 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 
110 static 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 
139 int __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 
161 int __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 
196 static 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 
203 static 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 
219 static 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 
231 static 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 
241 static 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 
247 static 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 
253 static 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 
259 static 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 
265 static 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 
271 static 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 
277 static 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 
289 static 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 
301 static 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 
318 static 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 
324 int
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 
347 static 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 
372 int __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)