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