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