thanks for the info.  i just said screwit and  i wrote a new module.

Apache2::xForwardedFornication

or

Apache2::xForwardedFor


i took Apache::ForwardedFor , tried to port it, disliked a lot of things, and decided this would be a good chance to just rewrite it entirely and add some new hooks

i think about 5 lines are the same :)

the big improvements ( i think ) are this:

        a- specify the x-forwarded-for header name
b- specify a required additional header + value ( say you want to embed x-forwarded-by='modperllist' on your gateway , to make sure its an internal item )
        c- returns forbidden on failed items
        d- ignores favicon
e- you can set the forwardedfor to be required or not ( in case you want to access the same server directly instead of through a proxy )

and, of course, all of that is configured in httpd.conf

i'm sure i made some mistakes though.

would people be so kind as to look it up and give me some feedback?

and should i contribute this to cpan or directly to mod_perl ?

package Apache2::xForwardedFor;
use strict;

use constant DEBUG=> 0;
use constant TEST=> 0; # note that there are 2 testing levels TEST>1 will set the required additional header

BEGIN {
	use vars qw ($VERSION);
    $VERSION= '0.01';
}

use Apache2::Const qw(:common);

sub handler {
	my 	( $r )= shift;
	DEBUG && print STDERR "\n============================ Apache2::xForwardedFor";
	return DECLINED if $r->uri eq '/favicon.ico';

	my 	$x_forwarded_for__header_name= $r->dir_config->get('xForwardedForAlternateHeaderName') || 'X-Forwarded-For' ;
	my 	$require_header= $r->dir_config->get('xForwardedForRequire') || undef;
	
	# for testing purposes, toss in a local header value
	TEST && $r->headers_in->set( $x_forwarded_for__header_name=> '10.0.1.140' );
	my 	$x_forwarded_for__header_value= $r->headers_in->{ $x_forwarded_for__header_name };

	# if we are requiring a header to be sent, and its not there, fail immediately
	if ( $require_header ) {
		DEBUG && print STDERR "\nRequire: true";
		if ( !$x_forwarded_for__header_value ) {
			DEBUG && print STDERR "\n \theader missing";
			return FORBIDDEN;
		}
	}

	# if we are requiring an additional header to be sent, and its not there or doesn't match, fail immediately
	if 	( my $require_header_other_name= $r->dir_config->get('xForwardedForRequireHeaderName') ) {
		TEST > 1 && $r->headers_in->set( $require_header_other_name=> $r->dir_config->get('xForwardedForRequireHeaderValue') );
		DEBUG && print STDERR "\nRequire Additional Header: true";
		my 	$require_header_other_value= $r->headers_in->{ $require_header_other_name };
		if 	( 
				!$require_header_other_value
				||
				( $require_header_other_value ne $r->dir_config->get('xForwardedForRequireHeaderValue') )
			) 
		{
			DEBUG && print STDERR "\n \tadditional header missing or invalid";
			return FORBIDDEN;		
		}
	};
	

    # Block based on Remove / Add AcceptForwarder values
    
	my 	$_accept= 0;
    my 	$remote_ip= $r->connection->remote_ip ;
	TEST && ( $remote_ip= '192.168.1.2');
	DEBUG && print STDERR "\n remote_ip__proxy: ". $remote_ip;
		my %ips_accept= map { $_=> 1 } $r->dir_config->get('xForwardedForAccept');
		if ( exists $ips_accept{$remote_ip} ) {
			$_accept= 1;
		}
		my %ips_deny= map { $_=> 1 } $r->dir_config->get('xForwardedForDeny');
		if ( exists $ips_deny{$remote_ip} ) {
			$_accept= -1;
		}

	if 	( $_accept < 0 ) {
		DEBUG && print STDERR "\n ip in blocked list";
		return FORBIDDEN;
	}
	elsif ( !$_accept && $require_header) {
		DEBUG && print STDERR "\n ip not passed, and header required";
		return FORBIDDEN;
	}
	elsif ( !$_accept && !$require_header) {
		DEBUG && print STDERR "\n ip not passed, but header not required";
	}
	

    DEBUG && print STDERR "\n x_forwarded_for__header_value: ".$x_forwarded_for__header_value;
    # Extract the desired IP address
    if ( my ($ip)= $x_forwarded_for__header_value=~ /^([\d\.]+)/ ) {
        DEBUG && print STDERR "\n original remote_ip: ". $remote_ip;
        $r->connection->remote_ip($ip);
        DEBUG && print STDERR "\n new remote_ip: ".$r->connection->remote_ip;
    } 
    else {
        # do nothing if no ip is in forwarded-for header
		# should we toss an error if this is because we couldn't parse an ip, but the header was there?
        DEBUG && print STDERR "\n no ip change";
    }

	# stacked handlers should still run off this
	return OK;
};

