OpenDNSSEC-signer  1.4.1
acl.c
Go to the documentation of this file.
1 /*
2  * $Id: acl.h 4958 2011-04-18 07:11:09Z matthijs $
3  *
4  * Copyright (c) 2011 NLNet Labs. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
34 #include "config.h"
35 #include "shared/log.h"
36 #include "shared/file.h"
37 #include "shared/status.h"
38 #include "wire/acl.h"
39 
40 static const char* acl_str = "acl";
41 
42 
48 static acl_range_type
49 acl_parse_range_type(char* ip, char** mask)
50 {
51  char *p;
52  if((p=strchr(ip, '&'))!=0) {
53  *p = 0;
54  *mask = p+1;
55  return ACL_RANGE_MASK;
56  }
57  if((p=strchr(ip, '/'))!=0) {
58  *p = 0;
59  *mask = p+1;
60  return ACL_RANGE_SUBNET;
61  }
62  if((p=strchr(ip, '-'))!=0) {
63  *p = 0;
64  *mask = p+1;
65  return ACL_RANGE_MINMAX;
66  }
67  *mask = 0;
68  return ACL_RANGE_SINGLE;
69 }
70 
71 
76 static ods_status
77 acl_parse_range_subnet(char* p, void* addr, int maxbits)
78 {
79  int subnet_bits = atoi(p);
80  uint8_t* addr_bytes = (uint8_t*)addr;
81  if (subnet_bits == 0 && strcmp(p, "0")!=0) {
83  }
84  if (subnet_bits < 0 || subnet_bits > maxbits) {
86  }
87  /* fill addr with n bits of 1s (struct has been zeroed) */
88  while(subnet_bits >= 8) {
89  *addr_bytes++ = 0xff;
90  subnet_bits -= 8;
91  }
92  if(subnet_bits > 0) {
93  uint8_t shifts[] =
94  {0x0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
95  *addr_bytes = shifts[subnet_bits];
96  }
97  return ODS_STATUS_OK;
98 }
99 
100 
105 int
106 acl_parse_family(const char* a)
107 {
108  /* see if addr is ipv6 or ipv4 -- by : and . */
109  while (*a) {
110  if (*a == '.') {
111  return AF_INET;
112  }
113  if (*a == ':') {
114  return AF_INET6;
115  }
116  ++a;
117  }
118  /* default to v4 */
119  return AF_INET;
120 }
121 
122 
127 acl_type*
128 acl_create(allocator_type* allocator, char* address, char* port,
129  char* tsig_name, tsig_type* tsig)
130 {
131  ods_status status = ODS_STATUS_OK;
132  acl_type* acl = NULL;
133  char* p = NULL;
134  if (!allocator) {
135  return NULL;
136  }
137  acl = (acl_type*) allocator_alloc(allocator, sizeof(acl_type));
138  if (!acl) {
139  ods_log_error("[%s] unable to create acl: allocator_alloc() "
140  "failed", acl_str);
141  return NULL;
142  }
143  acl->address = NULL;
144  acl->next = NULL;
145  acl->tsig = NULL;
146  if (tsig_name) {
147  acl->tsig = tsig_lookup_by_name(tsig, tsig_name);
148  if (!acl->tsig) {
149  ods_log_error("[%s] unable to create acl: tsig %s not found",
150  acl_str, tsig_name);
151  acl_cleanup(acl, allocator);
152  return NULL;
153  }
154  }
155  acl->port = 0;
156  if (port) {
157  acl->port = atoi((const char*) port);
158  }
159  memset(&acl->addr, 0, sizeof(union acl_addr_storage));
160  memset(&acl->range_mask, 0, sizeof(union acl_addr_storage));
161  if (address) {
162  acl->family = acl_parse_family(address);
163  acl->range_type = acl_parse_range_type(address, &p);
164  acl->address = allocator_strdup(allocator, address);
165  if (!acl->address) {
166  ods_log_error("[%s] unable to create acl: allocator_strdup() "
167  "failed", acl_str);
168  acl_cleanup(acl, allocator);
169  return NULL;
170  }
171  if (acl->family == AF_INET6) {
172  if (inet_pton(AF_INET6, acl->address, &acl->addr.addr6) != 1) {
173  ods_log_error("[%s] unable to create acl: bad ipv6 address "
174  "(%s)", acl_str, acl->address);
175  acl_cleanup(acl, allocator);
176  return NULL;
177  }
178  if (acl->range_type == ACL_RANGE_MASK ||
179  acl->range_type == ACL_RANGE_MINMAX) {
180  if (inet_pton(AF_INET6, p, &acl->range_mask.addr6) != 1) {
181  ods_log_error("[%s] unable to create acl: bad ipv6 address"
182  " mask (%s)", acl_str, p);
183  acl_cleanup(acl, allocator);
184  return NULL;
185  }
186  } else if (acl->range_type == ACL_RANGE_SUBNET) {
187  status = acl_parse_range_subnet(p, &acl->range_mask.addr6, 128);
188  if (status != ODS_STATUS_OK) {
189  ods_log_error("[%s] unable to create acl: %s (%s)",
190  acl_str, ods_status2str(status), p);
191  acl_cleanup(acl, allocator);
192  return NULL;
193  }
194  }
195  } else if (acl->family == AF_INET) {
196  if (inet_pton(AF_INET, acl->address, &acl->addr.addr) != 1) {
197  ods_log_error("[%s] unable to create acl: bad ipv4 address "
198  "(%s)", acl_str, acl->address);
199  acl_cleanup(acl, allocator);
200  return NULL;
201  }
202  if (acl->range_type == ACL_RANGE_MASK ||
203  acl->range_type == ACL_RANGE_MINMAX) {
204  if (inet_pton(AF_INET, p, &acl->range_mask.addr) != 1) {
205  ods_log_error("[%s] unable to create acl: bad ipv4 address"
206  " mask (%s)", acl_str, p);
207  acl_cleanup(acl, allocator);
208  return NULL;
209  }
210  } else if (acl->range_type == ACL_RANGE_SUBNET) {
211  status = acl_parse_range_subnet(p, &acl->range_mask.addr, 32);
212  if (status != ODS_STATUS_OK) {
213  ods_log_error("[%s] unable to create acl: %s (%s)",
214  acl_str, ods_status2str(status), p);
215  acl_cleanup(acl, allocator);
216  return NULL;
217  }
218  }
219  }
220  }
221  acl->ixfr_disabled = 0;
222  return acl;
223 }
224 
225 
230 static int
231 acl_addr_matches_mask(uint32_t* a, uint32_t* b, uint32_t* mask, size_t sz)
232 {
233  size_t i = 0;
234  ods_log_assert(sz % 4 == 0);
235  sz /= 4;
236  for (i=0; i<sz; ++i) {
237  if (((*a++)&*mask) != ((*b++)&*mask)) {
238  return 0;
239  }
240  ++mask;
241  }
242  return 1;
243 }
244 
249 static int
250 acl_addr_matches_range(uint32_t* minval, uint32_t* x, uint32_t* maxval,
251  size_t sz)
252 {
253  size_t i = 0;
254  uint8_t checkmin = 1;
255  uint8_t checkmax = 1;
256  ods_log_assert(sz % 4 == 0);
257  /* check treats x as one huge number */
258  sz /= 4;
259  for (i=0; i<sz; ++i) {
260  /* if outside bounds, we are done */
261  if (checkmin && minval[i] > x[i]) {
262  return 0;
263  }
264  if (checkmax && maxval[i] < x[i]) {
265  return 0;
266  }
267  /* if x is equal to a bound, that bound needs further checks */
268  if (checkmin && minval[i] != x[i]) {
269  checkmin = 0;
270  }
271  if (checkmax && maxval[i]!=x[i]) {
272  checkmax = 0;
273  }
274  if (!checkmin && !checkmax) {
275  return 1; /* will always match */
276  }
277  }
278  return 1;
279 }
280 
281 
286 static int
287 acl_addr_matches(acl_type* acl, struct sockaddr_storage* addr)
288 {
289  if (!acl) {
290  return 0;
291  }
292  if (!acl->address) {
293  /* all addresses match */
294  return 1;
295  }
296  if (acl->family == AF_INET6) {
297  struct sockaddr_in6* addr6 = (struct sockaddr_in6*) addr;
298  if (addr->ss_family != AF_INET6) {
299  return 0;
300  }
301  if (acl->port != 0 && acl->port != ntohs(addr6->sin6_port)) {
302  return 0;
303  }
304  switch(acl->range_type) {
305  case ACL_RANGE_MASK:
306  case ACL_RANGE_SUBNET:
307  if (!acl_addr_matches_mask((uint32_t*)&acl->addr.addr6,
308  (uint32_t*)&addr6->sin6_addr,
309  (uint32_t*)&acl->range_mask.addr6,
310  sizeof(struct in6_addr))) {
311  return 0;
312  }
313  break;
314  case ACL_RANGE_MINMAX:
315  if (!acl_addr_matches_range((uint32_t*)&acl->addr.addr6,
316  (uint32_t*)&addr6->sin6_addr,
317  (uint32_t*)&acl->range_mask.addr6,
318  sizeof(struct in6_addr))) {
319  return 0;
320  }
321  break;
322  case ACL_RANGE_SINGLE:
323  default:
324  if (memcmp(&addr6->sin6_addr, &acl->addr.addr6,
325  sizeof(struct in6_addr)) != 0) {
326  return 0;
327  }
328  break;
329  }
330  return 1;
331  } else {
332  struct sockaddr_in* addr4 = (struct sockaddr_in*)addr;
333  if (addr4->sin_family != AF_INET) {
334  return 0;
335  }
336  if (acl->port != 0 && acl->port != ntohs(addr4->sin_port)) {
337  return 0;
338  }
339  switch (acl->range_type) {
340  case ACL_RANGE_MASK:
341  case ACL_RANGE_SUBNET:
342  if (!acl_addr_matches_mask((uint32_t*)&acl->addr.addr,
343  (uint32_t*)&addr4->sin_addr,
344  (uint32_t*)&acl->range_mask.addr,
345  sizeof(struct in_addr))) {
346  return 0;
347  }
348  break;
349  case ACL_RANGE_MINMAX:
350  if (!acl_addr_matches_range((uint32_t*)&acl->addr.addr,
351  (uint32_t*)&addr4->sin_addr,
352  (uint32_t*)&acl->range_mask.addr,
353  sizeof(struct in_addr))) {
354  return 0;
355  }
356  break;
357  case ACL_RANGE_SINGLE:
358  default:
359  if (memcmp(&addr4->sin_addr, &acl->addr.addr,
360  sizeof(struct in_addr)) != 0) {
361  return 0;
362  }
363  break;
364  }
365  return 1;
366  }
367  /* not reached */
368  return 0;
369 }
370 
371 
376 static int
377 acl_tsig_matches(acl_type* acl, tsig_rr_type* tsig)
378 {
379  if (!acl || !tsig) {
380  ods_log_debug("[%s] no match: no acl or tsig", acl_str);
381  return 0; /* missing required elements */
382  }
383  if (!acl->tsig) {
384  if (tsig->status == TSIG_NOT_PRESENT) {
385  return 1;
386  }
387  ods_log_debug("[%s] no match: tsig present but no config", acl_str);
388  return 0; /* TSIG present but no config */
389  }
390  if (tsig->status != TSIG_OK) {
391  ods_log_debug("[%s] no match: tsig %s", acl_str,
392  tsig_status2str(tsig->status));
393  return 0; /* query has no TSIG */
394  }
395  if (tsig->error_code != LDNS_RCODE_NOERROR) {
396  ods_log_debug("[%s] no match: tsig error %d", acl_str,
397  tsig->error_code);
398  return 0; /* query has bork TSIG */
399  }
400  if (!tsig->key_name || !tsig->algo) {
401  ods_log_debug("[%s] no match: missing key/algo", acl_str);
402  return 0;
403  }
404  if (!acl->tsig->key) {
405  ods_log_debug("[%s] no match: no config", acl_str);
406  return 0; /* missing TSIG config */
407  }
408  if (ldns_dname_compare(tsig->key_name, acl->tsig->key->dname) != 0) {
409  ods_log_debug("[%s] no match: key names not the same", acl_str);
410  return 0; /* wrong key name */
411  }
412  if (ods_strlowercmp(tsig->algo->txt_name, acl->tsig->algorithm) != 0) {
413  ods_log_debug("[%s] no match: algorithms not the same", acl_str);
414  return 0; /* wrong algorithm name */
415  }
416  /* tsig matches */
417  return 1;
418 }
419 
420 
425 int
426 addr2ip(struct sockaddr_storage addr, char* ip, size_t len)
427 {
428  if (addr.ss_family == AF_INET6) {
429  if (!inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&addr)->sin6_addr,
430  ip, len)) {
431  return 0;
432  }
433  } else {
434  if (!inet_ntop(AF_INET, &((struct sockaddr_in *)&addr)->sin_addr,
435  ip, len))
436  return 0;
437  }
438  return 1;
439 }
440 
441 
446 acl_type*
447 acl_find(acl_type* acl, struct sockaddr_storage* addr, tsig_rr_type* trr)
448 {
449  acl_type* find = acl;
450  while (find) {
451  if (acl_addr_matches(find, addr) && acl_tsig_matches(find, trr)) {
452  ods_log_debug("[%s] match %s", acl_str, find->address);
453  return find;
454  }
455  find = find->next;
456  }
457  return NULL;
458 }
459 
460 
465 void
467 {
468  if (!acl || !allocator) {
469  return;
470  }
471  acl_cleanup(acl->next, allocator);
472  allocator_deallocate(allocator, (void*) acl->address);
473  allocator_deallocate(allocator, (void*) acl);
474  return;
475 }