If I understand correctly, you have serveral uplinks, and you redirect
requests coming from each uplink to dedicated servers, i.e. server A
handles all requests coming in through uplink A.
You want the return packets to go back through the appropriate uplink.
This should work:
Use rdr on the external interface like you are already doing.
On the internal interface use
pass out on fxp0 reply-to (fxp1 $ext_gw_a) from any \
to $int_net_a port 80 keep state
pass out on fxp0 reply-to (fxp1 $ext_gw_b) from any \
to $int_net_b port 80 keep state
Note that the rdr on the external interface has already replaced the
destination address when these rules are evaluated on the internal
interface.
As an example, an external client C sends a SYN to $ext_gw_b. This
packet will first hit the external interface, match the rdr rule, and
the destination address is replaced with int_net_b. This then goes out
through the internal interface, matching the second rule above.
When the SYN+ACK comes back from the server, it will match the second
rule's state entry, and the reply-to option gets used, bypassing the
normal routing table lookup. The packet will go out through the external
interface with $ext_gw_b's MAC address as destination. There it will
match the rdr rule's state, and the source address is replaced.
You might want to try with 'set state-policy if-bound', but it should
work either way.
This works as long as you have one dedicated server per external uplink.
If you want to load-balance all incoming requests to a server farm,
you'd have to use tags between the rdr rules and the reply-to rules.
Daniel