1 /* $NetBSD: npf_data.c,v 1.19 2012/11/26 20:34:28 rmind Exp $ */ 2 3 /*- 4 * Copyright (c) 2009-2012 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /* 30 * npfctl(8) data manipulation and helper routines. 31 */ 32 33 #include <sys/cdefs.h> 34 __RCSID("$NetBSD: npf_data.c,v 1.19 2012/11/26 20:34:28 rmind Exp $"); 35 36 #include <sys/types.h> 37 #include <sys/null.h> 38 39 #include <netinet/in.h> 40 #include <netinet/in_systm.h> 41 #include <netinet/ip.h> 42 #define ICMP_STRINGS 43 #include <netinet/ip_icmp.h> 44 #define ICMP6_STRINGS 45 #include <netinet/icmp6.h> 46 #include <netinet/tcp.h> 47 #include <net/if.h> 48 49 #include <stdlib.h> 50 #include <string.h> 51 #include <err.h> 52 #include <errno.h> 53 #include <ifaddrs.h> 54 #include <netdb.h> 55 56 #include "npfctl.h" 57 58 static struct ifaddrs * ifs_list = NULL; 59 60 unsigned long 61 npfctl_find_ifindex(const char *ifname) 62 { 63 unsigned long if_idx = if_nametoindex(ifname); 64 65 if (!if_idx) { 66 if ((if_idx = npfctl_debug_addif(ifname)) != 0) { 67 return if_idx; 68 } 69 yyerror("unknown interface '%s'", ifname); 70 } 71 return if_idx; 72 } 73 74 static bool 75 npfctl_copy_address(sa_family_t fam, npf_addr_t *addr, const void *ptr) 76 { 77 memset(addr, 0, sizeof(npf_addr_t)); 78 79 switch (fam) { 80 case AF_INET: { 81 const struct sockaddr_in *sin = ptr; 82 memcpy(addr, &sin->sin_addr, sizeof(sin->sin_addr)); 83 return true; 84 } 85 case AF_INET6: { 86 const struct sockaddr_in6 *sin6 = ptr; 87 memcpy(addr, &sin6->sin6_addr, sizeof(sin6->sin6_addr)); 88 return true; 89 } 90 default: 91 yyerror("unknown address family %u", fam); 92 return false; 93 } 94 } 95 96 static bool 97 npfctl_parse_fam_addr(const char *name, sa_family_t *fam, npf_addr_t *addr) 98 { 99 static const struct addrinfo hint = { 100 .ai_family = AF_UNSPEC, 101 .ai_flags = AI_NUMERICHOST 102 }; 103 struct addrinfo *ai; 104 int ret; 105 106 ret = getaddrinfo(name, NULL, &hint, &ai); 107 if (ret) { 108 yyerror("cannot parse '%s' (%s)", name, gai_strerror(ret)); 109 return false; 110 } 111 if (fam) { 112 *fam = ai->ai_family; 113 } 114 if (!npfctl_copy_address(*fam, addr, ai->ai_addr)) { 115 return false; 116 } 117 freeaddrinfo(ai); 118 return true; 119 } 120 121 static bool 122 npfctl_parse_mask(const char *s, sa_family_t fam, npf_netmask_t *mask) 123 { 124 char *ep = NULL; 125 npf_addr_t addr; 126 uint8_t *ap; 127 128 if (s) { 129 errno = 0; 130 *mask = (npf_netmask_t)strtol(s, &ep, 0); 131 if (*ep == '\0' && s != ep && errno != ERANGE) 132 return true; 133 if (!npfctl_parse_fam_addr(s, &fam, &addr)) 134 return false; 135 } 136 137 assert(fam == AF_INET || fam == AF_INET6); 138 *mask = NPF_NO_NETMASK; 139 if (ep == NULL) { 140 return true; 141 } 142 143 ap = addr.s6_addr + (*mask / 8) - 1; 144 while (ap >= addr.s6_addr) { 145 for (int j = 8; j > 0; j--) { 146 if (*ap & 1) 147 return true; 148 *ap >>= 1; 149 (*mask)--; 150 if (*mask == 0) 151 return true; 152 } 153 ap--; 154 } 155 return true; 156 } 157 158 /* 159 * npfctl_parse_fam_addr_mask: return address family, address and mask. 160 * 161 * => Mask is optional and can be NULL. 162 * => Returns true on success or false if unable to parse. 163 */ 164 npfvar_t * 165 npfctl_parse_fam_addr_mask(const char *addr, const char *mask, 166 unsigned long *nummask) 167 { 168 npfvar_t *vp = npfvar_create(".addr"); 169 fam_addr_mask_t fam; 170 171 memset(&fam, 0, sizeof(fam)); 172 173 if (!npfctl_parse_fam_addr(addr, &fam.fam_family, &fam.fam_addr)) 174 goto out; 175 176 /* 177 * Note: both mask and nummask may be NULL. In such case, 178 * npfctl_parse_mask() will handle and will set full mask. 179 */ 180 if (nummask) { 181 fam.fam_mask = *nummask; 182 } else if (!npfctl_parse_mask(mask, fam.fam_family, &fam.fam_mask)) { 183 goto out; 184 } 185 186 if (!npfvar_add_element(vp, NPFVAR_FAM, &fam, sizeof(fam))) 187 goto out; 188 189 return vp; 190 out: 191 npfvar_destroy(vp); 192 return NULL; 193 } 194 195 npfvar_t * 196 npfctl_parse_table_id(const char *id) 197 { 198 npfvar_t *vp; 199 200 if (!npfctl_table_exists_p(id)) { 201 yyerror("table '%s' is not defined", id); 202 return NULL; 203 } 204 vp = npfvar_create(".table"); 205 206 if (!npfvar_add_element(vp, NPFVAR_TABLE, id, strlen(id) + 1)) 207 goto out; 208 209 return vp; 210 out: 211 npfvar_destroy(vp); 212 return NULL; 213 } 214 215 /* 216 * npfctl_parse_port_range: create a port-range variable. Note that the 217 * passed port numbers should be in host byte order. 218 */ 219 npfvar_t * 220 npfctl_parse_port_range(in_port_t s, in_port_t e) 221 { 222 npfvar_t *vp = npfvar_create(".port_range"); 223 port_range_t pr; 224 225 pr.pr_start = htons(s); 226 pr.pr_end = htons(e); 227 228 if (!npfvar_add_element(vp, NPFVAR_PORT_RANGE, &pr, sizeof(pr))) 229 goto out; 230 231 return vp; 232 out: 233 npfvar_destroy(vp); 234 return NULL; 235 } 236 237 npfvar_t * 238 npfctl_parse_port_range_variable(const char *v) 239 { 240 npfvar_t *vp = npfvar_lookup(v); 241 size_t count = npfvar_get_count(vp); 242 npfvar_t *pvp = npfvar_create(".port_range"); 243 port_range_t *pr; 244 in_port_t p; 245 246 for (size_t i = 0; i < count; i++) { 247 int type = npfvar_get_type(vp, i); 248 void *data = npfvar_get_data(vp, type, i); 249 250 switch (type) { 251 case NPFVAR_IDENTIFIER: 252 case NPFVAR_STRING: 253 p = npfctl_portno(data); 254 npfvar_add_elements(pvp, npfctl_parse_port_range(p, p)); 255 break; 256 case NPFVAR_PORT_RANGE: 257 pr = data; 258 npfvar_add_element(pvp, NPFVAR_PORT_RANGE, pr, 259 sizeof(*pr)); 260 break; 261 case NPFVAR_NUM: 262 p = *(unsigned long *)data; 263 npfvar_add_elements(pvp, npfctl_parse_port_range(p, p)); 264 break; 265 default: 266 yyerror("wrong variable '%s' type '%s' for port range", 267 v, npfvar_type(type)); 268 npfvar_destroy(pvp); 269 return NULL; 270 } 271 } 272 return pvp; 273 } 274 275 npfvar_t * 276 npfctl_parse_ifnet(const char *ifname, const int family) 277 { 278 npfvar_t *vpa, *vp; 279 struct ifaddrs *ifa; 280 ifnet_addr_t ifna; 281 282 if (ifs_list == NULL && getifaddrs(&ifs_list) == -1) { 283 err(EXIT_FAILURE, "getifaddrs"); 284 } 285 286 vpa = npfvar_create(".ifaddrs"); 287 ifna.ifna_addrs = vpa; 288 ifna.ifna_index = npfctl_find_ifindex(ifname); 289 assert(ifna.ifna_index != 0); 290 291 for (ifa = ifs_list; ifa != NULL; ifa = ifa->ifa_next) { 292 fam_addr_mask_t fam; 293 struct sockaddr *sa; 294 295 if (strcmp(ifa->ifa_name, ifname) != 0) 296 continue; 297 298 if ((ifa->ifa_flags & IFF_UP) == 0) 299 warnx("interface '%s' is down", ifname); 300 301 sa = ifa->ifa_addr; 302 if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6) 303 continue; 304 if (family != AF_UNSPEC && sa->sa_family != family) 305 continue; 306 307 memset(&fam, 0, sizeof(fam)); 308 fam.fam_family = sa->sa_family; 309 fam.fam_ifindex = ifna.ifna_index; 310 311 if (!npfctl_copy_address(sa->sa_family, &fam.fam_addr, sa)) 312 goto out; 313 314 if (!npfctl_parse_mask(NULL, fam.fam_family, &fam.fam_mask)) 315 goto out; 316 317 if (!npfvar_add_element(vpa, NPFVAR_FAM, &fam, sizeof(fam))) 318 goto out; 319 } 320 if (npfvar_get_count(vpa) == 0) { 321 yyerror("no addresses matched for interface '%s'", ifname); 322 goto out; 323 } 324 325 vp = npfvar_create(".interface"); 326 npfvar_add_element(vp, NPFVAR_INTERFACE, &ifna, sizeof(ifna)); 327 return vp; 328 out: 329 npfvar_destroy(ifna.ifna_addrs); 330 return NULL; 331 } 332 333 bool 334 npfctl_parse_cidr(char *cidr, fam_addr_mask_t *fam, int *alen) 335 { 336 char *mask, *p; 337 338 p = strchr(cidr, '\n'); 339 if (p) { 340 *p = '\0'; 341 } 342 mask = strchr(cidr, '/'); 343 if (mask) { 344 *mask++ = '\0'; 345 } 346 347 memset(fam, 0, sizeof(*fam)); 348 if (!npfctl_parse_fam_addr(cidr, &fam->fam_family, &fam->fam_addr)) { 349 return false; 350 } 351 if (!npfctl_parse_mask(mask, fam->fam_family, &fam->fam_mask)) { 352 return false; 353 } 354 switch (fam->fam_family) { 355 case AF_INET: 356 *alen = sizeof(struct in_addr); 357 break; 358 case AF_INET6: 359 *alen = sizeof(struct in6_addr); 360 break; 361 default: 362 return false; 363 } 364 return true; 365 } 366 367 int 368 npfctl_protono(const char *proto) 369 { 370 struct protoent *pe; 371 372 pe = getprotobyname(proto); 373 if (pe == NULL) { 374 yyerror("unknown protocol '%s'", proto); 375 return -1; 376 } 377 return pe->p_proto; 378 } 379 380 /* 381 * npfctl_portno: convert port identifier (string) to a number. 382 * 383 * => Returns port number in host byte order. 384 */ 385 in_port_t 386 npfctl_portno(const char *port) 387 { 388 struct addrinfo *ai, *rai; 389 in_port_t p = 0; 390 int e; 391 392 e = getaddrinfo(NULL, port, NULL, &rai); 393 if (e != 0) { 394 yyerror("invalid port name '%s' (%s)", port, gai_strerror(e)); 395 return 0; 396 } 397 398 for (ai = rai; ai; ai = ai->ai_next) { 399 switch (ai->ai_family) { 400 case AF_INET: { 401 struct sockaddr_in *sin = (void *)ai->ai_addr; 402 p = sin->sin_port; 403 goto out; 404 } 405 case AF_INET6: { 406 struct sockaddr_in6 *sin6 = (void *)ai->ai_addr; 407 p = sin6->sin6_port; 408 goto out; 409 } 410 default: 411 break; 412 } 413 } 414 out: 415 freeaddrinfo(rai); 416 return ntohs(p); 417 } 418 419 npfvar_t * 420 npfctl_parse_tcpflag(const char *s) 421 { 422 uint8_t tfl = 0; 423 424 while (*s) { 425 switch (*s) { 426 case 'F': tfl |= TH_FIN; break; 427 case 'S': tfl |= TH_SYN; break; 428 case 'R': tfl |= TH_RST; break; 429 case 'P': tfl |= TH_PUSH; break; 430 case 'A': tfl |= TH_ACK; break; 431 case 'U': tfl |= TH_URG; break; 432 case 'E': tfl |= TH_ECE; break; 433 case 'W': tfl |= TH_CWR; break; 434 default: 435 yyerror("invalid flag '%c'", *s); 436 return NULL; 437 } 438 s++; 439 } 440 441 npfvar_t *vp = npfvar_create(".tcp_flag"); 442 if (!npfvar_add_element(vp, NPFVAR_TCPFLAG, &tfl, sizeof(tfl))) { 443 npfvar_destroy(vp); 444 return NULL; 445 } 446 447 return vp; 448 } 449 450 uint8_t 451 npfctl_icmptype(int proto, const char *type) 452 { 453 uint8_t ul; 454 455 switch (proto) { 456 case IPPROTO_ICMP: 457 for (ul = 0; icmp_type[ul]; ul++) 458 if (strcmp(icmp_type[ul], type) == 0) 459 return ul; 460 break; 461 case IPPROTO_ICMPV6: 462 for (ul = 0; icmp6_type_err[ul]; ul++) 463 if (strcmp(icmp6_type_err[ul], type) == 0) 464 return ul; 465 for (ul = 0; icmp6_type_info[ul]; ul++) 466 if (strcmp(icmp6_type_info[ul], type) == 0) 467 return (ul+128); 468 break; 469 default: 470 assert(false); 471 } 472 473 yyerror("unknown icmp-type %s", type); 474 return ~0; 475 } 476 477 uint8_t 478 npfctl_icmpcode(int proto, uint8_t type, const char *code) 479 { 480 const char * const *arr; 481 482 switch (proto) { 483 case IPPROTO_ICMP: 484 switch (type) { 485 case ICMP_ECHOREPLY: 486 case ICMP_SOURCEQUENCH: 487 case ICMP_ALTHOSTADDR: 488 case ICMP_ECHO: 489 case ICMP_ROUTERSOLICIT: 490 case ICMP_TSTAMP: 491 case ICMP_TSTAMPREPLY: 492 case ICMP_IREQ: 493 case ICMP_IREQREPLY: 494 case ICMP_MASKREQ: 495 case ICMP_MASKREPLY: 496 arr = icmp_code_none; 497 break; 498 case ICMP_ROUTERADVERT: 499 arr = icmp_code_routeradvert; 500 break; 501 case ICMP_UNREACH: 502 arr = icmp_code_unreach; 503 break; 504 case ICMP_REDIRECT: 505 arr = icmp_code_redirect; 506 break; 507 case ICMP_TIMXCEED: 508 arr = icmp_code_timxceed; 509 break; 510 case ICMP_PARAMPROB: 511 arr = icmp_code_paramprob; 512 break; 513 case ICMP_PHOTURIS: 514 arr = icmp_code_photuris; 515 break; 516 default: 517 yyerror("unknown icmp-type %d while parsing code %s", 518 type, code); 519 return ~0; 520 } 521 break; 522 case IPPROTO_ICMPV6: 523 switch (type) { 524 case ICMP6_DST_UNREACH: 525 arr = icmp6_code_unreach; 526 break; 527 case ICMP6_TIME_EXCEEDED: 528 arr = icmp6_code_timxceed; 529 break; 530 case ICMP6_PARAM_PROB: 531 arr = icmp6_code_paramprob; 532 break; 533 case ICMP6_PACKET_TOO_BIG: 534 /* code-less info ICMPs */ 535 case ICMP6_ECHO_REQUEST: 536 case ICMP6_ECHO_REPLY: 537 case MLD_LISTENER_QUERY: 538 case MLD_LISTENER_REPORT: 539 case MLD_LISTENER_DONE: 540 case ND_ROUTER_SOLICIT: 541 case ND_ROUTER_ADVERT: 542 case ND_NEIGHBOR_SOLICIT: 543 case ND_NEIGHBOR_ADVERT: 544 case ND_REDIRECT: 545 arr = icmp6_code_none; 546 break; 547 /* XXX TODO: info ICMPs with code values */ 548 default: 549 yyerror("unknown icmp-type %d while parsing code %s", 550 type, code); 551 return ~0; 552 } 553 break; 554 default: 555 assert(false); 556 } 557 558 for (uint8_t ul = 0; arr[ul]; ul++) { 559 if (strcmp(arr[ul], code) == 0) 560 return ul; 561 } 562 yyerror("unknown code %s for icmp-type %d", code, type); 563 return ~0; 564 } 565 566 npfvar_t * 567 npfctl_parse_icmp(int proto, int type, int code) 568 { 569 npfvar_t *vp = npfvar_create(".icmp"); 570 int varnum; 571 572 switch (proto) { 573 case IPPROTO_ICMP: 574 varnum = NPFVAR_ICMP; 575 break; 576 case IPPROTO_ICMPV6: 577 varnum = NPFVAR_ICMP6; 578 break; 579 default: 580 assert(false); 581 } 582 583 if (!npfvar_add_element(vp, varnum, &type, sizeof(type))) 584 goto out; 585 586 if (!npfvar_add_element(vp, varnum, &code, sizeof(code))) 587 goto out; 588 589 return vp; 590 out: 591 npfvar_destroy(vp); 592 return NULL; 593 } 594