1 /* $OpenBSD: sdl.c,v 1.22 2015/05/18 16:04:21 reyk Exp $ */ 2 3 /* 4 * Copyright (c) 2003-2007 Bob Beck. All rights reserved. 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * sdl.c - Implement spamd source lists 21 * 22 * This consists of everything we need to do to determine which lists 23 * someone is on. Spamd gets the connecting address, and looks it up 24 * against all lists to determine what deferral messages to feed back 25 * to the connecting machine. - The redirection to spamd will happen 26 * from pf in the kernel, first match will divert to us. Spamd (along with 27 * setup) must keep track of *all* matches, so as to tell someone all the 28 * lists that they are on. 29 */ 30 31 #include <sys/types.h> 32 #include <sys/socket.h> 33 #include <netinet/in.h> 34 #include <arpa/inet.h> 35 #include <errno.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include "sdl.h" 40 41 static void sdl_free(struct sdlist *); 42 static void sdl_clear(struct sdlist *); 43 44 extern int debug; 45 struct sdlist *blacklists = NULL; 46 int blc = 0, blu = 0; 47 48 int 49 sdl_add(char *sdname, char *sdstring, char **v4, u_int nv4, char **v6, u_int nv6) 50 { 51 int i, idx = -1; 52 char astring[40]; 53 char *addr = NULL; 54 unsigned int maskbits; 55 56 /* 57 * if a blacklist of same tag name is already there, replace it, 58 * otherwise append. 59 */ 60 for (i = 0; i < blu; i++) { 61 if (strcmp(blacklists[i].tag, sdname) == 0) { 62 idx = i; 63 break; 64 } 65 } 66 if (idx != -1) { 67 if (debug > 0) 68 printf("replacing list %s; %u new entries\n", 69 blacklists[idx].tag, nv4 + nv6); 70 sdl_free(&blacklists[idx]); 71 } else { 72 if (debug > 0) 73 printf("adding list %s; %u entries\n", sdname, nv4 + nv6); 74 if (blu == blc) { 75 struct sdlist *tmp; 76 77 tmp = reallocarray(blacklists, blc + 128, 78 sizeof(struct sdlist)); 79 if (tmp == NULL) 80 return (-1); 81 blacklists = tmp; 82 blc += 128; 83 sdl_clear(&blacklists[blu]); 84 } 85 idx = blu; 86 } 87 88 if ((blacklists[idx].tag = strdup(sdname)) == NULL) 89 goto misc_error; 90 if ((blacklists[idx].string = strdup(sdstring)) == NULL) 91 goto misc_error; 92 93 /* 94 * Cycle through addrs by family, converting. We assume they are 95 * correctly formatted v4 and v6 addrs, if they don't all convert 96 * correctly, the add fails. Each address should be address/maskbits. 97 */ 98 if (nv4 != 0) { 99 blacklists[idx].v4.naddrs = nv4; 100 blacklists[idx].v4.addrs = reallocarray(NULL, nv4, 101 sizeof(struct sdentry_v4)); 102 if (blacklists[idx].v4.addrs == NULL) 103 goto misc_error; 104 for (i = 0; i < nv4; i++) { 105 struct in_addr *m, *n; 106 int j; 107 108 n = &blacklists[idx].v4.addrs[i].sda; 109 m = &blacklists[idx].v4.addrs[i].sdm; 110 111 addr = v4[i]; 112 j = sscanf(addr, "%15[^/]/%u", astring, &maskbits); 113 if (j != 2) 114 goto parse_error; 115 /* 116 * sanity check! we don't allow a 0 mask - 117 * don't blacklist the entire net. 118 */ 119 if (maskbits == 0 || maskbits > 32) 120 goto parse_error; 121 j = inet_pton(AF_INET, astring, n); 122 if (j != 1) 123 goto parse_error; 124 if (debug > 0) 125 printf("added %s/%u\n", astring, maskbits); 126 127 /* set mask. */ 128 m->s_addr = 0xffffffffU << (32 - maskbits); 129 m->s_addr = htonl(m->s_addr); 130 131 /* mask off address bits that won't ever be used */ 132 n->s_addr = n->s_addr & m->s_addr; 133 } 134 } 135 if (nv6 != 0) { 136 blacklists[idx].v6.naddrs = nv6; 137 blacklists[idx].v6.addrs = reallocarray(NULL, nv6, 138 sizeof(struct sdentry_v6)); 139 if (blacklists[idx].v6.addrs == NULL) 140 goto misc_error; 141 142 for (i = 0; i < nv6; i++) { 143 int j, k; 144 struct sdaddr_v6 *m, *n; 145 146 n = &blacklists[idx].v6.addrs[i].sda; 147 m = &blacklists[idx].v6.addrs[i].sdm; 148 149 addr = v6[i]; 150 j = sscanf(addr, "%39[^/]/%u", astring, &maskbits); 151 if (j != 2) 152 goto parse_error; 153 /* 154 * sanity check! we don't allow a 0 mask - 155 * don't blacklist the entire net. 156 */ 157 if (maskbits == 0 || maskbits > 128) 158 goto parse_error; 159 j = inet_pton(AF_INET6, astring, n); 160 if (j != 1) 161 goto parse_error; 162 if (debug > 0) 163 printf("added %s/%u\n", astring, maskbits); 164 165 /* set mask, borrowed from pf */ 166 k = 0; 167 for (j = 0; j < 4; j++) 168 m->addr32[j] = 0; 169 while (maskbits >= 32) { 170 m->addr32[k++] = 0xffffffffU; 171 maskbits -= 32; 172 } 173 for (j = 31; j > 31 - maskbits; --j) 174 m->addr32[k] |= (1 << j); 175 if (maskbits) 176 m->addr32[k] = htonl(m->addr32[k]); 177 178 /* mask off address bits that won't ever be used */ 179 for (j = 0; j < 4; j++) 180 n->addr32[j] = n->addr32[j] & m->addr32[j]; 181 } 182 } 183 if (idx == blu) { 184 blu++; 185 sdl_clear(&blacklists[blu]); 186 } 187 return (0); 188 parse_error: 189 if (debug > 0) 190 printf("sdl_add: parse error, \"%s\"\n", addr); 191 misc_error: 192 sdl_free(&blacklists[idx]); 193 if (idx != blu) { 194 memmove(&blacklists[idx], &blacklists[idx + 1], 195 (blu - idx) * sizeof(*blacklists)); 196 blu--; 197 } 198 return (-1); 199 } 200 201 void 202 sdl_del(char *sdname) 203 { 204 int i, idx = -1; 205 206 for (i = 0; i < blu; i++) { 207 if (strcmp(blacklists[i].tag, sdname) == 0) { 208 idx = i; 209 break; 210 } 211 } 212 if (idx != -1) { 213 if (debug > 0) 214 printf("clearing list %s\n", sdname); 215 /* Must preserve tag. */ 216 free(blacklists[idx].string); 217 free(blacklists[idx].v4.addrs); 218 free(blacklists[idx].v6.addrs); 219 blacklists[idx].string = NULL; 220 blacklists[idx].v4.addrs = NULL; 221 blacklists[idx].v6.addrs = NULL; 222 blacklists[idx].v4.naddrs = 0; 223 blacklists[idx].v6.naddrs = 0; 224 } 225 } 226 227 /* 228 * Return 1 if the addresses a (with mask m) matches address b 229 * otherwise return 0. It is assumed that address a has been 230 * pre-masked out, we only need to mask b. 231 */ 232 static int 233 match_addr_v4(struct in_addr *a, struct in_addr *m, struct in_addr *b) 234 { 235 if (a->s_addr == (b->s_addr & m->s_addr)) 236 return (1); 237 return (0); 238 } 239 240 /* 241 * Return 1 if the addresses a (with mask m) matches address b 242 * otherwise return 0. It is assumed that address a has been 243 * pre-masked out, we only need to mask b. 244 */ 245 static int 246 match_addr_v6(struct sdaddr_v6 *a, struct sdaddr_v6 *m, struct sdaddr_v6 *b) 247 { 248 if (((a->addr32[0]) == (b->addr32[0] & m->addr32[0])) && 249 ((a->addr32[1]) == (b->addr32[1] & m->addr32[1])) && 250 ((a->addr32[2]) == (b->addr32[2] & m->addr32[2])) && 251 ((a->addr32[3]) == (b->addr32[3] & m->addr32[3]))) 252 return (1); 253 return (0); 254 } 255 256 #define grow_sdlist(sd, c, l) do { \ 257 if (c == l) { \ 258 struct sdlist **tmp; \ 259 \ 260 tmp = reallocarray(sd, l + 128, sizeof(struct sdlist *)); \ 261 if (tmp == NULL) { \ 262 /* \ 263 * XXX out of memory - return what we have \ 264 */ \ 265 return (sdnew); \ 266 } \ 267 sd = tmp; \ 268 l += 128; \ 269 } \ 270 } while (0) 271 272 static struct sdlist ** 273 sdl_lookup_v4(struct sdlist *sdl, struct in_addr *src) 274 { 275 struct sdentry_v4 *entry; 276 int i, matches = 0; 277 int sdnewlen = 0; 278 struct sdlist **sdnew = NULL; 279 280 while (sdl->tag != NULL) { 281 for (i = 0; i < sdl->v4.naddrs; i++) { 282 entry = &sdl->v4.addrs[i]; 283 if (match_addr_v4(&entry->sda, &entry->sdm, src)) { 284 grow_sdlist(sdnew, matches, sdnewlen); 285 sdnew[matches] = sdl; 286 matches++; 287 sdnew[matches] = NULL; 288 break; 289 } 290 } 291 sdl++; 292 } 293 return (sdnew); 294 } 295 296 static struct sdlist ** 297 sdl_lookup_v6(struct sdlist *sdl, struct sdaddr_v6 *src) 298 { 299 struct sdentry_v6 *entry; 300 int i, matches = 0; 301 int sdnewlen = 0; 302 struct sdlist **sdnew = NULL; 303 304 while (sdl->tag != NULL) { 305 for (i = 0; i < sdl->v6.naddrs; i++) { 306 entry = &sdl->v6.addrs[i]; 307 if (match_addr_v6(&entry->sda, &entry->sdm, src)) { 308 grow_sdlist(sdnew, matches, sdnewlen); 309 sdnew[matches] = sdl; 310 matches++; 311 sdnew[matches] = NULL; 312 break; 313 } 314 } 315 sdl++; 316 } 317 return (sdnew); 318 } 319 320 /* 321 * Given an address and address family 322 * return list of pointers to matching nodes. or NULL if none. 323 */ 324 struct sdlist ** 325 sdl_lookup(struct sdlist *head, int af, void *src) 326 { 327 if (head == NULL) 328 return (NULL); 329 330 switch (af) { 331 case AF_INET: 332 return (sdl_lookup_v4(head, src)); 333 case AF_INET6: 334 return (sdl_lookup_v6(head, src)); 335 default: 336 return (NULL); 337 } 338 } 339 340 static void 341 sdl_free(struct sdlist *sdl) 342 { 343 free(sdl->tag); 344 free(sdl->string); 345 free(sdl->v4.addrs); 346 free(sdl->v6.addrs); 347 sdl_clear(sdl); 348 } 349 350 static void 351 sdl_clear(struct sdlist *sdl) 352 { 353 sdl->tag = NULL; 354 sdl->string = NULL; 355 sdl->v4.addrs = NULL; 356 sdl->v4.naddrs = 0; 357 sdl->v6.addrs = NULL; 358 sdl->v6.naddrs = 0; 359 } 360