You are viewing a plain text version of this content. The canonical link for it is here.
Posted to modperl@perl.apache.org by André Warnier <aw...@ice-sa.com> on 2012/11/23 18:39:58 UTC

custom proxy setup with mod_perl

Hi.

I am trying to solve an unconventional (I think) issue with mod_perl (or even without it).
Environment : Apache 2.2/mod_perl 2 under Linux.

The issue :
A number of workstations are in a LAN, using a local DNS server under my control.
In the same LAN (192.168.45.0), I have a Linux host running Apache 2.2/mod_perl 2, also 
under my full control (IP 192.168.45.100).

Currently, the LAN workstations access external websites such as (for the sake of example) :
1) http://www.site-1.com  (IP 1.2.3.4)
2) http://www.site-2.biz  (IP 2.3.4.5)
3) http://www.site-3.org  (IP 3.4.5.6)
4) http://www.site-4.co.uk (IP 4.5.6.7)
(all these IP's being supposedly real public Internet IP addresses)

In the future, I would like that when the workstations try to access websites (2) and (4) 
above, they access them through my Apache/mod_perl host.
The reason for this is that
a) I need to authenticate the users
b) I need to allow some users to access these external servers, and deny other users (and 
for those, I need to return a nice page explaining why)

I already do the authentication/authorization using custom PerlAuth* handlers.
I also know how to write PerlFixupHandler and PerlTransHandler modules, and how to "push" 
other Perl "HTTP cycle" handlers when needed.

My basic scheme is as follows :
- the DNS server configuration is modified so that when resolving the hostnames (2) and 
(4) above, it returns the IP address of the internal Apache host (192.168.45.100).
When a workstation thus wants to connect to webserver (2) above, in reality it connects to 
the internal Apache host, where I want to perform my mod_perl magic.
- on the Apache host, there is a virtual host configured with
   ServerAlias www.site-2.biz
   ServerAlias www.site-4.co.uk
so it responds to these requests.

The Apache host has access to the "real" IP addresses of the above external webservers.
(For example, in its own "hosts" file; or it has itself an "uncorrupted" DNS server which 
delivers the original IP addresses).

In the Apache host, I have the following configuration section :
<Location />
   AuthType MyOwn
   AuthName CheckProxy
   PerlAuthenHandler my:AuthHandler->get_id
   PerlAuthzHandler my:AuthHandler->allow_or_not
   Require valid-user
   PerlFixupHandler ????
   PerlTransHandler ????
   ProxyPass http://(corresponding hostname)/(path and query as received)
</Location>

Now my questions are : if I do something at the level of the PerlFixupHandler or 
PerlTransHandler,
1) is that "early enough" to be before the Apache ProxyPass step ?
2) can I set the "(corresponding hostname)" above in such a Perl handler, or otherwise 
manipulate the URI before it gets proxy-ed ?
3) do I need this ProxyPass directive in my configuration, or can I just set the Apache 
response handler to be mod_proxy_http, in one of the Perl handlers ? and if yes, how ?

I'd be thankful for any answer or tip, even about a solution which does not involve 
mod_perl at all. (But in reality, I do need to do a bit more in my handlers than I allude 
to above).











Re: custom proxy setup with mod_perl

Posted by Fred Moyer <fr...@redhotpenguin.com>.
On Fri, Nov 23, 2012 at 3:06 PM, André Warnier <aw...@ice-sa.com> wrote:

> Ok, get it, thanks.
> All-in-one, as a substitute for mod_proxy.
> I will have a second look now.

Feel free to write me off list with any questions you have specific to
this module, but if you can do what you need with mod_proxy I would
recommend that approach.

Re: custom proxy setup with mod_perl

