How do you allow access to rpc services through ipf?
Use SMF with custom methods and dependencies to create Dynamic Ipfilter Rules for RPC Services.
Searching found a number of people with
the same questions and no good answers Darren
Reed: SunRPC proxy,OpenSolaris
Forums in which Darren states "There is a proxy, of sorts, in
the IPFilter source code at present, but it is of questionable
integrity". Unfortunately questionable
integrity is right out in this environment.
A simple solution was implemented, a
startup script was written by Borgan Chu to parse rpcinfo
and create ipfilter rules to allow traffic from the
-p
desired source addresses to the dynamic rpc service port. The script
uses a configuration file with
the following syntax, similar to the syntax of hosts.allow/hosts.deny.
rpcservice: addrmask addrmask
rpcservice: addrmask addrmask
It created rules using the following
logic:
Split each line into service and source
For each source add a rule to ipf to allow the desired traffic
e.g. pass in quick proto rpcproto from source
to dest port = rpcport keep
state | ipf -f -
pass in quick proto udp from pool/1001 to any port = 32782 keep state
pass in quick proto tcp from pool/1001 to
any port = 32808 keep state
pass in quick proto udp from pool/1002 to any port =
32782 keep state
pass in quick proto tcp from pool/1002 to
any port = 32808 keep state
The previous code acknowledged one Major
problem. The script only runs at boot, any restart of rpcbind an rpc
service could result in different port assignment invalidating the
previous rules. From an operational standpoint I pictured repeatedly
troubleshooting the same issue: A service mysteriously stops working,
Tier 2 Engineers look into the problem and find that the
service is running and can be reached locally and possibly from other
hosts but not from the problem host.
One other issue with the script was
apparent to me, future manual script execution would continue to add
entries to the rules with no way to clean up without flushing the
exiting rule set. This required a change to both the script and the
default ipf.conf rules. With the following changes
the script supports both a stop and start method, as well as creating
slightly different rules.
New base ipf rules:
# Allow Dynamic RPC entries
pass in on bge0 all head 100
# useless rule to allow for deletion of all inbound dynamic pass rules
# i.e. you can't delete the first rule in a group
pass in on lo0 all group 100
start()
Split each line into service and source
For each source add a rule to ipf to allow the desired traffic
e.g. pass in quick proto rpcproto from source
to dest port = rpcport keep
state group 100 | ipf -f -
stop()
/usr/sbin/ipfstat -i | /usr/bin/grep "group 100" | /usr/sbin/ipf -r -f -
pass in quick proto udp from pool/1002 to any port = 626 keep state
group 100
pass in quick proto tcp from pool/1002 to any port = 35913 keep state
group 100
pass in quick proto udp from pool/1001 to any port = 626 keep state
group 100
pass in quick proto tcp from pool/1001 to any port = 35913 keep state
group 100
The major problem of maintaining dynamic
rules can be resolved using SMF,
creating a service for our ipf rules script with require_all
dependencies
on ipfilter causes the new service to run only when ipfilter is enabled.
dependency
require_all/refresh svc:/network/ipfilter:default (online)
dependency
require_any/refresh
svc:/network/rpc/bind:default (online)
The execution can be further tuned by creating
require_any
dependencies
on various rpc services.
svcs "*rpc*"
After the manifest is loaded the properties of the service can be bulk
updated to cover most standard rpc services with the following command, or manually updated to
require_any
other specific rpc services.
svccfg -s ipfilter:rpcbind setprop
"rpc_services/entities = fmri:
(`svcs -H \*rpc\* \*nis\* \*nfs\* | awk '$NF !~ /ipfilter|bind:default/{ print $3 }'`)"
Replaces the manifest defined rpc_services dependencies with the following:
svc:/network/rpc/keyserv:default
svc:/network/rpc/nisplus:default
svc:/network/rpc/bootparams:default
svc:/network/rpc/gss:default
svc:/network/rpc/mdcomm:default
svc:/network/rpc/metamed:default
svc:/network/rpc/metamh:default
svc:/network/rpc/rex:default
svc:/network/rpc/rusers:default
svc:/network/rpc/spray:default
svc:/network/rpc/wall:default
svc:/network/rpc-100235_1/rpc_ticotsord:default
svc:/network/nfs/server:default
svc:/network/rpc/meta:default
svc:/network/rpc/smserver:default
svc:/network/rpc/rstat:default
svc:/network/nfs/rquota:default
svc:/network/nfs/client:default
svc:/network/nis/passwd:default
svc:/network/nis/update:default
svc:/network/nis/client:default
svc:/network/nis/server:default
svc:/network/nfs/cbd:default
svc:/network/nfs/mapid:default
svc:/network/nis/xfr:default
svc:/network/nfs/status:default
svc:/network/nfs/nlockmgr:default
Using a script similar to the one described above you could
specifically limit the dependent services to the ones specified in your
configuration file.
The Service Manifest:
<?xml version='1.0'?>
<!DOCTYPE service_bundle SYSTEM
"/usr/share/lib/xml/dtd/service_bundle.dtd.1">
<!--
Shawn Ferry yakshaving <@> sun.com
Service manifest for maintaining dynamic ipfilter rules
-->
<service_bundle type='manifest' name='ipfilter:dynamic'>
<service
name='application/ipfilter/dynamic'
type='service'
version='1'>
<!-- maybe more than one if this gets complex -->
<single_instance />
<!-- Require ipfilter, without an online ipfilter, don't try to add rules -->
<dependency
name='ipfilter'
grouping='require_all'
restart_on='refresh'
type='service'>
<service_fmri value='svc:/network/ipfilter:default' />
</dependency>
<!--
An
instance for rpcbind, additional instances
could be created for
additional services requiring
dynamic rules (this would be the time to disable single_instance)
-->
<instance
name="rpcbind" enabled="true">
<!-- If rpcbind is offline, no rules to add, don't do anything -->
<dependency
name='rpc_bind'
grouping='require_all'
restart_on='refresh'
type='service'>
<service_fmri value='svc:/network/rpc/bind:default' />
</dependency>
<!-- If rule creation config file is missing, don't do anything -->
<dependency
name='ipfilter_rpcbind_config'
grouping='require_all'
restart_on='refresh'
type='path'>
<service_fmri value='file://localhost/etc/ipf/ipfilter-dynamic_rpcbind.cfg' />
</dependency>
<!--
All of the dependencies in the rpc_services group
are "require_any".
With a "refresh" directive, on stop/start/refresh of those
services theipfilter/dynamic:rpcbind service will be restarted
keeping the ipf rules up to date
-->
<dependency
name='rpc_services'
grouping='require_any'
restart_on='refresh'
type='service'>
<service_fmri value='svc:/network/nfs/server:default' />
<service_fmri value='svc:/network/nfs/client:default' />
</dependency>
<!-- On "start" run the ipf rule script with the argument start -->
<exec_method
type='method'
name='start'
exec='/lib/svc/method/ipfilter-dynamic_rpcbind start'
timeout_seconds='30' />
<!-- On "stop" run the ipf rule script with the argument stop -->
<exec_method
type='method'
name='stop'
exec='/lib/svc/method/ipfilter-dynamic_rpcbind stop'
timeout_seconds='60' />
<!--
This is a transient service we are looking for a clean
exit code. i.e. a svcs -p shows no associated processes
-->
<property_group name='startd' type='framework'>
<propval name='duration' type='astring' value='transient'
/>
</property_group>
<!--
Useful Info:
svcs -xv dynamic:rpcbind
svc:/application/ipfilter/dynamic:rpcbind (Dynamic rpc service rules for ipfilter)
State: online since Fri Mar 17 19:41:14 2006
See: man -M /usr/share/man -s 1M ipf
See: man -M /usr/share/man -s 1M ipfstat
See: man -M /usr/share/man -s 4 ipf.conf
See: /var/svc/log/application-sungrid-ipfilter:rpcbind.log
Impact: None.
-->
<template>
<common_name>
<loctext xml:lang='C'>
Dynamic rpc service rules for ipfilter
</loctext>
</common_name>
<description>
<loctext xml:lang='C'>
Add Dynamic rpc services rules to ipfilter refresh rules on
restart/refresh of various services to maintain rules.
Manually clearing and reloading ipfilter rules with ipf will not
trigger this service to restart/refresh.
e.g. ipf -Fa -f /etc/ipf/ipf.conf
</loctext>
</description>
<documentation>
<manpage title='ipf' section='1M' manpath='/usr/share/man'
/>
<manpage title='ipfstat' section='1M' manpath='/usr/share/man'
/>
<manpage title='ipf.conf' section='4' manpath='/usr/share/man'
/>
</documentation>
</template>
</instance>
<stability
value='Unstable' />
</service>
</service_bundle>
References:
Liane Praza's: smf(5) fault/retry models
Service Developer Introduction
smf(5)
Notes:
Any IPF rules that are actively in use when the service restarts or is disabled are not removed. That particular aspect is not an issue for us as it is assumed that if the rule is in use the service is still listening.
topic:[Solaris]
topic:[SMF]
topic:[ipfilter]