libxt_devgroup.c revision c0f6d17764e9bc1724cedd78b880a80446363146
1/* Shared library add-on to iptables to add devgroup matching support. 2 * 3 * Copyright (c) 2011 Patrick McHardy <kaber@trash.net> 4 */ 5#include <stdbool.h> 6#include <stdio.h> 7#include <netdb.h> 8#include <string.h> 9#include <stdlib.h> 10#include <errno.h> 11#include <ctype.h> 12#include <getopt.h> 13#include <xtables.h> 14#include <linux/netfilter/xt_devgroup.h> 15 16static void devgroup_help(void) 17{ 18 printf( 19"devgroup match options:\n" 20"[!] --src-group value[/mask] Match device group of incoming device\n" 21"[!] --dst-group value[/mask] Match device group of outgoing device\n" 22 ); 23} 24 25enum { 26 XT_DEVGROUP_OPT_SRCGROUP = 1, 27 XT_DEVGROUP_OPT_DSTGROUP, 28}; 29 30static const struct option devgroup_opts[] = { 31 { .name = "src-group", .has_arg = true, .val = XT_DEVGROUP_OPT_SRCGROUP }, 32 { .name = "dst-group", .has_arg = true, .val = XT_DEVGROUP_OPT_DSTGROUP }, 33 XT_GETOPT_TABLEEND, 34}; 35 36struct devgroupname { 37 unsigned int id; 38 char *name; 39 int len; 40 struct devgroupname *next; 41}; 42 43/* array of devgroups from /etc/iproute2/group_map */ 44static struct devgroupname *devgroups; 45/* 1 if loading failed */ 46static int rdberr; 47 48static void load_devgroups(void) 49{ 50 const char* rfnm = "/etc/iproute2/group_map"; 51 char buf[512]; 52 FILE *fil; 53 char *cur, *nxt; 54 int id; 55 struct devgroupname *oldnm = NULL, *newnm = NULL; 56 57 fil = fopen(rfnm, "r"); 58 if (!fil) { 59 rdberr = 1; 60 return; 61 } 62 63 while (fgets(buf, sizeof(buf), fil)) { 64 cur = buf; 65 while ((*cur == ' ') || (*cur == '\t')) 66 cur++; 67 if ((*cur == '#') || (*cur == '\n') || (*cur == 0)) 68 continue; 69 70 /* iproute2 allows hex and dec format */ 71 errno = 0; 72 id = strtoul(cur, &nxt, strncmp(cur, "0x", 2) ? 10 : 16); 73 if ((nxt == cur) || errno) 74 continue; 75 76 /* same boundaries as in iproute2 */ 77 if (id < 0 || id > 255) 78 continue; 79 cur = nxt; 80 81 if (!isspace(*cur)) 82 continue; 83 while ((*cur == ' ') || (*cur == '\t')) 84 cur++; 85 if ((*cur == '#') || (*cur == '\n') || (*cur == 0)) 86 continue; 87 nxt = cur; 88 while ((*nxt != 0) && !isspace(*nxt)) 89 nxt++; 90 if (nxt == cur) 91 continue; 92 93 /* found valid data */ 94 newnm = malloc(sizeof(struct devgroupname)); 95 if (newnm == NULL) { 96 perror("libxt_devgroup: malloc failed"); 97 exit(1); 98 } 99 newnm->id = id; 100 newnm->len = nxt - cur; 101 newnm->name = malloc(newnm->len + 1); 102 if (newnm->name == NULL) { 103 perror("libxt_devgroup: malloc failed"); 104 exit(1); 105 } 106 strncpy(newnm->name, cur, newnm->len); 107 newnm->name[newnm->len] = 0; 108 newnm->next = NULL; 109 110 if (oldnm) 111 oldnm->next = newnm; 112 else 113 devgroups = newnm; 114 oldnm = newnm; 115 } 116 117 fclose(fil); 118} 119 120/* get devgroup id for name, -1 if error/not found */ 121static int devgroup_name2id(const char* name) 122{ 123 struct devgroupname* cur; 124 125 if ((devgroups == NULL) && (rdberr == 0)) 126 load_devgroups(); 127 cur = devgroups; 128 if (cur == NULL) 129 return -1; 130 while (cur) { 131 if (!strncmp(name, cur->name, cur->len + 1)) 132 return cur->id; 133 cur = cur->next; 134 } 135 return -1; 136} 137 138/* get devgroup name for id, NULL if error/not found */ 139static const char *devgroup_id2name(int id) 140{ 141 struct devgroupname* cur; 142 143 if ((devgroups == NULL) && (rdberr == 0)) 144 load_devgroups(); 145 cur = devgroups; 146 if (cur == NULL) 147 return NULL; 148 while (cur) { 149 if (id == cur->id) 150 return cur->name; 151 cur = cur->next; 152 } 153 return NULL; 154} 155 156static int devgroup_parse(int c, char **argv, int invert, unsigned int *flags, 157 const void *entry, struct xt_entry_match **match) 158{ 159 struct xt_devgroup_info *info = (struct xt_devgroup_info *)(*match)->data; 160 unsigned int id; 161 char *end; 162 163 switch (c) { 164 case XT_DEVGROUP_OPT_SRCGROUP: 165 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 166 end = optarg; 167 info->src_group = strtoul(optarg, &end, 0); 168 if (end != optarg && (*end == '/' || *end == '\0')) { 169 if (*end == '/') 170 info->src_mask = strtoul(end+1, &end, 0); 171 else 172 info->src_mask = 0xffffffff; 173 if (*end != '\0' || end == optarg) 174 xtables_error(PARAMETER_PROBLEM, 175 "Bad src-group value `%s'", 176 optarg); 177 } else { 178 id = devgroup_name2id(optarg); 179 if (id == -1) 180 xtables_error(PARAMETER_PROBLEM, 181 "Device group `%s' not found", 182 optarg); 183 info->src_group = id; 184 info->src_mask = 0xffffffff; 185 } 186 info->flags |= XT_DEVGROUP_MATCH_SRC; 187 if (invert) 188 info->flags |= XT_DEVGROUP_INVERT_SRC; 189 *flags |= c; 190 break; 191 case XT_DEVGROUP_OPT_DSTGROUP: 192 xtables_check_inverse(optarg, &invert, &optind, 0, argv); 193 end = optarg; 194 info->dst_group = strtoul(optarg, &end, 0); 195 if (end != optarg && (*end == '/' || *end == '\0')) { 196 if (*end == '/') 197 info->dst_mask = strtoul(end+1, &end, 0); 198 else 199 info->dst_mask = 0xffffffff; 200 if (*end != '\0' || end == optarg) 201 xtables_error(PARAMETER_PROBLEM, 202 "Bad dst-group value `%s'", 203 optarg); 204 } else { 205 id = devgroup_name2id(optarg); 206 if (id == -1) 207 xtables_error(PARAMETER_PROBLEM, 208 "Device group `%s' not found", 209 optarg); 210 info->dst_group = id; 211 info->dst_mask = 0xffffffff; 212 } 213 info->flags |= XT_DEVGROUP_MATCH_DST; 214 if (invert) 215 info->flags |= XT_DEVGROUP_INVERT_DST; 216 *flags |= c; 217 break; 218 } 219 return 1; 220} 221 222static void 223print_devgroup(unsigned int id, unsigned int mask, int numeric) 224{ 225 const char *name = NULL; 226 227 if (mask != 0xffffffff) 228 printf("0x%x/0x%x", id, mask); 229 else { 230 if (numeric == 0) 231 name = devgroup_id2name(id); 232 if (name) 233 printf("%s", name); 234 else 235 printf("0x%x", id); 236 } 237} 238 239static void devgroup_show(const char *pfx, const struct xt_devgroup_info *info, 240 int numeric) 241{ 242 if (info->flags & XT_DEVGROUP_MATCH_SRC) { 243 if (info->flags & XT_DEVGROUP_INVERT_SRC) 244 printf(" !"); 245 printf(" %ssrc-group ", pfx); 246 print_devgroup(info->src_group, info->src_mask, numeric); 247 } 248 249 if (info->flags & XT_DEVGROUP_MATCH_DST) { 250 if (info->flags & XT_DEVGROUP_INVERT_DST) 251 printf(" !"); 252 printf(" %sdst-group ", pfx); 253 print_devgroup(info->src_group, info->src_mask, numeric); 254 } 255} 256 257static void devgroup_print(const void *ip, const struct xt_entry_match *match, 258 int numeric) 259{ 260 const struct xt_devgroup_info *info = (const void *)match->data; 261 262 devgroup_show("", info, numeric); 263} 264 265static void devgroup_save(const void *ip, const struct xt_entry_match *match) 266{ 267 const struct xt_devgroup_info *info = (const void *)match->data; 268 269 devgroup_show("--", info, 0); 270} 271 272static void devgroup_check(unsigned int flags) 273{ 274 if (!flags) 275 xtables_error(PARAMETER_PROBLEM, 276 "devgroup match: You must specify either " 277 "'--src-group' or '--dst-group'"); 278} 279 280static struct xtables_match devgroup_mt_reg = { 281 .name = "devgroup", 282 .version = XTABLES_VERSION, 283 .family = NFPROTO_UNSPEC, 284 .size = XT_ALIGN(sizeof(struct xt_devgroup_info)), 285 .userspacesize = XT_ALIGN(sizeof(struct xt_devgroup_info)), 286 .help = devgroup_help, 287 .parse = devgroup_parse, 288 .final_check = devgroup_check, 289 .print = devgroup_print, 290 .save = devgroup_save, 291 .extra_opts = devgroup_opts, 292}; 293 294void _init(void) 295{ 296 xtables_register_match(&devgroup_mt_reg); 297} 298