Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

Question in short: How do I get traffic from a host on an internal network, using NAT behind a router, to use a VPN connection set up on the router?

I have a FreeBSD 9 router with 4 network interfaces. One external connected to my ISP and the others connected to internal subnets. The internal interfaces use NAT (by pf) to connect to the external world.

Now, I would like to have all traffic from a host on one of the subnets use a PPTP VPN connection set up on the FreeBSD machine. The end result would be that a host on the internal network uses a VPN without having to use a VPN client on the host itself.

I've managed to set up the VPN client with mpd5. Connecting from the router to the VPN server with mpd5, I get a new network interface — ng0 — with an ip address.

My problem is that I don't know where to go from here. There's just an interface (ng0) with an IP address. How do I make traffic from the internal, NATed, network use the VPN connection?

If you're trying to answer or point me in the right direction, you can start with the assumption I don't know or understand anything about VPNs, routing, NAT or pf — which I clearly almost don't. (Adding a route from where to where? Adding pf rules doing what to incoming and outgoing packets? etc.)

Configuration

This is right after connecting to the VPN server from the router.

My network

My /etc/pf.conf:

ext_if = "em0"
local_if = "em1"
wifi_if = "em2"
misc_if = "em3"
localnet = "{" $local_if:network $wifi_if:network $misc_if:network "}"
nat on $ext_if from $localnet to any -> ($ext_if)
pass in all
pass out all keep state

Routing table:

Destination        Gateway            Flags    Refs      Use  Netif Expire
default            188.60.52.1        UGS         0   998893    em0
10.0.1.0/24        link#10            U           0   159240    em1
10.0.1.1           link#10            UHS         0      358    lo0
10.0.2.0/24        link#11            U           0   503719    em2
10.0.2.1           link#11            UHS         0        0    lo0
10.0.3.0/24        link#12            U           0  3773731    em3
10.0.3.1           link#12            UHS         0        0    lo0
98.158.118.1       link#15            UH          0        0    ng0
98.158.118.63      link#15            UHS         0        0    lo0
127.0.0.1          link#13            UH          0        0    lo0
188.60.52.0/22     link#9             U           0        0    em0
188.60.55.17       link#9             UHS         0        0    lo0

To connect to the VPN server I have this in /usr/local/etc/mpd/mpd.conf:

strongvpn:
    create bundle static B1
    set bundle yes compression
    set ipcp ranges 0.0.0.0/0 0.0.0.0/0
    set ccp yes mppc
    set mppc yes e128
    set mppc yes stateless

    # Not using these yet, as I don't know what to put in them ...
    #set iface up-script /usr/local/etc/mpd5/ip-up.sh
    #set iface down-script /usr/local/etc/mpd5/ip-down.sh

    create link static L1 pptp
    set link action bundle B1
    set auth authname XXXXXXXXX
    set auth password XXXXXXXXX
    set link max-redial 0
    set link mtu 1460
    set link keep-alive 20 75
    set pptp peer 98.158.112.17
    set pptp disable windowing
    open
share|improve this question
    
Can I clarify - you want all the hosts on your network to go out your em0 interface except for a specific host which you want to go out the VPN? Or do you want to send all your internal network hosts out the VPN? –  Zanchey Feb 13 '12 at 4:12
    
I'd like a specific internal host or maybe an entire internal subnet — the important part is that it's not everything — to go out the VPN. All other internal traffic should go out the normal em0 way. –  Erik Tjernlund Feb 13 '12 at 8:41
add comment

3 Answers

I don't know if FreeBSD has ip command, but there most like is something similar to accomplish this.

# create special routing table
echo 7 special >> /etc/iproute2/rt_tables
# add default route for special table
ip route add table special default via 98.158.118.1
# see special table
ip route show table special
# add source based routing rule
ip rule add from 10.0.1.10/32 table special
# + add your nat rules unless the other end knows how to route back
# to your 10.0.1.0/24 network

@see ip layer network admin guide (linux)

share|improve this answer
add comment

To check that your VPN is working as expected, you can start by pinging the other side of your VPN tunnel from your FreeBSD box.

ping 98.158.118.1

