1 /* $NetBSD: prefix.c,v 1.3 2001/11/21 06:52:35 itojun Exp $ */ 2 /* $KAME: prefix.c,v 1.9 2001/07/02 14:36:49 itojun Exp $ */ 3 4 /* 5 * Copyright (C) 2000 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/types.h> 34 #include <sys/socket.h> 35 #include <netinet/in.h> 36 #include <stdio.h> 37 #include <netdb.h> 38 #include <string.h> 39 #include <stddef.h> 40 #include <stdlib.h> 41 #include <limits.h> 42 43 #ifndef offsetof 44 #define offsetof(type, member) ((size_t)(u_long)(&((type *)0)->member)) 45 #endif 46 47 #include "faithd.h" 48 #include "prefix.h" 49 50 static int prefix_set __P((const char *, struct prefix *, int)); 51 static struct config *config_load1 __P((const char *)); 52 #if 0 53 static void config_show1 __P((const struct config *)); 54 static void config_show __P((void)); 55 #endif 56 57 struct config *config_list = NULL; 58 #ifdef NI_WITHSCOPEID 59 const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID; 60 #else 61 const int niflags = NI_NUMERICHOST; 62 #endif 63 64 static int 65 prefix_set(s, prefix, slash) 66 const char *s; 67 struct prefix *prefix; 68 int slash; 69 { 70 char *p = NULL, *q, *r; 71 struct addrinfo hints, *res = NULL; 72 int max; 73 char *a; 74 75 p = strdup(s); 76 if (!p) 77 goto fail; 78 q = strchr(p, '/'); 79 if (q) { 80 if (!slash) 81 goto fail; 82 *q++ = '\0'; 83 } 84 85 memset(&hints, 0, sizeof(hints)); 86 hints.ai_family = PF_UNSPEC; 87 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 88 hints.ai_flags = AI_NUMERICHOST; 89 if (getaddrinfo(p, "0", &hints, &res)) 90 goto fail; 91 if (res->ai_next || res->ai_addrlen > sizeof(prefix->a)) 92 goto fail; 93 memcpy(&prefix->a, res->ai_addr, res->ai_addrlen); 94 95 switch (prefix->a.ss_family) { 96 case AF_INET: 97 max = 32; 98 a = (char *)&((struct sockaddr_in *)&prefix->a)->sin_addr; 99 break; 100 case AF_INET6: 101 max = 128; 102 a = (char *)&((struct sockaddr_in6 *)&prefix->a)->sin6_addr; 103 break; 104 default: 105 a = NULL; 106 max = -1; 107 break; 108 } 109 110 if (q) { 111 r = NULL; 112 prefix->l = (int)strtoul(q, &r, 10); 113 if (!*q || *r) 114 goto fail; 115 if (prefix->l < 0 || prefix->l > max) 116 goto fail; 117 } else 118 prefix->l = max; 119 120 if (p) 121 free(p); 122 if (res) 123 freeaddrinfo(res); 124 return 0; 125 126 fail: 127 if (p) 128 free(p); 129 if (res) 130 freeaddrinfo(res); 131 return -1; 132 } 133 134 const char * 135 prefix_string(prefix) 136 const struct prefix *prefix; 137 { 138 static char buf[NI_MAXHOST + 20]; 139 char hbuf[NI_MAXHOST]; 140 141 if (getnameinfo((const struct sockaddr *)&prefix->a, prefix->a.ss_len, 142 hbuf, sizeof(hbuf), NULL, 0, niflags)) 143 return NULL; 144 snprintf(buf, sizeof(buf), "%s/%d", hbuf, prefix->l); 145 return buf; 146 } 147 148 int 149 prefix_match(prefix, sa) 150 const struct prefix *prefix; 151 const struct sockaddr *sa; 152 { 153 struct sockaddr_storage a, b; 154 char *pa, *pb; 155 int off, l; 156 157 if (prefix->a.ss_family != sa->sa_family || 158 prefix->a.ss_len != sa->sa_len) 159 return 0; 160 161 if (prefix->a.ss_len > sizeof(a) || sa->sa_len > sizeof(b)) 162 return 0; 163 164 switch (prefix->a.ss_family) { 165 case AF_INET: 166 off = offsetof(struct sockaddr_in, sin_addr); 167 break; 168 case AF_INET6: 169 off = offsetof(struct sockaddr_in6, sin6_addr); 170 break; 171 default: 172 if (memcmp(&prefix->a, sa, prefix->a.ss_len) != 0) 173 return 0; 174 else 175 return 1; 176 } 177 178 memcpy(&a, &prefix->a, prefix->a.ss_len); 179 memcpy(&b, sa, sa->sa_len); 180 l = prefix->l / 8 + (prefix->l % 8 ? 1 : 0); 181 182 /* overrun check */ 183 if (off + l > a.ss_len) 184 return 0; 185 186 pa = ((char *)&a) + off; 187 pb = ((char *)&b) + off; 188 if (prefix->l % 8) { 189 pa[prefix->l / 8] &= 0xff00 >> (prefix->l % 8); 190 pb[prefix->l / 8] &= 0xff00 >> (prefix->l % 8); 191 } 192 if (memcmp(pa, pb, l) != 0) 193 return 0; 194 else 195 return 1; 196 } 197 198 /* 199 * prefix/prefixlen permit/deny prefix/prefixlen [srcaddr] 200 * 3ffe::/16 permit 10.0.0.0/8 10.1.1.1 201 */ 202 static struct config * 203 config_load1(line) 204 const char *line; 205 { 206 struct config *conf; 207 char buf[BUFSIZ]; 208 char *p; 209 char *token[4]; 210 int i; 211 212 if (strlen(line) + 1 > sizeof(buf)) 213 return NULL; 214 strlcpy(buf, line, sizeof(buf)); 215 216 p = strchr(buf, '\n'); 217 if (!p) 218 return NULL; 219 *p = '\0'; 220 p = strchr(buf, '#'); 221 if (p) 222 *p = '\0'; 223 if (strlen(buf) == 0) 224 return NULL; 225 226 p = buf; 227 memset(token, 0, sizeof(token)); 228 for (i = 0; i < sizeof(token) / sizeof(token[0]); i++) { 229 token[i] = strtok(p, "\t "); 230 p = NULL; 231 if (token[i] == NULL) 232 break; 233 } 234 /* extra tokens? */ 235 if (strtok(p, "\t ") != NULL) 236 return NULL; 237 /* insufficient tokens */ 238 switch (i) { 239 case 3: 240 case 4: 241 break; 242 default: 243 return NULL; 244 } 245 246 conf = (struct config *)malloc(sizeof(*conf)); 247 if (conf == NULL) 248 return NULL; 249 memset(conf, 0, sizeof(*conf)); 250 251 if (strcasecmp(token[1], "permit") == 0) 252 conf->permit = 1; 253 else if (strcasecmp(token[1], "deny") == 0) 254 conf->permit = 0; 255 else { 256 /* invalid keyword is considered as "deny" */ 257 conf->permit = 0; 258 } 259 260 if (prefix_set(token[0], &conf->match, 1) < 0) 261 goto fail; 262 if (prefix_set(token[2], &conf->dest, 1) < 0) 263 goto fail; 264 if (token[3]) { 265 if (prefix_set(token[3], &conf->src, 0) < 0) 266 goto fail; 267 } 268 269 return conf; 270 271 fail: 272 free(conf); 273 return NULL; 274 } 275 276 int 277 config_load(configfile) 278 const char *configfile; 279 { 280 FILE *fp; 281 char buf[BUFSIZ]; 282 struct config *conf, *p; 283 struct config sentinel; 284 285 config_list = NULL; 286 287 if (!configfile) 288 configfile = _PATH_PREFIX_CONF; 289 fp = fopen(configfile, "r"); 290 if (fp == NULL) 291 return -1; 292 293 p = &sentinel; 294 while (fgets(buf, sizeof(buf), fp) != NULL) { 295 conf = config_load1(buf); 296 if (conf) { 297 p->next = conf; 298 p = p->next; 299 } 300 } 301 config_list = sentinel.next; 302 303 fclose(fp); 304 return 0; 305 } 306 307 #if 0 308 static void 309 config_show1(conf) 310 const struct config *conf; 311 { 312 const char *p; 313 314 p = prefix_string(&conf->match); 315 printf("%s", p ? p : "?"); 316 317 if (conf->permit) 318 printf(" permit"); 319 else 320 printf(" deny"); 321 322 p = prefix_string(&conf->dest); 323 printf(" %s", p ? p : "?"); 324 325 printf("\n"); 326 } 327 328 static void 329 config_show() 330 { 331 struct config *conf; 332 333 for (conf = config_list; conf; conf = conf->next) 334 config_show1(conf); 335 } 336 #endif 337 338 const struct config * 339 config_match(sa1, sa2) 340 struct sockaddr *sa1, *sa2; 341 { 342 static struct config conf; 343 const struct config *p; 344 345 if (sa1->sa_len > sizeof(conf.match.a) || 346 sa2->sa_len > sizeof(conf.dest.a)) 347 return NULL; 348 349 memset(&conf, 0, sizeof(conf)); 350 if (!config_list) { 351 conf.permit = 1; 352 memcpy(&conf.match.a, sa1, sa1->sa_len); 353 memcpy(&conf.dest.a, sa2, sa2->sa_len); 354 return &conf; 355 } 356 357 for (p = config_list; p; p = p->next) 358 if (prefix_match(&p->match, sa1) && prefix_match(&p->dest, sa2)) 359 return p; 360 361 return NULL; 362 } 363