• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * (C) 2012 by Hans Schillstrom <hans.schillstrom@ericsson.com>
3  * (C) 2012 by Pablo Neira Ayuso <pablo@netfilter.org>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Description: shared library add-on to iptables to add HMARK target support
10  *
11  * Initial development by Hans Schillstrom. Pablo's improvements to this piece
12  * of software has been sponsored by Sophos Astaro <http://www.sophos.com>.
13  */
14 
15 #include <stdbool.h>
16 #include <stdio.h>
17 #include <string.h>
18 
19 #include "xtables.h"
20 #include <linux/netfilter/xt_HMARK.h>
21 
HMARK_help(void)22 static void HMARK_help(void)
23 {
24 	printf(
25 "HMARK target options, i.e. modify hash calculation by:\n"
26 "  --hmark-tuple [src|dst|sport|dport|spi|proto|ct][,...]\n"
27 "  --hmark-mod value		    nfmark modulus value\n"
28 "  --hmark-offset value		    Last action add value to nfmark\n\n"
29 "  --hmark-rnd			    Random see for hashing\n"
30 " Alternatively, fine tuning of what will be included in hash calculation\n"
31 "  --hmark-src-prefix length	    Source address mask CIDR prefix\n"
32 "  --hmark-dst-prefix length	    Dest address mask CIDR prefix\n"
33 "  --hmark-sport-mask value	    Mask src port with value\n"
34 "  --hmark-dport-mask value	    Mask dst port with value\n"
35 "  --hmark-spi-mask value	    For esp and ah AND spi with value\n"
36 "  --hmark-sport value		    OR src port with value\n"
37 "  --hmark-dport value		    OR dst port with value\n"
38 "  --hmark-spi value		    For esp and ah OR spi with value\n"
39 "  --hmark-proto-mask value	    Mask Protocol with value\n");
40 }
41 
42 #define hi struct xt_hmark_info
43 
44 enum {
45 	O_HMARK_SADDR_MASK,
46 	O_HMARK_DADDR_MASK,
47 	O_HMARK_SPI,
48 	O_HMARK_SPI_MASK,
49 	O_HMARK_SPORT,
50 	O_HMARK_DPORT,
51 	O_HMARK_SPORT_MASK,
52 	O_HMARK_DPORT_MASK,
53 	O_HMARK_PROTO_MASK,
54 	O_HMARK_RND,
55 	O_HMARK_MODULUS,
56 	O_HMARK_OFFSET,
57 	O_HMARK_CT,
58 	O_HMARK_TYPE,
59 };
60 
61 #define HMARK_OPT_PKT_MASK			\
62 	((1 << O_HMARK_SADDR_MASK)		| \
63 	 (1 << O_HMARK_DADDR_MASK)		| \
64 	 (1 << O_HMARK_SPI_MASK)		| \
65 	 (1 << O_HMARK_SPORT_MASK)		| \
66 	 (1 << O_HMARK_DPORT_MASK)		| \
67 	 (1 << O_HMARK_PROTO_MASK)		| \
68 	 (1 << O_HMARK_SPI_MASK)		| \
69 	 (1 << O_HMARK_SPORT)			| \
70 	 (1 << O_HMARK_DPORT)			| \
71 	 (1 << O_HMARK_SPI))
72 
73 static const struct xt_option_entry HMARK_opts[] = {
74 	{ .name  = "hmark-tuple",
75 	  .type  = XTTYPE_STRING,
76 	  .id	 = O_HMARK_TYPE,
77 	},
78 	{ .name  = "hmark-src-prefix",
79 	  .type  = XTTYPE_PLENMASK,
80 	  .id	 = O_HMARK_SADDR_MASK,
81 	  .flags = XTOPT_PUT, XTOPT_POINTER(hi, src_mask)
82 	},
83 	{ .name  = "hmark-dst-prefix",
84 	  .type  = XTTYPE_PLENMASK,
85 	  .id	 = O_HMARK_DADDR_MASK,
86 	  .flags = XTOPT_PUT, XTOPT_POINTER(hi, dst_mask)
87 	},
88 	{ .name  = "hmark-sport-mask",
89 	  .type  = XTTYPE_UINT16,
90 	  .id	 = O_HMARK_SPORT_MASK,
91 	  .flags = XTOPT_PUT, XTOPT_POINTER(hi, port_mask.p16.src)
92 	},
93 	{ .name  = "hmark-dport-mask",
94 	  .type  = XTTYPE_UINT16,
95 	  .id	 = O_HMARK_DPORT_MASK,
96 	  .flags = XTOPT_PUT, XTOPT_POINTER(hi, port_mask.p16.dst)
97 	},
98 	{ .name  = "hmark-spi-mask",
99 	  .type  = XTTYPE_UINT32,
100 	  .id	 = O_HMARK_SPI_MASK,
101 	  .flags = XTOPT_PUT, XTOPT_POINTER(hi, port_mask.v32)
102 	},
103 	{ .name  = "hmark-sport",
104 	  .type  = XTTYPE_UINT16,
105 	  .id	 = O_HMARK_SPORT,
106 	  .flags = XTOPT_PUT, XTOPT_POINTER(hi, port_set.p16.src)
107 	},
108 	{ .name  = "hmark-dport",
109 	  .type  = XTTYPE_UINT16,
110 	  .id	 = O_HMARK_DPORT,
111 	  .flags = XTOPT_PUT, XTOPT_POINTER(hi, port_set.p16.dst)
112 	},
113 	{ .name  = "hmark-spi",
114 	  .type  = XTTYPE_UINT32,
115 	  .id	 = O_HMARK_SPI,
116 	  .flags = XTOPT_PUT, XTOPT_POINTER(hi, port_set.v32)
117 	},
118 	{ .name  = "hmark-proto-mask",
119 	  .type  = XTTYPE_UINT16,
120 	  .id	 = O_HMARK_PROTO_MASK,
121 	  .flags = XTOPT_PUT, XTOPT_POINTER(hi, proto_mask)
122 	},
123 	{ .name  = "hmark-rnd",
124 	  .type  = XTTYPE_UINT32,
125 	  .id	 = O_HMARK_RND,
126 	  .flags = XTOPT_PUT, XTOPT_POINTER(hi, hashrnd)
127 	},
128 	{ .name = "hmark-mod",
129 	  .type = XTTYPE_UINT32,
130 	  .id = O_HMARK_MODULUS,
131 	  .min = 1,
132 	  .flags = XTOPT_PUT | XTOPT_MAND, XTOPT_POINTER(hi, hmodulus)
133 	},
134 	{ .name  = "hmark-offset",
135 	  .type  = XTTYPE_UINT32,
136 	  .id	 = O_HMARK_OFFSET,
137 	  .flags = XTOPT_PUT, XTOPT_POINTER(hi, hoffset)
138 	},
139 	XTOPT_TABLEEND,
140 };
141 
142 static int
hmark_parse(const char * type,size_t len,struct xt_hmark_info * info,unsigned int * xflags)143 hmark_parse(const char *type, size_t len, struct xt_hmark_info *info,
144 	    unsigned int *xflags)
145 {
146 	if (strncasecmp(type, "ct", len) == 0) {
147 		info->flags |= XT_HMARK_FLAG(XT_HMARK_CT);
148 		*xflags |= (1 << O_HMARK_CT);
149 	} else if (strncasecmp(type, "src", len) == 0) {
150 		memset(&info->src_mask, 0xff, sizeof(info->src_mask));
151 		info->flags |= XT_HMARK_FLAG(XT_HMARK_SADDR_MASK);
152 		*xflags |= (1 << O_HMARK_SADDR_MASK);
153 	} else if (strncasecmp(type, "dst", len) == 0) {
154 		memset(&info->dst_mask, 0xff, sizeof(info->dst_mask));
155 		info->flags |= XT_HMARK_FLAG(XT_HMARK_DADDR_MASK);
156 		*xflags |= (1 << O_HMARK_DADDR_MASK);
157 	} else if (strncasecmp(type, "sport", len) == 0) {
158 		memset(&info->port_mask.p16.src, 0xff,
159 			sizeof(info->port_mask.p16.src));
160 		info->flags |= XT_HMARK_FLAG(XT_HMARK_SPORT_MASK);
161 		*xflags |= (1 << O_HMARK_SPORT_MASK);
162 	} else if (strncasecmp(type, "dport", len) == 0) {
163 		memset(&info->port_mask.p16.dst, 0xff,
164 			sizeof(info->port_mask.p16.dst));
165 		info->flags |= XT_HMARK_FLAG(XT_HMARK_DPORT_MASK);
166 		*xflags |= (1 << O_HMARK_DPORT_MASK);
167 	} else if (strncasecmp(type, "proto", len) == 0) {
168 		memset(&info->proto_mask, 0xff, sizeof(info->proto_mask));
169 		info->flags |= XT_HMARK_FLAG(XT_HMARK_PROTO_MASK);
170 		*xflags |= (1 << O_HMARK_PROTO_MASK);
171 	} else if (strncasecmp(type, "spi", len) == 0) {
172 		memset(&info->port_mask.v32, 0xff, sizeof(info->port_mask.v32));
173 		info->flags |= XT_HMARK_FLAG(XT_HMARK_SPI_MASK);
174 		*xflags |= (1 << O_HMARK_SPI_MASK);
175 	} else
176 		return 0;
177 
178 	return 1;
179 }
180 
181 static void
hmark_parse_type(struct xt_option_call * cb)182 hmark_parse_type(struct xt_option_call *cb)
183 {
184 	const char *arg = cb->arg;
185 	struct xt_hmark_info *info = cb->data;
186 	const char *comma;
187 
188 	while ((comma = strchr(arg, ',')) != NULL) {
189 		if (comma == arg ||
190 		    !hmark_parse(arg, comma-arg, info, &cb->xflags))
191 			xtables_error(PARAMETER_PROBLEM, "Bad type \"%s\"", arg);
192 		arg = comma+1;
193 	}
194 	if (!*arg)
195 		xtables_error(PARAMETER_PROBLEM, "\"--hmark-tuple\" requires "
196 						 "a list of types with no "
197 						 "spaces, e.g. "
198 						 "src,dst,sport,dport,proto");
199 	if (strlen(arg) == 0 ||
200 	    !hmark_parse(arg, strlen(arg), info, &cb->xflags))
201 		xtables_error(PARAMETER_PROBLEM, "Bad type \"%s\"", arg);
202 }
203 
HMARK_parse(struct xt_option_call * cb,int plen)204 static void HMARK_parse(struct xt_option_call *cb, int plen)
205 {
206 	struct xt_hmark_info *info = cb->data;
207 
208 	xtables_option_parse(cb);
209 
210 	switch (cb->entry->id) {
211 	case O_HMARK_TYPE:
212 		hmark_parse_type(cb);
213 		break;
214 	case O_HMARK_SADDR_MASK:
215 		info->flags |= XT_HMARK_FLAG(XT_HMARK_SADDR_MASK);
216 		break;
217 	case O_HMARK_DADDR_MASK:
218 		info->flags |= XT_HMARK_FLAG(XT_HMARK_DADDR_MASK);
219 		break;
220 	case O_HMARK_SPI:
221 		info->port_set.v32 = htonl(cb->val.u32);
222 		info->flags |= XT_HMARK_FLAG(XT_HMARK_SPI);
223 		break;
224 	case O_HMARK_SPORT:
225 		info->port_set.p16.src = htons(cb->val.u16);
226 		info->flags |= XT_HMARK_FLAG(XT_HMARK_SPORT);
227 		break;
228 	case O_HMARK_DPORT:
229 		info->port_set.p16.dst = htons(cb->val.u16);
230 		info->flags |= XT_HMARK_FLAG(XT_HMARK_DPORT);
231 		break;
232 	case O_HMARK_SPORT_MASK:
233 		info->port_mask.p16.src = htons(cb->val.u16);
234 		info->flags |= XT_HMARK_FLAG(XT_HMARK_SPORT_MASK);
235 		break;
236 	case O_HMARK_DPORT_MASK:
237 		info->port_mask.p16.dst = htons(cb->val.u16);
238 		info->flags |= XT_HMARK_FLAG(XT_HMARK_DPORT_MASK);
239 		break;
240 	case O_HMARK_SPI_MASK:
241 		info->port_mask.v32 = htonl(cb->val.u32);
242 		info->flags |= XT_HMARK_FLAG(XT_HMARK_SPI_MASK);
243 		break;
244 	case O_HMARK_PROTO_MASK:
245 		info->flags |= XT_HMARK_FLAG(XT_HMARK_PROTO_MASK);
246 		break;
247 	case O_HMARK_RND:
248 		info->flags |= XT_HMARK_FLAG(XT_HMARK_RND);
249 		break;
250 	case O_HMARK_MODULUS:
251 		info->flags |= XT_HMARK_FLAG(XT_HMARK_MODULUS);
252 		break;
253 	case O_HMARK_OFFSET:
254 		info->flags |= XT_HMARK_FLAG(XT_HMARK_OFFSET);
255 		break;
256 	case O_HMARK_CT:
257 		info->flags |= XT_HMARK_FLAG(XT_HMARK_CT);
258 		break;
259 	}
260 	cb->xflags |= (1 << cb->entry->id);
261 }
262 
HMARK_ip4_parse(struct xt_option_call * cb)263 static void HMARK_ip4_parse(struct xt_option_call *cb)
264 {
265 	HMARK_parse(cb, 32);
266 }
HMARK_ip6_parse(struct xt_option_call * cb)267 static void HMARK_ip6_parse(struct xt_option_call *cb)
268 {
269 	HMARK_parse(cb, 128);
270 }
271 
HMARK_check(struct xt_fcheck_call * cb)272 static void HMARK_check(struct xt_fcheck_call *cb)
273 {
274 	if (!(cb->xflags & (1 << O_HMARK_MODULUS)))
275 		xtables_error(PARAMETER_PROBLEM, "--hmark-mod is mandatory");
276 	if (!(cb->xflags & (1 << O_HMARK_RND)))
277 		xtables_error(PARAMETER_PROBLEM, "--hmark-rnd is mandatory");
278 	if (cb->xflags & (1 << O_HMARK_SPI_MASK) &&
279 	    (cb->xflags & ((1 << O_HMARK_SPORT_MASK) |
280 			   (1 << O_HMARK_DPORT_MASK))))
281 		xtables_error(PARAMETER_PROBLEM, "you cannot use "
282 				"--hmark-spi-mask and --hmark-?port-mask,"
283 				"at the same time");
284 	if (!((cb->xflags & HMARK_OPT_PKT_MASK) ||
285 	       cb->xflags & (1 << O_HMARK_CT)))
286 		xtables_error(PARAMETER_PROBLEM, "you have to specify "
287 				"--hmark-tuple at least");
288 }
289 
HMARK_print(const struct xt_hmark_info * info)290 static void HMARK_print(const struct xt_hmark_info *info)
291 {
292 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPORT_MASK))
293 		printf("sport-mask 0x%x ", htons(info->port_mask.p16.src));
294 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_DPORT_MASK))
295 		printf("dport-mask 0x%x ", htons(info->port_mask.p16.dst));
296 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPI_MASK))
297 		printf("spi-mask 0x%x ", htonl(info->port_mask.v32));
298 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPORT))
299 		printf("sport 0x%x ", htons(info->port_set.p16.src));
300 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_DPORT))
301 		printf("dport 0x%x ", htons(info->port_set.p16.dst));
302 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPI))
303 		printf("spi 0x%x ", htonl(info->port_set.v32));
304 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_PROTO_MASK))
305 		printf("proto-mask 0x%x ", info->proto_mask);
306 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_RND))
307 		printf("rnd 0x%x ", info->hashrnd);
308 }
309 
HMARK_ip6_print(const void * ip,const struct xt_entry_target * target,int numeric)310 static void HMARK_ip6_print(const void *ip,
311 			    const struct xt_entry_target *target, int numeric)
312 {
313 	const struct xt_hmark_info *info =
314 			(const struct xt_hmark_info *)target->data;
315 
316 	printf(" HMARK ");
317 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_MODULUS))
318 		printf("mod %u ", info->hmodulus);
319 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_OFFSET))
320 		printf("+ 0x%x ", info->hoffset);
321 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_CT))
322 		printf("ct, ");
323 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_SADDR_MASK))
324 		printf("src-prefix %s ",
325 		       xtables_ip6mask_to_numeric(&info->src_mask.in6) + 1);
326 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_DADDR_MASK))
327 		printf("dst-prefix %s ",
328 		       xtables_ip6mask_to_numeric(&info->dst_mask.in6) + 1);
329 	HMARK_print(info);
330 }
HMARK_ip4_print(const void * ip,const struct xt_entry_target * target,int numeric)331 static void HMARK_ip4_print(const void *ip,
332 			    const struct xt_entry_target *target, int numeric)
333 {
334 	const struct xt_hmark_info *info =
335 		(const struct xt_hmark_info *)target->data;
336 
337 	printf(" HMARK ");
338 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_MODULUS))
339 		printf("mod %u ", info->hmodulus);
340 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_OFFSET))
341 		printf("+ 0x%x ", info->hoffset);
342 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_CT))
343 		printf("ct, ");
344 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_SADDR_MASK))
345 		printf("src-prefix %u ",
346 		       xtables_ipmask_to_cidr(&info->src_mask.in));
347 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_DADDR_MASK))
348 		printf("dst-prefix %u ",
349 		       xtables_ipmask_to_cidr(&info->dst_mask.in));
350 	HMARK_print(info);
351 }
352 
HMARK_save(const struct xt_hmark_info * info)353 static void HMARK_save(const struct xt_hmark_info *info)
354 {
355 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPORT_MASK))
356 		printf(" --hmark-sport-mask 0x%04x",
357 		       htons(info->port_mask.p16.src));
358 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_DPORT_MASK))
359 		printf(" --hmark-dport-mask 0x%04x",
360 		       htons(info->port_mask.p16.dst));
361 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPI_MASK))
362 		printf(" --hmark-spi-mask 0x%08x",
363 		       htonl(info->port_mask.v32));
364 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPORT))
365 		printf(" --hmark-sport 0x%04x",
366 		       htons(info->port_set.p16.src));
367 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_DPORT))
368 		printf(" --hmark-dport 0x%04x",
369 		       htons(info->port_set.p16.dst));
370 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_SPI))
371 		printf(" --hmark-spi 0x%08x", htonl(info->port_set.v32));
372 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_PROTO_MASK))
373 		printf(" --hmark-proto-mask 0x%02x", info->proto_mask);
374 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_RND))
375 		printf(" --hmark-rnd 0x%08x", info->hashrnd);
376 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_MODULUS))
377 		printf(" --hmark-mod %u", info->hmodulus);
378 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_OFFSET))
379 		printf(" --hmark-offset %u", info->hoffset);
380 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_CT))
381 		printf(" --hmark-tuple ct");
382 }
383 
HMARK_ip6_save(const void * ip,const struct xt_entry_target * target)384 static void HMARK_ip6_save(const void *ip, const struct xt_entry_target *target)
385 {
386 	const struct xt_hmark_info *info =
387 		(const struct xt_hmark_info *)target->data;
388 	int ret;
389 
390 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_SADDR_MASK)) {
391 		ret = xtables_ip6mask_to_cidr(&info->src_mask.in6);
392 		printf(" --hmark-src-prefix %d", ret);
393 	}
394 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_DADDR_MASK)) {
395 		ret = xtables_ip6mask_to_cidr(&info->dst_mask.in6);
396 		printf(" --hmark-dst-prefix %d", ret);
397 	}
398 	HMARK_save(info);
399 }
400 
HMARK_ip4_save(const void * ip,const struct xt_entry_target * target)401 static void HMARK_ip4_save(const void *ip, const struct xt_entry_target *target)
402 {
403 	const struct xt_hmark_info *info =
404 		(const struct xt_hmark_info *)target->data;
405 	int ret;
406 
407 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_SADDR_MASK)) {
408 		ret = xtables_ipmask_to_cidr(&info->src_mask.in);
409 		printf(" --hmark-src-prefix %d", ret);
410 	}
411 	if (info->flags & XT_HMARK_FLAG(XT_HMARK_DADDR_MASK)) {
412 		ret = xtables_ipmask_to_cidr(&info->dst_mask.in);
413 		printf(" --hmark-dst-prefix %d", ret);
414 	}
415 	HMARK_save(info);
416 }
417 
418 static struct xtables_target mark_tg_reg[] = {
419 	{
420 		.family        = NFPROTO_IPV4,
421 		.name	       = "HMARK",
422 		.version       = XTABLES_VERSION,
423 		.size	       = XT_ALIGN(sizeof(struct xt_hmark_info)),
424 		.userspacesize = XT_ALIGN(sizeof(struct xt_hmark_info)),
425 		.help	       = HMARK_help,
426 		.print	       = HMARK_ip4_print,
427 		.save	       = HMARK_ip4_save,
428 		.x6_parse      = HMARK_ip4_parse,
429 		.x6_fcheck     = HMARK_check,
430 		.x6_options    = HMARK_opts,
431 	},
432 	{
433 		.family        = NFPROTO_IPV6,
434 		.name	       = "HMARK",
435 		.version       = XTABLES_VERSION,
436 		.size	       = XT_ALIGN(sizeof(struct xt_hmark_info)),
437 		.userspacesize = XT_ALIGN(sizeof(struct xt_hmark_info)),
438 		.help	       = HMARK_help,
439 		.print	       = HMARK_ip6_print,
440 		.save	       = HMARK_ip6_save,
441 		.x6_parse      = HMARK_ip6_parse,
442 		.x6_fcheck     = HMARK_check,
443 		.x6_options    = HMARK_opts,
444 	},
445 };
446 
_init(void)447 void _init(void)
448 {
449 	xtables_register_targets(mark_tg_reg, ARRAY_SIZE(mark_tg_reg));
450 }
451