Posted: Fri Feb 25, 2011 21:09 Post subject: OVPN site-to-site dhcp and nat
I recently set up a Openvpn site to site bridge for gaming purposes. It seems DHCP on both ends of the bridged vpn causes issues, and I've scoured the web looking for a clean solution.
Right now I'm using these firewall rules found in this thread, which seem to be working.
Some of these rules may be excessive or unnecessary.
From what it sounds loading ebtabtles allows the firewall rules to also see broadcasts, which usually they do not. This however brings the a side effect, in that traffic over the vpn is then natted, and packets arriving from the opposite site show their source as the router rather than the clients.
These last two lines fix that.
LAN_NET="$(nvram get lan_ipaddr)/$(nvram get lan_netmask)"
iptables -t nat -D POSTROUTING -o br0 -s $LAN_NET -d $LAN_NET -j MASQUERADE
Taken from the thread mentioned
"So the downside of this is that loopback will no longer function correctly."
"Edit: I also noticed another downside of ebtables. Since every packet in the bridge is visible to the firewall, there is a much higher CPU usage on the router, when using WiFi. 100% CPU on the router, when transferring at only ~50 Mbps through WiFi."
I haven't so far tested whether using wifi really causes 100% cpu utilization.
What are the downsides of having loopback being broken?
Does anyone having any other solution, that block dhcp over the tunnel, and also does not causing natting or loopback issues? Provided having loopback broke is a serious issue. The goal for me is to find the best solution, and update the wiki with what works best.
Well I've scoured the internet for a couple more days, and have come up with a result. It's a shame none of this has been put into the wiki as of yet; probably could save people a lot of effort.
So basically, with regards to blocking dhcp over an openvpn bridge, dd-wrt is incomplete. As previously discussed here iptables by itself can't do it since it only sees osi layer 3 information. Dhcp being a broadcast, needs to be monitored at osi layer 2. To do this you need to load; ebtables, ebtable_filter, and ebt_ip.o. The first two modules are included, however, ebti_ip.o is not. The creation of a clever little script to do this was first found here. Discussion of this module and its hoped for integration into dd-wrt dates back to 2007 in this thread. Still hasn't happened yet.
Typing 'ebtables -L' over ssh shows that it isn't capable. So we need to load this functionality using the previously mentioned script.
I found this script with this particular special timing here, and added my own small addtion. Without the sleeps it won't load correctly. Obviously this will need to be placed after the creation of the tap. You may need to rename tap0 to whatever you called your tap. In my situation, these are able to load with time to spare before any waiting clients can connect. The first ebtable statments will block incoming dhcp packets on the tap. The second should prevent the router's own dhcp packets from being broadcast over the tap, which should generate less traffic.
This is probably the cleanest and most cpu efficient way to achieve this, and won't break the router's loop back. There's enough of us that need this and would also benefit from this module being integrated into a release version of dd-wrt.
Please excuse any errors, logical and/or grammatical. Let me know and I will correct them. I'll update the wiki to make this an easier process for future site-to-site tap bridgers.
Did you wait long enough for it all to load? It could be that you checked as soon as you had ssh access, but this generally isn't long enough for it to finish running the script.
Keep checking the 'ebtables -L' command for atleast a minute or two.
When I was checking, first I'd see the error that ebtables -L wasn't loaded. Then that it was loaded, but no policies. Then I'd see the first policy show up, 5 seconds later the second policy shows up.
It'll alteast take a minute or two, so give it some time.
This is the wiki, I updated it, so check that you're also following what it says.
Make sure you put the script very last in the startup sequence. If you've put it before you declare your tap, then it won't work. Let me know whether you're sucessful.
This is exactly what's in my router's startup script right now:
And this is my client's startup script, taking out my keys/certs and domain. The previous post is my server's, which is utilizing the openvpn gui for the rest of it. Just an example, you may be doing yours differently.
With these I'm successfully seeing the policies on both ends.
I'll note I'm using two wrt54gl's running the 14896 build.
I did wait for two minutes, and this is what it displays:
Bridge chain: INPUT, entries: 0, policy: ACCEPT
Bridge chain: FORWARD, entries: 0, policy: ACCEP
Bridge chain: OUTPUT, entries: 0, policy: ACCEPT
If i try any earlier or after an hour it just displays:
The kernel doesn't support the ebtables 'filter' table.
My Setup is as follows:
Router 1 WRT310NV2 with small VPN build 16214(This is the server)
Router 2 WRT320N with Mega build 16214(This is the client)
Here are the scripts that I am using:
Server:
Code:
cd /tmp
openvpn --mktun --dev tap0
brctl addif br0 tap0
ifconfig tap0 0.0.0.0 promisc up
echo "
# Tunnel options
mode server # Set OpenVPN major mode
proto udp # Setup the protocol (server)
port 1194 # TCP/UDP port number
dev tap0 # TUN/TAP virtual network device
keepalive 15 60 # Simplify the expression of --ping
daemon # Become a daemon after all initialization
verb 3 # Set output verbosity to n
comp-lzo # Use fast LZO compression
# OpenVPN server mode options
client-to-client # tells OpenVPN to internally route client-to-client traffic
duplicate-cn # Allow multiple clients with the same common name
# TLS Mode Options
tls-server # Enable TLS and assume server role during TLS handshake
ca ca.crt # Certificate authority (CA) file
dh dh1024.pem # File containing Diffie Hellman parameters
cert server.crt # Local peer's signed certificate
key server.key # Local peer's private key
" > openvpn.conf
Another question I had is that can i have more than one client connecting to the same server? If so do I need to different Certificate for each client?
echo "
daemon # Become a daemon after all initialization
client
dev tap0
proto udp
remote ServerIP 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert client.crt
key client.key
comp-lzo
verb 3
mssfix 1200
up \"/tmp/up.sh\"
" > client.conf
I suggest increasing the sleeps, perhaps with your routers it's not enough time for the previous commands to finish loading.
I've also noticed that over time it appears that ebtables becomes unloaded. The script loads it to the /tmp directory, so maybe it's getting thrown out over time. I haven't observed if this re-creates the dhcp issue, though I imagine it would/could.
If you can have complete control over your enviroment, I would almost suggest disabling dhcp and assigning IP's manually. With roaming wireles devices this could be a pain. Using TUN instead of Tap would also fix the dhcp issue. Playing games would just require the client to punch in the IP manually, instead of seeing the game by the broadcast sent, which isn't a huge deal. I actually don't have a need for Tap right now. I just wanted to know it could be done, and if I were to return to the site-to-site, I'd probably do a TUN.
I do have one device, the HD Homerun, which requires broadcast to function, but my internet is much too slow to do any streaming; like I said, I just wanted to see if it was possible. Hopefully they will include the last module, since they're already 2/3 of the way there.
Yes you can have multiple clients, you have two options when doing this.
1. You can create a unique security certificate for each client. These will function as either other sites (routers) or individual clients You may have to edit your client config to match the name of your certificates.
2. You can create one security certificate for all clients, and place 'duplicate-cn' in your server side script. This tells the server to allow more than one login per certificate. Otherwise, when one client connects, it will kick off the other connection.
Also, I couldn't say for sure if it's a router or firmware issue. I'm really no expert, just sharing what's worked with me in a specific niche of DD-WRT with my specific router. I'm happy to make suggestions though, and try to find a more universal answer.
This also seemed to work for me, though apparently there was some kind of drawback with loopback being disabled (??). Someone else would have to explain this one. It's discussed in this thread. I placed the following in the router exactly as below. Some of it may be unnecessary. "insmod ebt_ip" is the huge thing we're loading above, but here it's just called, so I don't know. I just remember it seeming to working alright. Just try replacing the other stuff with this.