=head1 NAME

Apache2::xForwardedFor - Re-set remote_ip to incoming client's ip when running mod_perl behind a reverse proxy server. 
In other words, copy the first IP from B<X-Forwarded-For> header, which was set by your reverse proxy server, 
to the B<remote_ip> connection property.

=head1 SYNOPSIS

  in httpd.conf

    PerlModule Apache2::xForwardedFor
	PerlSetVar  xForwardedForRequire 1
	PerlSetVar  xForwardedForAccept 192.168.1.1
	PerlAddVar  xForwardedForAccept 192.168.1.2
	PerlSetVar  xForwardedForRequireHeaderName X-Internal-Password
	PerlSetVar  xForwardedForRequireHeaderValue shibby
	PerlPostReadRequestHandler Apache2::xForwardedFor


=head1 USAGE

At this time you simply need to load the module and add it to the PerlPostReadRequestHandler phase of your mod_perl-enabled httpd, and set a few variables.

Apache2::xForwardedFor is really flexible and does some very odd things 

=head1 VARIABLES

=head2 xForwardedForAlternateHeaderName
should you want to receive the X-Forwarded-For info from the proxy server on another ip, the name of it would be the value of this variable.

=head2 xForwardedForRequire
require the X-Forwarded-For header (or alternate name).  return FORBIDDEN otherwise

Why would you do this?  So that by default you can use either access apache through the proxy or directly.  This is FALSE by default, if someone wants to patch to be TRUE by default, send it my way. 

=head2 xForwardedForRequireHeaderName
should you require an additional header, this is the name of it.

Why would you do this?  Maybe you don't trust your gateway/proxy admin to be filtering headers correctly.  So you want to put a hash or an internal lan marking on internal requests.

=head2 xForwardedForRequireHeaderValue
should you require an additional header (xForwardedForRequireHeaderName), this is the value.  this will be ignored if xForwardedForRequireHeaderName is not set.  if xForwardedForRequireHeader and this is UNDEF, the header value does not match, or the header is not sent, this will return FORBIDDEN


head2= xForwardedForAccept 
single item or list of IP addresses to accept

head3= xForwardedForDeny
single item or list of IP addresses to deny


=head1 AUTHOR

 Jonathan Vanasco - [EMAIL PROTECTED]
 http://2xlp.com 
 
=head1 COPYRIGHT

Copyright (c) 2006 Jonathan Vanasco. All rights reserved.
This program is free software; you can redistribute
it and/or modify it under the same terms as Perl itself. 

=head1 ACKNOWLEDGEMENTS

Based on the module Apache::ForwardedFor by Jay J. Lawrence ( [EMAIL PROTECTED] )

This has a lot of tweaks/additions that you might find useless

=cut

1; 






// Jonathan Vanasco

| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| FindMeOn.com - The cure for Multiple Web Personality Disorder
| Web Identity Management and 3D Social Networking
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| RoadSound.com - Tools For Bands, Stuff For Fans
| Collaborative Online Management And Syndication Tools
| - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


Reply via email to