rde_trie_test.c revision 1.3
1/* $OpenBSD: rde_trie_test.c,v 1.3 2018/09/10 20:51:59 benno 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 <netdb.h> 24#include <string.h> 25#include <stdlib.h> 26#include <stdio.h> 27#include <unistd.h> 28#include <util.h> 29 30#include "bgpd.h" 31#include "rde.h" 32 33 34static int 35host_v4(const char *s, struct bgpd_addr *h, u_int8_t *len, int *orl) 36{ 37 struct in_addr ina = { 0 }; 38 int bits = 32; 39 40 memset(h, 0, sizeof(*h)); 41 if (strrchr(s, '/') != NULL) { 42 if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1) 43 return (0); 44 } else { 45 if (inet_pton(AF_INET, s, &ina) != 1) 46 return (0); 47 } 48 h->aid = AID_INET; 49 h->v4.s_addr = ina.s_addr; 50 *len = bits; 51 return (1); 52} 53 54static int 55host_v6(const char *s, struct bgpd_addr *h, u_int8_t *len, int *orl) 56{ 57 struct addrinfo hints, *res; 58 const char *errstr; 59 char *p; 60 int mask = 128; 61 62 memset(h, 0, sizeof(*h)); 63 if ((p = strrchr(s, '/')) != NULL) { 64 mask = strtonum(p + 1, 0, 128, &errstr); 65 if (errstr) 66 return (0); 67 *p = '\0'; 68 } 69 70 bzero(&hints, sizeof(hints)); 71 hints.ai_family = AF_INET6; 72 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 73 hints.ai_flags = AI_NUMERICHOST; 74 if (getaddrinfo(s, "0", &hints, &res) == 0) { 75 h->aid = AID_INET6; 76 memcpy(&h->v6, &res->ai_addr->sa_data[6], sizeof(h->v6)); 77 freeaddrinfo(res); 78 *len = mask; 79 *p = '/'; 80 return (1); 81 } 82 *p = '/'; 83 84 return (0); 85} 86 87static int 88host_l(char *s, struct bgpd_addr *h, u_int8_t *len, int *orl) 89{ 90 char *c, *t; 91 92 *orl = 0; 93 if ((c = strchr(s, '\t')) != NULL) { 94 if (c[1] == '1') { 95 *orl = 1; 96 } 97 *c = '\0'; 98 } 99 100 if (host_v4(s, h, len, orl)) 101 return (1); 102 if (host_v6(s, h, len, orl)) 103 return (1); 104 return (0); 105} 106 107static const char * 108print_prefix(struct bgpd_addr *p) 109{ 110 static char buf[48]; 111 112 if (p->aid == AID_INET) { 113 if (inet_ntop(AF_INET, &p->ba, buf, sizeof(buf)) == NULL) 114 return "?"; 115 } else if (p->aid == AID_INET6) { 116 if (inet_ntop(AF_INET6, &p->ba, buf, sizeof(buf)) == NULL) 117 return "?"; 118 } else { 119 return "???"; 120 } 121 return buf; 122} 123 124static void 125parse_file(FILE *in, struct trie_head *th) 126{ 127 const char *errstr; 128 char *line, *s; 129 struct bgpd_addr prefix; 130 u_int8_t plen, min, max, maskmax; 131 int foo; 132 133 while ((line = fparseln(in, NULL, NULL, NULL, FPARSELN_UNESCALL))) { 134 int state = 0; 135 while ((s = strsep(&line, " \t"))) { 136 if (*s == '\0') 137 break; 138 switch (state) { 139 case 0: 140 if (!host_l(s, &prefix, &plen, &foo)) 141 errx(1, "could not parse prefix \"%s\"", 142 s); 143 break; 144 case 1: 145 if (prefix.aid == AID_INET6) 146 maskmax = 128; 147 else 148 maskmax = 32; 149 min = strtonum(s, 0, maskmax, &errstr); 150 if (errstr != NULL) 151 errx(1, "min is %s: %s", errstr, s); 152 break; 153 case 2: 154 if (prefix.aid == AID_INET6) 155 maskmax = 128; 156 else 157 maskmax = 32; 158 max = strtonum(s, 0, maskmax, &errstr); 159 if (errstr != NULL) 160 errx(1, "max is %s: %s", errstr, s); 161 break; 162 default: 163 errx(1, "could not parse \"%s\", confused", s); 164 } 165 state++; 166 } 167 168 if (trie_add(th, &prefix, plen, min, max) != 0) 169 errx(1, "trie_add(%s, %u, %u, %u) failed", 170 print_prefix(&prefix), plen, min, max); 171 172 free(line); 173 } 174} 175 176static void 177test_file(FILE *in, struct trie_head *th) 178{ 179 char *line; 180 struct bgpd_addr prefix; 181 u_int8_t plen; 182 int orlonger; 183 184 while ((line = fparseln(in, NULL, NULL, NULL, FPARSELN_UNESCALL))) { 185 if (!host_l(line, &prefix, &plen, &orlonger)) 186 errx(1, "could not parse prefix \"%s\"", line); 187 printf("%s ", line); 188 if (trie_match(th, &prefix, plen, orlonger)) 189 printf("MATCH %i\n", orlonger); 190 else 191 printf("miss %i\n", orlonger); 192 free(line); 193 } 194} 195 196static void 197usage(void) 198{ 199 extern char *__progname; 200 fprintf(stderr, "usage: %s prefixfile testfile\n", __progname); 201 exit(1); 202} 203 204int 205main(int argc, char **argv) 206{ 207 struct trie_head th = { 0 }; 208 FILE *in, *tin; 209 int ch; 210 211 if (argc != 3) 212 usage(); 213 214 in = fopen(argv[1], "r"); 215 if (in == NULL) 216 err(1, "fopen(%s)", argv[0]); 217 tin = fopen(argv[2], "r"); 218 if (tin == NULL) 219 err(1, "fopen(%s)", argv[1]); 220 221 parse_file(in, &th); 222 /* trie_dump(&th); */ 223 if (trie_equal(&th, &th) == 0) 224 errx(1, "trie_equal failure"); 225 test_file(tin, &th); 226 227 trie_free(&th); 228} 229