Mailing List Archive

New RA: IPredirect
Somewhat based on Dummy, and somewhat based on IPaddr2, here's an RA I put together to do port redirection via iptables.

I have an application (Shibboleth Identity Provider) that runs under Tomcat. Because Tomcat runs as a non-root user, the application server can only listen on ports over 1024. But this particular app must be on ports 80 and 443. The only way to do that is to use iptables and redirect traffic to the external ip address to an internal (10.0.0.1) address, changing the port used along the way. In order to manage this from Linux/HA, I needed a way to add and remove the necessary iptables rules as part of my resource group.

Setting up the resource group, I have this in it:

<primitive class="ocf" type="IPredirect" provider="heartbeat" is_managed="true" id="IPR_8_2">
<instance_attributes id="IPR_8_2_instance_attrs">
<attributes>
<nvpair name="interface" value="eth3"/>
<nvpair name="external_ip" value="131.156.21.44"/>
<nvpair name="external_port" value="443"/>
<nvpair name="internal_ip" value="10.0.0.1"/>
<nvpair name="internal_port" value="8443"/>
</attributes>
</instance_attributes>
<operations>
<op name="monitor" interval="10" timeout="10" start_delay="10"/>
<op name="start" timeout="10"/>
<op name="stop" timeout="10"/>
</operations>
</primitive>

to redirect external port 443 traffic to internal port 8443 where the application is actually listening. I'm using two IPaddr2 primitives to bind the external (131.156.21.44) and internal (10.0.0.1) to eth3. This group will have Filesystem and Tomcat primitives as well, to manage the shared storage and application server.

Tested here and seems to work. Comments or changes appreciated.


#!/bin/sh
#
# Description: Manages iptables port redirection firewall rules
# needed for a resource group under Heartbeat/LinuxHA
# control.
#
# Copyright 2012 Northern Illinois University, David Gersic
# All Rights Reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
#
#########################################################################################################################################
# OCF parameters:
# OCF_RESKEY_interface - Which interface to apply the rules to (ie: eth0, eth1, etc.)
# OCF_RESKEY_external_ip - External IP address to redirect from
# OCF_RESKEY_external_port - External IP port to redirect from
# OCF_RESKEY_internal_ip - Internal IP adddress to redirect to
# OCF_RESKEY_internal_port - Internal IP port to redirect to
#########################################################################################################################################

#######################################################################
# Initialization:
. ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs
#######################################################################

meta_data() {
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="IPredirect" version="0.9">
<version>1.0</version>

<longdesc lang="en">
This resource agent enables port redirection from an external IP address to an internal
IP address. This is useful for applications that must be reachable on a port below 1024,
but that must also run as non-root.
</longdesc>
<shortdesc lang="en">IPredirect resource agent</shortdesc>

<parameters>
<parameter name="interface" unique="1">
<longdesc lang="en">
Which interface to apply the rules to (ie: eth0, eth1, etc.)
</longdesc>
<shortdesc lang="en">Network interface</shortdesc>
</parameter>

<parameter name="external_ip" unique="1">
<longdesc lang="en">
External IP address to redirect from
</longdesc>
<shortdesc lang="en">External IP address</shortdesc>
</parameter>
<parameter name="external_port" unique="1">
<longdesc lang="en">
External IP port to redirect from
</longdesc>
<shortdesc lang="en">External IP port</shortdesc>
</parameter>
<parameter name="internal_ip" unique="1">
<longdesc lang="en">
Internal IP adddress to redirect to
</longdesc>
<shortdesc lang="en">Internal IP address</shortdesc>
</parameter>
<parameter name="internal_port" unique="1">
<longdesc lang="en">
Internal IP port to redirect to
</longdesc>
<shortdesc lang="en">Internal IP port</shortdesc>
</parameter>


</parameters>

<actions>
<action name="start" timeout="10" />
<action name="stop" timeout="10" />
<action name="monitor" timeout="10" interval="10" depth="0" start-delay="10" />
<action name="reload" timeout="20" />
<action name="meta-data" timeout="5" />
<action name="validate-all" timeout="10" />
</actions>
</resource-agent>
END
}


#######################################################################
# don't exit on TERM, to test that lrmd makes sure that we do exit
trap sigterm_handler TERM
sigterm_handler() {
ocf_log info "SIGTERM received."
return
}

ipredirect_usage() {
cat <<END
usage: $0 {start|stop|monitor|validate-all|meta-data}

Expects to have a fully populated OCF RA-compliant environment set.
END
}

ipredirect_start() {
ipredirect_monitor
if [ $? = $OCF_SUCCESS ]; then
return $OCF_SUCCESS
fi
/usr/sbin/iptables -t nat -A PREROUTING -i $OCF_RESKEY_interface -p tcp --destination $OCF_RESKEY_external_ip --dport $OCF_RESKEY_external_port -j DNAT --to $OCF_RESKEY_internal_ip:$OCF_RESKEY_internal_port
return $OCF_SUCCESS
}

