rde_trie_test.c revision 1.8
1/* $OpenBSD: rde_trie_test.c,v 1.8 2018/09/29 08:13:56 claudio Exp $ */ 2 3/* 4 * Copyright (c) 2018 Claudio Jeker <claudio@openbsd.org> 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#include <sys/types.h> 19#include <sys/queue.h> 20#include <sys/socket.h> 21 22#include <err.h> 23#include <limits.h> 24#include <netdb.h> 25#include <string.h> 26#include <stdlib.h> 27#include <stdio.h> 28#include <unistd.h> 29#include <util.h> 30 31#include "bgpd.h" 32#include "rde.h" 33 34int roa; 35int orlonger; 36 37int 38host_ip(const char *s, struct bgpd_addr *h, u_int8_t *len) 39{ 40 struct addrinfo hints, *res; 41 int bits; 42 43 bzero(&hints, sizeof(hints)); 44 hints.ai_family = AF_UNSPEC; 45 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 46 hints.ai_flags = AI_NUMERICHOST; 47 if (getaddrinfo(s, NULL, &hints, &res) == 0) { 48 *len = res->ai_family == AF_INET6 ? 128 : 32; 49 sa2addr(res->ai_addr, h); 50 freeaddrinfo(res); 51 } else { /* ie. for 10/8 parsing */ 52 if ((bits = inet_net_pton(AF_INET, s, &h->v4, sizeof(h->v4))) == -1) 53 return (0); 54 *len = bits; 55 h->aid = AID_INET; 56 } 57 58 return (1); 59} 60 61int 62host(const char *s, struct bgpd_addr *h, u_int8_t *len) 63{ 64 int mask = 128; 65 char *p, *ps; 66 const char *errstr; 67 68 if ((ps = strdup(s)) == NULL) 69 errx(1, "%s: strdup", __func__); 70 71 if ((p = strrchr(ps, '/')) != NULL) { 72 mask = strtonum(p+1, 0, 128, &errstr); 73 if (errstr) { 74 warnx("prefixlen is %s: %s", errstr, p+1); 75 return (0); 76 } 77 p[0] = '\0'; 78 } 79 80 bzero(h, sizeof(*h)); 81 82 if (host_ip(ps, h, len) == 0) { 83 free(ps); 84 return (0); 85 } 86 87 if (p != NULL) 88 *len = mask; 89 90 free(ps); 91 return (1); 92} 93 94 95static const char * 96print_prefix(struct bgpd_addr *p) 97{ 98 static char buf[48]; 99 100 if (p->aid == AID_INET) { 101 if (inet_ntop(AF_INET, &p->ba, buf, sizeof(buf)) == NULL) 102 return "?"; 103 } else if (p->aid == AID_INET6) { 104 if (inet_ntop(AF_INET6, &p->ba, buf, sizeof(buf)) == NULL) 105 return "?"; 106 } else { 107 return "???"; 108 } 109 return buf; 110} 111 112static void 113parse_file(FILE *in, struct trie_head *th) 114{ 115 const char *errstr; 116 char *line, *s; 117 struct bgpd_addr prefix; 118 u_int8_t plen; 119 120 while ((line = fparseln(in, NULL, NULL, NULL, FPARSELN_UNESCALL))) { 121 int state = 0; 122 u_int8_t min = 255, max = 255, maskmax = 0; 123 124 while ((s = strsep(&line, " \t\n"))) { 125 if (*s == '\0') 126 continue; 127 switch (state) { 128 case 0: 129 if (!host(s, &prefix, &plen)) 130 errx(1, "%s: could not parse " 131 "prefix \"%s\"", __func__, s); 132 if (prefix.aid == AID_INET6) 133 maskmax = 128; 134 else 135 maskmax = 32; 136 break; 137 case 1: 138 min = strtonum(s, 0, maskmax, &errstr); 139 if (errstr != NULL) 140 errx(1, "min is %s: %s", errstr, s); 141 break; 142 case 2: 143 max = strtonum(s, 0, maskmax, &errstr); 144 if (errstr != NULL) 145 errx(1, "max is %s: %s", errstr, s); 146 break; 147 default: 148 errx(1, "could not parse \"%s\", confused", s); 149 } 150 state++; 151 } 152 if (state == 0) 153 continue; 154 if (max == 255) 155 max = maskmax; 156 if (min == 255) 157 min = plen; 158 159 if (trie_add(th, &prefix, plen, min, max) != 0) 160 errx(1, "trie_add(%s, %u, %u, %u) failed", 161 print_prefix(&prefix), plen, min, max); 162 163 free(line); 164 } 165} 166 167static void 168parse_roa_file(FILE *in, struct trie_head *th) 169{ 170 const char *errstr; 171 char *line, *s; 172 struct set_table *set = NULL; 173 struct roa_set rs; 174 struct bgpd_addr prefix; 175 u_int8_t plen; 176 177 while ((line = fparseln(in, NULL, NULL, NULL, FPARSELN_UNESCALL))) { 178 int state = 0; 179 u_int32_t as; 180 u_int8_t max = 0; 181 182 while ((s = strsep(&line, " \t\n"))) { 183 if (*s == '\0') 184 continue; 185 if (strcmp(s, "source-as") == 0) { 186 state = 4; 187 continue; 188 } 189 if (strcmp(s, "maxlen") == 0) { 190 state = 2; 191 continue; 192 } 193 if (strcmp(s, "prefix") == 0) { 194 state = 0; 195 continue; 196 } 197 switch (state) { 198 case 0: 199 if (!host(s, &prefix, &plen)) 200 errx(1, "%s: could not parse " 201 "prefix \"%s\"", __func__, s); 202 break; 203 case 2: 204 max = strtonum(s, 0, 128, &errstr); 205 if (errstr != NULL) 206 errx(1, "max is %s: %s", errstr, s); 207 break; 208 case 4: 209 as = strtonum(s, 0, UINT_MAX, &errstr); 210 if (errstr != NULL) 211 errx(1, "source-as is %s: %s", errstr, 212 s); 213 break; 214 default: 215 errx(1, "could not parse \"%s\", confused", s); 216 } 217 } 218 219 if (state == 0) { 220 set_prep(set); 221 if (trie_roa_add(th, &prefix, plen, set) != 0) 222 errx(1, "trie_roa_add(%s, %u) failed", 223 print_prefix(&prefix), plen); 224 set = NULL; 225 } else { 226 if (set == NULL) { 227 if ((set = set_new(1, sizeof(rs))) == NULL) 228 err(1, "set_new"); 229 } 230 rs.as = as; 231 rs.maxlen = max; 232 if (set_add(set, &rs, 1) != 0) 233 err(1, "set_add"); 234 } 235 236 free(line); 237 } 238} 239 240static void 241test_file(FILE *in, struct trie_head *th) 242{ 243 char *line; 244 struct bgpd_addr prefix; 245 u_int8_t plen; 246 247 while ((line = fparseln(in, NULL, NULL, NULL, FPARSELN_UNESCALL))) { 248 if (!host(line, &prefix, &plen)) 249 errx(1, "%s: could not parse prefix \"%s\"", 250 __func__, line); 251 printf("%s/%u ", print_prefix(&prefix), plen); 252 if (trie_match(th, &prefix, plen, orlonger)) 253 printf("MATCH\n"); 254 else 255 printf("miss\n"); 256 free(line); 257 } 258} 259 260static void 261test_roa_file(FILE *in, struct trie_head *th) 262{ 263 const char *errstr; 264 char *line, *s; 265 struct bgpd_addr prefix; 266 u_int8_t plen; 267 u_int32_t as; 268 int r; 269 270 while ((line = fparseln(in, NULL, NULL, NULL, FPARSELN_UNESCALL))) { 271 s = strchr(line, ' '); 272 if (s) 273 *s++ = '\0'; 274 if (!host(line, &prefix, &plen)) 275 errx(1, "%s: could not parse prefix \"%s\"", 276 __func__, line); 277 if (s) 278 s = strstr(s, "source-as"); 279 if (s) { 280 s += strlen("source-as"); 281 as = strtonum(s, 0, UINT_MAX, &errstr); 282 if (errstr != NULL) 283 errx(1, "source-as is %s: %s", errstr, s); 284 } else 285 as = 0; 286 printf("%s/%u source-as %u is ", 287 print_prefix(&prefix), plen, as); 288 r = trie_roa_check(th, &prefix, plen, as); 289 switch (r) { 290 case ROA_NOTFOUND: 291 printf("not found\n"); 292 break; 293 case ROA_VALID: 294 printf("VALID\n"); 295 break; 296 case ROA_INVALID: 297 printf("invalid\n"); 298 break; 299 default: 300 printf("UNEXPECTED %d\n", r); 301 break; 302 } 303 free(line); 304 } 305} 306 307static void 308usage(void) 309{ 310 extern char *__progname; 311 fprintf(stderr, "usage: %s [-or] prefixfile testfile\n", __progname); 312 exit(1); 313} 314 315int 316main(int argc, char **argv) 317{ 318 struct trie_head th = { 0 }; 319 FILE *in, *tin; 320 int ch; 321 322 while ((ch = getopt(argc, argv, "or")) != -1) { 323 switch (ch) { 324 case 'o': 325 orlonger = 1; 326 break; 327 case 'r': 328 roa = 1; 329 break; 330 default: 331 usage(); 332 /* NOTREACHED */ 333 } 334 } 335 argc -= optind; 336 argv += optind; 337 338 if (argc != 2) 339 usage(); 340 341 in = fopen(argv[0], "r"); 342 if (in == NULL) 343 err(1, "fopen(%s)", argv[0]); 344 tin = fopen(argv[1], "r"); 345 if (tin == NULL) 346 err(1, "fopen(%s)", argv[1]); 347 348 if (roa) 349 parse_roa_file(in, &th); 350 else 351 parse_file(in, &th); 352 /* trie_dump(&th); */ 353 if (trie_equal(&th, &th) == 0) 354 errx(1, "trie_equal failure"); 355 if (roa) 356 test_roa_file(tin, &th); 357 else 358 test_file(tin, &th); 359 360 trie_free(&th); 361} 362