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
56const char *__proto2str(uint8_t protonum)
57{
58	return proto2str[protonum] ? proto2str[protonum] : "unknown";
59}
60
61const char *__l3proto2str(uint8_t protonum)
62{
63	return l3proto2str[protonum] ? l3proto2str[protonum] : "unknown";
64}
65
66static 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
78static 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
95int __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
123int __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
162static 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
181static 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
195static 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
209static 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
227static 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
242static 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
254int
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
284static 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
356static 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
379int __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	}
579err_out:
580	ret = snprintf(buf+offset, len, "</flow>");
581	BUFFER_SIZE(ret, size, len, offset);
582
583	return size;
584}
585