ipredirect_stop() {
ipredirect_monitor
if [ $? = $OCF_SUCCESS ]; then
/usr/sbin/iptables -t nat -D PREROUTING -i $OCF_RESKEY_interface -p tcp --destination $OCF_RESKEY_external_ip --dport $OCF_RESKEY_external_port -j DNAT --to $OCF_RESKEY_internal_ip:$OCF_RESKEY_internal_port
fi
return $OCF_SUCCESS
}

ipredirect_monitor() {
# Is this redirect in place?
/usr/sbin/iptables -t nat -L PREROUTING -n | /bin/grep -q -i $OCF_RESKEY_internal_port

if [ "$?" = "0" ]; then
ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION: Running"
return $OCF_SUCCESS
fi
ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION: Not Running"
return $OCF_NOT_RUNNING
}

ipredirect_validate() {
return $OCF_SUCCESS
}

case $__OCF_ACTION in
meta-data) meta_data
exit $OCF_SUCCESS
;;
start) ipredirect_start;;
stop) ipredirect_stop;;
monitor) ipredirect_monitor;;
reload) ocf_log err "Reloading..."
ipredirect_stop
ipredirect_start
;;
validate-all) ipredirect_validate;;
usage|help) ipredirect_usage
exit $OCF_SUCCESS
;;
*) ipredirect_usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
rc=$?
ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc"
exit $rc


_______________________________________________________
Linux-HA-Dev: Linux-HA-Dev@lists.linux-ha.org
http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev
Home Page: http://linux-ha.org/
Re: New RA: IPredirect [ In reply to ]
Hi David,

I write a demand from me.

1) Please implement the check of the parameter in ipredirect_validate.(For example, it is necessary to check a form and the port of the address are numerical value)
2) And please carry out ipredirect_validate.(I think that I should call it other than meta-data processing.)
3) Please process an error code by practice of iptables.
4) And please give the log at the time of the error.
5) In IPredirect, script should check iptables command is usable. (check_binary $IPTABLES)

Best Regards,
Hideo Yamauchi.

--- On Wed, 2012/2/1, David Gersic <dgersic@niu.edu> wrote:

