IPChains::PortFW - Perl module to manipulate portfw masquerading table.


Fwctl documentation Contained in the Fwctl distribution.

Index


Code Index:

NAME

Top

IPChains::PortFW - Perl module to manipulate portfw masquerading table.

SYNOPSIS

Top

  my $masq = new IPChains::PortFW( option => value, ... );
  $masq->append();

DESCRIPTION

Top

IPChains::PortFW is an perl interface to the linux kernel port forwarding facility. You must have ipmasqadm and the portfw module installed for this module to work. A kernel compiled with CONFIG_IP_MASQUERADE_IPPORTFW would also helps.

It has a similar interface than the IPChains(3) module. You create an IPChains::PortFW object with new(), you can query or set attributes with the attribute() method and you add or deletes the port forwarding rules using append() or delete().

ATTRIBUTES

Here are the attributes valids for IPChains::PortFW.

LocalAddr

This is the local address from which packets will be redirected.

LocalPort

This is the port from which packets will be redirected.

RemAddr

This is the address to which the packets will be forwarded to.

RemPort

This is the port to which the packets will be forwarded to.

Pref

This is a preferences value used for load balancing in the case when there are many possible remote destinations.

METHODS

new( [options], ... )

Create a new IPChains::PortFW object and sets its attributes.

attribute( attribute [, value] )

Get or sets an attribute. Use undef to delete a value.

clopts()

Unset all attributes.

append()

Append a rule to the port forwarding masquerade table as specified by the attributes of the current objects.

delete()

Deletes entries in the port forwarding masquerade table. The entries matching the attributes will be deleted.

flush()

Removes all entries from the port forwarding masquerade table.

list()

Returns an array of IPChains::PortFW objects. One for each entries in the port forwarding table.

EXAMPLE

Top

Redirecting http protocol to internal web server.

my $portfw = new IPChains::PortFW( Proto => 'udp', LocalAddr => '199.168.1.10', LocalPort => 80, RemAddr => '10.0.0.1', RemPort => 80 );

$portfw->append;

AUTHOR

Top

Francis J. Lacoste <francis.lacoste@insu.com>

COPYRIGHT

Top

SEE ALSO

Top

IPChains(3)


Fwctl documentation Contained in the Fwctl distribution.

#
#    PortFW.pm - Perl module to interface with ipmasqadm portfw command.
#
#    This file is part of Fwctl.
#
#    Author: Francis J. Lacoste <francis.lacoste@iNsu.COM>
#
#    Copyright (C) 1999,2000 iNsu Innovations Inc.
#
#    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.
#
package IPChains::PortFW;

use strict;

use Carp;
use Symbol;

use vars qw( $VERSION $IPMASQADM );

BEGIN {

  ($VERSION) = '$Revision: 1.4 $' =~ /Revision: ([0-9.]+)/;

}

my %VALID_OPTIONS = map { $_ => 1 } qw( LocalAddr LocalPort RemAddr RemPort
					Proto Pref
					);

sub new {
    my $proto = shift;
    my $class = ref $proto || $proto;
    my %args = @_;
    my $self = { };

    # Look for ipmasqadm
    my ($path) = grep { -x "$_/ipmasqadm" } split /:/, "/sbin:/bin:/usr/sbin:/usr/bin:$ENV{PATH}";
    die ( "Couldn't find ipmasqadm in PATH ($ENV{PATH})\n" ) unless $path;
    $self->{ipmasqadm} = "$path/ipmasqadm";

    bless $self, $class;

    while ( my ($key,$value) = each %args ) {
	$self->attribute( $key, $value );
    }

    $self;
}

sub attribute {
    my ($self,$key,$value) = @_;

    if ( @_ == 3 ) {
	if ( $VALID_OPTIONS{$key} ) {
	    $self->{$key} = $value;
	} else {
	    carp "Unknown option : $key";
	}
    }

    return $self->{$key};
}

sub clopts {
    my ( $self ) = shift;

    foreach my $key ( keys %VALID_OPTIONS ) {
	delete $self->{$key};
    }
}

sub run_portfw {
    my ( $self, @args ) = @_;

    my ($r_fh,$w_fh) = (gensym,gensym);
    pipe $r_fh, $w_fh
      or die "can't pipe: $!\n";

    my $pid = fork;
    die "can't fork: $!\n" unless defined $pid;

    if ( $pid ) {
	# Don't need this one
	close $w_fh;

	# Collect STDOUT and STDERR
	my $output;
	while ( my $line = <$r_fh> ) {
	    $output .= $line;
	}

	# Collect exit status
	waitpid $pid,0;

	die "ipmasq exit with non zero status:\n$output\n" if $?;

	$output;
    } else {
	# Don't need this one
	close $r_fh;

	# Redirect STDOUT and STDERR to parent
	open ( STDOUT, ">&" . fileno $w_fh )
	  or die "can't redirect STDOUT to proper pipe: $!\n";
	open ( STDERR, ">&" . fileno $w_fh )
	  or die "can't redirect STDERR to proper output fd: $!\n";
	exec( $self->{ipmasqadm}, "portfw", @args )
	  or die "can't exec ipmasqadm: $!";
    }
}

sub append {
    my ( $self ) = shift;

    my @args = ( "-a" );
    croak "missing protocol"	    unless exists $self->{Proto};
    croak "invalid protocol"	    unless $self->{Proto} =~ /udp|tcp|6|17/i;
    croak "missing local address"   unless exists $self->{LocalAddr};
    croak "missing local port"	    unless exists $self->{LocalPort};
    croak "missing remote address"  unless exists $self->{RemAddr};
    croak "missing remote port"	    unless exists $self->{RemPort};
    if ( exists $self->{Pref} ) {
	croak "invalid preference"  unless $self->{Pref} =~ /\d+/ &&
					   $self->{Pref} >= 0;
    }

    push @args, "-P", lc $self->{Proto}, "-L", $self->{LocalAddr},
      $self->{LocalPort}, "-R", $self->{RemAddr}, $self->{RemPort};
    push @args, "-p", $self->{Pref} if exists $self->{Pref};

    $self->run_portfw( @args );
}

sub delete {
    my ( $self ) = shift;

    my @args = ( "-d" );
    croak "missing protocol"	    unless exists $self->{Proto};
    croak "invalid protocol"	    unless $self->{Proto} =~ /udp|tcp|6|17/i;
    croak "missing local address"   unless exists $self->{LocalAddr};
    croak "missing local port"	    unless exists $self->{LocalPort};

    push @args, "-P", lc $self->{Proto}, "-L", $self->{LocalAddr},
      $self->{LocalPort};
    push @args, "-R", $self->{RemAddr}, $self->{RemPort}
      if exists $self->{RemAddr};

    $self->run_portfw( @args );

}

sub flush {
    $_[0]->run_portfw( "-f" );
}

sub list {
    my ($self, $use_dns) = @_;

    my @args = ( "-l" );
    push @args, "-n" unless defined $use_dns && $use_dns;

    my $output = $self->run_portfw( @args );
    return () unless defined $output;

    # Parse output
    my @lines = split /\n/, $output;

    # Skip header line
    shift @lines;

    my @rules = ();
    foreach my $line ( @lines ) {
	my ( $prot, $laddr, $raddr, $lport, $rport, $ignored, $pref ) =
	  split / +/, $line;
	push @rules, $self->new( Proto	    => lc $prot,
				  LocalAddr => $laddr,
				  RemAddr   => $raddr,
				  LocalPort => $lport,
				  RemPort   => $rport,
				);
    }

    @rules;
}

1;

__END__