1
2 /*
3 * ACL matching
4 *
5 * (c) Tomi Manninen <tomi.manninen@hut.fi>
6 * (c) Heikki Hannikainen
7 *
8 */
9
10 #include <string.h>
11 #include <netdb.h>
12 #include <stdio.h>
13 #include <errno.h>
14 #include <netinet/in.h>
15 #include <arpa/inet.h>
16
17 #include "hmalloc.h"
18 #include "acl.h"
19 #include "worker.h"
20 #include "hlog.h"
21 #include "cfgfile.h"
22
23 /*
24 * allocate an empty acl structure
25 */
26
acl_new(void)27 struct acl_t *acl_new(void)
28 {
29 struct acl_t *a;
30
31 a = hmalloc(sizeof(struct acl_t));
32
33 a->entries4 = NULL;
34 a->entries6 = NULL;
35
36 return a;
37 }
38
acl_free(struct acl_t * acl)39 void acl_free(struct acl_t *acl)
40 {
41 struct acl_e4_t *e4;
42 struct acl_e6_t *e6;
43
44 while (acl->entries4) {
45 e4 = acl->entries4->next;
46 hfree(acl->entries4);
47 acl->entries4 = e4;
48 }
49
50 while (acl->entries6) {
51 e6 = acl->entries6->next;
52 hfree(acl->entries6);
53 acl->entries6 = e6;
54 }
55
56 hfree(acl);
57 }
58
acl_dup(struct acl_t * acl)59 struct acl_t *acl_dup(struct acl_t *acl)
60 {
61 struct acl_e4_t *e4, *ne4;
62 struct acl_e6_t *e6, *ne6;
63 struct acl_t *a = acl_new();
64
65 for (e4 = acl->entries4; (e4); e4 = e4->next) {
66 ne4 = hmalloc(sizeof(*ne4));
67 memcpy(ne4, e4, sizeof(*ne4));
68 ne4->next = a->entries4;
69 a->entries4 = ne4;
70 }
71
72 for (e6 = acl->entries6; (e6); e6 = e6->next) {
73 ne6 = hmalloc(sizeof(*ne6));
74 memcpy(ne6, e6, sizeof(*ne6));
75 ne6->next = a->entries6;
76 a->entries6 = ne6;
77 }
78
79 return a;
80 }
81
82 /*
83 * Add an entry to the ACL
84 */
85
acl_add(struct acl_t * acl,char * netspec,int allow)86 int acl_add(struct acl_t *acl, char *netspec, int allow)
87 {
88 int prefixlen = 128;
89 char *prefixls;
90 struct addrinfo req, *ai, *nextai;
91 int i;
92 char dummyservice[] = "12345";
93 struct acl_e4_t *e4;
94 struct acl_e6_t *e6;
95 char *addr_s;
96 union sockaddr_u *sup;
97
98 prefixls = strchr(netspec, '/');
99 if (prefixls) {
100 // has netmask or prefix length
101 *prefixls = 0;
102 prefixls++;
103 }
104
105 // prepare for getaddrinfo
106 memset(&req, 0, sizeof(req));
107 req.ai_family = 0;
108 req.ai_socktype = SOCK_STREAM;
109 req.ai_protocol = IPPROTO_TCP;
110 req.ai_flags = 0;
111 ai = NULL;
112
113 // resolve the name
114 i = getaddrinfo(netspec, dummyservice, &req, &ai);
115 if (i != 0) {
116 hlog(LOG_ERR, "ACL: address parse failure of '%s': %s", netspec, gai_strerror(i));
117 return -1;
118 }
119
120 // parse the prefix length
121 if (prefixls) {
122 prefixlen = atoi(prefixls);
123 if (prefixlen < 0 || prefixlen > 128) {
124 hlog(LOG_ERR, "ACL: invalid prefix len '%s' for '%s'", prefixls, netspec);
125 if (ai)
126 freeaddrinfo(ai);
127 return -1;
128 }
129 }
130
131 while (ai) {
132 nextai = ai->ai_next;
133 addr_s = strsockaddr( ai->ai_addr, ai->ai_addrlen );
134 sup = (union sockaddr_u *)ai->ai_addr;
135
136 if (ai->ai_family == AF_INET6) {
137 //hlog(LOG_DEBUG, "ACL: Adding IPv6: %s/%d: %s/%d", netspec, prefixlen, addr_s, prefixlen);
138
139 e6 = hmalloc(sizeof(*e6));
140 e6->next = acl->entries6;
141 acl->entries6 = e6;
142 e6->allow = allow;
143
144 memcpy(e6->addr, sup->si6.sin6_addr.s6_addr, sizeof(e6->addr));
145 e6->prefixlen = prefixlen;
146 if (prefixlen == 128) {
147 memset(e6->mask, 0xff, 16);
148 } else {
149 memset(e6->mask, 0, 16);
150 uint32_t shift = prefixlen;
151 uint32_t s;
152
153 for (i = 0; i < 4; i++) {
154 s = (shift > 32) ? 32 : shift;
155 shift -= s;
156
157 e6->mask[i] = htonl(0UL - (1UL << (32UL - s)));
158 /* mask the address wih the mask so that no host bits are set */
159 e6->addr[i] = e6->addr[i] & e6->mask[i];
160 }
161 }
162
163 } else if (ai->ai_family == AF_INET) {
164 if (prefixlen > 32)
165 prefixlen = 32;
166
167 //hlog(LOG_DEBUG, "ACL: Adding IPv4: %s/%d", netspec, prefixlen);
168
169 e4 = hmalloc(sizeof(*e4));
170 e4->next = acl->entries4;
171 acl->entries4 = e4;
172 e4->allow = allow;
173
174 e4->addr = ntohl(sup->si.sin_addr.s_addr);
175 e4->mask = 0;
176 for (i = 0; i < prefixlen; i++) {
177 e4->mask = e4->mask >> 1;
178 e4->mask |= 1<<31;
179 }
180 e4->addr = e4->addr & e4->mask;
181 }
182
183 hfree(addr_s);
184 freeaddrinfo(ai);
185 ai = nextai;
186 }
187
188 return 0;
189 }
190
191 #define ACL_LINEBUF 1024
192
acl_load(char * s)193 struct acl_t *acl_load(char *s)
194 {
195 struct acl_t *acl;
196 FILE *fp;
197 char buf[ACL_LINEBUF];
198 char *eol;
199 char *argv[256];
200 int argc;
201 int failed = 0;
202 int line = 0;
203
204 //hlog(LOG_DEBUG, "ACL: Loading ACL file \"%s\"", s);
205
206 fp = fopen(s, "r");
207 if (!fp) {
208 hlog(LOG_ERR, "ACL load failed: Could not open \"%s\" for reading: %s", s, strerror(errno));
209 return NULL;
210 }
211
212 acl = acl_new();
213
214 while (fgets(buf, ACL_LINEBUF, fp)) {
215 line++;
216 // strip newlines
217 eol = strchr(buf, '\r');
218 if (eol)
219 *eol = 0;
220 eol = strchr(buf, '\n');
221 if (eol)
222 *eol = 0;
223
224 // strip comments
225 eol = strchr(buf, '#');
226 if (eol)
227 *eol = 0;
228
229 // skip empty lines
230 if (strlen(buf) == 0)
231 continue;
232
233 argc = parse_args(argv, buf);
234 if (argc != 2) {
235 hlog(LOG_ERR, "ACL load failed: %s: invalid number of arguments on line %d", s, line);
236 failed = 1;
237 }
238
239 int allow = 0;
240 if (strcasecmp(argv[0], "allow") == 0)
241 allow = 1;
242 else if (strcasecmp(argv[0], "deny") == 0)
243 allow = 0;
244 else {
245 hlog(LOG_ERR, "ACL load failed: %s: invalid command on line %d: %s", s, line, argv[0]);
246 failed = 1;
247 continue;
248 }
249
250 if (acl_add(acl, argv[1], allow)) {
251 hlog(LOG_ERR, "ACL load failed: %s: invalid netspec on line %d: %s", s, line, argv[1]);
252 failed = 1;
253 }
254 }
255
256 if (fclose(fp)) {
257 hlog(LOG_ERR, "ACL load failed: close(%s): %s", s, strerror(errno));
258 failed = 1;
259 }
260
261 if (failed) {
262 acl_free(acl);
263 return NULL;
264 }
265
266 return acl;
267 }
268
269 /*
270 * Match an IPv4 address agaist the ACL list
271 */
272
acl_check_4(struct acl_t * acl,uint32_t addr)273 static int acl_check_4(struct acl_t *acl, uint32_t addr)
274 {
275 struct acl_e4_t *a = acl->entries4;
276
277 while (a) {
278 if ((addr & a->mask) == a->addr)
279 return a->allow;
280 a = a->next;
281 }
282
283 return 0;
284 }
285
286 /*
287 * Match an IPv6 address agaist the ACL list
288 */
289
acl_check_6(struct acl_t * acl,uint32_t addr[4])290 static int acl_check_6(struct acl_t *acl, uint32_t addr[4])
291 {
292 struct acl_e6_t *a = acl->entries6;
293 int i;
294
295 //hlog(LOG_DEBUG, "acl_check_6");
296
297 while (a) {
298 int fail = 0;
299 for (i = 0; i < 4 && !fail; i++) {
300 if ((addr[i] & a->mask[i]) != a->addr[i]) {
301 fail = 1;
302 }
303 }
304
305 if (!fail) {
306 return a->allow;
307 }
308
309 a = a->next;
310 }
311
312 // Disallow by default
313 return 0;
314 }
315
316 /*
317 * Match a sockaddr against the ACL
318 */
319
acl_check(struct acl_t * acl,struct sockaddr * sa,int addr_len)320 int acl_check(struct acl_t *acl, struct sockaddr *sa, int addr_len)
321 {
322 union sockaddr_u su, *sup;
323 sup = (union sockaddr_u *)sa;
324
325 /* When we're listening on [::] address, IPv4 connections will be
326 * accepted too. The IPv4 source address will be given to mapped
327 * to an IPv6 address. Here, we map that back to an IPv4 address.
328 */
329 #ifdef IN6_IS_ADDR_V4MAPPED
330 if ( sa->sa_family == AF_INET6 &&
331 ( IN6_IS_ADDR_V4MAPPED(&(sup->si6.sin6_addr)) ||
332 IN6_IS_ADDR_V4COMPAT(&(sup->si6.sin6_addr)) ) ) {
333
334 memset(&su, 0, sizeof(su));
335 su.si.sin_family = AF_INET;
336 su.si.sin_port = sup->si6.sin6_port;
337 memcpy(& su.si.sin_addr, &((uint32_t*)(&(sup->si6.sin6_addr)))[3], 4);
338 sa = &su.sa;
339 sup = (union sockaddr_u *)sa;
340 // hlog(LOG_DEBUG, "Translating v4 mapped/compat address..");
341 }
342 #endif
343
344
345 if (sup->sa.sa_family == AF_INET)
346 return acl_check_4(acl, ntohl(sup->si.sin_addr.s_addr));
347 if (sup->sa.sa_family == AF_INET6)
348 return acl_check_6(acl, (uint32_t *)sup->si6.sin6_addr.s6_addr);
349
350 hlog(LOG_ERR, "acl_check failed: unknown address family or address length (family %d, length %d)", sup->sa.sa_family, addr_len);
351
352 return 0; // Disallow by default: unknown address family
353 }
354
355