Posted by André Warnier <aw...@ice-sa.com>.
Fred Moyer wrote:
> On Fri, Nov 23, 2012 at 2:18 PM, André Warnier <aw...@ice-sa.com> wrote:
>> Fred Moyer wrote:
>>> You might want to take a look at a mod_perl based proxy module I wrote
>>> - https://metacpan.org/module/Apache2::Proxy
>>>
>>> It was used in conjunction with Perlbal and a couple other tricks, but
>>> was pretty speedy given the crude nature of how I implemented it.
>>
>> No offense intended, Fred, but without much of a documentation, this is bit
>> above my level.  I have trouble even understanding where it fits in.
> 
> None taken, you're quite right, this needs (more) documentation. It
> was open sourced when still in rough form. I'll send a ping when I get
> it cleaned up and 0.05 released. Anyway, here's the basic way I used
> it. Torsten's solution is probably technically more adept, but I
> couldn't do what I needed to using filtering, so I had to write this.
> 
> <Location />
>     SetHandler          modperl
>     PerlHeaderParserHandler Apache2::Const::OK
>     PerlAccessHandler       Apache2::Const::OK
>     PerlAuthenHandler       Apache2::Const::OK
>     PerlAuthzHandler        Apache2::Const::OK
>     PerlTypeHandler         Apache2::Const::OK
>     PerlFixupHandler        Apache2::Const::OK
>     PerlResponseHandler     My::Proxy->handler
> </Location>
> 
> package My::Proxy;
> use base 'Apache2::Proxy';
> 
> sub handler {
>     my ($r, $class) = @_;
> 
>     # examine request to see if it needs to be modified
> 
>     # if not, pass to Apache2::Proxy
>     return $class->SUPER::handler($r);
> 
>     # else fixup the request as needed.
> }
> 
Ok, get it, thanks.
All-in-one, as a substitute for mod_proxy.
I will have a second look now.

Re: custom proxy setup with mod_perl

Posted by Fred Moyer <fr...@redhotpenguin.com>.
On Fri, Nov 23, 2012 at 2:18 PM, André Warnier <aw...@ice-sa.com> wrote:
> Fred Moyer wrote:
>>
>> You might want to take a look at a mod_perl based proxy module I wrote
>> - https://metacpan.org/module/Apache2::Proxy
>>
>> It was used in conjunction with Perlbal and a couple other tricks, but
>> was pretty speedy given the crude nature of how I implemented it.
>
>
> No offense intended, Fred, but without much of a documentation, this is bit
> above my level.  I have trouble even understanding where it fits in.

None taken, you're quite right, this needs (more) documentation. It
was open sourced when still in rough form. I'll send a ping when I get
it cleaned up and 0.05 released. Anyway, here's the basic way I used
it. Torsten's solution is probably technically more adept, but I
couldn't do what I needed to using filtering, so I had to write this.

<Location />
    SetHandler          modperl
    PerlHeaderParserHandler Apache2::Const::OK
    PerlAccessHandler       Apache2::Const::OK
    PerlAuthenHandler       Apache2::Const::OK
    PerlAuthzHandler        Apache2::Const::OK
    PerlTypeHandler         Apache2::Const::OK
    PerlFixupHandler        Apache2::Const::OK
    PerlResponseHandler     My::Proxy->handler
</Location>

package My::Proxy;
use base 'Apache2::Proxy';

sub handler {
    my ($r, $class) = @_;

    # examine request to see if it needs to be modified

    # if not, pass to Apache2::Proxy
    return $class->SUPER::handler($r);

    # else fixup the request as needed.
}

Re: custom proxy setup with mod_perl

Posted by André Warnier <aw...@ice-sa.com>.
Fred Moyer wrote:
> You might want to take a look at a mod_perl based proxy module I wrote
> - https://metacpan.org/module/Apache2::Proxy
> 
> It was used in conjunction with Perlbal and a couple other tricks, but
> was pretty speedy given the crude nature of how I implemented it.

No offense intended, Fred, but without much of a documentation, this is bit above my 
level.  I have trouble even understanding where it fits in.

Re: custom proxy setup with mod_perl

