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