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/tmp/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 TEMP=`mktemp /var/run/ipf_ovr.conf.pid$$.XXXXXX` 778 779 [ "$ovr_policy" = "deny" ] && acmd="block in log quick" 780 [ "$ovr_policy" = "allow" ] && acmd="pass in log" 781 782 apply2_list=`svcprop -p $FW_CONFIG_OVR_PG/$APPLY2_PROP $IPF_FMRI` 783 for name in $apply2_list; do 784 [ -z "$name" -o "$name" = '""' ] && continue 785 786 ifc=`get_interface $name` 787 if [ $? -eq 0 -a -n "$ifc" ]; then 788 echo "${acmd} on ${ifc} all" >>${TEMP} 789 continue 790 fi 791 792 addr=`get_IP ${name}` 793 if [ $? -eq 0 -a -n "$addr" ]; then 794 echo "${acmd} from ${addr} to any" >>${TEMP} 795 fi 796 done 797 798 replace_file ${IPFILOVRCONF} ${TEMP} 799 return $? 800} 801 802# 803# Service is put into maintenance state due to its invalid firewall 804# definition and/or policy. 805# 806svc_mark_maintenance() 807{ 808 svcadm mark maintenance $1 >/dev/null 2>&1 809 810 date=`date` 811 echo "[ $date ${0}: $1 has invalid ipf configuration. ]" 812 echo "[ $date ${0}: placing $1 in maintenance. ]" 813 814 # 815 # Move service's rule files to another location since 816 # they're most likely invalid. 817 # 818 ipfile=`fmri_to_file $1 $IPF_SUFFIX` 819 [ -f "$ipfile" ] && mv $ipfile "$ipfile.bak" 820 821 natfile=`fmri_to_file $1 $NAT_SUFFIX` 822 [ -f "$natfile" ] && mv $natfile "$natfile.bak" 823 824 return 0 825} 826 827svc_is_server() 828{ 829 svcprop -p $FW_CONFIG_PG $1 >/dev/null 2>&1 830} 831 832# 833# Create rules for enabled firewalling and client services. 834# - obtain the list of enabled services and process them 835# - save the list of rules file for later use 836# 837create_services_rules() 838{ 839 # 840 # Do nothing if global policy is 'custom' 841 # 842 global_policy=`get_global_def_policy` 843 [ "$global_policy" = "custom" ] && return 0 844 845 ipf_get_lock 846 847 # 848 # Get all enabled services 849 # 850 allsvcs=`svcprop -cf -p general/enabled -p general_ovr/enabled '*' \ 851 2>/dev/null | sed -n 's,^\(svc:.*\)/:properties/.* true$,\1,p' | sort -u` 852 853 # 854 # Process enabled services 855 # 856 for s in $allsvcs; do 857 service_is_enabled $s || continue 858 process_service $s || continue 859 860 ipfile=`fmri_to_file $s $IPF_SUFFIX` 861 if [ -n "$ipfile" -a -r "$ipfile" ]; then 862 check_ipf_syntax $ipfile 863 if [ $? -ne 0 ]; then 864 svc_mark_maintenance $s 865 continue 866 fi 867 868 svc_is_server $s 869 if [ $? -eq 0 ]; then 870 check_ipf_rules $ipfile 871 if [ $? -ne 0 ]; then 872 svc_mark_maintenance $s 873 continue 874 fi 875 fi 876 CONF_FILES="$CONF_FILES $ipfile" 877 fi 878 879 natfile=`fmri_to_file $s $NAT_SUFFIX` 880 if [ -n "$natfile" -a -r "$natfile" ]; then 881 check_nat_syntax $natfile 882 if [ $? -ne 0 ]; then 883 svc_mark_maintenance $s 884 continue 885 fi 886 887 NAT_FILES="$NAT_FILES $natfile" 888 fi 889 done 890 891 ipf_remove_lock 892 return 0 893} 894 895# 896# We update a services ipf ruleset in the following manners: 897# - service is disabled, tear down its rules. 898# - service is disable or refreshed(online), setup or update its rules. 899# 900service_update_rules() 901{ 902 # 903 # If ipfilter isn't online or global policy is 'custom', 904 # nothing should be done. 905 # 906 service_check_state $SMF_FMRI $SMF_ONLINE || return 0 907 [ "`get_global_def_policy`" = "custom" ] && return 0 908 909 svc=$1 910 911 ipfile=`fmri_to_file $svc $IPF_SUFFIX` 912 [ -z "$ipfile" ] && return 0 913 914 remove_rules $ipfile 915 916 natfile=`fmri_to_file $svc $NAT_SUFFIX` 917 [ -n "$natfile" ] && remove_nat_rules $natfile 918 919 # 920 # Don't go further if service is disabled or in maintenance. 921 # 922 service_is_enabled $svc || return 0 923 service_check_state $1 $SMF_MAINT && return 0 924 925 process_service $svc || return 1 926 if [ -f "$ipfile" ]; then 927 check_ipf_syntax $ipfile 928 if [ $? -ne 0 ]; then 929 svc_mark_maintenance $svc 930 return 1 931 fi 932 fi 933 934 if [ -f "$natfile" ]; then 935 check_nat_syntax $natfile 936 if [ $? -ne 0 ]; then 937 svc_mark_maintenance $svc 938 return 1 939 fi 940 fi 941 942 if [ -f "$ipfile" ]; then 943 svc_is_server $svc 944 if [ $? -eq 0 ]; then 945 update_check_ipf_rules $ipfile 946 if [ $? -ne 0 ]; then 947 svc_mark_maintenance $svc 948 return 1 949 fi 950 fi 951 952 prepend_new_rules $ipfile 953 954 # 955 # reload Global Override rules to 956 # maintain correct ordering. 957 # 958 remove_rules $IPFILOVRCONF 959 prepend_new_rules $IPFILOVRCONF 960 fi 961 962 [ -f "$natfile" ] && append_new_nat_rules $natfile 963 964 return 0 965} 966 967# 968# Call the service_update_rules with appropriate svc fmri. 969# 970# This is called from '/lib/svc/method/ipfilter fw_update' whenever 971# a service is disabled/enabled/refreshed. 972# 973service_update() 974{ 975 svc=$1 976 ret=0 977 978 ipf_get_lock 979 service_update_rules $svc || ret=1 980 981 ipf_remove_lock 982 return $ret 983} 984