Posted by Fred Moyer <fr...@redhotpenguin.com>.
You might want to take a look at a mod_perl based proxy module I wrote
- https://metacpan.org/module/Apache2::Proxy

It was used in conjunction with Perlbal and a couple other tricks, but
was pretty speedy given the crude nature of how I implemented it.

On Fri, Nov 23, 2012 at 9:39 AM, André Warnier <aw...@ice-sa.com> wrote:
> Hi.
>
> I am trying to solve an unconventional (I think) issue with mod_perl (or
> even without it).
> Environment : Apache 2.2/mod_perl 2 under Linux.
>
> The issue :
> A number of workstations are in a LAN, using a local DNS server under my
> control.
> In the same LAN (192.168.45.0), I have a Linux host running Apache
> 2.2/mod_perl 2, also under my full control (IP 192.168.45.100).
>
> Currently, the LAN workstations access external websites such as (for the
> sake of example) :
> 1) http://www.site-1.com  (IP 1.2.3.4)
> 2) http://www.site-2.biz  (IP 2.3.4.5)
> 3) http://www.site-3.org  (IP 3.4.5.6)
> 4) http://www.site-4.co.uk (IP 4.5.6.7)
> (all these IP's being supposedly real public Internet IP addresses)
>
> In the future, I would like that when the workstations try to access
> websites (2) and (4) above, they access them through my Apache/mod_perl
> host.
> The reason for this is that
> a) I need to authenticate the users
> b) I need to allow some users to access these external servers, and deny
> other users (and for those, I need to return a nice page explaining why)
>
> I already do the authentication/authorization using custom PerlAuth*
> handlers.
> I also know how to write PerlFixupHandler and PerlTransHandler modules, and
> how to "push" other Perl "HTTP cycle" handlers when needed.
>
> My basic scheme is as follows :
> - the DNS server configuration is modified so that when resolving the
> hostnames (2) and (4) above, it returns the IP address of the internal
> Apache host (192.168.45.100).
> When a workstation thus wants to connect to webserver (2) above, in reality
> it connects to the internal Apache host, where I want to perform my mod_perl
> magic.
> - on the Apache host, there is a virtual host configured with
>   ServerAlias www.site-2.biz
>   ServerAlias www.site-4.co.uk
> so it responds to these requests.
>
> The Apache host has access to the "real" IP addresses of the above external
> webservers.
> (For example, in its own "hosts" file; or it has itself an "uncorrupted" DNS
> server which delivers the original IP addresses).
>
> In the Apache host, I have the following configuration section :
> <Location />
>   AuthType MyOwn
>   AuthName CheckProxy
>   PerlAuthenHandler my:AuthHandler->get_id
>   PerlAuthzHandler my:AuthHandler->allow_or_not
>   Require valid-user
>   PerlFixupHandler ????
>   PerlTransHandler ????
>   ProxyPass http://(corresponding hostname)/(path and query as received)
> </Location>
>
> Now my questions are : if I do something at the level of the
> PerlFixupHandler or PerlTransHandler,
> 1) is that "early enough" to be before the Apache ProxyPass step ?
> 2) can I set the "(corresponding hostname)" above in such a Perl handler, or
> otherwise manipulate the URI before it gets proxy-ed ?
> 3) do I need this ProxyPass directive in my configuration, or can I just set
> the Apache response handler to be mod_proxy_http, in one of the Perl
> handlers ? and if yes, how ?
>
> I'd be thankful for any answer or tip, even about a solution which does not
> involve mod_perl at all. (But in reality, I do need to do a bit more in my
> handlers than I allude to above).
>
>
>
>
>
>
>
>
>
>

Re: custom proxy setup with mod_perl

