1 /* $OpenBSD: sdl.c,v 1.10 2003/09/26 16:07:29 deraadt Exp $ */ 2 /* 3 * Copyright (c) 2003 Bob Beck. 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 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 /* 27 * sdl.c - Implement spamd source lists 28 * 29 * This consists of everything we need to do to determine which lists 30 * someone is on. Spamd gets the connecting address, and looks it up 31 * against all lists to determine what deferral messages to feed back 32 * to the connecting machine. - The redirection to spamd will happen 33 * from pf in the kernel, first macth will rdr to us. Spamd (along with 34 * setup) must keep track of *all* matches, so as to tell someone all the 35 * lists that they are on. 36 */ 37 38 #include <sys/types.h> 39 #include <sys/socket.h> 40 #include <netinet/in.h> 41 #include <arpa/inet.h> 42 #include <errno.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include "sdl.h" 47 48 static void sdl_free(struct sdlist *); 49 static void sdl_clear(struct sdlist *); 50 int match_addr(struct sdaddr *a, struct sdaddr *m, struct sdaddr *b, 51 sa_family_t af); 52 53 extern int debug; 54 struct sdlist *blacklists = NULL; 55 int blc = 0, blu = 0; 56 57 int 58 sdl_add(char *sdname, char *sdstring, char ** addrs, int addrc) 59 { 60 int i, index = -1; 61 char astring[40]; 62 unsigned int maskbits; 63 struct sdaddr *m, *n; 64 65 /* 66 * if a blacklist of same tag name is already there, replace it, 67 * otherwise append. 68 */ 69 for (i = 0; i < blu; i++) { 70 if (strcmp(blacklists[i].tag, sdname) == 0) { 71 index = i; 72 break; 73 } 74 } 75 if (index != -1) { 76 if (debug > 0) 77 printf("replacing list %s\n", blacklists[index].tag); 78 sdl_free(&blacklists[index]); 79 } else { 80 if (debug > 0) 81 printf("adding list %s\n", sdname); 82 index = blu; 83 } 84 if (index == blu && blu == blc) { 85 struct sdlist *tmp; 86 87 tmp = realloc(blacklists, (blc + 128) * 88 sizeof(struct sdlist)); 89 if (tmp == NULL) 90 return (-1); 91 blacklists = tmp; 92 blc += 128; 93 sdl_clear(&blacklists[index]); 94 } 95 96 if ((blacklists[index].tag = strdup(sdname)) == NULL) 97 goto misc_error; 98 if ((blacklists[index].string = strdup(sdstring)) == NULL) 99 goto misc_error; 100 101 blacklists[index].naddrs = addrc; 102 103 /* 104 * Cycle through addrs, converting. We assume they are correctly 105 * formatted v4 and v6 addrs, if they don't all convert correctly, the 106 * add fails. Each address should be address/maskbits 107 */ 108 blacklists[index].addrs = malloc(addrc * sizeof(struct sdentry)); 109 if (blacklists[index].addrs == NULL) 110 goto misc_error; 111 112 for(i = 0; i < addrc; i++) { 113 int j, k, af; 114 115 n = &blacklists[index].addrs[i].sda; 116 m = &blacklists[index].addrs[i].sdm; 117 118 j = sscanf(addrs[i], "%39[^/]/%u", astring, &maskbits); 119 if (j != 2) 120 goto parse_error; 121 if (maskbits > 128) 122 goto parse_error; 123 /* 124 * sanity check! we don't allow a 0 mask - 125 * don't blacklist the entire net. 126 */ 127 if (maskbits == 0) 128 goto parse_error; 129 if (strchr(astring, ':') != NULL) 130 af = AF_INET6; 131 else 132 af = AF_INET; 133 if (af == AF_INET && maskbits > 32) 134 goto parse_error; 135 j = inet_pton(af, astring, n); 136 if (j != 1) 137 goto parse_error; 138 if (debug > 0) 139 printf("added %s/%u\n", astring, maskbits); 140 141 /* set mask, borrowed from pf */ 142 k = 0; 143 for (j = 0; j < 4; j++) 144 m->addr32[j] = 0; 145 while (maskbits >= 32) { 146 m->addr32[k++] = 0xffffffff; 147 maskbits -= 32; 148 } 149 for (j = 31; j > 31 - maskbits; --j) 150 m->addr32[k] |= (1 << j); 151 if (maskbits) 152 m->addr32[k] = htonl(m->addr32[k]); 153 154 /* mask off address bits that won't ever be used */ 155 for (j = 0; j < 4; j++) 156 n->addr32[j] = n->addr32[j] & m->addr32[j]; 157 } 158 if (index == blu) { 159 blu++; 160 blacklists[blu].tag = NULL; 161 } 162 return (0); 163 parse_error: 164 if (debug > 0) 165 printf("sdl_add: parse error, \"%s\"\n", addrs[i]); 166 misc_error: 167 sdl_free(&blacklists[index]); 168 return (-1); 169 } 170 171 172 /* 173 * Return 1 if the addresses a (with mask m) matches address b 174 * otherwise return 0. It is assumed that address a has been 175 * pre-masked out, we only need to mask b. 176 */ 177 int 178 match_addr(struct sdaddr *a, struct sdaddr *m, struct sdaddr *b, 179 sa_family_t af) 180 { 181 int match = 0; 182 183 switch (af) { 184 case AF_INET: 185 if ((a->addr32[0]) == 186 (b->addr32[0] & m->addr32[0])) 187 match++; 188 break; 189 case AF_INET6: 190 if (((a->addr32[0]) == 191 (b->addr32[0] & m->addr32[0])) && 192 ((a->addr32[1]) == 193 (b->addr32[1] & m->addr32[1])) && 194 ((a->addr32[2]) == 195 (b->addr32[2] & m->addr32[2])) && 196 ((a->addr32[3]) == 197 (b->addr32[3] & m->addr32[3]))) 198 match++; 199 break; 200 } 201 return (match); 202 } 203 204 205 /* 206 * Given an address and address family 207 * return list of pointers to matching nodes. or NULL if none. 208 */ 209 struct sdlist ** 210 sdl_lookup(struct sdlist *head, int af, void * src) 211 { 212 int i, matches = 0; 213 struct sdlist *sdl; 214 struct sdentry *sda; 215 struct sdaddr *source = (struct sdaddr *) src; 216 static int sdnewlen = 0; 217 static struct sdlist **sdnew = NULL; 218 219 if (head == NULL) 220 return (NULL); 221 else 222 sdl = head; 223 while (sdl->tag != NULL) { 224 for (i = 0; i < sdl->naddrs; i++) { 225 sda = sdl->addrs + i; 226 if (match_addr(&sda->sda, &sda->sdm, source, af)) { 227 if (matches == sdnewlen) { 228 struct sdlist **tmp; 229 230 tmp = realloc(sdnew, 231 (sdnewlen + 128) * 232 sizeof(struct sdlist *)); 233 if (tmp == NULL) 234 /* 235 * XXX out of memory - 236 * return what we have 237 */ 238 return (sdnew); 239 sdnew = tmp; 240 sdnewlen += 128; 241 } 242 sdnew[matches]= sdl; 243 matches++; 244 sdnew[matches]=NULL; 245 break; 246 } 247 } 248 sdl++; 249 } 250 return (sdnew); 251 } 252 253 static void 254 sdl_free(struct sdlist *sdl) 255 { 256 free(sdl->tag); 257 free(sdl->string); 258 free(sdl->addrs); 259 sdl_clear(sdl); 260 } 261 262 static void 263 sdl_clear(struct sdlist *sdl) 264 { 265 sdl->tag = NULL; 266 sdl->string = NULL; 267 sdl->addrs = NULL; 268 sdl->naddrs = 0; 269 } 270 271