1 /* 2 * Copyright (C) 1999-2001, 2003 by Darren Reed. 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 * 6 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 7 * Use is subject to license terms. 8 */ 9 10 #pragma ident "%Z%%M% %I% %E% SMI" 11 12 #if !defined(lint) 13 static const char rcsid[] = "@(#)$Id: ip_fil_solaris.c,v 2.36 2003/07/01 18:30:20 darrenr Exp $"; 14 #endif 15 16 #include <sys/types.h> 17 #include <sys/errno.h> 18 #include <sys/param.h> 19 #include <sys/cpuvar.h> 20 #include <sys/open.h> 21 #include <sys/ioctl.h> 22 #include <sys/filio.h> 23 #include <sys/systm.h> 24 #include <sys/cred.h> 25 #include <sys/ddi.h> 26 #include <sys/sunddi.h> 27 #include <sys/ksynch.h> 28 #include <sys/kmem.h> 29 #include <sys/mkdev.h> 30 #include <sys/protosw.h> 31 #include <sys/socket.h> 32 #include <sys/dditypes.h> 33 #include <sys/cmn_err.h> 34 #include <net/if.h> 35 #include <net/af.h> 36 #include <net/route.h> 37 #include <netinet/in.h> 38 #include <netinet/in_systm.h> 39 #include <netinet/ip.h> 40 #include <netinet/ip_var.h> 41 #include <netinet/tcp.h> 42 #include <netinet/udp.h> 43 #include <netinet/tcpip.h> 44 #include <netinet/ip_icmp.h> 45 #include "ip_compat.h" 46 #ifdef USE_INET6 47 # include <netinet/icmp6.h> 48 #endif 49 #include "ip_fil.h" 50 #include "ip_nat.h" 51 #include "ip_frag.h" 52 #include "ip_state.h" 53 #include "ip_auth.h" 54 #include "ip_proxy.h" 55 #ifdef IPFILTER_LOOKUP 56 #include "ip_lookup.h" 57 #endif 58 #ifdef IPFILTER_COMPILED 59 #include "ip_rules.h" 60 #endif 61 #include <inet/ip_ire.h> 62 63 #include <sys/md5.h> 64 65 extern int fr_flags, fr_active; 66 #if SOLARIS2 >= 7 67 extern timeout_id_t fr_timer_id; 68 #else 69 extern int fr_timer_id; 70 #endif 71 72 73 static int frzerostats __P((caddr_t)); 74 static int fr_send_ip __P((fr_info_t *fin, mblk_t *m)); 75 76 ipfmutex_t ipl_mutex, ipf_authmx, ipf_rw, ipf_stinsert; 77 ipfmutex_t ipf_nat_new, ipf_natio, ipf_timeoutlock; 78 ipfrwlock_t ipf_mutex, ipf_global, ipf_ipidfrag; 79 ipfrwlock_t ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth; 80 kcondvar_t iplwait, ipfauthwait; 81 #if SOLARIS2 < 10 82 #if SOLARIS2 >= 7 83 u_int *ip_ttl_ptr; 84 u_int *ip_mtudisc; 85 # if SOLARIS2 >= 8 86 int *ip_forwarding; 87 u_int *ip6_forwarding; 88 # else 89 u_int *ip_forwarding; 90 # endif 91 #else 92 u_long *ip_ttl_ptr; 93 u_long *ip_mtudisc; 94 u_long *ip_forwarding; 95 #endif 96 #endif 97 int ipf_locks_done = 0; 98 99 100 /* ------------------------------------------------------------------------ */ 101 /* Function: ipldetach */ 102 /* Returns: int - 0 == success, else error. */ 103 /* Parameters: Nil */ 104 /* */ 105 /* This function is responsible for undoing anything that might have been */ 106 /* done in a call to iplattach(). It must be able to clean up from a call */ 107 /* to iplattach() that did not succeed. Why might that happen? Someone */ 108 /* configures a table to be so large that we cannot allocate enough memory */ 109 /* for it. */ 110 /* ------------------------------------------------------------------------ */ 111 int ipldetach() 112 { 113 114 ASSERT(rw_read_locked(&ipf_global.ipf_lk) == 0); 115 116 if (fr_refcnt) 117 return EBUSY; 118 #if SOLARIS2 < 10 119 120 if (fr_control_forwarding & 2) { 121 *ip_forwarding = 0; 122 #if SOLARIS2 >= 8 123 *ip6_forwarding = 0; 124 #endif 125 } 126 #endif 127 128 #ifdef IPFDEBUG 129 cmn_err(CE_CONT, "ipldetach()\n"); 130 #endif 131 132 fr_fragunload(); 133 fr_authunload(); 134 fr_stateunload(); 135 fr_natunload(); 136 appr_unload(); 137 138 #ifdef IPFILTER_COMPILED 139 ipfrule_remove(); 140 #endif 141 142 (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE); 143 (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE); 144 145 #ifdef IPFILTER_LOOKUP 146 ip_lookup_unload(); 147 #endif 148 149 #ifdef IPFILTER_LOG 150 fr_logunload(); 151 #endif 152 153 if (ipf_locks_done == 1) { 154 MUTEX_DESTROY(&ipf_timeoutlock); 155 MUTEX_DESTROY(&ipf_rw); 156 RW_DESTROY(&ipf_ipidfrag); 157 ipf_locks_done = 0; 158 } 159 return 0; 160 } 161 162 163 int iplattach __P((void)) 164 { 165 #if SOLARIS2 < 10 166 int i; 167 #endif 168 169 #ifdef IPFDEBUG 170 cmn_err(CE_CONT, "iplattach()\n"); 171 #endif 172 173 ASSERT(rw_read_locked(&ipf_global.ipf_lk) == 0); 174 175 bzero((char *)frcache, sizeof(frcache)); 176 MUTEX_INIT(&ipf_rw, "ipf rw mutex"); 177 MUTEX_INIT(&ipf_timeoutlock, "ipf timeout lock mutex"); 178 RWLOCK_INIT(&ipf_ipidfrag, "ipf IP NAT-Frag rwlock"); 179 ipf_locks_done = 1; 180 181 #ifdef IPFILTER_LOG 182 if (fr_loginit() == -1) 183 return -1; 184 #endif 185 if (fr_natinit() == -1) 186 return -1; 187 if (fr_stateinit() == -1) 188 return -1; 189 if (fr_authinit() == -1) 190 return -1; 191 if (fr_fraginit() == -1) 192 return -1; 193 if (appr_init() == -1) 194 return -1; 195 #ifdef IPFILTER_SYNC 196 ipfsync_init(); 197 #endif 198 #ifdef IPFILTER_SCAN 199 isc_init(); 200 #endif 201 #ifdef IPFILTER_LOOKUP 202 if (ip_lookup_init() == -1) 203 return -1; 204 #endif 205 206 /* Do not use private interface ip_params_arr[] in Solaris 10 */ 207 #if SOLARIS2 < 10 208 209 #if SOLARIS2 >= 8 210 ip_forwarding = &ip_g_forward; 211 #endif 212 /* 213 * XXX - There is no terminator for this array, so it is not possible 214 * to tell if what we are looking for is missing and go off the end 215 * of the array. 216 */ 217 218 for (i = 0; ; i++) { 219 if (!strcmp(ip_param_arr[i].ip_param_name, "ip_def_ttl")) { 220 ip_ttl_ptr = &ip_param_arr[i].ip_param_value; 221 } else if (!strcmp(ip_param_arr[i].ip_param_name, 222 "ip_path_mtu_discovery")) { 223 ip_mtudisc = &ip_param_arr[i].ip_param_value; 224 } 225 #if SOLARIS2 < 8 226 else if (!strcmp(ip_param_arr[i].ip_param_name, 227 "ip_forwarding")) { 228 ip_forwarding = &ip_param_arr[i].ip_param_value; 229 } 230 #else 231 else if (!strcmp(ip_param_arr[i].ip_param_name, 232 "ip6_forwarding")) { 233 ip6_forwarding = &ip_param_arr[i].ip_param_value; 234 } 235 #endif 236 237 if (ip_mtudisc != NULL && ip_ttl_ptr != NULL && 238 #if SOLARIS2 >= 8 239 ip6_forwarding != NULL && 240 #endif 241 ip_forwarding != NULL) 242 break; 243 } 244 245 if (fr_control_forwarding & 1) { 246 *ip_forwarding = 1; 247 #if SOLARIS2 >= 8 248 *ip6_forwarding = 1; 249 #endif 250 } 251 252 #endif 253 254 return 0; 255 } 256 257 258 static int frzerostats(data) 259 caddr_t data; 260 { 261 friostat_t fio; 262 int error; 263 264 fr_getstat(&fio); 265 error = copyoutptr((caddr_t)&fio, data, sizeof(fio)); 266 if (error) 267 return error; 268 269 bzero((char *)frstats, sizeof(*frstats) * 2); 270 271 return 0; 272 } 273 274 275 /* 276 * Filter ioctl interface. 277 */ 278 /*ARGSUSED*/ 279 int iplioctl(dev, cmd, data, mode, cp, rp) 280 dev_t dev; 281 int cmd; 282 #if SOLARIS2 >= 7 283 intptr_t data; 284 #else 285 int *data; 286 #endif 287 int mode; 288 cred_t *cp; 289 int *rp; 290 { 291 int error = 0, tmp; 292 friostat_t fio; 293 minor_t unit; 294 u_int enable; 295 296 #ifdef IPFDEBUG 297 cmn_err(CE_CONT, "iplioctl(%x,%x,%x,%d,%x,%d)\n", 298 dev, cmd, data, mode, cp, rp); 299 #endif 300 unit = getminor(dev); 301 if (IPL_LOGMAX < unit) 302 return ENXIO; 303 304 if (fr_running <= 0) { 305 if (unit != IPL_LOGIPF) 306 return EIO; 307 if (cmd != SIOCIPFGETNEXT && cmd != SIOCIPFGET && 308 cmd != SIOCIPFSET && cmd != SIOCFRENB && cmd != SIOCGETFS) 309 return EIO; 310 } 311 312 READ_ENTER(&ipf_global); 313 314 error = fr_ioctlswitch(unit, (caddr_t)data, cmd, mode); 315 if (error != -1) { 316 RWLOCK_EXIT(&ipf_global); 317 return error; 318 } 319 error = 0; 320 321 switch (cmd) 322 { 323 case SIOCFRENB : 324 if (!(mode & FWRITE)) 325 error = EPERM; 326 else { 327 error = COPYIN((caddr_t)data, (caddr_t)&enable, 328 sizeof(enable)); 329 if (error != 0) { 330 error = EFAULT; 331 break; 332 } 333 334 RWLOCK_EXIT(&ipf_global); 335 WRITE_ENTER(&ipf_global); 336 if (enable) { 337 if (fr_running > 0) 338 error = 0; 339 else 340 error = iplattach(); 341 if (error == 0) 342 fr_running = 1; 343 else 344 (void) ipldetach(); 345 } else { 346 error = ipldetach(); 347 if (error == 0) 348 fr_running = -1; 349 } 350 } 351 break; 352 case SIOCIPFSET : 353 if (!(mode & FWRITE)) { 354 error = EPERM; 355 break; 356 } 357 /* FALLTHRU */ 358 case SIOCIPFGETNEXT : 359 case SIOCIPFGET : 360 error = fr_ipftune(cmd, (char *)data); 361 break; 362 case SIOCSETFF : 363 if (!(mode & FWRITE)) 364 error = EPERM; 365 else { 366 error = COPYIN((caddr_t)data, (caddr_t)&fr_flags, 367 sizeof(fr_flags)); 368 if (error != 0) 369 error = EFAULT; 370 } 371 break; 372 case SIOCGETFF : 373 error = COPYOUT((caddr_t)&fr_flags, (caddr_t)data, 374 sizeof(fr_flags)); 375 if (error != 0) 376 error = EFAULT; 377 break; 378 case SIOCFUNCL : 379 error = fr_resolvefunc((void *)data); 380 break; 381 case SIOCINAFR : 382 case SIOCRMAFR : 383 case SIOCADAFR : 384 case SIOCZRLST : 385 if (!(mode & FWRITE)) 386 error = EPERM; 387 else 388 error = frrequest(unit, cmd, (caddr_t)data, 389 fr_active, 1); 390 break; 391 case SIOCINIFR : 392 case SIOCRMIFR : 393 case SIOCADIFR : 394 if (!(mode & FWRITE)) 395 error = EPERM; 396 else 397 error = frrequest(unit, cmd, (caddr_t)data, 398 1 - fr_active, 1); 399 break; 400 case SIOCSWAPA : 401 if (!(mode & FWRITE)) 402 error = EPERM; 403 else { 404 WRITE_ENTER(&ipf_mutex); 405 bzero((char *)frcache, sizeof(frcache[0]) * 2); 406 error = COPYOUT((caddr_t)&fr_active, (caddr_t)data, 407 sizeof(fr_active)); 408 if (error != 0) 409 error = EFAULT; 410 else 411 fr_active = 1 - fr_active; 412 RWLOCK_EXIT(&ipf_mutex); 413 } 414 break; 415 case SIOCGETFS : 416 fr_getstat(&fio); 417 error = fr_outobj((void *)data, &fio, IPFOBJ_IPFSTAT); 418 break; 419 case SIOCFRZST : 420 if (!(mode & FWRITE)) 421 error = EPERM; 422 else 423 error = frzerostats((caddr_t)data); 424 break; 425 case SIOCIPFFL : 426 if (!(mode & FWRITE)) 427 error = EPERM; 428 else { 429 error = COPYIN((caddr_t)data, (caddr_t)&tmp, 430 sizeof(tmp)); 431 if (!error) { 432 tmp = frflush(unit, 4, tmp); 433 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 434 sizeof(tmp)); 435 if (error != 0) 436 error = EFAULT; 437 } else 438 error = EFAULT; 439 } 440 break; 441 #ifdef USE_INET6 442 case SIOCIPFL6 : 443 if (!(mode & FWRITE)) 444 error = EPERM; 445 else { 446 error = COPYIN((caddr_t)data, (caddr_t)&tmp, 447 sizeof(tmp)); 448 if (!error) { 449 tmp = frflush(unit, 6, tmp); 450 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 451 sizeof(tmp)); 452 if (error != 0) 453 error = EFAULT; 454 } else 455 error = EFAULT; 456 } 457 break; 458 #endif 459 case SIOCSTLCK : 460 error = COPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 461 if (error == 0) { 462 fr_state_lock = tmp; 463 fr_nat_lock = tmp; 464 fr_frag_lock = tmp; 465 fr_auth_lock = tmp; 466 } else 467 error = EFAULT; 468 break; 469 #ifdef IPFILTER_LOG 470 case SIOCIPFFB : 471 if (!(mode & FWRITE)) 472 error = EPERM; 473 else { 474 tmp = ipflog_clear(unit); 475 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 476 sizeof(tmp)); 477 if (error) 478 error = EFAULT; 479 } 480 break; 481 #endif /* IPFILTER_LOG */ 482 case SIOCFRSYN : 483 if (!(mode & FWRITE)) 484 error = EPERM; 485 else { 486 RWLOCK_EXIT(&ipf_global); 487 WRITE_ENTER(&ipf_global); 488 error = ipfsync(); 489 } 490 break; 491 case SIOCGFRST : 492 error = fr_outobj((void *)data, fr_fragstats(), 493 IPFOBJ_FRAGSTAT); 494 break; 495 case FIONREAD : 496 #ifdef IPFILTER_LOG 497 tmp = (int)iplused[IPL_LOGIPF]; 498 499 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, sizeof(tmp)); 500 if (error != 0) 501 error = EFAULT; 502 #endif 503 break; 504 default : 505 cmn_err(CE_NOTE, "Unknown: cmd 0x%x data %p", 506 cmd, (void *)data); 507 error = EINVAL; 508 break; 509 } 510 RWLOCK_EXIT(&ipf_global); 511 return error; 512 } 513 514 #ifndef IRE_ILL_CN 515 ill_t *get_unit(name, v) 516 char *name; 517 int v; 518 { 519 size_t len = strlen(name) + 1; /* includes \0 */ 520 ill_t *il; 521 #if SOLARIS2 >= 10 522 ill_walk_context_t ctx; 523 #endif 524 int sap; 525 526 if (v == 4) 527 sap = 0x0800; 528 else if (v == 6) 529 sap = 0x86dd; 530 else 531 return NULL; 532 #if SOLARIS2 >= 10 533 for (il = ILL_START_WALK_ALL(&ctx); il; il = ill_next(&ctx, il)) 534 #else 535 for (il = ill_g_head; il; il = il->ill_next) 536 #endif 537 if ((len == il->ill_name_length) && (il->ill_sap == sap) && 538 !strncmp(il->ill_name, name, len)) 539 return il; 540 return NULL; 541 } 542 #else 543 s_ill_t *get_unit(name, v) 544 char *name; 545 int v; 546 { 547 s_ill_t *il; 548 549 int sap; 550 551 if (v == 4) 552 sap = 0x0800; 553 else if (v == 6) 554 sap = 0x86dd; 555 else 556 return NULL; 557 558 mutex_enter(&s_ill_g_head_lock); 559 for (il = s_ill_g_head; il; il = il->ill_next) 560 if ((il->ill_sap == sap) && 561 !strncmp(il->ill_name, name, LIFNAMSIZ)) 562 break; 563 mutex_exit(&s_ill_g_head_lock); 564 return il; 565 } 566 #endif /* IRE_ILL_CN */ 567 568 569 /* 570 * routines below for saving IP headers to buffer 571 */ 572 /*ARGSUSED*/ 573 int iplopen(devp, flags, otype, cred) 574 dev_t *devp; 575 int flags, otype; 576 cred_t *cred; 577 { 578 minor_t min = getminor(*devp); 579 580 #ifdef IPFDEBUG 581 cmn_err(CE_CONT, "iplopen(%x,%x,%x,%x)\n", devp, flags, otype, cred); 582 #endif 583 if (!(otype & OTYP_CHR)) 584 return ENXIO; 585 586 min = (IPL_LOGMAX < min) ? ENXIO : 0; 587 return min; 588 } 589 590 591 /*ARGSUSED*/ 592 int iplclose(dev, flags, otype, cred) 593 dev_t dev; 594 int flags, otype; 595 cred_t *cred; 596 { 597 minor_t min = getminor(dev); 598 599 #ifdef IPFDEBUG 600 cmn_err(CE_CONT, "iplclose(%x,%x,%x,%x)\n", dev, flags, otype, cred); 601 #endif 602 603 min = (IPL_LOGMAX < min) ? ENXIO : 0; 604 return min; 605 } 606 607 #ifdef IPFILTER_LOG 608 /* 609 * iplread/ipllog 610 * both of these must operate with at least splnet() lest they be 611 * called during packet processing and cause an inconsistancy to appear in 612 * the filter lists. 613 */ 614 /*ARGSUSED*/ 615 int iplread(dev, uio, cp) 616 dev_t dev; 617 register struct uio *uio; 618 cred_t *cp; 619 { 620 # ifdef IPFDEBUG 621 cmn_err(CE_CONT, "iplread(%x,%x,%x)\n", dev, uio, cp); 622 # endif 623 # ifdef IPFILTER_SYNC 624 if (getminor(dev) == IPL_LOGSYNC) 625 return ipfsync_read(uio); 626 # endif 627 628 return ipflog_read(getminor(dev), uio); 629 } 630 #endif /* IPFILTER_LOG */ 631 632 633 #ifdef IPFILTER_SYNC 634 /* 635 * iplread/ipllog 636 * both of these must operate with at least splnet() lest they be 637 * called during packet processing and cause an inconsistancy to appear in 638 * the filter lists. 639 */ 640 int iplwrite(dev, uio, cp) 641 dev_t dev; 642 register struct uio *uio; 643 cred_t *cp; 644 { 645 #ifdef IPFDEBUG 646 cmn_err(CE_CONT, "iplwrite(%x,%x,%x)\n", dev, uio, cp); 647 #endif 648 if (getminor(dev) != IPL_LOGSYNC) 649 return ENXIO; 650 return ipfsync_write(uio); 651 } 652 #endif /* IPFILTER_SYNC */ 653 654 655 /* 656 * fr_send_reset - this could conceivably be a call to tcp_respond(), but that 657 * requires a large amount of setting up and isn't any more efficient. 658 */ 659 int fr_send_reset(fin) 660 fr_info_t *fin; 661 { 662 tcphdr_t *tcp, *tcp2; 663 int tlen, hlen; 664 mblk_t *m; 665 #ifdef USE_INET6 666 ip6_t *ip6; 667 #endif 668 ip_t *ip; 669 670 tcp = fin->fin_dp; 671 if (tcp->th_flags & TH_RST) 672 return -1; 673 674 #ifndef IPFILTER_CKSUM 675 if (fr_checkl4sum(fin) == -1) 676 return -1; 677 #endif 678 679 tlen = (tcp->th_flags & (TH_SYN|TH_FIN)) ? 1 : 0; 680 #ifdef USE_INET6 681 if (fin->fin_v == 6) 682 hlen = sizeof(ip6_t); 683 else 684 #endif 685 hlen = sizeof(ip_t); 686 hlen += sizeof(*tcp2); 687 if ((m = (mblk_t *)allocb(hlen + 64, BPRI_HI)) == NULL) 688 return -1; 689 690 m->b_rptr += 64; 691 MTYPE(m) = M_DATA; 692 m->b_wptr = m->b_rptr + hlen; 693 bzero((char *)m->b_rptr, hlen); 694 tcp2 = (struct tcphdr *)(m->b_rptr + hlen - sizeof(*tcp2)); 695 tcp2->th_dport = tcp->th_sport; 696 tcp2->th_sport = tcp->th_dport; 697 if (tcp->th_flags & TH_ACK) { 698 tcp2->th_seq = tcp->th_ack; 699 tcp2->th_flags = TH_RST; 700 } else { 701 tcp2->th_ack = ntohl(tcp->th_seq); 702 tcp2->th_ack += tlen; 703 tcp2->th_ack = htonl(tcp2->th_ack); 704 tcp2->th_flags = TH_RST|TH_ACK; 705 } 706 tcp2->th_off = sizeof(struct tcphdr) >> 2; 707 708 /* 709 * This is to get around a bug in the Solaris 2.4/2.5 TCP checksum 710 * computation that is done by their put routine. 711 */ 712 #ifdef USE_INET6 713 if (fin->fin_v == 6) { 714 ip6 = (ip6_t *)m->b_rptr; 715 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 716 ip6->ip6_src = fin->fin_dst6; 717 ip6->ip6_dst = fin->fin_src6; 718 ip6->ip6_plen = htons(sizeof(*tcp)); 719 ip6->ip6_nxt = IPPROTO_TCP; 720 tcp2->th_sum = fr_cksum(m, (ip_t *)ip6, IPPROTO_TCP, tcp2); 721 } else 722 #endif 723 { 724 ip = (ip_t *)m->b_rptr; 725 ip->ip_src.s_addr = fin->fin_daddr; 726 ip->ip_dst.s_addr = fin->fin_saddr; 727 ip->ip_id = fr_nextipid(fin); 728 ip->ip_hl = sizeof(*ip) >> 2; 729 ip->ip_p = IPPROTO_TCP; 730 ip->ip_len = sizeof(*ip) + sizeof(*tcp); 731 ip->ip_tos = fin->fin_ip->ip_tos; 732 tcp2->th_sum = fr_cksum(m, ip, IPPROTO_TCP, tcp2); 733 } 734 return fr_send_ip(fin, m); 735 } 736 737 738 /* 739 * Function: fr_send_ip 740 * Returns: 0: success 741 * -1: failed 742 * Parameters: 743 * fin: packet information 744 * m: the message block where ip head starts 745 * 746 * Send a new packet through the IP stack. 747 * 748 * For IPv4 packets, ip_len must be in host byte order, and ip_v, 749 * ip_ttl, ip_off, and ip_sum are ignored (filled in by this 750 * function). 751 * 752 * For IPv6 packets, ip6_flow, ip6_vfc, and ip6_hlim are filled 753 * in by this function. 754 * 755 * All other portions of the packet must be in on-the-wire format. 756 */ 757 static int fr_send_ip(fin, m) 758 fr_info_t *fin; 759 mblk_t *m; 760 { 761 int i; 762 763 #ifdef USE_INET6 764 if (fin->fin_v == 6) { 765 ip6_t *ip6; 766 767 ip6 = (ip6_t *)m->b_rptr; 768 ip6->ip6_vfc = 0x60; 769 ip6->ip6_hlim = 127; 770 } else 771 #endif 772 { 773 ip_t *ip; 774 775 ip = (ip_t *)m->b_rptr; 776 ip->ip_v = IPVERSION; 777 778 #if SOLARIS2 >= 10 779 ip->ip_ttl = 255; 780 781 ip->ip_off = IP_DF; 782 #else 783 ip->ip_ttl = (u_char)(*ip_ttl_ptr); 784 ip->ip_off = *ip_mtudisc ? IP_DF : 0; 785 #endif 786 787 ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip)); 788 789 } 790 i = fr_fastroute(m, &m, fin, NULL); 791 return i; 792 } 793 794 795 int fr_send_icmp_err(type, fin, dst) 796 int type; 797 fr_info_t *fin; 798 int dst; 799 { 800 struct in_addr dst4; 801 struct icmp *icmp; 802 int hlen, code; 803 qif_t *qif; 804 u_short sz; 805 #ifdef USE_INET6 806 mblk_t *mb; 807 #endif 808 mblk_t *m; 809 #ifdef icmp_nextmtu 810 #ifndef IRE_ILL_CN 811 ill_t *il; 812 #else 813 s_ill_t *il; 814 #endif /* IRE_ILL_CN */ 815 #endif 816 #ifdef USE_INET6 817 ip6_t *ip6; 818 #endif 819 ip_t *ip; 820 821 #ifdef icmp_nextmtu 822 /* lint fodder */ 823 il = NULL; 824 il = il; 825 #endif 826 827 if ((type < 0) || (type > ICMP_MAXTYPE)) 828 return -1; 829 830 code = fin->fin_icode; 831 #ifdef USE_INET6 832 if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) 833 return -1; 834 #endif 835 836 #ifndef IPFILTER_CKSUM 837 if (fr_checkl4sum(fin) == -1) 838 return -1; 839 #endif 840 841 qif = fin->fin_qif; 842 843 #ifdef USE_INET6 844 mb = fin->fin_qfm; 845 846 if (fin->fin_v == 6) { 847 sz = sizeof(ip6_t); 848 sz += MIN(mb->b_wptr - mb->b_rptr, 512); 849 hlen = sizeof(ip6_t); 850 type = icmptoicmp6types[type]; 851 if (type == ICMP6_DST_UNREACH) 852 code = icmptoicmp6unreach[code]; 853 } else 854 #endif 855 { 856 if ((fin->fin_p == IPPROTO_ICMP) && 857 !(fin->fin_flx & FI_SHORT)) 858 switch (ntohs(fin->fin_data[0]) >> 8) 859 { 860 case ICMP_ECHO : 861 case ICMP_TSTAMP : 862 case ICMP_IREQ : 863 case ICMP_MASKREQ : 864 break; 865 default : 866 return 0; 867 } 868 869 sz = sizeof(ip_t) * 2; 870 sz += 8; /* 64 bits of data */ 871 hlen = sizeof(ip_t); 872 } 873 874 sz += offsetof(struct icmp, icmp_ip); 875 if ((m = (mblk_t *)allocb((size_t)sz + 64, BPRI_HI)) == NULL) 876 return -1; 877 MTYPE(m) = M_DATA; 878 m->b_rptr += 64; 879 m->b_wptr = m->b_rptr + sz; 880 bzero((char *)m->b_rptr, (size_t)sz); 881 icmp = (struct icmp *)(m->b_rptr + hlen); 882 icmp->icmp_type = type & 0xff; 883 icmp->icmp_code = code & 0xff; 884 #ifndef IRE_ILL_CN 885 #ifdef icmp_nextmtu 886 if (type == ICMP_UNREACH && ((il = qif->qf_ill) != NULL) && 887 fin->fin_icode == ICMP_UNREACH_NEEDFRAG) 888 icmp->icmp_nextmtu = htons(il->ill_max_frag); 889 #endif 890 #endif /* IRE_ILL_CN */ 891 892 #ifdef USE_INET6 893 if (fin->fin_v == 6) { 894 struct in6_addr dst6; 895 int csz; 896 897 if (dst == 0) { 898 if (fr_ifpaddr(6, FRI_NORMAL, qif->qf_ill, 899 (struct in_addr *)&dst6, NULL) == -1) { 900 FREE_MB_T(m); 901 return -1; 902 } 903 } else 904 dst6 = fin->fin_dst6; 905 906 csz = sz; 907 sz -= sizeof(ip6_t); 908 ip6 = (ip6_t *)m->b_rptr; 909 ip6->ip6_flow = ((ip6_t *)fin->fin_ip)->ip6_flow; 910 ip6->ip6_plen = htons((u_short)sz); 911 ip6->ip6_nxt = IPPROTO_ICMPV6; 912 ip6->ip6_src = dst6; 913 ip6->ip6_dst = fin->fin_src6; 914 sz -= offsetof(struct icmp, icmp_ip); 915 bcopy((char *)mb->b_rptr, (char *)&icmp->icmp_ip, sz); 916 icmp->icmp_cksum = csz - sizeof(ip6_t); 917 } else 918 #endif 919 { 920 ip = (ip_t *)m->b_rptr; 921 ip->ip_hl = sizeof(*ip) >> 2; 922 ip->ip_p = IPPROTO_ICMP; 923 ip->ip_id = fin->fin_ip->ip_id; 924 ip->ip_tos = fin->fin_ip->ip_tos; 925 ip->ip_len = (u_short)sz; 926 if (dst == 0) { 927 if (fr_ifpaddr(4, FRI_NORMAL, qif->qf_ill, 928 &dst4, NULL) == -1) { 929 FREE_MB_T(m); 930 return -1; 931 } 932 } else 933 dst4 = fin->fin_dst; 934 ip->ip_src = dst4; 935 ip->ip_dst = fin->fin_src; 936 bcopy((char *)fin->fin_ip, (char *)&icmp->icmp_ip, 937 sizeof(*fin->fin_ip)); 938 bcopy((char *)fin->fin_ip + fin->fin_hlen, 939 (char *)&icmp->icmp_ip + sizeof(*fin->fin_ip), 8); 940 icmp->icmp_ip.ip_len = htons(icmp->icmp_ip.ip_len); 941 icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 942 sz - sizeof(ip_t)); 943 } 944 945 /* 946 * Need to exit out of these so we don't recursively call rw_enter 947 * from fr_qout. 948 */ 949 return fr_send_ip(fin, m); 950 } 951 952 #ifdef IRE_ILL_CN 953 #include <sys/time.h> 954 #include <sys/varargs.h> 955 956 #ifndef _KERNEL 957 #include <stdio.h> 958 #endif 959 960 #define NULLADDR_RATE_LIMIT 10 /* 10 seconds */ 961 962 963 /* 964 * Print out warning message at rate-limited speed. 965 */ 966 static void rate_limit_message(int rate, const char *message, ...) 967 { 968 static time_t last_time = 0; 969 time_t now; 970 va_list args; 971 char msg_buf[256]; 972 int need_printed = 0; 973 974 now = ddi_get_time(); 975 976 /* make sure, no multiple entries */ 977 ASSERT(MUTEX_NOT_HELD(&(ipf_rw.ipf_lk))); 978 MUTEX_ENTER(&ipf_rw); 979 if (now - last_time >= rate) { 980 need_printed = 1; 981 last_time = now; 982 } 983 MUTEX_EXIT(&ipf_rw); 984 985 if (need_printed) { 986 va_start(args, message); 987 (void)vsnprintf(msg_buf, 255, message, args); 988 va_end(args); 989 #ifdef _KERNEL 990 cmn_err(CE_WARN, msg_buf); 991 #else 992 fprintf(std_err, msg_buf); 993 #endif 994 } 995 } 996 #endif 997 998 /* 999 * return the first IP Address associated with an interface 1000 */ 1001 /*ARGSUSED*/ 1002 int fr_ifpaddr(v, atype, ifptr, inp, inpmask) 1003 int v, atype; 1004 void *ifptr; 1005 struct in_addr *inp, *inpmask; 1006 { 1007 #ifdef USE_INET6 1008 struct sockaddr_in6 sin6, mask6; 1009 #endif 1010 struct sockaddr_in sin, mask; 1011 1012 #ifndef IRE_ILL_CN 1013 ill_t *ill = ifptr; 1014 ipif_t *ipif; 1015 #else 1016 s_ill_t *ill = ifptr; 1017 #endif /* IRE_ILL_CN */ 1018 1019 if ((ifptr == NULL) || (ifptr == (void *)-1)) 1020 return -1; 1021 1022 #ifdef USE_INET6 1023 if (v == 6) { 1024 #ifndef IRE_ILL_CN 1025 in6_addr_t *inp6; 1026 1027 /* 1028 * First is always link local. 1029 */ 1030 for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next) { 1031 inp6 = &ipif->ipif_v6lcl_addr; 1032 if (!IN6_IS_ADDR_LINKLOCAL(inp6) && 1033 !IN6_IS_ADDR_LOOPBACK(inp6)) 1034 break; 1035 } 1036 if (ipif == NULL) 1037 return -1; 1038 1039 mask6.sin6_addr = ipif->ipif_v6net_mask; 1040 if (atype == FRI_BROADCAST) 1041 sin6.sin6_addr = ipif->ipif_v6brd_addr; 1042 else if (atype == FRI_PEERADDR) 1043 sin6.sin6_addr = ipif->ipif_v6pp_dst_addr; 1044 else 1045 sin6.sin6_addr = *inp6; 1046 #else /* IRE_ILL_CN */ 1047 if (IN6_IS_ADDR_UNSPECIFIED(&ill->netmask.in6.sin6_addr) || 1048 IN6_IS_ADDR_UNSPECIFIED(&ill->localaddr.in6.sin6_addr)) { 1049 rate_limit_message(NULLADDR_RATE_LIMIT, 1050 "Check pfild is running: IP#/netmask is 0 on %s.\n", 1051 ill->ill_name); 1052 return -1; 1053 } 1054 mask6 = ill->netmask.in6; 1055 if (atype == FRI_BROADCAST) 1056 sin6 = ill->broadaddr.in6; 1057 else if (atype == FRI_PEERADDR) 1058 sin6 = ill->dstaddr.in6; 1059 else 1060 sin6 = ill->localaddr.in6; 1061 #endif /* IRE_ILL_CN */ 1062 return fr_ifpfillv6addr(atype, &sin6, &mask6, inp, inpmask); 1063 } 1064 #endif 1065 #ifndef IRE_ILL_CN 1066 ipif = ill->ill_ipif; 1067 1068 mask.sin_addr.s_addr = ipif->ipif_net_mask; 1069 if (atype == FRI_BROADCAST) 1070 #if SOLARIS2 < 7 1071 sin.sin_addr.s_addr = ipif->ipif_broadcast_addr; 1072 #else 1073 sin.sin_addr.s_addr = ipif->ipif_brd_addr; 1074 #endif 1075 else if (atype == FRI_PEERADDR) 1076 sin.sin_addr.s_addr = ipif->ipif_pp_dst_addr; 1077 else 1078 #if SOLARIS2 < 7 1079 sin.sin_addr.s_addr = ipif->ipif_local_addr; 1080 #else 1081 sin.sin_addr.s_addr = ipif->ipif_lcl_addr; 1082 #endif 1083 1084 #else 1085 if (ill->netmask.in.sin_addr.s_addr == 0 || 1086 ill->localaddr.in.sin_addr.s_addr == 0) { 1087 rate_limit_message(NULLADDR_RATE_LIMIT, 1088 "Check pfild is running: IP#/netmask is 0 on %s.\n", 1089 ill->ill_name); 1090 return -1; 1091 } 1092 mask = ill->netmask.in; 1093 if (atype == FRI_BROADCAST) 1094 sin = ill->broadaddr.in; 1095 else if (atype == FRI_PEERADDR) 1096 sin = ill->dstaddr.in; 1097 else 1098 sin = ill->localaddr.in; 1099 #endif /* IRE_ILL_CN */ 1100 return fr_ifpfillv4addr(atype, &sin, &mask, inp, inpmask); 1101 } 1102 1103 1104 1105 #ifdef IRE_ILL_CN 1106 /* ARGSUSED */ 1107 #endif 1108 void fr_resolvdest(fdp, v) 1109 frdest_t *fdp; 1110 int v; 1111 { 1112 #ifndef IRE_ILL_CN 1113 ipif_t *ipif; 1114 ill_t *ill; 1115 ire_t *ire; 1116 1117 ire = NULL; 1118 1119 if (*fdp->fd_ifname) { 1120 ill = get_unit(fdp->fd_ifname, v); 1121 if (ill == NULL) 1122 ire = (ire_t *)-1; 1123 else if (((ipif = ill->ill_ipif) != NULL) && (v == 4)) { 1124 #if SOLARIS2 > 5 1125 ire = ire_ctable_lookup(ipif->ipif_local_addr, 0, 1126 IRE_LOCAL, NULL, NULL, 1127 MATCH_IRE_TYPE); 1128 #else 1129 ire = ire_lookup_myaddr(ipif->ipif_local_addr); 1130 #endif 1131 if (ire == NULL) 1132 ire = (ire_t *)-1; 1133 } 1134 #ifdef USE_INET6 1135 else if (((ipif = ill->ill_ipif) != NULL) && (v == 6)) { 1136 ire = ire_ctable_lookup_v6(&ipif->ipif_v6lcl_addr, 0, 1137 IRE_LOCAL, NULL, NULL, 1138 MATCH_IRE_TYPE); 1139 if (ire == NULL) 1140 ire = (ire_t *)-1; 1141 } 1142 #endif 1143 } 1144 fdp->fd_ifp = (struct ifnet *)ire; 1145 #else 1146 #endif /*IRE_ILL_CN */ 1147 } 1148 1149 1150 u_32_t fr_newisn(fin) 1151 fr_info_t *fin; 1152 { 1153 static int iss_seq_off = 0; 1154 u_char hash[16]; 1155 u_32_t newiss; 1156 MD5_CTX ctx; 1157 1158 /* 1159 * Compute the base value of the ISS. It is a hash 1160 * of (saddr, sport, daddr, dport, secret). 1161 */ 1162 MD5Init(&ctx); 1163 1164 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, 1165 sizeof(fin->fin_fi.fi_src)); 1166 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, 1167 sizeof(fin->fin_fi.fi_dst)); 1168 MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); 1169 1170 MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); 1171 1172 MD5Final(hash, &ctx); 1173 1174 bcopy(hash, &newiss, sizeof(newiss)); 1175 1176 /* 1177 * Now increment our "timer", and add it in to 1178 * the computed value. 1179 * 1180 * XXX Use `addin'? 1181 * XXX TCP_ISSINCR too large to use? 1182 */ 1183 iss_seq_off += 0x00010000; 1184 newiss += iss_seq_off; 1185 return newiss; 1186 } 1187 1188 1189 /* ------------------------------------------------------------------------ */ 1190 /* Function: fr_nextipid */ 1191 /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 1192 /* Parameters: fin(I) - pointer to packet information */ 1193 /* */ 1194 /* Returns the next IPv4 ID to use for this packet. */ 1195 /* ------------------------------------------------------------------------ */ 1196 INLINE u_short fr_nextipid(fin) 1197 fr_info_t *fin; 1198 { 1199 static u_short ipid = 0; 1200 ipstate_t *is; 1201 nat_t *nat; 1202 u_short id; 1203 1204 MUTEX_ENTER(&ipf_rw); 1205 if (fin->fin_state != NULL) { 1206 is = fin->fin_state; 1207 id = (u_short)(is->is_pkts[(fin->fin_rev << 1) + 1] & 0xffff); 1208 } else if (fin->fin_nat != NULL) { 1209 nat = fin->fin_nat; 1210 id = (u_short)(nat->nat_pkts[fin->fin_out] & 0xffff); 1211 } else 1212 id = ipid++; 1213 MUTEX_EXIT(&ipf_rw); 1214 1215 return id; 1216 } 1217 1218 1219 #ifndef IPFILTER_CKSUM 1220 /* ARGSUSED */ 1221 #endif 1222 INLINE void fr_checkv4sum(fin) 1223 fr_info_t *fin; 1224 { 1225 #ifdef IPFILTER_CKSUM 1226 if (fr_checkl4sum(fin) == -1) 1227 fin->fin_flx |= FI_BAD; 1228 #endif 1229 } 1230 1231 1232 #ifdef USE_INET6 1233 /* ARGSUSED */ 1234 INLINE void fr_checkv6sum(fin) 1235 fr_info_t *fin; 1236 { 1237 # ifdef IPFILTER_CKSUM 1238 if (fr_checkl4sum(fin) == -1) 1239 fin->fin_flx |= FI_BAD; 1240 # endif 1241 } 1242 #endif /* USE_INET6 */ 1243