Posted by André Warnier <aw...@ice-sa.com>.
Torsten Förtsch wrote:
> On 11/23/2012 06:39 PM, André Warnier wrote:
>> 1) is that "early enough" to be before the Apache ProxyPass step ?
> 
> yes, the proxy works as usual in the response phase.
> 
>> 2) can I set the "(corresponding hostname)" above in such a Perl
>> handler, or otherwise manipulate the URI before it gets proxy-ed ?
> 
> yes
> 
>> 3) do I need this ProxyPass directive in my configuration, or can I just
>> set the Apache response handler to be mod_proxy_http, in one of the Perl
>> handlers ? and if yes, how ?
> 
> no, the fixup handler can configure the request to be handled by mod_proxy.
> 
>   # Perhaps 2 is better here, since your server actually acts as
>   # reverse proxy. The differences are subtle. Have a look at the code
>   # for better understanding.
>   $r->proxyreq(1);
>   $r->filename("proxy:".$url);
>   $r->handler('proxy_server');
> 
> That's what I would begin with. $url is then 'http://www.site-...'.

Many thanks.  I would not have found this by myself.  Of course, now that I know .. 
http://perl.apache.org/docs/2.0/api/Apache2/RequestRec.html#C_proxyreq_
but I would not have looked there.

> 
> A problem here is perhaps if the user wants to use https. 

Yes, that's the next issue :

5) https://www.site-5.edu

You can of
> course fake up a certificate. You perhaps can even have the browser
> accept it without warning. But nevertheless, a user with sufficient
> knowledge can identify the man in the middle.

That last is not really an issue here.  The users are (supposed to be) cooperative .
The real context is that the client/company has subscriptions with certain sites, limited 
in number of users and nominative.  If the user is not registered yet, the message they 
receive is to get in touch with the appropriate department, to obtain a subscription.
If they are registered, then they can be passed through to the target transparently.
The reason for being able to manipulate the URI's, is that on some of these sites the 
subscriptions are only valid for a part of the site.

Also, I don't necessarily want to do all this heavy-duty stuff for all calls to the 
external sites (e.g. not for css, images etc..).  That's why I wanted to achieve this with 
mod_perl, to retain a maximum of flexibility.  Once you start combining a bunch of 
criteria on multiple target sites, things get pretty messy with standard Rewrite* and 
Proxy* and SetEnvIf..

The browser warning may be an issue because it's ugly from a user point of view, and we 
would have to warn them to disregard it.  It may even be that they are not allowed to 
disregard it, if their corporate IE + policies allow to set this.
In this case, there are 10 sites in total, and one of them is a https:// one.  But there 
may be more in future.
I'll cross that bridge when I get to it.


> 
> See also
> 
>   http://foertsch.name/ModPerl-Tricks/using-modproxy-as-useragent.shtml
> 
> for a different but also unusual usage of mod_proxy.

Now that I read this, I remember seeing that before. But I forgot about it.
Thanks for reminding me.

Re: custom proxy setup with mod_perl

Posted by Torsten Förtsch <to...@gmx.net>.
On 11/23/2012 06:39 PM, André Warnier wrote:
> 1) is that "early enough" to be before the Apache ProxyPass step ?

yes, the proxy works as usual in the response phase.

> 2) can I set the "(corresponding hostname)" above in such a Perl
> handler, or otherwise manipulate the URI before it gets proxy-ed ?

yes

> 3) do I need this ProxyPass directive in my configuration, or can I just
> set the Apache response handler to be mod_proxy_http, in one of the Perl
> handlers ? and if yes, how ?

no, the fixup handler can configure the request to be handled by mod_proxy.

  # Perhaps 2 is better here, since your server actually acts as
  # reverse proxy. The differences are subtle. Have a look at the code
  # for better understanding.
  $r->proxyreq(1);
  $r->filename("proxy:".$url);
  $r->handler('proxy_server');

That's what I would begin with. $url is then 'http://www.site-...'.

A problem here is perhaps if the user wants to use https. You can of
course fake up a certificate. You perhaps can even have the browser
accept it without warning. But nevertheless, a user with sufficient
knowledge can identify the man in the middle.

See also

  http://foertsch.name/ModPerl-Tricks/using-modproxy-as-useragent.shtml

for a different but also unusual usage of mod_proxy.

Torsten