Git init
[profile/ivi/iptables.git] / extensions / libipt_realm.c
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
17 static void realm_help(void)
18 {
19         printf(
20 "realm match options:\n"
21 "[!] --realm value[/mask]\n"
22 "                               Match realm\n");
23 }
24
25 static const struct option realm_opts[] = {
26         { "realm", 1, NULL, '1' },
27         { .name = NULL }
28 };
29
30 struct 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 */
38 static struct realmname *realms;
39 /* 1 if loading failed */
40 static int rdberr;
41
42 static 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 */
115 static 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 */
133 static 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
150 static 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(optarg, &invert, &optind, 0, argv);
160                 end = optarg = optarg;
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
189 static void
190 print_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
206 static 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
218 static 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
229 static void realm_check(unsigned int flags)
230 {
231         if (!flags)
232                 xtables_error(PARAMETER_PROBLEM,
233                            "realm match: You must specify `--realm'");
234 }
235
236 static 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
250 void _init(void)
251 {
252         xtables_register_match(&realm_mt_reg);
253 }