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