1*6d9ddefdSjmc /* $OpenBSD: sdl.c,v 1.25 2022/12/26 20:06:43 jmc Exp $ */
284d82a5fSderaadt
3461ebb7fSbeck /*
4af63bb60Sbeck * Copyright (c) 2003-2007 Bob Beck. All rights reserved.
5461ebb7fSbeck *
6af63bb60Sbeck * Permission to use, copy, modify, and distribute this software for any
7af63bb60Sbeck * purpose with or without fee is hereby granted, provided that the above
8af63bb60Sbeck * copyright notice and this permission notice appear in all copies.
9461ebb7fSbeck *
10af63bb60Sbeck * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11af63bb60Sbeck * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12af63bb60Sbeck * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13af63bb60Sbeck * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14af63bb60Sbeck * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15af63bb60Sbeck * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16af63bb60Sbeck * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17461ebb7fSbeck */
18461ebb7fSbeck
19461ebb7fSbeck /*
20461ebb7fSbeck * sdl.c - Implement spamd source lists
21461ebb7fSbeck *
22461ebb7fSbeck * This consists of everything we need to do to determine which lists
23461ebb7fSbeck * someone is on. Spamd gets the connecting address, and looks it up
24461ebb7fSbeck * against all lists to determine what deferral messages to feed back
25461ebb7fSbeck * to the connecting machine. - The redirection to spamd will happen
260f849a0cSreyk * from pf in the kernel, first match will divert to us. Spamd (along with
27461ebb7fSbeck * setup) must keep track of *all* matches, so as to tell someone all the
28461ebb7fSbeck * lists that they are on.
29461ebb7fSbeck */
30461ebb7fSbeck
31461ebb7fSbeck #include <sys/types.h>
32461ebb7fSbeck #include <sys/socket.h>
33461ebb7fSbeck #include <netinet/in.h>
34461ebb7fSbeck #include <arpa/inet.h>
35461ebb7fSbeck #include <errno.h>
36461ebb7fSbeck #include <stdio.h>
37461ebb7fSbeck #include <stdlib.h>
38461ebb7fSbeck #include <string.h>
39461ebb7fSbeck #include "sdl.h"
40461ebb7fSbeck
41ae3f7e48Scloder static void sdl_free(struct sdlist *);
42ae3f7e48Scloder static void sdl_clear(struct sdlist *);
43ae3f7e48Scloder
44461ebb7fSbeck extern int debug;
45461ebb7fSbeck struct sdlist *blacklists = NULL;
46461ebb7fSbeck int blc = 0, blu = 0;
47461ebb7fSbeck
48b1aaf36bSmillert static int
compar_v4(const void * va,const void * vb)49b1aaf36bSmillert compar_v4(const void *va, const void *vb)
50b1aaf36bSmillert {
51b1aaf36bSmillert const struct sdentry_v4 *a = va;
52b1aaf36bSmillert const struct sdentry_v4 *b = vb;
53b1aaf36bSmillert struct in_addr aa;
54b1aaf36bSmillert struct in_addr bb;
55b1aaf36bSmillert
56b1aaf36bSmillert /* The mask has already been applied. */
57b1aaf36bSmillert aa.s_addr = ntohl(a->sda.s_addr);
58b1aaf36bSmillert bb.s_addr = ntohl(b->sda.s_addr);
59b1aaf36bSmillert
60b1aaf36bSmillert if (aa.s_addr > bb.s_addr)
61b1aaf36bSmillert return (1);
62b1aaf36bSmillert if (aa.s_addr < bb.s_addr)
63b1aaf36bSmillert return (-1);
64b1aaf36bSmillert return (0);
65b1aaf36bSmillert }
66b1aaf36bSmillert
67b1aaf36bSmillert static int
compar_v6(const void * va,const void * vb)68b1aaf36bSmillert compar_v6(const void *va, const void *vb)
69b1aaf36bSmillert {
70b1aaf36bSmillert const struct sdentry_v6 *a = va;
71b1aaf36bSmillert const struct sdentry_v6 *b = vb;
72b1aaf36bSmillert struct sdaddr_v6 aa;
73b1aaf36bSmillert struct sdaddr_v6 bb;
74b1aaf36bSmillert
75b1aaf36bSmillert /* The mask has already been applied. */
76b1aaf36bSmillert aa.addr32[0] = ntohl(a->sda.addr32[0]);
77b1aaf36bSmillert aa.addr32[1] = ntohl(a->sda.addr32[1]);
78b1aaf36bSmillert aa.addr32[2] = ntohl(a->sda.addr32[2]);
79b1aaf36bSmillert aa.addr32[3] = ntohl(a->sda.addr32[3]);
80b1aaf36bSmillert
81b1aaf36bSmillert bb.addr32[0] = ntohl(b->sda.addr32[0]);
82b1aaf36bSmillert bb.addr32[1] = ntohl(b->sda.addr32[1]);
83b1aaf36bSmillert bb.addr32[2] = ntohl(b->sda.addr32[2]);
84b1aaf36bSmillert bb.addr32[3] = ntohl(b->sda.addr32[3]);
85b1aaf36bSmillert
86b1aaf36bSmillert if (aa.addr32[0] > bb.addr32[0])
87b1aaf36bSmillert return (1);
88b1aaf36bSmillert if (aa.addr32[0] < bb.addr32[0])
89b1aaf36bSmillert return (-1);
90b1aaf36bSmillert if (aa.addr32[1] > bb.addr32[1])
91b1aaf36bSmillert return (1);
92b1aaf36bSmillert if (aa.addr32[1] < bb.addr32[1])
93b1aaf36bSmillert return (-1);
94b1aaf36bSmillert if (aa.addr32[2] > bb.addr32[2])
95b1aaf36bSmillert return (1);
96b1aaf36bSmillert if (aa.addr32[2] < bb.addr32[2])
97b1aaf36bSmillert return (-1);
98b1aaf36bSmillert if (aa.addr32[3] > bb.addr32[3])
99b1aaf36bSmillert return (1);
100b1aaf36bSmillert if (aa.addr32[3] < bb.addr32[3])
101b1aaf36bSmillert return (-1);
102b1aaf36bSmillert return (0);
103b1aaf36bSmillert }
104b1aaf36bSmillert
105461ebb7fSbeck int
sdl_add(char * sdname,char * sdstring,char ** v4,u_int nv4,char ** v6,u_int nv6)106694ff69bSmillert sdl_add(char *sdname, char *sdstring, char **v4, u_int nv4, char **v6, u_int nv6)
107461ebb7fSbeck {
10882acdfc5Sderaadt int i, idx = -1;
109461ebb7fSbeck char astring[40];
110694ff69bSmillert char *addr = NULL;
111461ebb7fSbeck unsigned int maskbits;
112461ebb7fSbeck
113461ebb7fSbeck /*
114461ebb7fSbeck * if a blacklist of same tag name is already there, replace it,
115461ebb7fSbeck * otherwise append.
116461ebb7fSbeck */
117ae3f7e48Scloder for (i = 0; i < blu; i++) {
118ae3f7e48Scloder if (strcmp(blacklists[i].tag, sdname) == 0) {
11982acdfc5Sderaadt idx = i;
120ae3f7e48Scloder break;
121ae3f7e48Scloder }
122ae3f7e48Scloder }
12382acdfc5Sderaadt if (idx != -1) {
124461ebb7fSbeck if (debug > 0)
125694ff69bSmillert printf("replacing list %s; %u new entries\n",
126694ff69bSmillert blacklists[idx].tag, nv4 + nv6);
12782acdfc5Sderaadt sdl_free(&blacklists[idx]);
128461ebb7fSbeck } else {
129461ebb7fSbeck if (debug > 0)
130694ff69bSmillert printf("adding list %s; %u entries\n", sdname, nv4 + nv6);
131b49d95e6Smillert if (blu == blc) {
132461ebb7fSbeck struct sdlist *tmp;
133e764c767Sderaadt
13425f35012Sdoug tmp = reallocarray(blacklists, blc + 128,
135461ebb7fSbeck sizeof(struct sdlist));
136461ebb7fSbeck if (tmp == NULL)
137461ebb7fSbeck return (-1);
138461ebb7fSbeck blacklists = tmp;
139461ebb7fSbeck blc += 128;
140b49d95e6Smillert sdl_clear(&blacklists[blu]);
141b49d95e6Smillert }
142b49d95e6Smillert idx = blu;
143461ebb7fSbeck }
144ae3f7e48Scloder
14582acdfc5Sderaadt if ((blacklists[idx].tag = strdup(sdname)) == NULL)
146ae3f7e48Scloder goto misc_error;
14782acdfc5Sderaadt if ((blacklists[idx].string = strdup(sdstring)) == NULL)
148ae3f7e48Scloder goto misc_error;
149ae3f7e48Scloder
150cffe49deSderaadt /*
151694ff69bSmillert * Cycle through addrs by family, converting. We assume they are
152694ff69bSmillert * correctly formatted v4 and v6 addrs, if they don't all convert
153694ff69bSmillert * correctly, the add fails. Each address should be address/maskbits.
154461ebb7fSbeck */
155694ff69bSmillert if (nv4 != 0) {
156694ff69bSmillert blacklists[idx].v4.naddrs = nv4;
157694ff69bSmillert blacklists[idx].v4.addrs = reallocarray(NULL, nv4,
158694ff69bSmillert sizeof(struct sdentry_v4));
159694ff69bSmillert if (blacklists[idx].v4.addrs == NULL)
160ae3f7e48Scloder goto misc_error;
161694ff69bSmillert for (i = 0; i < nv4; i++) {
162694ff69bSmillert struct in_addr *m, *n;
163694ff69bSmillert int j;
164461ebb7fSbeck
165694ff69bSmillert n = &blacklists[idx].v4.addrs[i].sda;
166694ff69bSmillert m = &blacklists[idx].v4.addrs[i].sdm;
167cffe49deSderaadt
168694ff69bSmillert addr = v4[i];
169694ff69bSmillert j = sscanf(addr, "%15[^/]/%u", astring, &maskbits);
170461ebb7fSbeck if (j != 2)
171461ebb7fSbeck goto parse_error;
172cffe49deSderaadt /*
173cffe49deSderaadt * sanity check! we don't allow a 0 mask -
174461ebb7fSbeck * don't blacklist the entire net.
175461ebb7fSbeck */
176694ff69bSmillert if (maskbits == 0 || maskbits > 32)
177461ebb7fSbeck goto parse_error;
178694ff69bSmillert j = inet_pton(AF_INET, astring, n);
179694ff69bSmillert if (j != 1)
180461ebb7fSbeck goto parse_error;
181694ff69bSmillert if (debug > 0)
182694ff69bSmillert printf("added %s/%u\n", astring, maskbits);
183694ff69bSmillert
184694ff69bSmillert /* set mask. */
185694ff69bSmillert m->s_addr = 0xffffffffU << (32 - maskbits);
186694ff69bSmillert m->s_addr = htonl(m->s_addr);
187694ff69bSmillert
188694ff69bSmillert /* mask off address bits that won't ever be used */
189694ff69bSmillert n->s_addr = n->s_addr & m->s_addr;
190694ff69bSmillert }
191b1aaf36bSmillert /* spamd-setup output is sorted in host byte order */
192b1aaf36bSmillert mergesort(blacklists[idx].v4.addrs, nv4,
193b1aaf36bSmillert sizeof(struct sdentry_v4), compar_v4);
194694ff69bSmillert }
195694ff69bSmillert if (nv6 != 0) {
196694ff69bSmillert blacklists[idx].v6.naddrs = nv6;
197694ff69bSmillert blacklists[idx].v6.addrs = reallocarray(NULL, nv6,
198694ff69bSmillert sizeof(struct sdentry_v6));
199694ff69bSmillert if (blacklists[idx].v6.addrs == NULL)
200694ff69bSmillert goto misc_error;
201694ff69bSmillert
202694ff69bSmillert for (i = 0; i < nv6; i++) {
203694ff69bSmillert int j, k;
204694ff69bSmillert struct sdaddr_v6 *m, *n;
205694ff69bSmillert
206694ff69bSmillert n = &blacklists[idx].v6.addrs[i].sda;
207694ff69bSmillert m = &blacklists[idx].v6.addrs[i].sdm;
208694ff69bSmillert
209694ff69bSmillert addr = v6[i];
210694ff69bSmillert j = sscanf(addr, "%39[^/]/%u", astring, &maskbits);
211694ff69bSmillert if (j != 2)
212694ff69bSmillert goto parse_error;
213694ff69bSmillert /*
214694ff69bSmillert * sanity check! we don't allow a 0 mask -
215694ff69bSmillert * don't blacklist the entire net.
216694ff69bSmillert */
217694ff69bSmillert if (maskbits == 0 || maskbits > 128)
218694ff69bSmillert goto parse_error;
219694ff69bSmillert j = inet_pton(AF_INET6, astring, n);
220461ebb7fSbeck if (j != 1)
221461ebb7fSbeck goto parse_error;
222461ebb7fSbeck if (debug > 0)
223461ebb7fSbeck printf("added %s/%u\n", astring, maskbits);
224461ebb7fSbeck
225461ebb7fSbeck /* set mask, borrowed from pf */
226461ebb7fSbeck k = 0;
227461ebb7fSbeck for (j = 0; j < 4; j++)
228461ebb7fSbeck m->addr32[j] = 0;
229461ebb7fSbeck while (maskbits >= 32) {
230694ff69bSmillert m->addr32[k++] = 0xffffffffU;
231461ebb7fSbeck maskbits -= 32;
232461ebb7fSbeck }
233461ebb7fSbeck for (j = 31; j > 31 - maskbits; --j)
234461ebb7fSbeck m->addr32[k] |= (1 << j);
235461ebb7fSbeck if (maskbits)
236461ebb7fSbeck m->addr32[k] = htonl(m->addr32[k]);
237461ebb7fSbeck
238461ebb7fSbeck /* mask off address bits that won't ever be used */
239461ebb7fSbeck for (j = 0; j < 4; j++)
240461ebb7fSbeck n->addr32[j] = n->addr32[j] & m->addr32[j];
241461ebb7fSbeck }
242b1aaf36bSmillert /* spamd-setup output is sorted in host byte order */
243b1aaf36bSmillert mergesort(blacklists[idx].v6.addrs, nv6,
244b1aaf36bSmillert sizeof(struct sdentry_v6), compar_v6);
245694ff69bSmillert }
24682acdfc5Sderaadt if (idx == blu) {
247461ebb7fSbeck blu++;
248b49d95e6Smillert sdl_clear(&blacklists[blu]);
249461ebb7fSbeck }
250461ebb7fSbeck return (0);
251461ebb7fSbeck parse_error:
252461ebb7fSbeck if (debug > 0)
253694ff69bSmillert printf("sdl_add: parse error, \"%s\"\n", addr);
254ae3f7e48Scloder misc_error:
25582acdfc5Sderaadt sdl_free(&blacklists[idx]);
256b49d95e6Smillert if (idx != blu) {
257b49d95e6Smillert memmove(&blacklists[idx], &blacklists[idx + 1],
258b49d95e6Smillert (blu - idx) * sizeof(*blacklists));
259b49d95e6Smillert blu--;
260b49d95e6Smillert }
261461ebb7fSbeck return (-1);
262461ebb7fSbeck }
263461ebb7fSbeck
264e25a0afeSbeck void
sdl_del(char * sdname)265e25a0afeSbeck sdl_del(char *sdname)
266e25a0afeSbeck {
267e25a0afeSbeck int i, idx = -1;
268e25a0afeSbeck
269e25a0afeSbeck for (i = 0; i < blu; i++) {
270e25a0afeSbeck if (strcmp(blacklists[i].tag, sdname) == 0) {
271e25a0afeSbeck idx = i;
272e25a0afeSbeck break;
273e25a0afeSbeck }
274e25a0afeSbeck }
275e25a0afeSbeck if (idx != -1) {
276e25a0afeSbeck if (debug > 0)
277e25a0afeSbeck printf("clearing list %s\n", sdname);
278694ff69bSmillert /* Must preserve tag. */
279e25a0afeSbeck free(blacklists[idx].string);
280694ff69bSmillert free(blacklists[idx].v4.addrs);
281694ff69bSmillert free(blacklists[idx].v6.addrs);
282e25a0afeSbeck blacklists[idx].string = NULL;
283694ff69bSmillert blacklists[idx].v4.addrs = NULL;
284694ff69bSmillert blacklists[idx].v6.addrs = NULL;
285694ff69bSmillert blacklists[idx].v4.naddrs = 0;
286694ff69bSmillert blacklists[idx].v6.naddrs = 0;
287e25a0afeSbeck }
288e25a0afeSbeck }
289461ebb7fSbeck
290461ebb7fSbeck /*
291*6d9ddefdSjmc * Return 0 if the address a (with mask m) matches address key
292b1aaf36bSmillert * otherwise return 1 if a > key or -1 if a < key. It is assumed
293b1aaf36bSmillert * that address a has been pre-masked out, we only need to mask key.
294461ebb7fSbeck */
295694ff69bSmillert static int
match_addr_v4(const void * vkey,const void * ventry)296b1aaf36bSmillert match_addr_v4(const void *vkey, const void *ventry)
297461ebb7fSbeck {
298b1aaf36bSmillert const struct in_addr *k = vkey;
299b1aaf36bSmillert const struct in_addr *a = &((const struct sdentry_v4 *)ventry)->sda;
300b1aaf36bSmillert const struct in_addr *m = &((const struct sdentry_v4 *)ventry)->sdm;
301b1aaf36bSmillert struct in_addr kk;
302b1aaf36bSmillert struct in_addr aa;
303b1aaf36bSmillert
304b1aaf36bSmillert kk.s_addr = ntohl(k->s_addr & m->s_addr);
305b1aaf36bSmillert aa.s_addr = ntohl(a->s_addr);
306b1aaf36bSmillert if (kk.s_addr > aa.s_addr)
307694ff69bSmillert return (1);
308b1aaf36bSmillert if (kk.s_addr < aa.s_addr)
309b1aaf36bSmillert return (-1);
310694ff69bSmillert return (0);
311461ebb7fSbeck }
312461ebb7fSbeck
313461ebb7fSbeck /*
314*6d9ddefdSjmc * Return 0 if the address a (with mask m) matches address key
315b1aaf36bSmillert * otherwise return 1 if a > key or -1 if a < key. It is assumed
316b1aaf36bSmillert * that address a has been pre-masked out, we only need to mask key.
317461ebb7fSbeck */
318694ff69bSmillert static int
match_addr_v6(const void * vkey,const void * ventry)319b1aaf36bSmillert match_addr_v6(const void *vkey, const void *ventry)
320461ebb7fSbeck {
321b1aaf36bSmillert const struct sdaddr_v6 *k = vkey;
322b1aaf36bSmillert const struct sdaddr_v6 *a = &((const struct sdentry_v6 *)ventry)->sda;
323b1aaf36bSmillert const struct sdaddr_v6 *m = &((const struct sdentry_v6 *)ventry)->sdm;
324b1aaf36bSmillert struct sdaddr_v6 kk;
325b1aaf36bSmillert struct sdaddr_v6 aa;
326b1aaf36bSmillert
327b1aaf36bSmillert kk.addr32[0] = ntohl(k->addr32[0] & m->addr32[0]);
328b1aaf36bSmillert kk.addr32[1] = ntohl(k->addr32[1] & m->addr32[1]);
329b1aaf36bSmillert kk.addr32[2] = ntohl(k->addr32[2] & m->addr32[2]);
330b1aaf36bSmillert kk.addr32[3] = ntohl(k->addr32[3] & m->addr32[3]);
331b1aaf36bSmillert
332b1aaf36bSmillert aa.addr32[0] = ntohl(a->addr32[0]);
333b1aaf36bSmillert aa.addr32[1] = ntohl(a->addr32[1]);
334b1aaf36bSmillert aa.addr32[2] = ntohl(a->addr32[2]);
335b1aaf36bSmillert aa.addr32[3] = ntohl(a->addr32[3]);
336b1aaf36bSmillert
337b1aaf36bSmillert if (kk.addr32[0] > aa.addr32[0])
338694ff69bSmillert return (1);
339b1aaf36bSmillert if (kk.addr32[0] < aa.addr32[0])
340b1aaf36bSmillert return (-1);
341b1aaf36bSmillert if (kk.addr32[1] > aa.addr32[1])
342b1aaf36bSmillert return (1);
343b1aaf36bSmillert if (kk.addr32[1] < aa.addr32[1])
344b1aaf36bSmillert return (-1);
345b1aaf36bSmillert if (kk.addr32[2] > aa.addr32[2])
346b1aaf36bSmillert return (1);
347b1aaf36bSmillert if (kk.addr32[2] < aa.addr32[2])
348b1aaf36bSmillert return (-1);
349b1aaf36bSmillert if (kk.addr32[3] > aa.addr32[3])
350b1aaf36bSmillert return (1);
351b1aaf36bSmillert if (kk.addr32[3] < aa.addr32[3])
352b1aaf36bSmillert return (-1);
353694ff69bSmillert return (0);
354694ff69bSmillert }
355694ff69bSmillert
356694ff69bSmillert #define grow_sdlist(sd, c, l) do { \
357694ff69bSmillert if (c == l) { \
358694ff69bSmillert struct sdlist **tmp; \
359694ff69bSmillert \
360694ff69bSmillert tmp = reallocarray(sd, l + 128, sizeof(struct sdlist *)); \
361694ff69bSmillert if (tmp == NULL) { \
362694ff69bSmillert /* \
363694ff69bSmillert * XXX out of memory - return what we have \
364694ff69bSmillert */ \
365694ff69bSmillert return (sdnew); \
366694ff69bSmillert } \
367694ff69bSmillert sd = tmp; \
368694ff69bSmillert l += 128; \
369694ff69bSmillert } \
370694ff69bSmillert } while (0)
371694ff69bSmillert
372694ff69bSmillert static struct sdlist **
sdl_lookup_v4(struct sdlist * sdl,struct in_addr * src)373694ff69bSmillert sdl_lookup_v4(struct sdlist *sdl, struct in_addr *src)
374694ff69bSmillert {
375b1aaf36bSmillert int matches = 0;
3761f68c1d4Sbeck int sdnewlen = 0;
3771f68c1d4Sbeck struct sdlist **sdnew = NULL;
378461ebb7fSbeck
379461ebb7fSbeck while (sdl->tag != NULL) {
380b1aaf36bSmillert if (bsearch(src, sdl->v4.addrs, sdl->v4.naddrs,
381b1aaf36bSmillert sizeof(struct sdentry_v4), match_addr_v4) != NULL) {
382694ff69bSmillert grow_sdlist(sdnew, matches, sdnewlen);
383461ebb7fSbeck sdnew[matches] = sdl;
384461ebb7fSbeck matches++;
385461ebb7fSbeck sdnew[matches] = NULL;
386461ebb7fSbeck break;
387461ebb7fSbeck }
388461ebb7fSbeck sdl++;
389461ebb7fSbeck }
390461ebb7fSbeck return (sdnew);
391461ebb7fSbeck }
392ae3f7e48Scloder
393694ff69bSmillert static struct sdlist **
sdl_lookup_v6(struct sdlist * sdl,struct sdaddr_v6 * src)394694ff69bSmillert sdl_lookup_v6(struct sdlist *sdl, struct sdaddr_v6 *src)
395694ff69bSmillert {
396b1aaf36bSmillert int matches = 0;
397694ff69bSmillert int sdnewlen = 0;
398694ff69bSmillert struct sdlist **sdnew = NULL;
399694ff69bSmillert
400694ff69bSmillert while (sdl->tag != NULL) {
401b1aaf36bSmillert if (bsearch(src, sdl->v6.addrs, sdl->v6.naddrs,
402b1aaf36bSmillert sizeof(struct sdentry_v6), match_addr_v6) != NULL) {
403694ff69bSmillert grow_sdlist(sdnew, matches, sdnewlen);
404694ff69bSmillert sdnew[matches] = sdl;
405694ff69bSmillert matches++;
406694ff69bSmillert sdnew[matches] = NULL;
407694ff69bSmillert break;
408694ff69bSmillert }
409694ff69bSmillert sdl++;
410694ff69bSmillert }
411694ff69bSmillert return (sdnew);
412694ff69bSmillert }
413694ff69bSmillert
414694ff69bSmillert /*
415694ff69bSmillert * Given an address and address family
416694ff69bSmillert * return list of pointers to matching nodes. or NULL if none.
417694ff69bSmillert */
418694ff69bSmillert struct sdlist **
sdl_lookup(struct sdlist * head,int af,void * src)419694ff69bSmillert sdl_lookup(struct sdlist *head, int af, void *src)
420694ff69bSmillert {
421694ff69bSmillert if (head == NULL)
422694ff69bSmillert return (NULL);
423694ff69bSmillert
424694ff69bSmillert switch (af) {
425694ff69bSmillert case AF_INET:
426694ff69bSmillert return (sdl_lookup_v4(head, src));
427694ff69bSmillert case AF_INET6:
428694ff69bSmillert return (sdl_lookup_v6(head, src));
429694ff69bSmillert default:
430694ff69bSmillert return (NULL);
431694ff69bSmillert }
432694ff69bSmillert }
433694ff69bSmillert
43466baed91Smillert static int
sdl_check_v4(struct sdlist * sdl,struct in_addr * src)43566baed91Smillert sdl_check_v4(struct sdlist *sdl, struct in_addr *src)
43666baed91Smillert {
43766baed91Smillert while (sdl->tag != NULL) {
43866baed91Smillert if (bsearch(src, sdl->v4.addrs, sdl->v4.naddrs,
43966baed91Smillert sizeof(struct sdentry_v4), match_addr_v4) != NULL)
44066baed91Smillert return (1);
44166baed91Smillert sdl++;
44266baed91Smillert }
44366baed91Smillert return (0);
44466baed91Smillert }
44566baed91Smillert
44666baed91Smillert static int
sdl_check_v6(struct sdlist * sdl,struct sdaddr_v6 * src)44766baed91Smillert sdl_check_v6(struct sdlist *sdl, struct sdaddr_v6 *src)
44866baed91Smillert {
44966baed91Smillert while (sdl->tag != NULL) {
45066baed91Smillert if (bsearch(src, sdl->v6.addrs, sdl->v6.naddrs,
45166baed91Smillert sizeof(struct sdentry_v6), match_addr_v6) != NULL)
45266baed91Smillert return (1);
45366baed91Smillert sdl++;
45466baed91Smillert }
45566baed91Smillert return (0);
45666baed91Smillert }
45766baed91Smillert
45866baed91Smillert /*
45966baed91Smillert * Given an address and address family
46066baed91Smillert * returns 1 if address is on a blacklist, else 0.
46166baed91Smillert */
46266baed91Smillert int
sdl_check(struct sdlist * head,int af,void * src)46366baed91Smillert sdl_check(struct sdlist *head, int af, void *src)
46466baed91Smillert {
46566baed91Smillert if (head == NULL)
46666baed91Smillert return (0);
46766baed91Smillert
46866baed91Smillert switch (af) {
46966baed91Smillert case AF_INET:
47066baed91Smillert return (sdl_check_v4(head, src));
47166baed91Smillert case AF_INET6:
47266baed91Smillert return (sdl_check_v6(head, src));
47366baed91Smillert default:
47466baed91Smillert return (0);
47566baed91Smillert }
47666baed91Smillert }
47766baed91Smillert
478ae3f7e48Scloder static void
sdl_free(struct sdlist * sdl)479ae3f7e48Scloder sdl_free(struct sdlist *sdl)
480ae3f7e48Scloder {
481ae3f7e48Scloder free(sdl->tag);
482ae3f7e48Scloder free(sdl->string);
483694ff69bSmillert free(sdl->v4.addrs);
484694ff69bSmillert free(sdl->v6.addrs);
485ae3f7e48Scloder sdl_clear(sdl);
486ae3f7e48Scloder }
487ae3f7e48Scloder
488ae3f7e48Scloder static void
sdl_clear(struct sdlist * sdl)489ae3f7e48Scloder sdl_clear(struct sdlist *sdl)
490ae3f7e48Scloder {
491ae3f7e48Scloder sdl->tag = NULL;
492ae3f7e48Scloder sdl->string = NULL;
493694ff69bSmillert sdl->v4.addrs = NULL;
494694ff69bSmillert sdl->v4.naddrs = 0;
495694ff69bSmillert sdl->v6.addrs = NULL;
496694ff69bSmillert sdl->v6.naddrs = 0;
497ae3f7e48Scloder }
498