> Somewhat based on Dummy, and somewhat based on IPaddr2, here's an RA I put together to do port redirection via iptables.
>
> I have an application (Shibboleth Identity Provider) that runs under Tomcat. Because Tomcat runs as a non-root user, the application server can only listen on ports over 1024. But this particular app must be on ports 80 and 443. The only way to do that is to use iptables and redirect traffic to the external ip address to an internal (10.0.0.1) address, changing the port used along the way. In order to manage this from Linux/HA, I needed a way to add and remove the necessary iptables rules as part of my resource group.
>
> Setting up the resource group, I have this in it:
>
>          <primitive class="ocf" type="IPredirect" provider="heartbeat" is_managed="true" id="IPR_8_2">
>            <instance_attributes id="IPR_8_2_instance_attrs">
>              <attributes>
>                <nvpair name="interface" value="eth3"/>
>                <nvpair name="external_ip" value="131.156.21.44"/>
>                <nvpair name="external_port" value="443"/>
>                <nvpair name="internal_ip" value="10.0.0.1"/>
>                <nvpair name="internal_port" value="8443"/>
>              </attributes>
>            </instance_attributes>
>            <operations>
>              <op name="monitor" interval="10" timeout="10" start_delay="10"/>
>              <op name="start" timeout="10"/>
>              <op name="stop" timeout="10"/>
>            </operations>
>          </primitive>
>
> to redirect external port 443 traffic to internal port 8443 where the application is actually listening. I'm using two IPaddr2 primitives to bind the external (131.156.21.44) and internal (10.0.0.1) to eth3. This group will have Filesystem and Tomcat primitives as well, to manage the shared storage and application server.
>
> Tested here and seems to work. Comments or changes appreciated.
>
>
> #!/bin/sh
> #
> # Description:  Manages iptables port redirection firewall rules
> #               needed for a resource group under Heartbeat/LinuxHA
> #               control.
> #
> # Copyright 2012 Northern Illinois University, David Gersic
> #                    All Rights Reserved.
> #
> # This program is free software; you can redistribute it and/or
> # modify it under the terms of the GNU General Public License
> # as published by the Free Software Foundation; either version 2
> # of the License, or (at your option) any later version.
> #
> # This program is distributed in the hope that it will be useful,
> # but WITHOUT ANY WARRANTY; without even the implied warranty of
> # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> # GNU General Public License for more details.
> #
> # You should have received a copy of the GNU General Public License
> # along with this program; if not, write to the Free Software
> # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
> # 02110-1301, USA.
> #
> #########################################################################################################################################
> # OCF parameters:
> #   OCF_RESKEY_interface - Which interface to apply the rules to (ie: eth0, eth1, etc.)
> #   OCF_RESKEY_external_ip - External IP address to redirect from
> #   OCF_RESKEY_external_port - External IP port to redirect from
> #   OCF_RESKEY_internal_ip - Internal IP adddress to redirect to
> #   OCF_RESKEY_internal_port - Internal IP port to redirect to
> #########################################################################################################################################
>
> #######################################################################
> # Initialization:
> . ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs
> #######################################################################
>
> meta_data() {
>     cat <<END
> <?xml version="1.0"?>
> <!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
> <resource-agent name="IPredirect" version="0.9">
> <version>1.0</version>
>
> <longdesc lang="en">
> This resource agent enables port redirection from an external IP address to an internal
> IP address. This is useful for applications that must be reachable on a port below 1024,
> but that must also run as non-root.
> </longdesc>
> <shortdesc lang="en">IPredirect resource agent</shortdesc>
>
> <parameters>
> <parameter name="interface" unique="1">
> <longdesc lang="en">
> Which interface to apply the rules to (ie: eth0, eth1, etc.)
> </longdesc>
> <shortdesc lang="en">Network interface</shortdesc>
> </parameter>
>
> <parameter name="external_ip" unique="1">
> <longdesc lang="en">
> External IP address to redirect from
> </longdesc>
> <shortdesc lang="en">External IP address</shortdesc>
> </parameter>
> <parameter name="external_port" unique="1">
> <longdesc lang="en">
> External IP port to redirect from
> </longdesc>
> <shortdesc lang="en">External IP port</shortdesc>
> </parameter>
> <parameter name="internal_ip" unique="1">
> <longdesc lang="en">
> Internal IP adddress to redirect to
> </longdesc>
> <shortdesc lang="en">Internal IP address</shortdesc>
> </parameter>
> <parameter name="internal_port" unique="1">
> <longdesc lang="en">
> Internal IP port to redirect to
> </longdesc>
> <shortdesc lang="en">Internal IP port</shortdesc>
> </parameter>
>
>
> </parameters>
>
> <actions>
> <action name="start"        timeout="10" />
> <action name="stop"         timeout="10" />
> <action name="monitor"      timeout="10" interval="10" depth="0" start-delay="10" />
> <action name="reload"       timeout="20" />
> <action name="meta-data"    timeout="5" />
> <action name="validate-all"   timeout="10" />
> </actions>
> </resource-agent>
> END
> }
>
>
> #######################################################################
> # don't exit on TERM, to test that lrmd makes sure that we do exit
> trap sigterm_handler TERM
> sigterm_handler() {
>     ocf_log info "SIGTERM received."
>     return
> }
>
> ipredirect_usage() {
>     cat <<END
> usage: $0 {start|stop|monitor|validate-all|meta-data}
>
> Expects to have a fully populated OCF RA-compliant environment set.
> END
> }
>
> ipredirect_start() {
>     ipredirect_monitor
>     if [ $? =  $OCF_SUCCESS ]; then
>     return $OCF_SUCCESS
>     fi
>     /usr/sbin/iptables -t nat -A PREROUTING -i $OCF_RESKEY_interface -p tcp --destination $OCF_RESKEY_external_ip --dport $OCF_RESKEY_external_port -j DNAT --to $OCF_RESKEY_internal_ip:$OCF_RESKEY_internal_port
>     return $OCF_SUCCESS
> }
>
> ipredirect_stop() {
>     ipredirect_monitor
>     if [ $? =  $OCF_SUCCESS ]; then
>          /usr/sbin/iptables -t nat -D PREROUTING -i $OCF_RESKEY_interface -p tcp --destination $OCF_RESKEY_external_ip --dport $OCF_RESKEY_external_port -j DNAT --to $OCF_RESKEY_internal_ip:$OCF_RESKEY_internal_port
>     fi
>     return $OCF_SUCCESS
> }
>
> ipredirect_monitor() {
>     # Is this redirect in place?
>     /usr/sbin/iptables -t nat -L PREROUTING -n | /bin/grep -q -i $OCF_RESKEY_internal_port
>
>     if [ "$?" = "0" ]; then
>         ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION: Running"
>         return $OCF_SUCCESS
>     fi
>     ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION: Not Running"
>     return $OCF_NOT_RUNNING
> }
>
> ipredirect_validate() {
>     return $OCF_SUCCESS
> }
>
> case $__OCF_ACTION in
> meta-data)    meta_data
>         exit $OCF_SUCCESS
>         ;;
> start)        ipredirect_start;;
> stop)        ipredirect_stop;;
> monitor)    ipredirect_monitor;;
> reload)        ocf_log err "Reloading..."
>                 ipredirect_stop
>             ipredirect_start
>         ;;
> validate-all)    ipredirect_validate;;
> usage|help)    ipredirect_usage
>         exit $OCF_SUCCESS
>         ;;
> *)        ipredirect_usage
>         exit $OCF_ERR_UNIMPLEMENTED
>         ;;
> esac
> rc=$?
> ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc"
> exit $rc
>
>
> _______________________________________________________
> Linux-HA-Dev: Linux-HA-Dev@lists.linux-ha.org
> http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev
> Home Page: http://linux-ha.org/
>
_______________________________________________________
Linux-HA-Dev: Linux-HA-Dev@lists.linux-ha.org
http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev
Home Page: http://linux-ha.org/