util.c revision 1.5
1/* $OpenBSD: util.c,v 1.5 2016/03/24 07:03:30 mpi Exp $ */ 2 3/* 4 * Copyright (c) 2015 Martin Pieuchot 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#include "srp_compat.h" 20 21#include <sys/socket.h> 22#include <sys/domain.h> 23#include <sys/queue.h> 24#include <sys/srp.h> 25 26#include <net/rtable.h> 27#include <net/route.h> 28 29#include <netinet/in.h> 30#include <arpa/inet.h> 31 32#include <assert.h> 33#include <err.h> 34#include <stddef.h> 35#include <stdio.h> 36#include <stdlib.h> 37#include <string.h> 38 39#include "util.h" 40 41struct sockaddr *rt_plen2mask(struct rtentry *, struct sockaddr_in6 *); 42 43struct domain inetdomain = { 44 AF_INET, "inet", NULL, NULL, NULL, NULL, NULL, 45 sizeof(struct sockaddr_in), offsetof(struct sockaddr_in, sin_addr), 46 32, 47}; 48 49struct domain inet6domain = { 50 AF_INET6, "inet6", NULL, NULL, NULL, NULL, NULL, 51 sizeof(struct sockaddr_in6), offsetof(struct sockaddr_in6, sin6_addr), 52 128, 53}; 54 55struct domain *domains[] = { &inetdomain, &inet6domain, NULL }; 56 57/* 58 * Insert a route from a string containing a destination: "192.168.1/24" 59 */ 60void 61route_insert(unsigned int rid, sa_family_t af, char *string) 62{ 63 struct sockaddr_storage ss, ms; 64 struct sockaddr *ndst, *dst = (struct sockaddr *)&ss; 65 struct sockaddr *mask = (struct sockaddr *)&ms; 66 struct rtentry *rt, *nrt; 67 char ip[INET6_ADDRSTRLEN]; 68 int plen, error; 69 70 rt = calloc(1, sizeof(*rt)); 71 if (rt == NULL) 72 errx(1, "out of memory"); 73 74 plen = inet_net_ptosa(af, string, dst, mask); 75 if (plen == -1) 76 err(1, "wrong line: %s", string); 77 78 /* Normalize sockaddr a la rtrequest1(9) */ 79 ndst = malloc(dst->sa_len); 80 if (ndst == NULL) 81 errx(1, "out of memory"); 82 rt_maskedcopy(dst, ndst, mask); 83 84 if ((error = rtable_insert(rid, ndst, mask, NULL, 0, rt)) != 0) { 85 inet_net_satop(af, rt_key(rt), plen, ip, sizeof(ip)); 86 errx(1, "can't add route: %s, %s\n", ip, strerror(error)); 87 } 88 nrt = rtable_lookup(rid, dst, mask, NULL, RTP_ANY); 89 if (nrt != rt) { 90 inet_net_satop(af, rt_key(rt), plen, ip, sizeof(ip)); 91 errx(1, "added route not found: %s\n", ip); 92 } 93} 94 95/* 96 * Delete a route from a string containing a destination: "192.168.1/24" 97 */ 98void 99route_delete(unsigned int rid, sa_family_t af, char *string) 100{ 101 struct sockaddr_storage ss, ms; 102 struct sockaddr *dst = (struct sockaddr *)&ss; 103 struct sockaddr *mask = (struct sockaddr *)&ms; 104 struct rtentry *rt, *nrt; 105 char ip[INET6_ADDRSTRLEN]; 106 int plen, error; 107 108 plen = inet_net_ptosa(af, string, dst, mask); 109 if (plen == -1) 110 err(1, "wrong line: %s", string); 111 112 rt = rtable_lookup(0, dst, mask, NULL, RTP_ANY); 113 if (rt == NULL) { 114 inet_net_satop(af, dst, plen, ip, sizeof(ip)); 115 errx(1, "can't find route: %s\n", ip); 116 } 117 118 assert(memcmp(rt_key(rt), dst, dst->sa_len) == 0); 119 assert(rt_plen(rt) == rtable_satoplen(af, mask)); 120 121 if ((error = rtable_delete(0, dst, mask, rt)) != 0) { 122 inet_net_satop(af, dst, plen, ip, sizeof(ip)); 123 errx(1, "can't rm route: %s, %s\n", ip, strerror(error)); 124 } 125 126 nrt = rtable_lookup(0, dst, mask, NULL, RTP_ANY); 127 if (nrt != NULL) { 128 char ip0[INET6_ADDRSTRLEN]; 129 inet_net_satop(af, rt_key(nrt), plen, ip, sizeof(ip)); 130 inet_net_satop(af, rt_key(rt), plen, ip0, sizeof(ip0)); 131 errx(1, "found: %s after deleting: %s", ip, ip0); 132 } 133 134 free(rt_key(rt)); 135 free(rt); 136} 137 138/* 139 * Lookup a route from a string containing a destination: "192.168.1/24" 140 */ 141void 142route_lookup(unsigned int rid, sa_family_t af, char *string) 143{ 144 struct sockaddr_storage ss, ms; 145 struct sockaddr *dst = (struct sockaddr *)&ss; 146 struct sockaddr *mask = (struct sockaddr *)&ms; 147 struct rtentry *rt; 148 char ip[INET6_ADDRSTRLEN]; 149 int plen; 150 151 plen = inet_net_ptosa(af, string, dst, mask); 152 if (plen == -1) 153 err(1, "wrong line: %s", string); 154 155 rt = rtable_lookup(0, dst, mask, NULL, RTP_ANY); 156 if (rt == NULL) { 157 inet_net_satop(af, dst, plen, ip, sizeof(ip)); 158 errx(1, "%s not found\n", ip); 159 } 160 assert(memcmp(rt_key(rt), dst, dst->sa_len) == 0); 161 assert(rt_plen(rt) == rtable_satoplen(af, mask)); 162} 163 164int 165do_from_file(unsigned int rid, sa_family_t af, char *filename, 166 void (*func)(unsigned int, sa_family_t, char *)) 167{ 168 FILE *fp; 169 char *buf; 170 size_t len; 171 int lines = 0; 172 173 if ((fp = fopen(filename, "r")) == NULL) 174 errx(1, "No such file: %s\n", filename); 175 176 while ((buf = fgetln(fp, &len)) != NULL) { 177 if (buf[len - 1] == '\n') 178 buf[len - 1] = '\0'; 179 180 (*func)(rid, af, buf); 181 lines++; 182 } 183 fclose(fp); 184 185 return (lines); 186} 187 188int 189rtentry_dump(struct rtentry *rt, void *w, unsigned int rid) 190{ 191 char dest[INET6_ADDRSTRLEN]; 192 sa_family_t af = rt_key(rt)->sa_family; 193 194 inet_net_satop(af, rt_key(rt), rt_plen(rt), dest, sizeof(dest)); 195 printf("%s\n", dest); 196 197 return (0); 198} 199 200int 201rtentry_delete(struct rtentry *rt, void *w, unsigned int rid) 202{ 203 char dest[INET6_ADDRSTRLEN]; 204 sa_family_t af = rt_key(rt)->sa_family; 205 struct sockaddr_in6 sa_mask; 206 struct sockaddr *mask = rt_plen2mask(rt, &sa_mask); 207 int error; 208 209 assert(rt_plen(rt) == rtable_satoplen(af, mask)); 210 211 if ((error = rtable_delete(0, rt_key(rt), mask, rt)) != 0) { 212 inet_net_satop(af, rt_key(rt), rt_plen(rt), dest, sizeof(dest)); 213 errx(1, "can't rm route: %s, %s\n", dest, strerror(error)); 214 } 215 216 return (0); 217} 218 219void 220rt_maskedcopy(struct sockaddr *src, struct sockaddr *dst, 221 struct sockaddr *netmask) 222{ 223 uint8_t *cp1 = (uint8_t *)src; 224 uint8_t *cp2 = (uint8_t *)dst; 225 uint8_t *cp3 = (uint8_t *)netmask; 226 uint8_t *cplim = cp2 + *cp3; 227 uint8_t *cplim2 = cp2 + *cp1; 228 229 *cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ 230 cp3 += 2; 231 if (cplim > cplim2) 232 cplim = cplim2; 233 while (cp2 < cplim) 234 *cp2++ = *cp1++ & *cp3++; 235 if (cp2 < cplim2) 236 memset(cp2, 0, (unsigned int)(cplim2 - cp2)); 237} 238 239void 240in_prefixlen2mask(struct in_addr *maskp, int plen) 241{ 242 if (plen == 0) 243 maskp->s_addr = 0; 244 else 245 maskp->s_addr = htonl(0xffffffff << (32 - plen)); 246} 247 248void 249in6_prefixlen2mask(struct in6_addr *maskp, int len) 250{ 251 uint8_t maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; 252 int bytelen, bitlen, i; 253 254 assert(0 <= len && len <= 128); 255 256 memset(maskp, 0, sizeof(*maskp)); 257 bytelen = len / 8; 258 bitlen = len % 8; 259 for (i = 0; i < bytelen; i++) 260 maskp->s6_addr[i] = 0xff; 261 /* len == 128 is ok because bitlen == 0 then */ 262 if (bitlen) 263 maskp->s6_addr[bytelen] = maskarray[bitlen - 1]; 264} 265 266struct sockaddr * 267rt_plentosa(sa_family_t af, int plen, struct sockaddr_in6 *sa_mask) 268{ 269 struct sockaddr_in *sin = (struct sockaddr_in *)sa_mask; 270 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa_mask; 271 272 assert(plen >= 0 || plen == -1); 273 274 if (plen == -1) 275 return (NULL); 276 277 memset(sa_mask, 0, sizeof(*sa_mask)); 278 279 switch (af) { 280 case AF_INET: 281 sin->sin_family = AF_INET; 282 sin->sin_len = sizeof(struct sockaddr_in); 283 in_prefixlen2mask(&sin->sin_addr, plen); 284 break; 285 case AF_INET6: 286 sin6->sin6_family = AF_INET6; 287 sin6->sin6_len = sizeof(struct sockaddr_in6); 288 in6_prefixlen2mask(&sin6->sin6_addr, plen); 289 break; 290 default: 291 return (NULL); 292 } 293 294 return ((struct sockaddr *)sa_mask); 295} 296 297struct sockaddr * 298rt_plen2mask(struct rtentry *rt, struct sockaddr_in6 *sa_mask) 299{ 300#ifndef ART 301 return (rt_mask(rt)); 302#else 303 return (rt_plentosa(rt_key(rt)->sa_family, rt_plen(rt), sa_mask)); 304#endif /* ART */ 305} 306 307 308int 309inet_net_ptosa(sa_family_t af, const char *buf, struct sockaddr *sa, 310 struct sockaddr *ma) 311{ 312 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 313 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 314 int i, plen; 315 316 switch (af) { 317 case AF_INET: 318 memset(sin, 0, sizeof(*sin)); 319 sin->sin_family = af; 320 sin->sin_len = sizeof(*sin); 321 plen = inet_net_pton(af, buf, &sin->sin_addr, 322 sizeof(sin->sin_addr)); 323 if (plen == -1 || ma == NULL) 324 break; 325 326 sin = (struct sockaddr_in *)ma; 327 memset(sin, 0, sizeof(*sin)); 328 sin->sin_len = sizeof(*sin); 329 sin->sin_family = 0; 330 in_prefixlen2mask(&sin->sin_addr, plen); 331 break; 332 case AF_INET6: 333 memset(sin6, 0, sizeof(*sin6)); 334 sin6->sin6_family = af; 335 sin6->sin6_len = sizeof(*sin6); 336 plen = inet_net_pton(af, buf, &sin6->sin6_addr, 337 sizeof(sin6->sin6_addr)); 338 if (plen == -1 || ma == NULL) 339 break; 340 341 sin6 = (struct sockaddr_in6 *)ma; 342 memset(sin6, 0, sizeof(*sin6)); 343 sin6->sin6_len = sizeof(*sin6); 344 sin6->sin6_family = 0; 345 for (i = 0; i < plen / 8; i++) 346 sin6->sin6_addr.s6_addr[i] = 0xff; 347 i = plen % 8; 348 if (i) 349 sin6->sin6_addr.s6_addr[plen / 8] = 0xff00 >> i; 350 break; 351 default: 352 plen = -1; 353 } 354 355 return (plen); 356} 357 358/* 359 * Only compare the address fields, we cannot use memcmp(3) because 360 * the radix tree abuses the first fields of the mask sockaddr for 361 * a different purpose. 362 */ 363int 364maskcmp(sa_family_t af, struct sockaddr *sa1, struct sockaddr *sa2) 365{ 366 struct sockaddr_in *sin1, *sin2; 367 struct sockaddr_in6 *sin61, *sin62; 368 int len; 369 370 switch (af) { 371 case AF_INET: 372 sin1 = (struct sockaddr_in *)sa1; 373 sin2 = (struct sockaddr_in *)sa2; 374 len = sizeof(sin1->sin_addr); 375 return memcmp(&sin1->sin_addr, &sin2->sin_addr, len); 376 case AF_INET6: 377 sin61 = (struct sockaddr_in6 *)sa1; 378 sin62 = (struct sockaddr_in6 *)sa2; 379 len = sizeof(sin61->sin6_addr); 380 return memcmp(&sin61->sin6_addr, &sin62->sin6_addr, len); 381 default: 382 return (-1); 383 } 384} 385 386char * 387inet_net_satop(sa_family_t af, struct sockaddr *sa, int plen, char *buf, 388 size_t len) 389{ 390 struct sockaddr_in *sin = (struct sockaddr_in *)sa; 391 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 392 393 switch (af) { 394 case AF_INET: 395 return inet_net_ntop(af, &sin->sin_addr, plen, buf, len); 396 case AF_INET6: 397 return inet_net_ntop(af, &sin6->sin6_addr, plen, buf, len); 398 default: 399 return (NULL); 400 } 401} 402