Home | History | Annotate | Download | only in extensions
      1 /* Shared library add-on to iptables to add devgroup matching support.
      2  *
      3  * Copyright (c) 2011 Patrick McHardy <kaber (at) trash.net>
      4  */
      5 #include <stdio.h>
      6 #include <string.h>
      7 #include <stdlib.h>
      8 #include <errno.h>
      9 #include <xtables.h>
     10 #include <linux/netfilter/xt_devgroup.h>
     11 
     12 static void devgroup_help(void)
     13 {
     14 	printf(
     15 "devgroup match options:\n"
     16 "[!] --src-group value[/mask]	Match device group of incoming device\n"
     17 "[!] --dst-group value[/mask]	Match device group of outgoing device\n"
     18 		);
     19 }
     20 
     21 enum {
     22 	O_SRC_GROUP = 0,
     23 	O_DST_GROUP,
     24 };
     25 
     26 static const struct xt_option_entry devgroup_opts[] = {
     27 	{.name = "src-group", .id = O_SRC_GROUP, .type = XTTYPE_STRING,
     28 	 .flags = XTOPT_INVERT},
     29 	{.name = "dst-group", .id = O_DST_GROUP, .type = XTTYPE_STRING,
     30 	 .flags = XTOPT_INVERT},
     31 	XTOPT_TABLEEND,
     32 };
     33 
     34 /* array of devgroups from /etc/iproute2/group_map */
     35 static struct xtables_lmap *devgroups;
     36 
     37 static void devgroup_init(struct xt_entry_match *match)
     38 {
     39 	const char file[] = "/etc/iproute2/group_map";
     40 	devgroups = xtables_lmap_init(file);
     41 	if (devgroups == NULL && errno != ENOENT)
     42 		fprintf(stderr, "Warning: %s: %s\n", file, strerror(errno));
     43 }
     44 
     45 static void devgroup_parse_groupspec(const char *arg, unsigned int *group,
     46 				     unsigned int *mask)
     47 {
     48 	char *end;
     49 	bool ok;
     50 
     51 	ok = xtables_strtoui(arg, &end, group, 0, UINT32_MAX);
     52 	if (ok && (*end == '/' || *end == '\0')) {
     53 		if (*end == '/')
     54 			ok = xtables_strtoui(end + 1, NULL, mask,
     55 			                     0, UINT32_MAX);
     56 		else
     57 			*mask = ~0U;
     58 		if (!ok)
     59 			xtables_error(PARAMETER_PROBLEM,
     60 				      "Bad group value \"%s\"", arg);
     61 	} else {
     62 		*group = xtables_lmap_name2id(devgroups, arg);
     63 		if (*group == -1)
     64 			xtables_error(PARAMETER_PROBLEM,
     65 				      "Device group \"%s\" not found", arg);
     66 		*mask = ~0U;
     67 	}
     68 }
     69 
     70 static void devgroup_parse(struct xt_option_call *cb)
     71 {
     72 	struct xt_devgroup_info *info = cb->data;
     73 	unsigned int id, mask;
     74 
     75 	xtables_option_parse(cb);
     76 	switch (cb->entry->id) {
     77 	case O_SRC_GROUP:
     78 		devgroup_parse_groupspec(cb->arg, &id, &mask);
     79 		info->src_group = id;
     80 		info->src_mask  = mask;
     81 		info->flags |= XT_DEVGROUP_MATCH_SRC;
     82 		if (cb->invert)
     83 			info->flags |= XT_DEVGROUP_INVERT_SRC;
     84 		break;
     85 	case O_DST_GROUP:
     86 		devgroup_parse_groupspec(cb->arg, &id, &mask);
     87 		info->dst_group = id;
     88 		info->dst_mask  = mask;
     89 		info->flags |= XT_DEVGROUP_MATCH_DST;
     90 		if (cb->invert)
     91 			info->flags |= XT_DEVGROUP_INVERT_DST;
     92 		break;
     93 	}
     94 }
     95 
     96 static void
     97 print_devgroup(unsigned int id, unsigned int mask, int numeric)
     98 {
     99 	const char *name = NULL;
    100 
    101 	if (mask != 0xffffffff)
    102 		printf("0x%x/0x%x", id, mask);
    103 	else {
    104 		if (numeric == 0)
    105 			name = xtables_lmap_id2name(devgroups, id);
    106 		if (name)
    107 			printf("%s", name);
    108 		else
    109 			printf("0x%x", id);
    110 	}
    111 }
    112 
    113 static void devgroup_show(const char *pfx, const struct xt_devgroup_info *info,
    114 			  int numeric)
    115 {
    116 	if (info->flags & XT_DEVGROUP_MATCH_SRC) {
    117 		if (info->flags & XT_DEVGROUP_INVERT_SRC)
    118 			printf(" !");
    119 		printf(" %ssrc-group ", pfx);
    120 		print_devgroup(info->src_group, info->src_mask, numeric);
    121 	}
    122 
    123 	if (info->flags & XT_DEVGROUP_MATCH_DST) {
    124 		if (info->flags & XT_DEVGROUP_INVERT_DST)
    125 			printf(" !");
    126 		printf(" %sdst-group ", pfx);
    127 		print_devgroup(info->src_group, info->src_mask, numeric);
    128 	}
    129 }
    130 
    131 static void devgroup_print(const void *ip, const struct xt_entry_match *match,
    132                         int numeric)
    133 {
    134 	const struct xt_devgroup_info *info = (const void *)match->data;
    135 
    136 	devgroup_show("", info, numeric);
    137 }
    138 
    139 static void devgroup_save(const void *ip, const struct xt_entry_match *match)
    140 {
    141 	const struct xt_devgroup_info *info = (const void *)match->data;
    142 
    143 	devgroup_show("--", info, 0);
    144 }
    145 
    146 static void devgroup_check(struct xt_fcheck_call *cb)
    147 {
    148 	if (cb->xflags == 0)
    149 		xtables_error(PARAMETER_PROBLEM,
    150 			      "devgroup match: You must specify either "
    151 			      "'--src-group' or '--dst-group'");
    152 }
    153 
    154 static struct xtables_match devgroup_mt_reg = {
    155 	.name		= "devgroup",
    156 	.version	= XTABLES_VERSION,
    157 	.family		= NFPROTO_UNSPEC,
    158 	.size		= XT_ALIGN(sizeof(struct xt_devgroup_info)),
    159 	.userspacesize	= XT_ALIGN(sizeof(struct xt_devgroup_info)),
    160 	.init		= devgroup_init,
    161 	.help		= devgroup_help,
    162 	.print		= devgroup_print,
    163 	.save		= devgroup_save,
    164 	.x6_parse	= devgroup_parse,
    165 	.x6_fcheck	= devgroup_check,
    166 	.x6_options	= devgroup_opts,
    167 };
    168 
    169 void _init(void)
    170 {
    171 	xtables_register_match(&devgroup_mt_reg);
    172 }
    173