1 /* 2 * Copyright (C) 1999-2001, 2003 by Darren Reed. 3 * 4 * See the IPFILTER.LICENCE file for details on licencing. 5 * 6 * Copyright 2004 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, FR_INQUE|FR_OUTQUE|FR_INACTIVE); 143 (void) frflush(IPL_LOGIPF, 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, 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 case SIOCSTLCK : 442 error = COPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); 443 if (error == 0) { 444 fr_state_lock = tmp; 445 fr_nat_lock = tmp; 446 fr_frag_lock = tmp; 447 fr_auth_lock = tmp; 448 } else 449 error = EFAULT; 450 break; 451 #ifdef IPFILTER_LOG 452 case SIOCIPFFB : 453 if (!(mode & FWRITE)) 454 error = EPERM; 455 else { 456 tmp = ipflog_clear(unit); 457 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, 458 sizeof(tmp)); 459 if (error) 460 error = EFAULT; 461 } 462 break; 463 #endif /* IPFILTER_LOG */ 464 case SIOCFRSYN : 465 if (!(mode & FWRITE)) 466 error = EPERM; 467 else { 468 RWLOCK_EXIT(&ipf_global); 469 WRITE_ENTER(&ipf_global); 470 error = ipfsync(); 471 } 472 break; 473 case SIOCGFRST : 474 error = fr_outobj((void *)data, fr_fragstats(), 475 IPFOBJ_FRAGSTAT); 476 break; 477 case FIONREAD : 478 #ifdef IPFILTER_LOG 479 tmp = (int)iplused[IPL_LOGIPF]; 480 481 error = COPYOUT((caddr_t)&tmp, (caddr_t)data, sizeof(tmp)); 482 if (error != 0) 483 error = EFAULT; 484 #endif 485 break; 486 default : 487 cmn_err(CE_NOTE, "Unknown: cmd 0x%x data %p", 488 cmd, (void *)data); 489 error = EINVAL; 490 break; 491 } 492 RWLOCK_EXIT(&ipf_global); 493 return error; 494 } 495 496 #ifndef IRE_ILL_CN 497 ill_t *get_unit(name, v) 498 char *name; 499 int v; 500 { 501 size_t len = strlen(name) + 1; /* includes \0 */ 502 ill_t *il; 503 #if SOLARIS2 >= 10 504 ill_walk_context_t ctx; 505 #endif 506 int sap; 507 508 if (v == 4) 509 sap = 0x0800; 510 else if (v == 6) 511 sap = 0x86dd; 512 else 513 return NULL; 514 #if SOLARIS2 >= 10 515 for (il = ILL_START_WALK_ALL(&ctx); il; il = ill_next(&ctx, il)) 516 #else 517 for (il = ill_g_head; il; il = il->ill_next) 518 #endif 519 if ((len == il->ill_name_length) && (il->ill_sap == sap) && 520 !strncmp(il->ill_name, name, len)) 521 return il; 522 return NULL; 523 } 524 #else 525 s_ill_t *get_unit(name, v) 526 char *name; 527 int v; 528 { 529 s_ill_t *il; 530 531 int sap; 532 533 if (v == 4) 534 sap = 0x0800; 535 else if (v == 6) 536 sap = 0x86dd; 537 else 538 return NULL; 539 540 mutex_enter(&s_ill_g_head_lock); 541 for (il = s_ill_g_head; il; il = il->ill_next) 542 if ((il->ill_sap == sap) && 543 !strncmp(il->ill_name, name, LIFNAMSIZ)) 544 break; 545 mutex_exit(&s_ill_g_head_lock); 546 return il; 547 } 548 #endif /* IRE_ILL_CN */ 549 550 551 /* 552 * routines below for saving IP headers to buffer 553 */ 554 /*ARGSUSED*/ 555 int iplopen(devp, flags, otype, cred) 556 dev_t *devp; 557 int flags, otype; 558 cred_t *cred; 559 { 560 minor_t min = getminor(*devp); 561 562 #ifdef IPFDEBUG 563 cmn_err(CE_CONT, "iplopen(%x,%x,%x,%x)\n", devp, flags, otype, cred); 564 #endif 565 if (!(otype & OTYP_CHR)) 566 return ENXIO; 567 568 min = (IPL_LOGMAX < min) ? ENXIO : 0; 569 return min; 570 } 571 572 573 /*ARGSUSED*/ 574 int iplclose(dev, flags, otype, cred) 575 dev_t dev; 576 int flags, otype; 577 cred_t *cred; 578 { 579 minor_t min = getminor(dev); 580 581 #ifdef IPFDEBUG 582 cmn_err(CE_CONT, "iplclose(%x,%x,%x,%x)\n", dev, flags, otype, cred); 583 #endif 584 585 min = (IPL_LOGMAX < min) ? ENXIO : 0; 586 return min; 587 } 588 589 #ifdef IPFILTER_LOG 590 /* 591 * iplread/ipllog 592 * both of these must operate with at least splnet() lest they be 593 * called during packet processing and cause an inconsistancy to appear in 594 * the filter lists. 595 */ 596 /*ARGSUSED*/ 597 int iplread(dev, uio, cp) 598 dev_t dev; 599 register struct uio *uio; 600 cred_t *cp; 601 { 602 # ifdef IPFDEBUG 603 cmn_err(CE_CONT, "iplread(%x,%x,%x)\n", dev, uio, cp); 604 # endif 605 # ifdef IPFILTER_SYNC 606 if (getminor(dev) == IPL_LOGSYNC) 607 return ipfsync_read(uio); 608 # endif 609 610 return ipflog_read(getminor(dev), uio); 611 } 612 #endif /* IPFILTER_LOG */ 613 614 615 #ifdef IPFILTER_SYNC 616 /* 617 * iplread/ipllog 618 * both of these must operate with at least splnet() lest they be 619 * called during packet processing and cause an inconsistancy to appear in 620 * the filter lists. 621 */ 622 int iplwrite(dev, uio, cp) 623 dev_t dev; 624 register struct uio *uio; 625 cred_t *cp; 626 { 627 #ifdef IPFDEBUG 628 cmn_err(CE_CONT, "iplwrite(%x,%x,%x)\n", dev, uio, cp); 629 #endif 630 if (getminor(dev) != IPL_LOGSYNC) 631 return ENXIO; 632 return ipfsync_write(uio); 633 } 634 #endif /* IPFILTER_SYNC */ 635 636 637 /* 638 * fr_send_reset - this could conceivably be a call to tcp_respond(), but that 639 * requires a large amount of setting up and isn't any more efficient. 640 */ 641 int fr_send_reset(fin) 642 fr_info_t *fin; 643 { 644 tcphdr_t *tcp, *tcp2; 645 int tlen, hlen; 646 mblk_t *m; 647 #ifdef USE_INET6 648 ip6_t *ip6; 649 #endif 650 ip_t *ip; 651 652 tcp = fin->fin_dp; 653 if (tcp->th_flags & TH_RST) 654 return -1; 655 656 #ifndef IPFILTER_CKSUM 657 if (fr_checkl4sum(fin) == -1) 658 return -1; 659 #endif 660 661 tlen = (tcp->th_flags & (TH_SYN|TH_FIN)) ? 1 : 0; 662 #ifdef USE_INET6 663 if (fin->fin_v == 6) 664 hlen = sizeof(ip6_t); 665 else 666 #endif 667 hlen = sizeof(ip_t); 668 hlen += sizeof(*tcp2); 669 if ((m = (mblk_t *)allocb(hlen + 64, BPRI_HI)) == NULL) 670 return -1; 671 672 m->b_rptr += 64; 673 MTYPE(m) = M_DATA; 674 m->b_wptr = m->b_rptr + hlen; 675 bzero((char *)m->b_rptr, hlen); 676 tcp2 = (struct tcphdr *)(m->b_rptr + hlen - sizeof(*tcp2)); 677 tcp2->th_dport = tcp->th_sport; 678 tcp2->th_sport = tcp->th_dport; 679 if (tcp->th_flags & TH_ACK) { 680 tcp2->th_seq = tcp->th_ack; 681 tcp2->th_flags = TH_RST; 682 } else { 683 tcp2->th_ack = ntohl(tcp->th_seq); 684 tcp2->th_ack += tlen; 685 tcp2->th_ack = htonl(tcp2->th_ack); 686 tcp2->th_flags = TH_RST|TH_ACK; 687 } 688 tcp2->th_off = sizeof(struct tcphdr) >> 2; 689 690 /* 691 * This is to get around a bug in the Solaris 2.4/2.5 TCP checksum 692 * computation that is done by their put routine. 693 */ 694 #ifdef USE_INET6 695 if (fin->fin_v == 6) { 696 ip6 = (ip6_t *)m->b_rptr; 697 ip6->ip6_src = fin->fin_dst6; 698 ip6->ip6_dst = fin->fin_src6; 699 ip6->ip6_plen = htons(sizeof(*tcp)); 700 ip6->ip6_nxt = IPPROTO_TCP; 701 } else 702 #endif 703 { 704 ip = (ip_t *)m->b_rptr; 705 ip->ip_src.s_addr = fin->fin_daddr; 706 ip->ip_dst.s_addr = fin->fin_saddr; 707 ip->ip_id = fr_nextipid(fin); 708 ip->ip_hl = sizeof(*ip) >> 2; 709 ip->ip_p = IPPROTO_TCP; 710 ip->ip_len = htons(sizeof(*ip) + sizeof(*tcp)); 711 ip->ip_tos = fin->fin_ip->ip_tos; 712 tcp2->th_sum = fr_cksum(m, ip, IPPROTO_TCP, tcp2); 713 } 714 return fr_send_ip(fin, m); 715 } 716 717 718 static int fr_send_ip(fin, m) 719 fr_info_t *fin; 720 mblk_t *m; 721 { 722 int i; 723 724 #ifdef USE_INET6 725 if (fin->fin_v == 6) { 726 ip6_t *ip6; 727 728 ip6 = (ip6_t *)m->b_rptr; 729 ip6->ip6_flow = 0; 730 ip6->ip6_vfc = 0x60; 731 ip6->ip6_hlim = 127; 732 } else 733 #endif 734 { 735 ip_t *ip; 736 737 ip = (ip_t *)m->b_rptr; 738 ip->ip_v = IPVERSION; 739 740 #if SOLARIS2 >= 10 741 ip->ip_ttl = 255; 742 ip->ip_off = htons(IP_DF); 743 #else 744 ip->ip_ttl = (u_char)(*ip_ttl_ptr); 745 ip->ip_off = htons(*ip_mtudisc ? IP_DF : 0); 746 #endif 747 748 ip->ip_sum = ipf_cksum((u_short *)ip, sizeof(*ip)); 749 750 } 751 i = fr_fastroute(m, &m, fin, NULL); 752 return i; 753 } 754 755 756 int fr_send_icmp_err(type, fin, dst) 757 int type; 758 fr_info_t *fin; 759 int dst; 760 { 761 struct in_addr dst4; 762 struct icmp *icmp; 763 int hlen, code; 764 qif_t *qif; 765 u_short sz; 766 #ifdef USE_INET6 767 mblk_t *mb; 768 #endif 769 mblk_t *m; 770 #ifdef icmp_nextmtu 771 #ifndef IRE_ILL_CN 772 ill_t *il; 773 #else 774 s_ill_t *il; 775 #endif /* IRE_ILL_CN */ 776 #endif 777 #ifdef USE_INET6 778 ip6_t *ip6; 779 #endif 780 ip_t *ip; 781 782 #ifdef icmp_nextmtu 783 /* lint fodder */ 784 il = NULL; 785 il = il; 786 #endif 787 788 if ((type < 0) || (type > ICMP_MAXTYPE)) 789 return -1; 790 791 code = fin->fin_icode; 792 #ifdef USE_INET6 793 if ((code < 0) || (code > sizeof(icmptoicmp6unreach)/sizeof(int))) 794 return -1; 795 #endif 796 797 #ifndef IPFILTER_CKSUM 798 if (fr_checkl4sum(fin) == -1) 799 return -1; 800 #endif 801 802 qif = fin->fin_qif; 803 804 #ifdef USE_INET6 805 mb = fin->fin_qfm; 806 807 if (fin->fin_v == 6) { 808 sz = sizeof(ip6_t); 809 sz += MIN(mb->b_wptr - mb->b_rptr, 512); 810 hlen = sizeof(ip6_t); 811 type = icmptoicmp6types[type]; 812 if (type == ICMP6_DST_UNREACH) 813 code = icmptoicmp6unreach[code]; 814 } else 815 #endif 816 { 817 if ((fin->fin_p == IPPROTO_ICMP) && 818 !(fin->fin_flx & FI_SHORT)) 819 switch (ntohs(fin->fin_data[0]) >> 8) 820 { 821 case ICMP_ECHO : 822 case ICMP_TSTAMP : 823 case ICMP_IREQ : 824 case ICMP_MASKREQ : 825 break; 826 default : 827 return 0; 828 } 829 830 sz = sizeof(ip_t) * 2; 831 sz += 8; /* 64 bits of data */ 832 hlen = sizeof(ip_t); 833 } 834 835 sz += offsetof(struct icmp, icmp_ip); 836 if ((m = (mblk_t *)allocb((size_t)sz + 64, BPRI_HI)) == NULL) 837 return -1; 838 MTYPE(m) = M_DATA; 839 m->b_rptr += 64; 840 m->b_wptr = m->b_rptr + sz; 841 bzero((char *)m->b_rptr, (size_t)sz); 842 icmp = (struct icmp *)(m->b_rptr + hlen); 843 icmp->icmp_type = type & 0xff; 844 icmp->icmp_code = code & 0xff; 845 #ifndef IRE_ILL_CN 846 #ifdef icmp_nextmtu 847 if (type == ICMP_UNREACH && ((il = qif->qf_ill) != NULL) && 848 fin->fin_icode == ICMP_UNREACH_NEEDFRAG) 849 icmp->icmp_nextmtu = htons(il->ill_max_frag); 850 #endif 851 #endif /* IRE_ILL_CN */ 852 853 #ifdef USE_INET6 854 if (fin->fin_v == 6) { 855 struct in6_addr dst6; 856 int csz; 857 858 if (dst == 0) { 859 if (fr_ifpaddr(6, FRI_NORMAL, qif->qf_ill, 860 (struct in_addr *)&dst6, NULL) == -1) { 861 FREE_MB_T(m); 862 return -1; 863 } 864 } else 865 dst6 = fin->fin_dst6; 866 867 csz = sz; 868 sz -= sizeof(ip6_t); 869 ip6 = (ip6_t *)m->b_rptr; 870 ip6->ip6_plen = htons((u_short)sz); 871 ip6->ip6_nxt = IPPROTO_ICMPV6; 872 ip6->ip6_src = dst6; 873 ip6->ip6_dst = fin->fin_src6; 874 sz -= offsetof(struct icmp, icmp_ip); 875 bcopy((char *)mb->b_rptr, (char *)&icmp->icmp_ip, sz); 876 icmp->icmp_cksum = csz - sizeof(ip6_t); 877 } else 878 #endif 879 { 880 ip = (ip_t *)m->b_rptr; 881 ip->ip_hl = sizeof(*ip) >> 2; 882 ip->ip_p = IPPROTO_ICMP; 883 ip->ip_id = fin->fin_ip->ip_id; 884 ip->ip_tos = fin->fin_ip->ip_tos; 885 ip->ip_len = htons((u_short)sz); 886 if (dst == 0) { 887 if (fr_ifpaddr(4, FRI_NORMAL, qif->qf_ill, 888 &dst4, NULL) == -1) { 889 FREE_MB_T(m); 890 return -1; 891 } 892 } else 893 dst4 = fin->fin_dst; 894 ip->ip_src = dst4; 895 ip->ip_dst = fin->fin_src; 896 bcopy((char *)fin->fin_ip, (char *)&icmp->icmp_ip, 897 sizeof(*fin->fin_ip)); 898 bcopy((char *)fin->fin_ip + fin->fin_hlen, 899 (char *)&icmp->icmp_ip + sizeof(*fin->fin_ip), 8); 900 icmp->icmp_cksum = ipf_cksum((u_short *)icmp, 901 sz - sizeof(ip_t)); 902 } 903 904 /* 905 * Need to exit out of these so we don't recursively call rw_enter 906 * from fr_qout. 907 */ 908 return fr_send_ip(fin, m); 909 } 910 911 #ifdef IRE_ILL_CN 912 #include <sys/time.h> 913 #include <sys/varargs.h> 914 915 #ifndef _KERNEL 916 #include <stdio.h> 917 #endif 918 919 #define NULLADDR_RATE_LIMIT 10 /* 10 seconds */ 920 921 922 /* 923 * Print out warning message at rate-limited speed. 924 */ 925 static void rate_limit_message(int rate, const char *message, ...) 926 { 927 static time_t last_time = 0; 928 time_t now; 929 va_list args; 930 char msg_buf[256]; 931 int need_printed = 0; 932 933 now = ddi_get_time(); 934 935 /* make sure, no multiple entries */ 936 ASSERT(MUTEX_NOT_HELD(&(ipf_rw.ipf_lk))); 937 MUTEX_ENTER(&ipf_rw); 938 if (now - last_time >= rate) { 939 need_printed = 1; 940 last_time = now; 941 } 942 MUTEX_EXIT(&ipf_rw); 943 944 if (need_printed) { 945 va_start(args, message); 946 (void)vsnprintf(msg_buf, 255, message, args); 947 va_end(args); 948 #ifdef _KERNEL 949 cmn_err(CE_WARN, msg_buf); 950 #else 951 fprintf(std_err, msg_buf); 952 #endif 953 } 954 } 955 #endif 956 957 /* 958 * return the first IP Address associated with an interface 959 */ 960 /*ARGSUSED*/ 961 int fr_ifpaddr(v, atype, ifptr, inp, inpmask) 962 int v, atype; 963 void *ifptr; 964 struct in_addr *inp, *inpmask; 965 { 966 #ifdef USE_INET6 967 struct sockaddr_in6 sin6, mask6; 968 #endif 969 struct sockaddr_in sin, mask; 970 971 #ifndef IRE_ILL_CN 972 ill_t *ill = ifptr; 973 ipif_t *ipif; 974 #else 975 s_ill_t *ill = ifptr; 976 #endif /* IRE_ILL_CN */ 977 978 if ((ifptr == NULL) || (ifptr == (void *)-1)) 979 return -1; 980 981 #ifdef USE_INET6 982 if (v == 6) { 983 #ifndef IRE_ILL_CN 984 in6_addr_t *inp6; 985 986 /* 987 * First is always link local. 988 */ 989 for (ipif = ill->ill_ipif; ipif; ipif = ipif->ipif_next) { 990 inp6 = &ipif->ipif_v6lcl_addr; 991 if (!IN6_IS_ADDR_LINKLOCAL(inp6) && 992 !IN6_IS_ADDR_LOOPBACK(inp6)) 993 break; 994 } 995 if (ipif == NULL) 996 return -1; 997 998 mask6.sin6_addr = ipif->ipif_v6net_mask; 999 if (atype == FRI_BROADCAST) 1000 sin6.sin6_addr = ipif->ipif_v6brd_addr; 1001 else if (atype == FRI_PEERADDR) 1002 sin6.sin6_addr = ipif->ipif_v6pp_dst_addr; 1003 else 1004 sin6.sin6_addr = *inp6; 1005 #else /* IRE_ILL_CN */ 1006 if (IN6_IS_ADDR_UNSPECIFIED(ill->netmask.in6) || 1007 IN6_IS_ADDR_UNSPECIFIED(ill->localaddr.in6)) { 1008 rate_limit_message(NULLADDR_RATE_LIMIT, 1009 "Check pfild is running: " 1010 "IP#/netmask is 0 on %s.\n" 1011 ill->ill_name); 1012 return -1; 1013 } 1014 mask6 = ill->netmask.in6; 1015 if (atype == FRI_BROADCAST) 1016 sin6 = ill->broadaddr.in6; 1017 else if (atype == FRI_PEERADDR) 1018 sin6 = ill->dstaddr.in6; 1019 else 1020 sin6 = ill->localaddr.in6; 1021 #endif /* IRE_ILL_CN */ 1022 return fr_ifpfillv6addr(atype, &sin6, &mask6, inp, inpmask); 1023 } 1024 #endif 1025 #ifndef IRE_ILL_CN 1026 ipif = ill->ill_ipif; 1027 1028 mask.sin_addr.s_addr = ipif->ipif_net_mask; 1029 if (atype == FRI_BROADCAST) 1030 #if SOLARIS2 < 7 1031 sin.sin_addr.s_addr = ipif->ipif_broadcast_addr; 1032 #else 1033 sin.sin_addr.s_addr = ipif->ipif_brd_addr; 1034 #endif 1035 else if (atype == FRI_PEERADDR) 1036 sin.sin_addr.s_addr = ipif->ipif_pp_dst_addr; 1037 else 1038 #if SOLARIS2 < 7 1039 sin.sin_addr.s_addr = ipif->ipif_local_addr; 1040 #else 1041 sin.sin_addr.s_addr = ipif->ipif_lcl_addr; 1042 #endif 1043 1044 #else 1045 if (ill->netmask.in.sin_addr.s_addr == 0 || 1046 ill->localaddr.in.sin_addr.s_addr == 0) { 1047 rate_limit_message(NULLADDR_RATE_LIMIT, 1048 "Check pfild is running: IP#/netmask is 0 on %s.\n", 1049 ill->ill_name); 1050 return -1; 1051 } 1052 mask = ill->netmask.in; 1053 if (atype == FRI_BROADCAST) 1054 sin = ill->broadaddr.in; 1055 else if (atype == FRI_PEERADDR) 1056 sin = ill->dstaddr.in; 1057 else 1058 sin = ill->localaddr.in; 1059 #endif /* IRE_ILL_CN */ 1060 return fr_ifpfillv4addr(atype, &sin, &mask, inp, inpmask); 1061 } 1062 1063 1064 1065 #ifdef IRE_ILL_CN 1066 /* ARGSUSED */ 1067 #endif 1068 void fr_resolvdest(fdp, v) 1069 frdest_t *fdp; 1070 int v; 1071 { 1072 #ifndef IRE_ILL_CN 1073 ipif_t *ipif; 1074 ill_t *ill; 1075 ire_t *ire; 1076 1077 ire = NULL; 1078 1079 if (*fdp->fd_ifname) { 1080 ill = get_unit(fdp->fd_ifname, v); 1081 if (ill == NULL) 1082 ire = (ire_t *)-1; 1083 else if (((ipif = ill->ill_ipif) != NULL) && (v == 4)) { 1084 #if SOLARIS2 > 5 1085 ire = ire_ctable_lookup(ipif->ipif_local_addr, 0, 1086 IRE_LOCAL, NULL, NULL, 1087 MATCH_IRE_TYPE); 1088 #else 1089 ire = ire_lookup_myaddr(ipif->ipif_local_addr); 1090 #endif 1091 if (ire == NULL) 1092 ire = (ire_t *)-1; 1093 } 1094 #ifdef USE_INET6 1095 else if (((ipif = ill->ill_ipif) != NULL) && (v == 6)) { 1096 ire = ire_ctable_lookup_v6(&ipif->ipif_v6lcl_addr, 0, 1097 IRE_LOCAL, NULL, NULL, 1098 MATCH_IRE_TYPE); 1099 if (ire == NULL) 1100 ire = (ire_t *)-1; 1101 } 1102 #endif 1103 } 1104 fdp->fd_ifp = (struct ifnet *)ire; 1105 #else 1106 #endif /*IRE_ILL_CN */ 1107 } 1108 1109 1110 u_32_t fr_newisn(fin) 1111 fr_info_t *fin; 1112 { 1113 static int iss_seq_off = 0; 1114 u_char hash[16]; 1115 u_32_t newiss; 1116 MD5_CTX ctx; 1117 1118 /* 1119 * Compute the base value of the ISS. It is a hash 1120 * of (saddr, sport, daddr, dport, secret). 1121 */ 1122 MD5Init(&ctx); 1123 1124 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_src, 1125 sizeof(fin->fin_fi.fi_src)); 1126 MD5Update(&ctx, (u_char *) &fin->fin_fi.fi_dst, 1127 sizeof(fin->fin_fi.fi_dst)); 1128 MD5Update(&ctx, (u_char *) &fin->fin_dat, sizeof(fin->fin_dat)); 1129 1130 MD5Update(&ctx, ipf_iss_secret, sizeof(ipf_iss_secret)); 1131 1132 MD5Final(hash, &ctx); 1133 1134 bcopy(hash, &newiss, sizeof(newiss)); 1135 1136 /* 1137 * Now increment our "timer", and add it in to 1138 * the computed value. 1139 * 1140 * XXX Use `addin'? 1141 * XXX TCP_ISSINCR too large to use? 1142 */ 1143 iss_seq_off += 0x00010000; 1144 newiss += iss_seq_off; 1145 return newiss; 1146 } 1147 1148 1149 /* ------------------------------------------------------------------------ */ 1150 /* Function: fr_nextipid */ 1151 /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 1152 /* Parameters: fin(I) - pointer to packet information */ 1153 /* */ 1154 /* Returns the next IPv4 ID to use for this packet. */ 1155 /* ------------------------------------------------------------------------ */ 1156 INLINE u_short fr_nextipid(fin) 1157 fr_info_t *fin; 1158 { 1159 static u_short ipid = 0; 1160 ipstate_t *is; 1161 nat_t *nat; 1162 u_short id; 1163 1164 MUTEX_ENTER(&ipf_rw); 1165 if (fin->fin_state != NULL) { 1166 is = fin->fin_state; 1167 id = (u_short)(is->is_pkts[(fin->fin_rev << 1) + 1] & 0xffff); 1168 } else if (fin->fin_nat != NULL) { 1169 nat = fin->fin_nat; 1170 id = (u_short)(nat->nat_pkts[fin->fin_out] & 0xffff); 1171 } else 1172 id = ipid++; 1173 MUTEX_EXIT(&ipf_rw); 1174 1175 return id; 1176 } 1177 1178 1179 #ifndef IPFILTER_CKSUM 1180 /* ARGSUSED */ 1181 #endif 1182 INLINE void fr_checkv4sum(fin) 1183 fr_info_t *fin; 1184 { 1185 #ifdef IPFILTER_CKSUM 1186 if (fr_checkl4sum(fin) == -1) 1187 fin->fin_flx |= FI_BAD; 1188 #endif 1189 } 1190 1191 1192 #ifdef USE_INET6 1193 INLINE void fr_checkv6sum(fin) 1194 fr_info_t *fin; 1195 { 1196 # ifdef IPFILTER_CKSUM 1197 if (fr_checkl4sum(fin) == -1) 1198 fin->fin_flx |= FI_BAD; 1199 # endif 1200 } 1201 #endif /* USE_INET6 */ 1202