• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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