Hi,

I agree that the "transparent" keyword is not really documented.

The "transparent" keyword enables the use of the SO_BINDANY socket
option that was added a few releases ago.  It is an option for relays
to use the IP address of the client as the source of the forwarded
connection instead of the local gateway IP address of the relayd
machine.  A relay uses two socket connections a) a server socket that
is connected to the client and b) a client socket that is connected to
the target server.  SO_BINDANY is an option on b) that allows to
bind(2) the source address to a non-local IP address, to the source
address of a) in this case.  It is not directly related to the way of
accepting connections on a) and it doesn't really matter if it is via
rdr-to, divert-to or a direct listener on a public IP address.

>From the manpage setsockopt(2):

     SO_BINDANY allows the socket to be bound to addresses which are not local
     to the machine, so it can be used to make a transparent proxy.  Note that
     this option is limited to the super-user.  In order to receive packets
     for these addresses, SO_BINDANY needs to be combined with matching
     outgoing pf(4) divert rules.  For example, with the following rule the
     socket receives packets for 192.168.0.10 even if it is not a local
     address:

           pass out inet from 192.168.0.10 divert-reply

Here is a little ASCII art:

 10.0.0.2            ix0: 10.0.0.1     ix1: 192.168.1.1      192.168.1.100
+--------+                     +--------+                     +--------+
| Client |---------------------| relayd |---------------------| Server |
+--------+                     +--------+                     +--------+
     |   a) 10.0.0.2->10.0.0.1     ||   b) 10.0.0.2->192.168.1.100 |
     |---------------------------->||----------------------------->|
                                   ||

Without transparent mode b) would be 192.168.1.1->192.168.1.100.  For
the return traffic it is important that the server 192.168.1.100 knows
about the 10.0.0.0/8 network and that it sends any replies back via
the gateway 10.0.0.1 - so it doesn't make sense with NAT.  The gateway
that is running relayd and pf will know about the return traffic to
10.0.0.2 and and receives it locally instead of forwarding it to the
internal host because of the pf state that was entered by the
divert-reply rule.  You can also run transparent SSL acceleration this
way: a) with SSL, b) with plain TCP but coming from the original
client IP.

You can simply test divert-reply on any gateway that is running pf
using the nc(1) tool. Our "netcat" is trying to use SO_BINDANY by
default if you're binding the source to a non-local address as root.

A simplified example that could be run on the gateway above:

# echo "pass out on ix1 from 10.0.0.2 divert-reply" >> /etc/pf.conf
# pfctl -f /etc/pf.conf
# nc -s 10.0.0.2 192.168.1.100 22

Ok, now back to relayd.  As I mentioned before it does not really
matter how the traffic got into relayd.  The are different possible
examples to use transparent mode:

1) A normal listener on an IP address that is directly reachable by
clients:

relayd.conf:
relay transfwd {
        listen on 10.0.0.1 port 25
        transparent forward to <mail_servers> port smtp check tcp interface ix1
}

pf.conf:
pass out on ix1 to <mail_servers> divert-reply

2) A transparent proxy using rdr-to:

relayd.conf:
relay transrdrproxy {
        listen on 127.0.0.1 port 2525
        transparent forward to nat lookup port smtp check tcp interface ix1
}

pf.conf:
pass in on ix1 proto tcp to port 25 rdr-to 127.0.0.1 port 2525
pass out on ix1 divert-reply

3) A transparent proxy using divert-to:

relayd.conf:
relay transdivertproxy {
        listen on 127.0.0.1 port 2525
        transparent forward to destination port smtp check tcp interface ix1
}

pf.conf:
pass in on ix1 proto tcp to port 25 divert-to 127.0.0.1 port 2525
pass out on ix1 divert-reply

Note: 2) divert-to is preferred over 3) rdr-to and support for nat
lookups with 3) will probably go away in the future.

OK... now the big question: why do we have to specify the "interface
ix1" with the transparent keyword? Answer: the grammar requires it,
but it is currently not used in the code!  The reason for the
mandatory "interface" keyword was that I intended to inject the
divert-reply rule in the relayd/* anchor automatically but I didn't
implement this yet.  So you should specify the interface of the
outgoing connection here and hope that I implement it some day...

btw.: I'm currently cleaning up the relayd code before I move forward
to implement and fix some outstanding things in relayd.  Please have a
look at the large diff that I sent to tech@ yesterday which needs
testers.  No new features, just to make sure if this diff doesn't
break any existing setups!

Reyk

On Sat, May 07, 2011 at 11:49:48AM +0000, Stuart Henderson wrote:
> Derek Buttineau <derek <at> csolve.net> writes:
> > I'm attempting to setup a reverse proxy using relayd using the  
> > transparent forward to configuration (non-transparent works fine)  
> > under OpenBSD 4.4.
> 
> Following up to an old mail...but since nobody has ever posted how
> to get this working I imagine pretty much everyone who tried it is
> confused :-)
> 
> This bit is fine:
> 
> > relay maildelivery {
> >      listen on $relayd_addr port 2525
> >      protocol "tcp_service"
> >      transparent forward to <pop3_servers> port smtp check tcp interface 
> > bnx1
> > }
> 
> ("interface XX" is not yet documented but it is needed
> for "transparent forward").
> 
> Here is the problem:
> 
> > rdr on $ext_if proto tcp from $netguard to 66.159.112.123 port smtp ->  
> > lo0 port 2525
> 
> Thanks to phessler for the clue; this must be done
> with a divert-to rule.
> 
> So, with modern PF syntax:
> 
> pass in quick on $ext_if inet proto tcp from $netguard to \
>    66.159.112.123 port smtp divert-to lo0 port 2525
> 
> I'll try and come up with something for the docs.

Reply via email to