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