libipt_realm.c revision bf97128c7262f17a02fec41cdae75b472ba77f88
1/* Shared library add-on to iptables to add realm matching support. */ 2#include <stdio.h> 3#include <netdb.h> 4#include <string.h> 5#include <stdlib.h> 6#include <errno.h> 7#include <ctype.h> 8#include <getopt.h> 9#if defined(__GLIBC__) && __GLIBC__ == 2 10#include <net/ethernet.h> 11#else 12#include <linux/if_ether.h> 13#endif 14#include <xtables.h> 15#include <linux/netfilter_ipv4/ipt_realm.h> 16 17static void realm_help(void) 18{ 19 printf( 20"realm match options:\n" 21"[!] --realm value[/mask]\n" 22" Match realm\n"); 23} 24 25static const struct option realm_opts[] = { 26 { "realm", 1, NULL, '1' }, 27 { .name = NULL } 28}; 29 30struct realmname { 31 int id; 32 char* name; 33 int len; 34 struct realmname* next; 35}; 36 37/* array of realms from /etc/iproute2/rt_realms */ 38static struct realmname *realms; 39/* 1 if loading failed */ 40static int rdberr; 41 42static void load_realms(void) 43{ 44 const char* rfnm = "/etc/iproute2/rt_realms"; 45 char buf[512]; 46 FILE *fil; 47 char *cur, *nxt; 48 int id; 49 struct realmname *oldnm = NULL, *newnm = NULL; 50 51 fil = fopen(rfnm, "r"); 52 if (!fil) { 53 rdberr = 1; 54 return; 55 } 56 57 while (fgets(buf, sizeof(buf), fil)) { 58 cur = buf; 59 while ((*cur == ' ') || (*cur == '\t')) 60 cur++; 61 if ((*cur == '#') || (*cur == '\n') || (*cur == 0)) 62 continue; 63 64 /* iproute2 allows hex and dec format */ 65 errno = 0; 66 id = strtoul(cur, &nxt, strncmp(cur, "0x", 2) ? 10 : 16); 67 if ((nxt == cur) || errno) 68 continue; 69 70 /* same boundaries as in iproute2 */ 71 if (id < 0 || id > 255) 72 continue; 73 cur = nxt; 74 75 if (!isspace(*cur)) 76 continue; 77 while ((*cur == ' ') || (*cur == '\t')) 78 cur++; 79 if ((*cur == '#') || (*cur == '\n') || (*cur == 0)) 80 continue; 81 nxt = cur; 82 while ((*nxt != 0) && !isspace(*nxt)) 83 nxt++; 84 if (nxt == cur) 85 continue; 86 87 /* found valid data */ 88 newnm = malloc(sizeof(struct realmname)); 89 if (newnm == NULL) { 90 perror("libipt_realm: malloc failed"); 91 exit(1); 92 } 93 newnm->id = id; 94 newnm->len = nxt - cur; 95 newnm->name = malloc(newnm->len + 1); 96 if (newnm->name == NULL) { 97 perror("libipt_realm: malloc failed"); 98 exit(1); 99 } 100 strncpy(newnm->name, cur, newnm->len); 101 newnm->name[newnm->len] = 0; 102 newnm->next = NULL; 103 104 if (oldnm) 105 oldnm->next = newnm; 106 else 107 realms = newnm; 108 oldnm = newnm; 109 } 110 111 fclose(fil); 112} 113 114/* get realm id for name, -1 if error/not found */ 115static int realm_name2id(const char* name) 116{ 117 struct realmname* cur; 118 119 if ((realms == NULL) && (rdberr == 0)) 120 load_realms(); 121 cur = realms; 122 if (cur == NULL) 123 return -1; 124 while (cur) { 125 if (!strncmp(name, cur->name, cur->len + 1)) 126 return cur->id; 127 cur = cur->next; 128 } 129 return -1; 130} 131 132/* get realm name for id, NULL if error/not found */ 133static const char *realm_id2name(int id) 134{ 135 struct realmname* cur; 136 137 if ((realms == NULL) && (rdberr == 0)) 138 load_realms(); 139 cur = realms; 140 if (cur == NULL) 141 return NULL; 142 while (cur) { 143 if (id == cur->id) 144 return cur->name; 145 cur = cur->next; 146 } 147 return NULL; 148} 149 150static int realm_parse(int c, char **argv, int invert, unsigned int *flags, 151 const void *entry, struct xt_entry_match **match) 152{ 153 struct ipt_realm_info *realminfo = (struct ipt_realm_info *)(*match)->data; 154 int id; 155 156 switch (c) { 157 char *end; 158 case '1': 159 xtables_check_inverse(argv[optind-1], &invert, &optind, 0, argv); 160 end = optarg = argv[optind-1]; 161 realminfo->id = strtoul(optarg, &end, 0); 162 if (end != optarg && (*end == '/' || *end == '\0')) { 163 if (*end == '/') 164 realminfo->mask = strtoul(end+1, &end, 0); 165 else 166 realminfo->mask = 0xffffffff; 167 if (*end != '\0' || end == optarg) 168 xtables_error(PARAMETER_PROBLEM, 169 "Bad realm value `%s'", optarg); 170 } else { 171 id = realm_name2id(optarg); 172 if (id == -1) 173 xtables_error(PARAMETER_PROBLEM, 174 "Realm `%s' not found", optarg); 175 realminfo->id = id; 176 realminfo->mask = 0xffffffff; 177 } 178 if (invert) 179 realminfo->invert = 1; 180 *flags = 1; 181 break; 182 183 default: 184 return 0; 185 } 186 return 1; 187} 188 189static void 190print_realm(unsigned long id, unsigned long mask, int numeric) 191{ 192 const char* name = NULL; 193 194 if (mask != 0xffffffff) 195 printf("0x%lx/0x%lx ", id, mask); 196 else { 197 if (numeric == 0) 198 name = realm_id2name(id); 199 if (name) 200 printf("%s ", name); 201 else 202 printf("0x%lx ", id); 203 } 204} 205 206static void realm_print(const void *ip, const struct xt_entry_match *match, 207 int numeric) 208{ 209 const struct ipt_realm_info *ri = (const void *)match->data; 210 211 if (ri->invert) 212 printf("! "); 213 214 printf("realm "); 215 print_realm(ri->id, ri->mask, numeric); 216} 217 218static void realm_save(const void *ip, const struct xt_entry_match *match) 219{ 220 const struct ipt_realm_info *ri = (const void *)match->data; 221 222 if (ri->invert) 223 printf("! "); 224 225 printf("--realm "); 226 print_realm(ri->id, ri->mask, 0); 227} 228 229static void realm_check(unsigned int flags) 230{ 231 if (!flags) 232 xtables_error(PARAMETER_PROBLEM, 233 "realm match: You must specify `--realm'"); 234} 235 236static struct xtables_match realm_mt_reg = { 237 .name = "realm", 238 .version = XTABLES_VERSION, 239 .family = NFPROTO_IPV4, 240 .size = XT_ALIGN(sizeof(struct ipt_realm_info)), 241 .userspacesize = XT_ALIGN(sizeof(struct ipt_realm_info)), 242 .help = realm_help, 243 .parse = realm_parse, 244 .final_check = realm_check, 245 .print = realm_print, 246 .save = realm_save, 247 .extra_opts = realm_opts, 248}; 249 250void _init(void) 251{ 252 xtables_register_match(&realm_mt_reg); 253} 254