Blob


1 /*
2 * Copyright (c) 2014 Peter J. Philipp
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
29 /*
30 * this file is based on filter.c
31 */
33 #include "include.h"
34 #include "dns.h"
35 #include "db.h"
37 int find_whitelist(struct sockaddr_storage *, int);
38 void init_whitelist(void);
39 int insert_whitelist(char *, char *);
41 extern void dolog(int, char *, ...);
42 extern in_addr_t getmask(int);
43 extern int getmask6(int, struct sockaddr_in6 *);
45 extern int debug, verbose;
47 int whitelist = 0; /* whitelist is off by default */
49 SLIST_HEAD(listhead, whitelistentry) whitelisthead;
51 static struct whitelistentry {
52 char name[INET6_ADDRSTRLEN];
53 int family;
54 struct sockaddr_storage hostmask;
55 struct sockaddr_storage netmask;
56 u_int8_t prefixlen;
57 SLIST_ENTRY(whitelistentry) whitelist_entry;
58 } *wln2, *wlnp;
61 static const char rcsid[] = "$Id: whitelist.c,v 1.1 2014/05/18 18:47:54 pjp Exp $";
63 /*
64 * INIT_FILTER - initialize the whitelist singly linked list
65 */
67 void
68 init_whitelist(void)
69 {
70 SLIST_INIT(&whitelisthead);
71 return;
72 }
74 /*
75 * INSERT_FILTER - insert an address and prefixlen into the whitelist slist
76 */
78 int
79 insert_whitelist(char *address, char *prefixlen)
80 {
81 struct sockaddr_in *sin;
82 struct sockaddr_in6 *sin6;
83 int pnum;
84 int ret;
86 pnum = atoi(prefixlen);
87 wln2 = malloc(sizeof(struct whitelistentry)); /* Insert after. */
89 if (strchr(address, ':') != NULL) {
90 wln2->family = AF_INET6;
91 sin6 = (struct sockaddr_in6 *)&wln2->hostmask;
92 if ((ret = inet_pton(AF_INET6, address, &sin6->sin6_addr.s6_addr)) != 1)
93 return (-1);
94 sin6->sin6_family = AF_INET6;
95 sin6 = (struct sockaddr_in6 *)&wln2->netmask;
96 sin6->sin6_family = AF_INET6;
97 if (getmask6(pnum, sin6) < 0)
98 return(-1);
99 wln2->prefixlen = pnum;
100 } else {
102 wln2->family = AF_INET;
103 sin = (struct sockaddr_in *)&wln2->hostmask;
104 sin->sin_family = AF_INET;
105 sin->sin_addr.s_addr = inet_addr(address);
106 sin = (struct sockaddr_in *)&wln2->netmask;
107 sin->sin_family = AF_INET;
108 sin->sin_addr.s_addr = getmask(pnum);
109 wln2->prefixlen = pnum;
113 SLIST_INSERT_HEAD(&whitelisthead, wln2, whitelist_entry);
115 return (0);
118 /*
119 * FIND_FILTER - walk the whitelist list and find the correponding network
120 * if a network matches return 1, if no match is found return
121 * 0.
122 */
124 int
125 find_whitelist(struct sockaddr_storage *sst, int family)
127 struct sockaddr_in *sin, *sin0;
128 struct sockaddr_in6 *sin6, *sin60, *sin61;
129 u_int32_t hostmask, netmask;
130 u_int32_t a;
131 #ifdef __amd64
132 u_int64_t *hm[2], *nm[2], *a6[2];
133 #else
134 u_int32_t *hm[4], *nm[4], *a6[4];
135 #endif
137 SLIST_FOREACH(wlnp, &whitelisthead, whitelist_entry) {
138 if (wlnp->family == AF_INET) {
139 if (family != AF_INET)
140 continue;
141 sin = (struct sockaddr_in *)sst;
142 a = sin->sin_addr.s_addr;
143 sin = (struct sockaddr_in *)&wlnp->hostmask;
144 sin0 = (struct sockaddr_in *)&wlnp->netmask;
145 hostmask = sin->sin_addr.s_addr;
146 netmask = sin0->sin_addr.s_addr;
147 if ((hostmask & netmask) == (a & netmask)) {
148 return (1);
149 } /* if hostmask */
150 } else if (wlnp->family == AF_INET6) {
151 if (family != AF_INET6)
152 continue;
153 sin6 = (struct sockaddr_in6 *)sst;
154 sin60 = (struct sockaddr_in6 *)&wlnp->hostmask;
155 sin61 = (struct sockaddr_in6 *)&wlnp->netmask;
156 #ifdef __amd64
157 /*
158 * If this is on a 64 bit machine, we'll benefit
159 * by using 64 bit registers, this should make it
160 * a tad faster...
161 */
162 hm[0] = (u_int64_t *)&sin60->sin6_addr.s6_addr;
163 hm[1] = (hm[0] + 1);
164 nm[0] = (u_int64_t *)&sin61->sin6_addr.s6_addr;
165 nm[1] = (nm[0] + 1);
166 a6[0] = (u_int64_t *)&sin6->sin6_addr.s6_addr;
167 a6[1] = (a6[0] + 1);
168 if ( ((*hm[0] & *nm[0]) == (*a6[0] & *nm[0]))&&
169 ((*hm[1] & *nm[1]) == (*a6[1] & *nm[1]))) {
170 #else
171 hm[0] = (u_int32_t *)&sin60->sin6_addr.s6_addr;
172 hm[1] = (hm[0] + 1); hm[2] = (hm[1] + 1);
173 hm[3] = (hm[2] + 1);
174 nm[0] = (u_int32_t *)&sin61->sin6_addr.s6_addr;
175 nm[1] = (nm[0] + 1); nm[2] = (nm[1] + 1);
176 nm[3] = (nm[2] + 1);
177 a6[0] = (u_int32_t *)&sin6->sin6_addr.s6_addr;
178 a6[1] = (a6[0] + 1); a6[2] = (a6[1] + 1);
179 a6[3] = (a6[2] + 1);
181 if ( ((*hm[0] & *nm[0]) == (*a6[0] & *nm[0]))&&
182 ((*hm[1] & *nm[1]) == (*a6[1] & *nm[1]))&&
183 ((*hm[2] & *nm[2]) == (*a6[2] & *nm[2]))&&
184 ((*hm[3] & *nm[3]) == (*a6[3] & *nm[3]))) {
185 #endif
187 return (1);
188 } /* if ip6 address */
190 } /* if AF_INET6 */
191 } /* SLIST */
193 return (0);