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 27ETC_IPF_DIR=/etc/ipf 28IP6FILCONF=$ETC_IPF_DIR/ipf6.conf 29IPNATCONF=$ETC_IPF_DIR/ipnat.conf 30IPPOOLCONF=$ETC_IPF_DIR/ippool.conf 31VAR_IPF_DIR=/var/run/ipf 32IPFILCONF=$VAR_IPF_DIR/ipf.conf 33IPFILOVRCONF=$VAR_IPF_DIR/ipf_ovr.conf 34IPF_LOCK=/var/run/ipflock 35CONF_FILES="" 36NAT_FILES="" 37IPF_SUFFIX=".ipf" 38NAT_SUFFIX=".nat" 39 40# version for configuration upgrades 41CURRENT_VERSION=1 42 43IPF_FMRI="svc:/network/ipfilter:default" 44INETDFMRI="svc:/network/inetd:default" 45RPCBINDFMRI="svc:/network/rpc/bind:default" 46 47SMF_ONLINE="online" 48SMF_MAINT="maintenance" 49SMF_NONE="none" 50 51FW_CONTEXT_PG="firewall_context" 52METHOD_PROP="ipf_method" 53 54FW_CONFIG_PG="firewall_config" 55POLICY_PROP="policy" 56APPLY2_PROP="apply_to" 57EXCEPTIONS_PROP="exceptions" 58 59FW_CONFIG_DEF_PG="firewall_config_default" 60FW_CONFIG_OVR_PG="firewall_config_override" 61CUSTOM_FILE_PROP="custom_policy_file" 62OPEN_PORTS_PROP="open_ports" 63 64PREFIX_HOST="host:" 65PREFIX_NET="network:" 66PREFIX_POOL="pool:" 67PREFIX_IF="if:" 68 69SERVINFO=/usr/lib/servinfo 70 71# 72# Given a service, gets its config pg name 73# 74get_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# 87get_policy() 88{ 89 config_pg=`get_config_pg $1` 90 svcprop -p $config_pg/${POLICY_PROP} $1 2>/dev/null 91} 92 93get_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# 101get_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# 110get_apply2_list() 111{ 112 config_pg=`get_config_pg $1` 113 svcprop -p $config_pg/${APPLY2_PROP} $1 2>/dev/null 114} 115 116check_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# 125fmri_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# 135service_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# 158service_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# 175get_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 183get_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# 195value_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# 204remove_rules() 205{ 206 [ -f "$1" ] && ipf -r -f $1 >/dev/null 2>&1 207} 208 209remove_nat_rules() 210{ 211 [ -f "$1" ] && ipnat -r -f $1 >/dev/null 2>&1 212} 213 214check_ipf_syntax() 215{ 216 ipf -n -f $1 >/dev/null 2>&1 217} 218 219check_nat_syntax() 220{ 221 ipnat -n -f $1 >/dev/null 2>&1 222} 223 224file_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 231get_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# 241sets_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# 262update_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 272server_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# 281check_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 291prepend_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 297append_new_rules() 298{ 299 check_ipf_syntax $1 && ipf -f $1 >/dev/null 2>&1 300} 301 302append_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# 310tuple_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# 339tuple_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 348ipf_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# 375ipf_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# 386custom_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# 402replace_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# 425process_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# 512generate_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# 593process_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# 620process_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# 663create_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# 763create_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# 810svc_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 831svc_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# 841create_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# 904service_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# 977service_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