1 #include <stdio.h>
2 #include <string.h>
3 #include <xtables.h>
4 #include <linux/netfilter/xt_connbytes.h>
5 
6 enum {
7 	O_CONNBYTES = 0,
8 	O_CONNBYTES_DIR,
9 	O_CONNBYTES_MODE,
10 };
11 
connbytes_help(void)12 static void connbytes_help(void)
13 {
14 	printf(
15 "connbytes match options:\n"
16 " [!] --connbytes from:[to]\n"
17 "     --connbytes-dir [original, reply, both]\n"
18 "     --connbytes-mode [packets, bytes, avgpkt]\n");
19 }
20 
21 static const struct xt_option_entry connbytes_opts[] = {
22 	{.name = "connbytes", .id = O_CONNBYTES, .type = XTTYPE_UINT64RC,
23 	 .flags = XTOPT_MAND | XTOPT_INVERT},
24 	{.name = "connbytes-dir", .id = O_CONNBYTES_DIR, .type = XTTYPE_STRING,
25 	 .flags = XTOPT_MAND},
26 	{.name = "connbytes-mode", .id = O_CONNBYTES_MODE,
27 	 .type = XTTYPE_STRING, .flags = XTOPT_MAND},
28 	XTOPT_TABLEEND,
29 };
30 
connbytes_parse(struct xt_option_call * cb)31 static void connbytes_parse(struct xt_option_call *cb)
32 {
33 	struct xt_connbytes_info *sinfo = cb->data;
34 	unsigned long long i;
35 
36 	xtables_option_parse(cb);
37 	switch (cb->entry->id) {
38 	case O_CONNBYTES:
39 		sinfo->count.from = cb->val.u64_range[0];
40 		sinfo->count.to   = UINT64_MAX;
41 		if (cb->nvals == 2)
42 			sinfo->count.to = cb->val.u64_range[1];
43 
44 		if (sinfo->count.to < sinfo->count.from)
45 			xtables_error(PARAMETER_PROBLEM, "%llu should be less than %llu",
46 					(unsigned long long)sinfo->count.from,
47 					(unsigned long long)sinfo->count.to);
48 		if (cb->invert) {
49 			i = sinfo->count.from;
50 			sinfo->count.from = sinfo->count.to;
51 			sinfo->count.to = i;
52 		}
53 		break;
54 	case O_CONNBYTES_DIR:
55 		if (strcmp(cb->arg, "original") == 0)
56 			sinfo->direction = XT_CONNBYTES_DIR_ORIGINAL;
57 		else if (strcmp(cb->arg, "reply") == 0)
58 			sinfo->direction = XT_CONNBYTES_DIR_REPLY;
59 		else if (strcmp(cb->arg, "both") == 0)
60 			sinfo->direction = XT_CONNBYTES_DIR_BOTH;
61 		else
62 			xtables_error(PARAMETER_PROBLEM,
63 				   "Unknown --connbytes-dir `%s'", cb->arg);
64 		break;
65 	case O_CONNBYTES_MODE:
66 		if (strcmp(cb->arg, "packets") == 0)
67 			sinfo->what = XT_CONNBYTES_PKTS;
68 		else if (strcmp(cb->arg, "bytes") == 0)
69 			sinfo->what = XT_CONNBYTES_BYTES;
70 		else if (strcmp(cb->arg, "avgpkt") == 0)
71 			sinfo->what = XT_CONNBYTES_AVGPKT;
72 		else
73 			xtables_error(PARAMETER_PROBLEM,
74 				   "Unknown --connbytes-mode `%s'", cb->arg);
75 		break;
76 	}
77 }
78 
print_mode(const struct xt_connbytes_info * sinfo)79 static void print_mode(const struct xt_connbytes_info *sinfo)
80 {
81 	switch (sinfo->what) {
82 		case XT_CONNBYTES_PKTS:
83 			fputs(" packets", stdout);
84 			break;
85 		case XT_CONNBYTES_BYTES:
86 			fputs(" bytes", stdout);
87 			break;
88 		case XT_CONNBYTES_AVGPKT:
89 			fputs(" avgpkt", stdout);
90 			break;
91 		default:
92 			fputs(" unknown", stdout);
93 			break;
94 	}
95 }
96 
print_direction(const struct xt_connbytes_info * sinfo)97 static void print_direction(const struct xt_connbytes_info *sinfo)
98 {
99 	switch (sinfo->direction) {
100 		case XT_CONNBYTES_DIR_ORIGINAL:
101 			fputs(" original", stdout);
102 			break;
103 		case XT_CONNBYTES_DIR_REPLY:
104 			fputs(" reply", stdout);
105 			break;
106 		case XT_CONNBYTES_DIR_BOTH:
107 			fputs(" both", stdout);
108 			break;
109 		default:
110 			fputs(" unknown", stdout);
111 			break;
112 	}
113 }
114 
print_from_to(const struct xt_connbytes_info * sinfo,const char * prefix)115 static void print_from_to(const struct xt_connbytes_info *sinfo, const char *prefix)
116 {
117 	unsigned long long from, to;
118 
119 	if (sinfo->count.from > sinfo->count.to) {
120 		fputs(" !", stdout);
121 		from = sinfo->count.to;
122 		to = sinfo->count.from;
123 	} else {
124 		to = sinfo->count.to;
125 		from = sinfo->count.from;
126 	}
127 	printf(" %sconnbytes %llu", prefix, from);
128 	if (to && to < UINT64_MAX)
129 		printf(":%llu", to);
130 }
131 
132 static void
connbytes_print(const void * ip,const struct xt_entry_match * match,int numeric)133 connbytes_print(const void *ip, const struct xt_entry_match *match, int numeric)
134 {
135 	const struct xt_connbytes_info *sinfo = (const void *)match->data;
136 
137 	print_from_to(sinfo, "");
138 
139 	fputs(" connbytes mode", stdout);
140 	print_mode(sinfo);
141 
142 	fputs(" connbytes direction", stdout);
143 	print_direction(sinfo);
144 }
145 
connbytes_save(const void * ip,const struct xt_entry_match * match)146 static void connbytes_save(const void *ip, const struct xt_entry_match *match)
147 {
148 	const struct xt_connbytes_info *sinfo = (const void *)match->data;
149 
150 	print_from_to(sinfo, "--");
151 
152 	fputs(" --connbytes-mode", stdout);
153 	print_mode(sinfo);
154 
155 	fputs(" --connbytes-dir", stdout);
156 	print_direction(sinfo);
157 }
158 
159 static struct xtables_match connbytes_match = {
160 	.family		= NFPROTO_UNSPEC,
161 	.name 		= "connbytes",
162 	.version 	= XTABLES_VERSION,
163 	.size 		= XT_ALIGN(sizeof(struct xt_connbytes_info)),
164 	.userspacesize	= XT_ALIGN(sizeof(struct xt_connbytes_info)),
165 	.help		= connbytes_help,
166 	.print		= connbytes_print,
167 	.save 		= connbytes_save,
168 	.x6_parse	= connbytes_parse,
169 	.x6_options	= connbytes_opts,
170 };
171 
_init(void)172 void _init(void)
173 {
174 	xtables_register_match(&connbytes_match);
175 }
176