1 #!/sbin/sh 2 # 3 # CDDL HEADER START 4 # 5 # The contents of this file are subject to the terms of the 6 # Common Development and Distribution License (the "License"). 7 # You may not use this file except in compliance with the License. 8 # 9 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 # or http://www.opensolaris.org/os/licensing. 11 # See the License for the specific language governing permissions 12 # and limitations under the License. 13 # 14 # When distributing Covered Code, include this CDDL HEADER in each 15 # file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 # If applicable, add the following below this CDDL HEADER, with the 17 # fields enclosed by brackets "[]" replaced with your own identifying 18 # information: Portions Copyright [yyyy] [name of copyright owner] 19 # 20 # CDDL HEADER END 21 # 22 # 23 # Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 # Use is subject to license terms. 25 # 26 27 ETC_IPF_DIR=/etc/ipf 28 IP6FILCONF=$ETC_IPF_DIR/ipf6.conf 29 IPNATCONF=$ETC_IPF_DIR/ipnat.conf 30 IPPOOLCONF=$ETC_IPF_DIR/ippool.conf 31 VAR_IPF_DIR=/var/run/ipf 32 IPFILCONF=$VAR_IPF_DIR/ipf.conf 33 IPFILOVRCONF=$VAR_IPF_DIR/ipf_ovr.conf 34 IPF_LOCK=/var/run/ipflock 35 CONF_FILES="" 36 NAT_FILES="" 37 IPF_SUFFIX=".ipf" 38 NAT_SUFFIX=".nat" 39 40 # version for configuration upgrades 41 CURRENT_VERSION=1 42 43 IPF_FMRI="svc:/network/ipfilter:default" 44 INETDFMRI="svc:/network/inetd:default" 45 RPCBINDFMRI="svc:/network/rpc/bind:default" 46 47 SMF_ONLINE="online" 48 SMF_MAINT="maintenance" 49 SMF_NONE="none" 50 51 FW_CONTEXT_PG="firewall_context" 52 METHOD_PROP="ipf_method" 53 54 FW_CONFIG_PG="firewall_config" 55 POLICY_PROP="policy" 56 APPLY2_PROP="apply_to" 57 EXCEPTIONS_PROP="exceptions" 58 59 FW_CONFIG_DEF_PG="firewall_config_default" 60 FW_CONFIG_OVR_PG="firewall_config_override" 61 CUSTOM_FILE_PROP="custom_policy_file" 62 OPEN_PORTS_PROP="open_ports" 63 64 PREFIX_HOST="host:" 65 PREFIX_NET="network:" 66 PREFIX_POOL="pool:" 67 PREFIX_IF="if:" 68 69 SERVINFO=/usr/lib/servinfo 70 71 # 72 # Given a service, gets its config pg name 73 # 74 get_config_pg() 75 { 76 if [ "$1" = "$IPF_FMRI" ]; then 77 echo "$FW_CONFIG_DEF_PG" 78 else 79 echo "$FW_CONFIG_PG" 80 fi 81 return 0 82 } 83 84 # 85 # Given a service, gets its firewall policy 86 # 87 get_policy() 88 { 89 config_pg=`get_config_pg $1` 90 svcprop -p $config_pg/${POLICY_PROP} $1 2>/dev/null 91 } 92 93 get_global_def_policy() 94 { 95 svcprop -p ${FW_CONFIG_DEF_PG}/${POLICY_PROP} $IPF_FMRI 2>/dev/null 96 } 97 98 # 99 # Given a service, gets its firewall policy 100 # 101 get_exceptions() 102 { 103 config_pg=`get_config_pg $1` 104 svcprop -p $config_pg/${EXCEPTIONS_PROP} $1 2>/dev/null 105 } 106 107 # 108 # Given a service, gets its firewall policy 109 # 110 get_apply2_list() 111 { 112 config_pg=`get_config_pg $1` 113 svcprop -p $config_pg/${APPLY2_PROP} $1 2>/dev/null 114 } 115 116 check_ipf_dir() 117 { 118 [ -d $VAR_IPF_DIR ] && return 0 119 mkdir $VAR_IPF_DIR >/dev/null 2>&1 || return 1 120 } 121 122 # 123 # fmri_to_file fmri suffix 124 # 125 fmri_to_file() 126 { 127 check_ipf_dir || return 1 128 fprefix="${VAR_IPF_DIR}/`echo $1 | tr -s '/:' '__'`" 129 echo "${fprefix}${2}" 130 } 131 132 # 133 # Return service's enabled property 134 # 135 service_is_enabled() 136 { 137 # 138 # Temporary enabled state overrides the persistent state 139 # so check it first. 140 # 141 enabled_ovr=`svcprop -c -p general_ovr/enabled $1 2>/dev/null` 142 if [ -n "$enabled_ovr" ]; then 143 [ "$enabled_ovr" = "true" ] && return 0 || return 1 144 fi 145 146 enabled=`svcprop -c -p general/enabled $1 2>/dev/null` 147 [ -n "$enabled" -a "$enabled" = "true" ] && return 0 || return 1 148 } 149 150 # 151 # Return whether service is desired state 152 # 153 # Args: fmri state 154 # Return: 155 # 0 - desired state is service's current state 156 # 1 - desired state is not service's current state 157 # 158 service_check_state() 159 { 160 # 161 # Make sure we're done with ongoing state transition 162 # 163 while [ "`svcprop -p restarter/next_state $1`" != "$SMF_NONE" ]; do 164 sleep 1 165 done 166 167 [ "`svcprop -p restarter/state $1`" = "$2" ] && return 0 || return 1 168 } 169 170 # 171 # Deny/Allow list stores values in the form "host:addr", "network:addr/netmask", 172 # "pool:number", and "if:interface". This function returns the 173 # IP(addr or addr/netmask) value or a pool number. 174 # 175 get_IP() 176 { 177 value_is_interface $1 && return 1 178 echo "$1" | sed -n -e 's,^pool:\(.*\),pool/\1,p' \ 179 -e 's,^host:\(.*\),\1,p' \ 180 -e 's,^network:\(.*\),\1,p' 181 } 182 183 get_interface() 184 { 185 value_is_interface $1 || return 1 186 scratch=`echo "$1" | sed -e 's/^if://'` 187 188 ifconfig $scratch >/dev/null 2>&1 || return 1 189 echo $scratch | sed -e 's/:.*//' 190 } 191 192 # 193 # 194 # 195 value_is_interface() 196 { 197 [ -z "$1" ] && return 1 198 echo $1 | grep "^if:" >/dev/null 2>&1 199 } 200 201 # 202 # Remove rules in given file from active list without restarting ipfilter 203 # 204 remove_rules() 205 { 206 [ -f "$1" ] && ipf -r -f $1 >/dev/null 2>&1 207 } 208 209 remove_nat_rules() 210 { 211 [ -f "$1" ] && ipnat -r -f $1 >/dev/null 2>&1 212 } 213 214 check_ipf_syntax() 215 { 216 ipf -n -f $1 >/dev/null 2>&1 217 } 218 219 check_nat_syntax() 220 { 221 ipnat -n -f $1 >/dev/null 2>&1 222 } 223 224 file_get_ports() 225 { 226 ipf -n -v -f $1 2>/dev/null | sed -n -e \ 227 's/.*to.* port = \([a-z0-9]*\).*/\1/p' | uniq | \ 228 awk '{if (length($0) > 1) {printf("%s ", $1)}}' 229 } 230 231 get_active_ports() 232 { 233 ipfstat -io 2>/dev/null | sed -n -e \ 234 's/.*to.* port = \([a-z0-9]*\).*/\1/p' | uniq | \ 235 awk '{if (length($0) > 1) {printf("%s ",$1)}}' 236 } 237 238 # 239 # Given two list of ports, return failure if there's a duplicate. 240 # 241 sets_check_duplicate() 242 { 243 # 244 # If either list is empty, there isn't any conflict. 245 # 246 [ -z "$1" -o -z "$2" ] && return 0 247 248 for p in $1; do 249 for ap in $2; do 250 [ "$p" = "$ap" ] && return 1 251 done 252 done 253 254 return 0 255 } 256 257 # 258 # Given a file containing ipf rules, check the syntax and verify 259 # the rules don't conflict, use same port number, with active 260 # rules (ipfstat -io output). 261 # 262 update_check_ipf_rules() 263 { 264 check_ipf_syntax $1 || return 1 265 266 lports=`file_get_ports $1` 267 lactive_ports=`get_active_ports` 268 269 sets_check_duplicate "$lports" "$lactive_ports" || return 1 270 } 271 272 server_port_list="" 273 274 # 275 # Given a file containing ipf rules, check the syntax and verify 276 # the rules don't conflict with already processed services. 277 # 278 # The list of processed services' ports are maintained in the global 279 # variable 'server_port_list'. 280 # 281 check_ipf_rules() 282 { 283 check_ipf_syntax $1 || return 1 284 285 lports=`file_get_ports $1` 286 sets_check_duplicate "$lports" "$server_port_list" || return 1 287 server_port_list="$server_port_list $lports" 288 return 0 289 } 290 291 prepend_new_rules() 292 { 293 check_ipf_syntax $1 && tail -r $1 | sed -e 's/^[a-z]/@0 &/' | \ 294 ipf -f - >/dev/null 2>&1 295 } 296 297 append_new_rules() 298 { 299 check_ipf_syntax $1 && ipf -f $1 >/dev/null 2>&1 300 } 301 302 append_new_nat_rules() 303 { 304 check_nat_syntax $1 && ipnat -f $1 >/dev/null 2>&1 305 } 306 307 # 308 # get port information from string of the form "proto:{port | port-port}" 309 # 310 tuple_get_port() 311 { 312 port_str=`echo "$1" | sed -e 's/ //g; s/.*://' 2>/dev/null` 313 [ -z "$port_str" ] && return 1 314 315 echo $port_str | grep "-" >/dev/null 316 if [ $? -eq 0 ]; then 317 echo $port_str | grep '^[0-9]\{1,5\}-[0-9]\{1,5\}$' >/dev/null || \ 318 return 1 319 ports=`echo $port_str | ( IFS=- read a b ; \ 320 [ $a \-le $b ] && echo $a $b || echo $b $a )` 321 322 for p in $ports; do 323 [ $p -gt 65535 ] && return 1 324 done 325 echo "$ports" 326 else 327 # 328 # port_str is a single port, verify and return it. 329 # 330 echo "$port_str" | grep '^[0-9]\{1,5\}$' >/dev/null || return 1 331 [ $port_str -gt 65535 ] && return 1 332 echo "$port_str" 333 fi 334 } 335 336 # 337 # get proto info from string of the form "{tcp | udp}:port" 338 # 339 tuple_get_proto() 340 { 341 proto=`echo "$1" | sed -e 's/ //g; s/:.*//' 2>/dev/null` 342 [ -z "$proto" ] && return 0 343 344 [ "$proto" = "tcp" -o "$proto" = "udp" ] && echo $proto || return 1 345 return 0 346 } 347 348 ipf_get_lock() 349 { 350 newpid=$$ 351 352 if [ -f "$IPF_LOCK/pid" ]; then 353 curpid=`cat $IPF_LOCK/pid 2>/dev/null` 354 [ "$curpid" = "$newpid" ] && return 0 355 356 # 357 # Clear lock if the owning process is no longer around. 358 # 359 ps -p $curpid >/dev/null 2>&1 || rm -r $IPF_LOCK >/dev/null 2>&1 360 fi 361 362 # 363 # Grab the lock 364 # 365 while :; do 366 mkdir $IPF_LOCK 2>/dev/null && break; 367 sleep 1 368 done 369 echo $newpid > $IPF_LOCK/pid 370 } 371 372 # 373 # Remove lock if it's ours 374 # 375 ipf_remove_lock() 376 { 377 if [ -f "$IPF_LOCK/pid" ]; then 378 [ "`cat $IPF_LOCK/pid`" = "$$" ] && rm -r $IPF_LOCK 379 fi 380 return 0 381 } 382 383 # 384 # Make IPFILCONF, /var/tmp/ipf/ipf.conf, a symlink to the input file argument. 385 # 386 custom_set_symlink() 387 { 388 # 389 # Nothing to do if the input file doesn't exist. 390 # 391 [ ! -f "$1" ] && return 0 392 393 check_ipf_dir || return 1 394 395 rm $IPFILCONF >/dev/null 2>&1 396 ln -s $1 $IPFILCONF >/dev/null 2>&1 397 } 398 399 # 400 # New file replaces original file if they have different content 401 # 402 replace_file() 403 { 404 orig=$1 405 new=$2 406 407 # 408 # IPFILCONF may be a symlink, remove it if that's the case 409 # 410 if [ -L "$orig" ]; then 411 rm $orig 412 touch $orig 413 fi 414 415 check_ipf_dir || return 1 416 mv $new $orig && return 0 || return 1 417 } 418 419 # 420 # Given a service, gets the following details for ipf rule: 421 # - policy 422 # - protocol 423 # - port(IANA port obtained by running servinfo) 424 # 425 process_server_svc() 426 { 427 service=$1 428 ip="any" 429 policy=`get_policy ${service}` 430 431 # 432 # Empties service's rules file so callers won't use existing rule if 433 # we fail here. 434 # 435 file=`fmri_to_file $service $IPF_SUFFIX` 436 [ -z "$file" ] && return 1 437 echo "# $service" >${file} 438 439 # 440 # Nothing to do if policy is "use_global" 441 # 442 [ "$policy" = "use_global" ] && return 0 443 444 restarter=`svcprop -p general/restarter $service 2>/dev/null` 445 if [ "$restarter" = "$INETDFMRI" ]; then 446 iana_name=`svcprop -p inetd/name $service 2>/dev/null` 447 isrpc=`svcprop -p inetd/isrpc $service 2>/dev/null` 448 else 449 iana_name=`svcprop -p $FW_CONTEXT_PG/name $service 2>/dev/null` 450 isrpc=`svcprop -p $FW_CONTEXT_PG/isrpc $service 2>/dev/null` 451 fi 452 453 # 454 # Bail if iana_name isn't defined. Services with static rules 455 # like nis/client don't need to generate rules using 456 # iana name and protocol information. 457 # 458 [ -z "$iana_name" ] && return 1 459 460 # 461 # RPC services 462 # 463 if [ "$isrpc" = "true" ]; then 464 tports=`$SERVINFO -R -p -t -s $iana_name 2>/dev/null` 465 if [ -n "$tports" ]; then 466 for tport in $tports; do 467 generate_rules $service $policy "tcp" \ 468 $ip $tport $file 469 done 470 fi 471 472 uports=`$SERVINFO -R -p -u -s $iana_name 2>/dev/null` 473 if [ -n "$uports" ]; then 474 for uport in $uports; do 475 generate_rules $service $policy "udp" \ 476 $ip $uport $file 477 done 478 fi 479 480 return 0 481 fi 482 483 # 484 # Get the IANA port and supported protocols(tcp and udp) 485 # No support for IPv6 at this point. 486 # 487 tport=`$SERVINFO -p -t -s $iana_name 2>&1` 488 if [ $? -eq 0 -a -n "$tport" ]; then 489 generate_rules $service $policy "tcp" $ip $tport $file 490 fi 491 492 uport=`$SERVINFO -p -u -s $iana_name 2>&1` 493 if [ $? -eq 0 -a -n "$uport" ]; then 494 generate_rules $service $policy "udp" $ip $uport $file 495 fi 496 497 return 0 498 } 499 500 # 501 # Given a service's name, policy, protocol and port, generate ipf rules 502 # - list of host/network/interface to apply policy 503 # 504 # A 'use_global' policy inherits the system-wided Global Default policy 505 # from network/ipfilter. For {deny | allow} policies, the rules are 506 # ordered as: 507 # 508 # - make exceptions to policy for those in "exceptions" list 509 # - apply policy to those specified in "apply_to" list 510 # - policy rule 511 # 512 generate_rules() 513 { 514 service=$1 515 mypolicy=$2 516 proto=$3 517 ip=$4 518 port=$5 519 out=$6 520 521 # 522 # Default mode is to inherit from global's policy 523 # 524 [ "$mypolicy" = "use_global" ] && return 0 525 526 tcp_opts="" 527 [ "$proto" = "tcp" ] && tcp_opts="flags S keep state keep frags" 528 529 # 530 # Allow all if policy is 'none' 531 # 532 if [ "$mypolicy" = "none" ]; then 533 echo "pass in log quick proto ${proto} from any to ${ip}" \ 534 "port = ${port} ${tcp_opts}" >>${out} 535 return 0 536 fi 537 538 # 539 # For now, let's concern only with incoming traffic. 540 # 541 [ "$mypolicy" = "deny" ] && { ecmd="pass"; acmd="block"; } 542 [ "$mypolicy" = "allow" ] && { ecmd="block"; acmd="pass"; } 543 544 for name in `get_exceptions $service`; do 545 [ -z "$name" -o "$name" = '""' ] && continue 546 547 ifc=`get_interface $name` 548 if [ $? -eq 0 -a -n "$ifc" ]; then 549 echo "${ecmd} in log quick on ${ifc} from any to" \ 550 "${ip} port = ${port}" >>${out} 551 continue 552 fi 553 554 addr=`get_IP ${name}` 555 if [ $? -eq 0 -a -n "$addr" ]; then 556 echo "${ecmd} in log quick proto ${proto} from ${addr}" \ 557 "to ${ip} port = ${port} ${tcp_opts}" >>${out} 558 fi 559 done 560 561 for name in `get_apply2_list $service`; do 562 [ -z "$name" -o "$name" = '""' ] && continue 563 564 ifc=`get_interface $name` 565 if [ $? -eq 0 -a -n "$ifc" ]; then 566 echo "${acmd} in log quick on ${ifc} from any to" \ 567 "${ip} port = ${port}" >>${out} 568 continue 569 fi 570 571 addr=`get_IP ${name}` 572 if [ $? -eq 0 -a -n "$addr" ]; then 573 echo "${acmd} in log quick proto ${proto} from ${addr}" \ 574 "to ${ip} port = ${port} ${tcp_opts}" >>${out} 575 fi 576 done 577 578 echo "${ecmd} in log quick proto ${proto} from any to ${ip}" \ 579 "port = ${port} ${tcp_opts}" >>${out} 580 581 return 0 582 } 583 584 # 585 # Service has either IANA ports and proto or its own firewall method to 586 # generate the rules. 587 # 588 # - if service has a custom method, use it to populate its rules 589 # - if service has a firewall_config pg, use process_server_svc 590 # 591 # Argument - fmri 592 # 593 process_service() 594 { 595 # 596 # Don't process network/ipfilter 597 # 598 [ "$1" = "$IPF_FMRI" ] && return 0 599 600 service_check_state $1 $SMF_MAINT && return 1 601 602 method=`svcprop -p $FW_CONTEXT_PG/$METHOD_PROP $1 2>/dev/null | \ 603 sed 's/\\\//g'` 604 if [ -n "$method" -a "$method" != '""' ]; then 605 ( exec $method $1 >/dev/null ) 606 else 607 svcprop -p $FW_CONFIG_PG $1 >/dev/null 2>&1 || return 1 608 process_server_svc $1 || return 1 609 fi 610 return 0 611 } 612 613 # 614 # Generate rules for protocol/port defined in firewall_config_default/open_ports 615 # property. These are non-service programs whose network resource info are 616 # defined as "{tcp | upd}:{PORT | PORT-PORT}". Essentially, these programs need 617 # some specific local ports to be opened. For example, BitTorrent clients need to 618 # have 6881-6889 opened. 619 # 620 process_nonsvc_progs() 621 { 622 out=$1 623 echo "# Non-service programs rules" >>${out} 624 progs=`svcprop -p ${FW_CONFIG_DEF_PG}/${OPEN_PORTS_PROP} \ 625 $SMF_FMRI 2>/dev/null` 626 627 for prog in $progs; do 628 [ -z "$prog" -o "$prog" = '""' ] && continue 629 630 port=`tuple_get_port $prog` 631 [ $? -eq 1 -o -z "$port" ] && continue 632 633 proto=`tuple_get_proto $prog` 634 [ $? -eq 1 ] && continue 635 636 set -- $port 637 if [ $# -gt 1 ]; then 638 if [ -z "$proto" ]; then 639 echo "pass in log quick from any to any" \ 640 "port ${1} >< ${2}" >>${out} 641 else 642 echo "pass in log quick proto ${proto} from any" \ 643 "to any port ${1} >< ${2}" >>${out} 644 fi 645 else 646 if [ -z "$proto" ]; then 647 echo "pass in log quick from any to any" \ 648 "port = ${1}" >>${out} 649 else 650 echo "pass in log quick proto ${proto} from any" \ 651 "to any port = ${1}" >>${out} 652 fi 653 fi 654 done 655 656 return 0 657 } 658 659 # 660 # Generate a new /etc/ipf/ipf.conf. If firewall policy is 'none', 661 # ipf.conf is empty . 662 # 663 create_global_rules() 664 { 665 policy=`get_global_def_policy` 666 667 if [ "$policy" = "custom" ]; then 668 file=`svcprop -p ${FW_CONFIG_DEF_PG}/${CUSTOM_FILE_PROP} $SMF_FMRI` 669 670 [ -n "$file" ] && custom_set_symlink $file 671 return 0 672 fi 673 674 TEMP=`mktemp /var/run/ipf.conf.pid$$.XXXXXX` 675 process_nonsvc_progs $TEMP 676 677 echo "# Global Default rules" >>${TEMP} 678 if [ "$policy" != "none" ]; then 679 echo "pass out log quick all keep state" >>${TEMP} 680 fi 681 682 case "$policy" in 683 'none') 684 # No rules 685 replace_file ${IPFILCONF} ${TEMP} 686 return $? 687 ;; 688 689 'deny') 690 ecmd="pass" 691 acmd="block" 692 ;; 693 694 'allow') 695 ecmd="block" 696 acmd="pass" 697 ;; 698 *) 699 return 1; 700 ;; 701 esac 702 703 for name in `get_exceptions $SMF_FMRI`; do 704 [ -z "$name" -o "$name" = '""' ] && continue 705 706 ifc=`get_interface $name` 707 if [ $? -eq 0 -a -n "$ifc" ]; then 708 echo "${ecmd} in log quick on ${ifc} all" >>${TEMP} 709 continue 710 fi 711 712 addr=`get_IP ${name}` 713 if [ $? -eq 0 -a -n "$addr" ]; then 714 echo "${ecmd} in log quick from ${addr} to any" >>${TEMP} 715 fi 716 717 done 718 719 for name in `get_apply2_list $SMF_FMRI`; do 720 [ -z "$name" -o "$name" = '""' ] && continue 721 722 ifc=`get_interface $name` 723 if [ $? -eq 0 -a -n "$ifc" ]; then 724 echo "${acmd} in log quick on ${ifc} all" >>${TEMP} 725 continue 726 fi 727 728 addr=`get_IP ${name}` 729 if [ $? -eq 0 -a -n "$addr" ]; then 730 echo "${acmd} in log quick from ${addr} to any" >>${TEMP} 731 fi 732 done 733 734 if [ "$policy" = "allow" ]; then 735 # 736 # Allow DHCP traffic if running as a DHCP client 737 # 738 /sbin/netstrategy | grep dhcp >/dev/null 2>&1 739 if [ $? -eq 0 ]; then 740 echo "pass out log quick from any port = 68" \ 741 "keep state" >>${TEMP} 742 echo "pass out log quick from any port = 546" \ 743 "keep state" >>${TEMP} 744 echo "pass in log quick from any to any port = 68" >>${TEMP} 745 echo "pass in log quick from any to any port = 546" >>${TEMP} 746 fi 747 echo "block in log all" >>${TEMP} 748 fi 749 750 replace_file ${IPFILCONF} ${TEMP} 751 return $? 752 } 753 754 # 755 # Generate a new /etc/ipf/ipf_ovr.conf, the override system-wide policy. It's 756 # a simplified policy that doesn't support 'exceptions' entities. 757 # 758 # If firewall policy is "none", no rules are generated. 759 # 760 # Note that "pass" rules don't have "quick" as we don't want 761 # them to override services' block rules. 762 # 763 create_global_ovr_rules() 764 { 765 # 766 # Simply empty override file if global policy is 'custom' 767 # 768 if [ "`get_global_def_policy`" = "custom" ]; then 769 echo "# 'custom' global policy" >$IPFILOVRCONF 770 return 0 771 fi 772 773 # 774 # Get and process override policy 775 # 776 ovr_policy=`svcprop -p ${FW_CONFIG_OVR_PG}/${POLICY_PROP} $IPF_FMRI` 777 if [ "$ovr_policy" = "none" ]; then 778 echo "# global override policy is 'none'" >$IPFILOVRCONF 779 return 0 780 fi 781 782 TEMP=`mktemp /var/run/ipf_ovr.conf.pid$$.XXXXXX` 783 [ "$ovr_policy" = "deny" ] && acmd="block in log quick" 784 [ "$ovr_policy" = "allow" ] && acmd="pass in log" 785 786 apply2_list=`svcprop -p $FW_CONFIG_OVR_PG/$APPLY2_PROP $IPF_FMRI` 787 for name in $apply2_list; do 788 [ -z "$name" -o "$name" = '""' ] && continue 789 790 ifc=`get_interface $name` 791 if [ $? -eq 0 -a -n "$ifc" ]; then 792 echo "${acmd} on ${ifc} all" >>${TEMP} 793 continue 794 fi 795 796 addr=`get_IP ${name}` 797 if [ $? -eq 0 -a -n "$addr" ]; then 798 echo "${acmd} from ${addr} to any" >>${TEMP} 799 fi 800 done 801 802 replace_file ${IPFILOVRCONF} ${TEMP} 803 return $? 804 } 805 806 # 807 # Service is put into maintenance state due to its invalid firewall 808 # definition and/or policy. 809 # 810 svc_mark_maintenance() 811 { 812 svcadm mark maintenance $1 >/dev/null 2>&1 813 814 date=`date` 815 echo "[ $date ${0}: $1 has invalid ipf configuration. ]" 816 echo "[ $date ${0}: placing $1 in maintenance. ]" 817 818 # 819 # Move service's rule files to another location since 820 # they're most likely invalid. 821 # 822 ipfile=`fmri_to_file $1 $IPF_SUFFIX` 823 [ -f "$ipfile" ] && mv $ipfile "$ipfile.bak" 824 825 natfile=`fmri_to_file $1 $NAT_SUFFIX` 826 [ -f "$natfile" ] && mv $natfile "$natfile.bak" 827 828 return 0 829 } 830 831 svc_is_server() 832 { 833 svcprop -p $FW_CONFIG_PG $1 >/dev/null 2>&1 834 } 835 836 # 837 # Create rules for enabled firewalling and client services. 838 # - obtain the list of enabled services and process them 839 # - save the list of rules file for later use 840 # 841 create_services_rules() 842 { 843 # 844 # Do nothing if global policy is 'custom' 845 # 846 global_policy=`get_global_def_policy` 847 [ "$global_policy" = "custom" ] && return 0 848 849 ipf_get_lock 850 851 # 852 # Get all enabled services 853 # 854 allsvcs=`svcprop -cf -p general/enabled -p general_ovr/enabled '*' \ 855 2>/dev/null | sed -n 's,^\(svc:.*\)/:properties/.* true$,\1,p' | sort -u` 856 857 # 858 # Process enabled services 859 # 860 for s in $allsvcs; do 861 service_is_enabled $s || continue 862 process_service $s || continue 863 864 ipfile=`fmri_to_file $s $IPF_SUFFIX` 865 if [ -n "$ipfile" -a -r "$ipfile" ]; then 866 check_ipf_syntax $ipfile 867 if [ $? -ne 0 ]; then 868 svc_mark_maintenance $s 869 continue 870 fi 871 872 svc_is_server $s 873 if [ $? -eq 0 ]; then 874 check_ipf_rules $ipfile 875 if [ $? -ne 0 ]; then 876 svc_mark_maintenance $s 877 continue 878 fi 879 fi 880 CONF_FILES="$CONF_FILES $ipfile" 881 fi 882 883 natfile=`fmri_to_file $s $NAT_SUFFIX` 884 if [ -n "$natfile" -a -r "$natfile" ]; then 885 check_nat_syntax $natfile 886 if [ $? -ne 0 ]; then 887 svc_mark_maintenance $s 888 continue 889 fi 890 891 NAT_FILES="$NAT_FILES $natfile" 892 fi 893 done 894 895 ipf_remove_lock 896 return 0 897 } 898 899 # 900 # We update a services ipf ruleset in the following manners: 901 # - service is disabled, tear down its rules. 902 # - service is disable or refreshed(online), setup or update its rules. 903 # 904 service_update_rules() 905 { 906 # 907 # If ipfilter isn't online or global policy is 'custom', 908 # nothing should be done. 909 # 910 service_check_state $SMF_FMRI $SMF_ONLINE || return 0 911 [ "`get_global_def_policy`" = "custom" ] && return 0 912 913 svc=$1 914 915 ipfile=`fmri_to_file $svc $IPF_SUFFIX` 916 [ -z "$ipfile" ] && return 0 917 918 remove_rules $ipfile 919 920 natfile=`fmri_to_file $svc $NAT_SUFFIX` 921 [ -n "$natfile" ] && remove_nat_rules $natfile 922 923 # 924 # Don't go further if service is disabled or in maintenance. 925 # 926 service_is_enabled $svc || return 0 927 service_check_state $1 $SMF_MAINT && return 0 928 929 process_service $svc || return 1 930 if [ -f "$ipfile" ]; then 931 check_ipf_syntax $ipfile 932 if [ $? -ne 0 ]; then 933 svc_mark_maintenance $svc 934 return 1 935 fi 936 fi 937 938 if [ -f "$natfile" ]; then 939 check_nat_syntax $natfile 940 if [ $? -ne 0 ]; then 941 svc_mark_maintenance $svc 942 return 1 943 fi 944 fi 945 946 if [ -f "$ipfile" ]; then 947 svc_is_server $svc 948 if [ $? -eq 0 ]; then 949 update_check_ipf_rules $ipfile 950 if [ $? -ne 0 ]; then 951 svc_mark_maintenance $svc 952 return 1 953 fi 954 fi 955 956 prepend_new_rules $ipfile 957 958 # 959 # reload Global Override rules to 960 # maintain correct ordering. 961 # 962 remove_rules $IPFILOVRCONF 963 prepend_new_rules $IPFILOVRCONF 964 fi 965 966 [ -f "$natfile" ] && append_new_nat_rules $natfile 967 968 return 0 969 } 970 971 # 972 # Call the service_update_rules with appropriate svc fmri. 973 # 974 # This is called from '/lib/svc/method/ipfilter fw_update' whenever 975 # a service is disabled/enabled/refreshed. 976 # 977 service_update() 978 { 979 svc=$1 980 ret=0 981 982 ipf_get_lock 983 service_update_rules $svc || ret=1 984 985 ipf_remove_lock 986 return $ret 987 } 988