19ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy/* Shared library add-on to iptables to add devgroup matching support.
29ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy *
39ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy * Copyright (c) 2011 Patrick McHardy <kaber@trash.net>
49ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy */
59ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy#include <stdio.h>
69ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy#include <string.h>
79ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy#include <stdlib.h>
89ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy#include <errno.h>
99ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy#include <xtables.h>
109ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy#include <linux/netfilter/xt_devgroup.h>
119ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy
129ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardystatic void devgroup_help(void)
139ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy{
149ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy	printf(
159ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy"devgroup match options:\n"
169ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy"[!] --src-group value[/mask]	Match device group of incoming device\n"
179ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy"[!] --dst-group value[/mask]	Match device group of outgoing device\n"
189ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy		);
199ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy}
209ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy
219ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardyenum {
225d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt	O_SRC_GROUP = 0,
235d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt	O_DST_GROUP,
249ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy};
259ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy
265d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardtstatic const struct xt_option_entry devgroup_opts[] = {
275d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt	{.name = "src-group", .id = O_SRC_GROUP, .type = XTTYPE_STRING,
285d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt	 .flags = XTOPT_INVERT},
295d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt	{.name = "dst-group", .id = O_DST_GROUP, .type = XTTYPE_STRING,
305d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt	 .flags = XTOPT_INVERT},
315d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt	XTOPT_TABLEEND,
329ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy};
339ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy
349ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy/* array of devgroups from /etc/iproute2/group_map */
355d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardtstatic struct xtables_lmap *devgroups;
369ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy
375d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardtstatic void devgroup_init(struct xt_entry_match *match)
389ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy{
395d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt	const char file[] = "/etc/iproute2/group_map";
405d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt	devgroups = xtables_lmap_init(file);
415d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt	if (devgroups == NULL && errno != ENOENT)
425d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt		fprintf(stderr, "Warning: %s: %s\n", file, strerror(errno));
439ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy}
449ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy
45c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardtstatic void devgroup_parse_groupspec(const char *arg, unsigned int *group,
46c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt				     unsigned int *mask)
47c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt{
48c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt	char *end;
49d18b451ec82bbaeaf385241ebdf926912a075adeJan Engelhardt	bool ok;
50c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt
51d18b451ec82bbaeaf385241ebdf926912a075adeJan Engelhardt	ok = xtables_strtoui(arg, &end, group, 0, UINT32_MAX);
52d18b451ec82bbaeaf385241ebdf926912a075adeJan Engelhardt	if (ok && (*end == '/' || *end == '\0')) {
53c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt		if (*end == '/')
54d18b451ec82bbaeaf385241ebdf926912a075adeJan Engelhardt			ok = xtables_strtoui(end + 1, NULL, mask,
55d18b451ec82bbaeaf385241ebdf926912a075adeJan Engelhardt			                     0, UINT32_MAX);
56c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt		else
57c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt			*mask = ~0U;
58d18b451ec82bbaeaf385241ebdf926912a075adeJan Engelhardt		if (!ok)
59c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt			xtables_error(PARAMETER_PROBLEM,
60c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt				      "Bad group value \"%s\"", arg);
61c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt	} else {
62c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt		*group = xtables_lmap_name2id(devgroups, arg);
63c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt		if (*group == -1)
64c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt			xtables_error(PARAMETER_PROBLEM,
65c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt				      "Device group \"%s\" not found", arg);
66c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt		*mask = ~0U;
67c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt	}
68c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt}
69c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt
705d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardtstatic void devgroup_parse(struct xt_option_call *cb)
719ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy{
725d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt	struct xt_devgroup_info *info = cb->data;
73c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt	unsigned int id, mask;
749ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy
755d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt	xtables_option_parse(cb);
765d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt	switch (cb->entry->id) {
775d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt	case O_SRC_GROUP:
78c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt		devgroup_parse_groupspec(cb->arg, &id, &mask);
79c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt		info->src_group = id;
80c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt		info->src_mask  = mask;
8117f7937f79af4d260c60cb800e56fc0df0a48b37Lutz Jaenicke		info->flags |= XT_DEVGROUP_MATCH_SRC;
825d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt		if (cb->invert)
839ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy			info->flags |= XT_DEVGROUP_INVERT_SRC;
849ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy		break;
855d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt	case O_DST_GROUP:
86c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt		devgroup_parse_groupspec(cb->arg, &id, &mask);
87c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt		info->dst_group = id;
88c0b7138f39882e2bf8f3d85d15e0ffbd868ed7baJan Engelhardt		info->dst_mask  = mask;
8917f7937f79af4d260c60cb800e56fc0df0a48b37Lutz Jaenicke		info->flags |= XT_DEVGROUP_MATCH_DST;
905d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt		if (cb->invert)
919ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy			info->flags |= XT_DEVGROUP_INVERT_DST;
929ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy		break;
939ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy	}
949ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy}
959ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy
969ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardystatic void
979ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardyprint_devgroup(unsigned int id, unsigned int mask, int numeric)
989ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy{
999ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy	const char *name = NULL;
1009ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy
1019ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy	if (mask != 0xffffffff)
102c0f6d17764e9bc1724cedd78b880a80446363146Jan Engelhardt		printf("0x%x/0x%x", id, mask);
1039ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy	else {
1049ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy		if (numeric == 0)
1055d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt			name = xtables_lmap_id2name(devgroups, id);
1069ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy		if (name)
107c0f6d17764e9bc1724cedd78b880a80446363146Jan Engelhardt			printf("%s", name);
1089ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy		else
109c0f6d17764e9bc1724cedd78b880a80446363146Jan Engelhardt			printf("0x%x", id);
1109ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy	}
1119ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy}
1129ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy
1139ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardystatic void devgroup_show(const char *pfx, const struct xt_devgroup_info *info,
1149ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy			  int numeric)
1159ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy{
1169ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy	if (info->flags & XT_DEVGROUP_MATCH_SRC) {
1179ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy		if (info->flags & XT_DEVGROUP_INVERT_SRC)
118c0f6d17764e9bc1724cedd78b880a80446363146Jan Engelhardt			printf(" !");
119c0f6d17764e9bc1724cedd78b880a80446363146Jan Engelhardt		printf(" %ssrc-group ", pfx);
1209ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy		print_devgroup(info->src_group, info->src_mask, numeric);
1219ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy	}
1229ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy
1239ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy	if (info->flags & XT_DEVGROUP_MATCH_DST) {
1249ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy		if (info->flags & XT_DEVGROUP_INVERT_DST)
125c0f6d17764e9bc1724cedd78b880a80446363146Jan Engelhardt			printf(" !");
126c0f6d17764e9bc1724cedd78b880a80446363146Jan Engelhardt		printf(" %sdst-group ", pfx);
1279ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy		print_devgroup(info->src_group, info->src_mask, numeric);
1289ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy	}
1299ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy}
1309ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy
1319ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardystatic void devgroup_print(const void *ip, const struct xt_entry_match *match,
1329ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy                        int numeric)
1339ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy{
1349ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy	const struct xt_devgroup_info *info = (const void *)match->data;
1359ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy
1369ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy	devgroup_show("", info, numeric);
1379ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy}
1389ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy
1399ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardystatic void devgroup_save(const void *ip, const struct xt_entry_match *match)
1409ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy{
1419ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy	const struct xt_devgroup_info *info = (const void *)match->data;
1429ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy
1439ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy	devgroup_show("--", info, 0);
1449ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy}
1459ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy
1465d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardtstatic void devgroup_check(struct xt_fcheck_call *cb)
1479ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy{
1485d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt	if (cb->xflags == 0)
1499ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy		xtables_error(PARAMETER_PROBLEM,
1509ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy			      "devgroup match: You must specify either "
1519ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy			      "'--src-group' or '--dst-group'");
1529ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy}
1539ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy
1549ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardystatic struct xtables_match devgroup_mt_reg = {
1559ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy	.name		= "devgroup",
1569ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy	.version	= XTABLES_VERSION,
1579ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy	.family		= NFPROTO_UNSPEC,
1589ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy	.size		= XT_ALIGN(sizeof(struct xt_devgroup_info)),
1599ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy	.userspacesize	= XT_ALIGN(sizeof(struct xt_devgroup_info)),
1605d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt	.init		= devgroup_init,
1619ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy	.help		= devgroup_help,
1629ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy	.print		= devgroup_print,
1639ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy	.save		= devgroup_save,
1645d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt	.x6_parse	= devgroup_parse,
1655d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt	.x6_fcheck	= devgroup_check,
1665d8e61ef4636383ca47cd748cd7457a238de37a6Jan Engelhardt	.x6_options	= devgroup_opts,
1679ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy};
1689ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy
1699ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardyvoid _init(void)
1709ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy{
1719ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy	xtables_register_match(&devgroup_mt_reg);
1729ee2a9fe2f74b616da34878104bd1ff406534ad1Patrick McHardy}
173