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