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 or 390 # if the input file is the "/etc/ipf/ipf.conf" file. 391 # 392 [ ! -f "$1" ] && return 0 393 394 rm $IPFILCONF >/dev/null 2>&1 395 ln -s $1 $IPFILCONF >/dev/null 2>&1 396} 397 398# 399# New file replaces original file if they have different content 400# 401replace_file() 402{ 403 orig=$1 404 new=$2 405 406 # 407 # IPFILCONF may be a symlink, remove it if that's the case 408 # 409 if [ -L "$orig" ]; then 410 rm $orig 411 touch $orig 412 fi 413 414 mv $new $orig && return 0 || return 1 415} 416 417# 418# Given a service, gets the following details for ipf rule: 419# - policy 420# - protocol 421# - port(IANA port obtained by running servinfo) 422# 423process_server_svc() 424{ 425 service=$1 426 ip="any" 427 policy=`get_policy ${service}` 428 429 # 430 # Empties service's rules file so callers won't use existing rule if 431 # we fail here. 432 # 433 file=`fmri_to_file $service $IPF_SUFFIX` 434 [ -z "$file" ] && return 1 435 echo "# $service" >${file} 436 437 # 438 # Nothing to do if policy is "use_global" 439 # 440 [ "$policy" = "use_global" ] && return 0 441 442 restarter=`svcprop -p general/restarter $service 2>/dev/null` 443 if [ "$restarter" = "$INETDFMRI" ]; then 444 iana_name=`svcprop -p inetd/name $service 2>/dev/null` 445 isrpc=`svcprop -p inetd/isrpc $service 2>/dev/null` 446 else 447 iana_name=`svcprop -p $FW_CONTEXT_PG/name $service 2>/dev/null` 448 isrpc=`svcprop -p $FW_CONTEXT_PG/isrpc $service 2>/dev/null` 449 fi 450 451 # 452 # Bail if iana_name isn't defined. Services with static rules 453 # like nis/client don't need to generate rules using 454 # iana name and protocol information. 455 # 456 [ -z "$iana_name" ] && return 1 457 458 # 459 # RPC services 460 # 461 if [ "$isrpc" = "true" ]; then 462 tports=`$SERVINFO -R -p -t -s $iana_name 2>/dev/null` 463 if [ -n "$tports" ]; then 464 for tport in $tports; do 465 generate_rules $service $policy "tcp" \ 466 $ip $tport $file 467 done 468 fi 469 470 uports=`$SERVINFO -R -p -u -s $iana_name 2>/dev/null` 471 if [ -n "$uports" ]; then 472 for uport in $uports; do 473 generate_rules $service $policy "udp" \ 474 $ip $uport $file 475 done 476 fi 477 478 return 0 479 fi 480 481 # 482 # Get the IANA port and supported protocols(tcp and udp) 483 # No support for IPv6 at this point. 484 # 485 tport=`$SERVINFO -p -t -s $iana_name 2>&1` 486 if [ $? -eq 0 -a -n "$tport" ]; then 487 generate_rules $service $policy "tcp" $ip $tport $file 488 fi 489 490 uport=`$SERVINFO -p -u -s $iana_name 2>&1` 491 if [ $? -eq 0 -a -n "$uport" ]; then 492 generate_rules $service $policy "udp" $ip $uport $file 493 fi 494 495 return 0 496} 497 498# 499# Given a service's name, policy, protocol and port, generate ipf rules 500# - list of host/network/interface to apply policy 501# 502# A 'use_global' policy inherits the system-wided Global Default policy 503# from network/ipfilter. For {deny | allow} policies, the rules are 504# ordered as: 505# 506# - make exceptions to policy for those in "exceptions" list 507# - apply policy to those specified in "apply_to" list 508# - policy rule 509# 510generate_rules() 511{ 512 service=$1 513 mypolicy=$2 514 proto=$3 515 ip=$4 516 port=$5 517 out=$6 518 519 # 520 # Default mode is to inherit from global's policy 521 # 522 [ "$mypolicy" = "use_global" ] && return 0 523 524 tcp_opts="" 525 [ "$proto" = "tcp" ] && tcp_opts="flags S keep state keep frags" 526 527 # 528 # Allow all if policy is 'none' 529 # 530 if [ "$mypolicy" = "none" ]; then 531 echo "pass in log quick proto ${proto} from any to ${ip}" \ 532 "port = ${port} ${tcp_opts}" >>${out} 533 return 0 534 fi 535 536 # 537 # For now, let's concern only with incoming traffic. 538 # 539 [ "$mypolicy" = "deny" ] && { ecmd="pass"; acmd="block"; } 540 [ "$mypolicy" = "allow" ] && { ecmd="block"; acmd="pass"; } 541 542 for name in `get_exceptions $service`; do 543 [ -z "$name" -o "$name" = '""' ] && continue 544 545 ifc=`get_interface $name` 546 if [ $? -eq 0 -a -n "$ifc" ]; then 547 echo "${ecmd} in log quick on ${ifc} from any to" \ 548 "${ip} port = ${port}" >>${out} 549 continue 550 fi 551 552 addr=`get_IP ${name}` 553 if [ $? -eq 0 -a -n "$addr" ]; then 554 echo "${ecmd} in log quick proto ${proto} from ${addr}" \ 555 "to ${ip} port = ${port} ${tcp_opts}" >>${out} 556 fi 557 done 558 559 for name in `get_apply2_list $service`; do 560 [ -z "$name" -o "$name" = '""' ] && continue 561 562 ifc=`get_interface $name` 563 if [ $? -eq 0 -a -n "$ifc" ]; then 564 echo "${acmd} in log quick on ${ifc} from any to" \ 565 "${ip} port = ${port}" >>${out} 566 continue 567 fi 568 569 addr=`get_IP ${name}` 570 if [ $? -eq 0 -a -n "$addr" ]; then 571 echo "${acmd} in log quick proto ${proto} from ${addr}" \ 572 "to ${ip} port = ${port} ${tcp_opts}" >>${out} 573 fi 574 done 575 576 echo "${ecmd} in log quick proto ${proto} from any to ${ip}" \ 577 "port = ${port} ${tcp_opts}" >>${out} 578 579 return 0 580} 581 582# 583# Service has either IANA ports and proto or its own firewall method to 584# generate the rules. 585# 586# - if service has a custom method, use it to populate its rules 587# - if service has a firewall_config pg, use process_server_svc 588# 589# Argument - fmri 590# 591process_service() 592{ 593 # 594 # Don't process network/ipfilter 595 # 596 [ "$1" = "$IPF_FMRI" ] && return 0 597 598 service_check_state $1 $SMF_MAINT && return 1 599 600 method=`svcprop -p $FW_CONTEXT_PG/$METHOD_PROP $1 2>/dev/null | \ 601 sed 's/\\\//g'` 602 if [ -n "$method" -a "$method" != '""' ]; then 603 ( exec $method $1 >/dev/null ) 604 else 605 svcprop -p $FW_CONFIG_PG $1 >/dev/null 2>&1 || return 1 606 process_server_svc $1 || return 1 607 fi 608 return 0 609} 610 611# 612# Generate rules for protocol/port defined in firewall_config_default/open_ports 613# property. These are non-service programs whose network resource info are 614# defined as "{tcp | upd}:{PORT | PORT-PORT}". Essentially, these programs need 615# some specific local ports to be opened. For example, BitTorrent clients need to 616# have 6881-6889 opened. 617# 618process_nonsvc_progs() 619{ 620 out=$1 621 echo "# Non-service programs rules" >>${out} 622 progs=`svcprop -p ${FW_CONFIG_DEF_PG}/${OPEN_PORTS_PROP} \ 623 $SMF_FMRI 2>/dev/null` 624 625 for prog in $progs; do 626 [ -z "$prog" -o "$prog" = '""' ] && continue 627 628 port=`tuple_get_port $prog` 629 [ $? -eq 1 -o -z "$port" ] && continue 630 631 proto=`tuple_get_proto $prog` 632 [ $? -eq 1 ] && continue 633 634 set -- $port 635 if [ $# -gt 1 ]; then 636 if [ -z "$proto" ]; then 637 echo "pass in log quick from any to any" \ 638 "port ${1} >< ${2}" >>${out} 639 else 640 echo "pass in log quick proto ${proto} from any" \ 641 "to any port ${1} >< ${2}" >>${out} 642 fi 643 else 644 if [ -z "$proto" ]; then 645 echo "pass in log quick from any to any" \ 646 "port = ${1}" >>${out} 647 else 648 echo "pass in log quick proto ${proto} from any" \ 649 "to any port = ${1}" >>${out} 650 fi 651 fi 652 done 653 654 return 0 655} 656 657# 658# Generate a new /etc/ipf/ipf.conf. If firewall policy is 'none', 659# ipf.conf is empty . 660# 661create_global_rules() 662{ 663 policy=`get_global_def_policy` 664 665 if [ "$policy" = "custom" ]; then 666 file=`svcprop -p ${FW_CONFIG_DEF_PG}/${CUSTOM_FILE_PROP} $SMF_FMRI` 667 668 [ -n "$file" ] && custom_set_symlink $file 669 return 0 670 fi 671 672 TEMP=`mktemp /var/run/ipf.conf.pid$$.XXXXXX` 673 process_nonsvc_progs $TEMP 674 675 echo "# Global Default rules" >>${TEMP} 676 if [ "$policy" != "none" ]; then 677 echo "pass out log quick all keep state" >>${TEMP} 678 fi 679 680 case "$policy" in 681 'none') 682 # No rules 683 replace_file ${IPFILCONF} ${TEMP} 684 return $? 685 ;; 686 687 'deny') 688 ecmd="pass" 689 acmd="block" 690 ;; 691 692 'allow') 693 ecmd="block" 694 acmd="pass" 695 ;; 696 *) 697 return 1; 698 ;; 699 esac 700 701 for name in `get_exceptions $SMF_FMRI`; do 702 [ -z "$name" -o "$name" = '""' ] && continue 703 704 ifc=`get_interface $name` 705 if [ $? -eq 0 -a -n "$ifc" ]; then 706 echo "${ecmd} in log quick on ${ifc} all" >>${TEMP} 707 continue 708 fi 709 710 addr=`get_IP ${name}` 711 if [ $? -eq 0 -a -n "$addr" ]; then 712 echo "${ecmd} in log quick from ${addr} to any" >>${TEMP} 713 fi 714 715 done 716 717 for name in `get_apply2_list $SMF_FMRI`; do 718 [ -z "$name" -o "$name" = '""' ] && continue 719 720 ifc=`get_interface $name` 721 if [ $? -eq 0 -a -n "$ifc" ]; then 722 echo "${acmd} in log quick on ${ifc} all" >>${TEMP} 723 continue 724 fi 725 726 addr=`get_IP ${name}` 727 if [ $? -eq 0 -a -n "$addr" ]; then 728 echo "${acmd} in log quick from ${addr} to any" >>${TEMP} 729 fi 730 done 731 732 if [ "$policy" = "allow" ]; then 733 # 734 # Allow DHCP traffic if running as a DHCP client 735 # 736 /sbin/netstrategy | grep dhcp >/dev/null 2>&1 737 if [ $? -eq 0 ]; then 738 echo "pass out log quick from any port = 68" \ 739 "keep state" >>${TEMP} 740 echo "pass out log quick from any port = 546" \ 741 "keep state" >>${TEMP} 742 echo "pass in log quick from any to any port = 68" >>${TEMP} 743 echo "pass in log quick from any to any port = 546" >>${TEMP} 744 fi 745 echo "block in log all" >>${TEMP} 746 fi 747 748 replace_file ${IPFILCONF} ${TEMP} 749 return $? 750} 751 752# 753# Generate a new /etc/ipf/ipf_ovr.conf, the override system-wide policy. It's 754# a simplified policy that doesn't support 'exceptions' entities. 755# 756# If firewall policy is "none", no rules are generated. 757# 758# Note that "pass" rules don't have "quick" as we don't want 759# them to override services' block rules. 760# 761create_global_ovr_rules() 762{ 763 # 764 # Simply empty override file if global policy is 'custom' 765 # 766 if [ "`get_global_def_policy`" = "custom" ]; then 767 echo "# 'custom' global policy" >$IPFILOVRCONF 768 return 0 769 fi 770 771 # 772 # Get and process override policy 773 # 774 ovr_policy=`svcprop -p ${FW_CONFIG_OVR_PG}/${POLICY_PROP} $IPF_FMRI` 775 TEMP=`mktemp /var/run/ipf_ovr.conf.pid$$.XXXXXX` 776 777 [ "$ovr_policy" = "deny" ] && acmd="block in log quick" 778 [ "$ovr_policy" = "allow" ] && acmd="pass in log" 779 780 apply2_list=`svcprop -p $FW_CONFIG_OVR_PG/$APPLY2_PROP $IPF_FMRI` 781 for name in $apply2_list; do 782 [ -z "$name" -o "$name" = '""' ] && continue 783 784 ifc=`get_interface $name` 785 if [ $? -eq 0 -a -n "$ifc" ]; then 786 echo "${acmd} on ${ifc} all" >>${TEMP} 787 continue 788 fi 789 790 addr=`get_IP ${name}` 791 if [ $? -eq 0 -a -n "$addr" ]; then 792 echo "${acmd} from ${addr} to any" >>${TEMP} 793 fi 794 done 795 796 replace_file ${IPFILOVRCONF} ${TEMP} 797 return $? 798} 799 800# 801# Service is put into maintenance state due to its invalid firewall 802# definition and/or policy. 803# 804svc_mark_maintenance() 805{ 806 svcadm mark maintenance $1 >/dev/null 2>&1 807 808 date=`date` 809 echo "[ $date ${0}: $1 has invalid ipf configuration. ]" 810 echo "[ $date ${0}: placing $1 in maintenance. ]" 811 812 # 813 # Move service's rule files to another location since 814 # they're most likely invalid. 815 # 816 ipfile=`fmri_to_file $1 $IPF_SUFFIX` 817 [ -f "$ipfile" ] && mv $ipfile "$ipfile.bak" 818 819 natfile=`fmri_to_file $1 $NAT_SUFFIX` 820 [ -f "$natfile" ] && mv $natfile "$natfile.bak" 821 822 return 0 823} 824 825svc_is_server() 826{ 827 svcprop -p $FW_CONFIG_PG $1 >/dev/null 2>&1 828} 829 830# 831# Create rules for enabled firewalling and client services. 832# - obtain the list of enabled services and process them 833# - save the list of rules file for later use 834# 835create_services_rules() 836{ 837 # 838 # Do nothing if global policy is 'custom' 839 # 840 global_policy=`get_global_def_policy` 841 [ "$global_policy" = "custom" ] && return 0 842 843 ipf_get_lock 844 845 # 846 # Get all enabled services 847 # 848 allsvcs=`svcprop -cf -p general/enabled -p general_ovr/enabled '*' \ 849 2>/dev/null | sed -n 's,^\(svc:.*\)/:properties/.* true$,\1,p' | sort -u` 850 851 # 852 # Process enabled services 853 # 854 for s in $allsvcs; do 855 service_is_enabled $s || continue 856 process_service $s || continue 857 858 ipfile=`fmri_to_file $s $IPF_SUFFIX` 859 if [ -n "$ipfile" -a -r "$ipfile" ]; then 860 check_ipf_syntax $ipfile 861 if [ $? -ne 0 ]; then 862 svc_mark_maintenance $s 863 continue 864 fi 865 866 svc_is_server $s 867 if [ $? -eq 0 ]; then 868 check_ipf_rules $ipfile 869 if [ $? -ne 0 ]; then 870 svc_mark_maintenance $s 871 continue 872 fi 873 fi 874 CONF_FILES="$CONF_FILES $ipfile" 875 fi 876 877 natfile=`fmri_to_file $s $NAT_SUFFIX` 878 if [ -n "$natfile" -a -r "$natfile" ]; then 879 check_nat_syntax $natfile 880 if [ $? -ne 0 ]; then 881 svc_mark_maintenance $s 882 continue 883 fi 884 885 NAT_FILES="$NAT_FILES $natfile" 886 fi 887 done 888 889 ipf_remove_lock 890 return 0 891} 892 893# 894# We update a services ipf ruleset in the following manners: 895# - service is disabled, tear down its rules. 896# - service is disable or refreshed(online), setup or update its rules. 897# 898service_update_rules() 899{ 900 # 901 # If ipfilter isn't online or global policy is 'custom', 902 # nothing should be done. 903 # 904 service_check_state $SMF_FMRI $SMF_ONLINE || return 0 905 [ "`get_global_def_policy`" = "custom" ] && return 0 906 907 svc=$1 908 909 ipfile=`fmri_to_file $svc $IPF_SUFFIX` 910 [ -z "$ipfile" ] && return 0 911 912 remove_rules $ipfile 913 914 natfile=`fmri_to_file $svc $NAT_SUFFIX` 915 [ -n "$natfile" ] && remove_nat_rules $natfile 916 917 # 918 # Don't go further if service is disabled or in maintenance. 919 # 920 service_is_enabled $svc || return 0 921 service_check_state $1 $SMF_MAINT && return 0 922 923 process_service $svc || return 1 924 if [ -f "$ipfile" ]; then 925 check_ipf_syntax $ipfile 926 if [ $? -ne 0 ]; then 927 svc_mark_maintenance $svc 928 return 1 929 fi 930 fi 931 932 if [ -f "$natfile" ]; then 933 check_nat_syntax $natfile 934 if [ $? -ne 0 ]; then 935 svc_mark_maintenance $svc 936 return 1 937 fi 938 fi 939 940 if [ -f "$ipfile" ]; then 941 svc_is_server $svc 942 if [ $? -eq 0 ]; then 943 update_check_ipf_rules $ipfile 944 if [ $? -ne 0 ]; then 945 svc_mark_maintenance $svc 946 return 1 947 fi 948 fi 949 950 prepend_new_rules $ipfile 951 952 # 953 # reload Global Override rules to 954 # maintain correct ordering. 955 # 956 remove_rules $IPFILOVRCONF 957 prepend_new_rules $IPFILOVRCONF 958 fi 959 960 [ -f "$natfile" ] && append_new_nat_rules $natfile 961 962 return 0 963} 964 965# 966# Call the service_update_rules with appropriate svc fmri. 967# 968# This is called from '/lib/svc/method/ipfilter fw_update' whenever 969# a service is disabled/enabled/refreshed. 970# 971service_update() 972{ 973 svc=$1 974 ret=0 975 976 ipf_get_lock 977 service_update_rules $svc || ret=1 978 979 ipf_remove_lock 980 return $ret 981} 982