2 * These are ACL routines for the main module of CNTLM
4 * CNTLM is free software; you can redistribute it and/or modify it under the
5 * terms of the GNU General Public License as published by the Free Software
6 * Foundation; either version 2 of the License, or (at your option) any later
9 * CNTLM is distributed in the hope that it will be useful, but WITHOUT ANY
10 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
16 * St, Fifth Floor, Boston, MA 02110-1301, USA.
18 * Copyright (c) 2007 David Kubicek
22 #include <sys/types.h>
23 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
35 * TODO: retest ACLs on big-endian
39 * Add the rule spec to the ACL list.
41 int acl_add(plist_t
*rules
, char *spec
, enum acl_t acl
) {
42 struct in_addr source
;
51 aux
= (network_t
*)new(sizeof(network_t
));
52 i
= strcspn(spec
, "/");
53 if (i
< strlen(spec
)) {
55 mask
= strtol(spec
+i
+1, &tmp
, 10);
56 if (mask
< 0 || mask
> 32 || spec
[i
+1] == 0 || *tmp
!= 0) {
57 syslog(LOG_ERR
, "ACL netmask for %s is invalid\n", spec
);
64 if (!strcmp("*", spec
)) {
68 if (!strcmp("0", spec
)) {
70 } else if (!so_resolv(&source
, spec
)) {
71 syslog(LOG_ERR
, "ACL source address %s is invalid\n", spec
);
78 aux
->ip
= source
.s_addr
;
80 mask
= swap32(~(((uint64_t)1 << (32-mask
)) - 1));
81 if ((source
.s_addr
& mask
) != source
.s_addr
)
82 syslog(LOG_WARNING
, "Subnet definition might be incorrect: %s/%d\n", inet_ntoa(source
), aux
->mask
);
84 syslog(LOG_INFO
, "New ACL rule: %s %s/%d\n", (acl
== ACL_ALLOW
? "allow" : "deny"), inet_ntoa(source
), aux
->mask
);
85 *rules
= plist_add(*rules
, acl
, (char *)aux
);
92 * Takes client IP address (network order) and walks the
93 * ACL rules until a match is found, returning ACL_ALLOW
94 * or ACL_DENY accordingly. If no rule matches, connection
95 * is allowed (such is the case with no ACLs).
97 * Proper policy should always end with a default rule,
98 * targetting either "*" or "0/0" to explicitly express
101 enum acl_t
acl_check(plist_t rules
, struct in_addr naddr
) {
106 aux
= (network_t
*)rules
->aux
;
107 mask
= swap32(~(((uint64_t)1 << (32-aux
->mask
)) - 1));
109 if ((naddr
.s_addr
& mask
) == (aux
->ip
& mask
))