The main issue once you are sure that your VPN is ok is "routing" all the traffic coming from your inside interfaces to the gn0 interface and doing NAT as well on this interface. You cannot do that by simply modifying the default router or you would shoot you in the foot, as the VPN requires its packets to route through your ISP ;)

The word here is "divert", but as far as I know (see " Does PF support divert like IPFW? "), this is not supported by the current FreeBSD "pf" port (this port is always older than the OpenBSD "pf", as being the original). Maybe in the future ...

Here are some hints for a solution which imply you changing from "pf" to "ipfw" which support "divert":

  • read the FreeBSD official ipfw documentation, as this is a good start for the next steps.
  • rebuild your kernel with "ipfw" and "divert" enable (chapter 31.6.2 of the "ipfw" documentation)
  • enable "ipfw" and set the "natd" out interface from your "/etc/rc.conf" file:

    firewall_enable="YES"
    firewall_script="/etc/rc.firewall-myown"
    natd_enable="YES"
    natd_flags="-f /etc/natd.conf"
    natd_interface="ng0"
    
  • write your own "/etc/rc.firewall-myown" (you can use the default "/etc/rc.firewall" as a starting point):

    ipfw -f flush 
    ipfw add 10002 divert natd all from any to any via em2
    ipfw add 10003 divert natd all from any to any via em3
    ipfw add 10004 divert natd all from any to any via em4
    

The "natd" daemon configuration is quite straightforward and is mostly used to set port forwarding.

I did not check everything, especially the fact that you have 3 interfaces to NAT but I use "ipfw" for my own FreeBSD routing box and I did some VPN diverting in the past.

Enjoy !

share|improve this answer
    
Firstly, yes, I can ping the VPN address (98.158.118.1). That address replies to ping even without the VPN, but I think my pings are going through the tunnel because I can see the traffic if i do a tcpdump -i ng0. Lots of trying stuff has led me to believe, like you suggest, that it's the NAT that's the problem. I'll have a closer look at the ipfw stuff you suggest ... –  Erik Tjernlund Feb 12 '12 at 22:43
    
Good to know that your VPN is working. Now comes the hard part: "routing", that is "diverting" in your case ;) Just remember for testing that your FreeBSD box will be blind, only the client hosts will be able to go through your VPN. –  Ouki Feb 13 '12 at 0:23
    
Actually, I'm pretty sure you can just modify the default route, as long as you insert a more specific route to ensure you can reach the VPN server (which you can do with a pre-up script). –  Zanchey Feb 13 '12 at 4:31
    
Of course you can. But the question is to make traffic only from the internal interfaces go through the VPN. Maybe I was a bit too literal in my answer ;) –  Ouki Feb 13 '12 at 9:56
add comment

The key question here is, "Did you try the VPN yet?" Everything seems fine. If your FreeBSD box can already route to the remote side of the VPN, your job is almost done. That means that the connection is valid and it is aware of the route to the remote network.

The host behind the router shouldn't require any changes at all to communicate "through the VPN." If it has the router set as its default gateway, then all traffic to remote networks (including the other side of the VPN) should go through the router, which as we stated, is already aware of the appropriate route. If you want to be very explicit, add a static route to the routing table of the host in question to ensure that it is aware of the correct route to the remote side of the VPN.

share|improve this answer
    
As far as I can tell the VPN connection works. The output from mpd5 looks good and stuff like show link indicates there's a proper connection. I get a network interface – ng0 – with an ip address. But my problem, as I've clearly explained, is that I don't know how to get any traffic to use the VPN connection. There's no route, no pf rules, nothing. So how could it work? (And it doesn't). That's my whole question: how do I get traffic to use the VPN. –  Erik Tjernlund Feb 11 '12 at 12:59
    
I should clarify my previous comment. No, the VPN doesn't work in full (that's a big part of my original question). There's an network interface after starting mpd5 (ng0), but there's no routing information (neither manual nor any script run by the mpd5 configuration — see above from mpd.conf). So when I say that the "VPN connection works", I mean that mpd5 connects to the VPN server and I get a ng0 interface on the router, but that's it. –  Erik Tjernlund Feb 11 '12 at 14:53
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.