Modify

Opened 7 years ago

Closed 7 years ago

Last modified 7 years ago

#1180 closed enhancement (fixed)

Support Static IP addresses for OpenVPN clients through the Client Config Directories (CCD) option

Reported by: Jon "The Nice Guy" Spriggs <jon@…> Owned by:
Priority: normal Milestone: Firmware 2.3.7.0
Component: fon-plugin-openvpn Version: N/A
Severity: major
Cc: Hardware: both

Description

I don't exactly know how this is going to work... but I think I can work it through.

First, initialize the CCD option in OpenVPN:

uci set openvpn.openvpn.client_control_dir=/etc/openvpn/ccd
/etc/init.d/openvpn restart
mkdir /etc/openvpn/ccd

Next, (and this is the bit I'm not sure how to do it), add to each of the clients under the OpenVPN UCI stores the IP address of the host we want to use. These are /30 subnets from the range provided by the --server directive (obtainable from the UCI openvpn.openvpn.server value as an ip address and netmask), which is, by default, 10.8.0.0/24. The first /30 is dedicated to the server, and can't be used. Typically addresses from the second /30 onwards would be used. See http://openvpn.net/index.php/open-source/documentation/howto.html#policy for a list of IP address pairings we would expect to see in a /24.

If we could provide a drop down for the IP address, that would be useful :)

We then need to create the CCD files. These use the SSL CN as the filename and the content looks like this:

ifconfig-push 10.8.0.5 10.8.0.6

This is a bit of a pipedream really, but it would be nice to have something like this :)

Attachments (1)

luci-openvpn-static.patch (8.6 KB) - added by matthijs 7 years ago.
Patch for the luci part

Download all attachments as: .zip

Change History (15)

comment:1 Changed 7 years ago by anonymous

Another option could be to move the ipp.txt file from the /tmp folder to /etc and also update /etc/config/openvpn to reflect this and then have it filed with static address for however many clients you may need.
I think because dev tun is used the IP's in the ipp.txt would one or maybe two less than the one assigned, so the ipp.txt would be like

client1, 10.8.0.whatever
client2, 10.8.0.thenextone 

comment:2 Changed 7 years ago by matthijs

  • Milestone set to Firmware 2.3
  • Status changed from new to confirmed

The latter option would probably be easier, but I suspect also more fragile. It could serve as a "light" version of the future, which does not allow explicitly setting addresses, but does make sure that addresses are persistent (i.e., a client gets a dynamic address on the first connection and then the same address on every subsequent connection).

However, I'm inclined to want the "full" solution, since it's more explicit.

Two caveats that just occured to me:

  1. If you assign some clients a static address, can you still assign the others a dynamic address? Or will the dynamic clients then also get assigned addresses from the static clients? If this is indeed a problem, I guess this could be circumvented by generating a /tmp/ipp.txt on startup (but that sort of removes the need for having this ccd stuff in the first place, perhaps...)
  2. If you assign a static address, I guess a single client can't be connected twice, since it would get the same address assigned? Or is this impossible already (I guess ipp.txt could already prevent this from happening, of course...).

As for storing the IP addresses per client, there is already a section per client in /etc/config/openvpn. We could easily add the ip address as a value to that section and then use that to generate the contents of /etc/openvpn/ccd and/or /tmp/ipp.txt in /etc/fonstated/ReconfVPN.

Depending on the answer to caveat 1 above, this ip address value could be absent (meaning "automatic"), or the default could be to pick an unused address from the pool instead (when adding a new client).

One more thing: Assigning static addresses could limit the amount of clients to 254, but I guess we can just assume that won't be a problem for anyone, right?

I'm setting the milestone to 2.3 (i.e. post 2.3.7.0) for now, but if you come up with a patch, I'll be happy to include in 2.3.7.0 as well.

comment:3 follow-up: Changed 7 years ago by Jon "The Nice Guy" Spriggs <jon@…>

  1. If you assign some clients a static address, can you still assign the others a dynamic address? Or will the dynamic clients then also get assigned addresses from the static clients? If this is indeed a problem, I guess this could be circumvented by generating a /tmp/ipp.txt on startup (but that sort of removes the need for having this ccd stuff in the first place, perhaps...)

From my limited testing, it would appear that static addresses and dynamic addresses are allocated from the same pool, so if you use 10.8.0.5 for your first host, the server may allocate .6 to the first dynamic client (which as part of the same /30, is a no-no).

However, the CCD entries can go into another subnet, so for example, you could use 10.8.0.0/24 for the dynamic pool (as is) and then allocate in the 10.8.0.0/16 range for the statics, omitting the first /24

OK, this is getting potentially quite complex!

  1. If you assign a static address, I guess a single client can't be connected twice, since it would get the same address assigned? Or is this impossible already (I guess ipp.txt could already prevent this from happening, of course...).

There is a parameter to permit multiple connections from single certificate (for example, if you've got a single certificate for all the remote workers and you want them to authenticate with a second factor - like Radius, PAM or equivalent), but I think without that the subsequent clients will all get denied.

As for storing the IP addresses per client, there is already a section per client in /etc/config/openvpn. We could easily add the ip address as a value to that section and then use that to generate the contents of /etc/openvpn/ccd and/or /tmp/ipp.txt in /etc/fonstated/ReconfVPN.

I was thinking that's probably the best way to do it.

Depending on the answer to caveat 1 above, this ip address value could be absent (meaning "automatic"), or the default could be to pick an unused address from the pool instead (when adding a new client).

I think that's probably the best bet, but see the next comment and this section of the OpenVPN manual for the appropriate addressing: http://openvpn.net/index.php/open-source/documentation/howto.html#policy (Note you can do the IP's in either order, I tend to do the first number as the client end, but that doesn't really make sense given the way the server is addressed...)

One more thing: Assigning static addresses could limit the amount of clients to 254, but I guess we can just assume that won't be a problem for anyone, right?

You can only have 64 clients in a /24, as each client has a /30 subnet assigned to it for the p2p tunnel.

comment:4 in reply to: ↑ 3 Changed 7 years ago by matthijs

  • Hardware changed from unknown to both

The option of just pregenerating /tmp/ipp.txt and then use that to tell OpenVPN about our static allocations is probably not going to work. The manpage about the ifconfig-pool-persist option says:

Note that the entries in this file are treated by OpenVPN as suggestions only, based on past associations between a common name and IP address. They do not guarantee that the given common name will always receive the given IP address.

I'm not sure in what cases these guarantees will be broken (probably when the pool is full, but possibly other cases as well), so we should probably not use this.

Replying to Jon "The Nice Guy" Spriggs <jon@…>:

However, the CCD entries can go into another subnet, so for example, you could use 10.8.0.0/24 for the dynamic pool (as is) and then allocate in the 10.8.0.0/16 range for the statics, omitting the first /24

Hmm, complex stuff :-)

Note that if you actually have two separate subnets, this would require extra routing stuffs, but we could probably get away with single bigger subnet, and just use a subset of this for dynamic allocation (I think we can achieve this by adding an extra --ifconfig-pool option to the commandline. It should probably be _after_ the --server option, since the latter also sets the --ifconfig-pool option).

Also, we could go for a /23 instead of /16, and then use 10.8.1.x for static allocation and 10.8.0.x for dynamic, for example.

As an alternative for generating ccd files, we could use the --client-connect script, which is called on connect and can specify options to push. For example, we could write a script that contains something like:

CLIENT_IP=$(uci get "openvpn.$common_name.ip") if [ -n "$CLIENT_IP" ]; then

PEER_IP=some_magic_to_add_or_subtract_one echo ifconfig-push $CLIENT_IP $PEER_IP > "$1"

fi exit 0

Which just gets the IP address to use on connect (and when no IP is set, it just does not generate any settings, causing the pool to be used).

Depending on the answer to caveat 1 above, this ip address value could be absent (meaning "automatic"), or the default could be to pick an unused address from the pool instead (when adding a new client).

I guess absent == "automatic" is probably the easiest to understand for users.

One more thing: Assigning static addresses could limit the amount of clients to 254, but I guess we can just assume that won't be a problem for anyone, right?

You can only have 64 clients in a /24, as each client has a /30 subnet assigned to it for the p2p tunnel.

Uh, of course. But still, 64 clients shouldn't be a problem either, I guess.

So, did we tackle all issues now?

comment:5 Changed 7 years ago by Jon "The Nice Guy" Spriggs <jon@…>

There's two things - first is, as far as I can tell (and needs a quick test to be sure) is that the CCD files are treated as extra to the IP pool, which is why when you specify them, they don't disappear from the main pool... so theoretically, we could have 10.8.0.0/24 for the dynamic IP pool, then individuals on 192.168.18.0/30, 172.16.244.128/30 and 10.0.0.192/30 - the server just works with them. So, if we treat the first /24 as the dynamic pool (although we could make this larger - see my next comment), and then have a larger, yet inclusive subnet (so we don't need to mess any more with the routing) for the statics.

The other thing is about the size of the subnet. Sure, a /16 is overkill, but with only 64 /30's in a /24, with the change we made previously we could potentially have 1024 concurrent connections. So, if a /24 is 64 /30's, we'd need a /20 to give us 1024 /30's... I was overcompensating because I hadn't done my maths and wasn't sure just how far up we'd need to go.

Obviously, I'd be rather shocked if we did actually get 1024 concurrent OpenVPN connections into a Fon 2.0g, or even really into a 2.0n, but if we're saying "you can do it", we should probably scope for it, and it's something I should really have thought about when we made our previous change permitting that many concurrent connections.

I do like the idea of the Client Connect script. It feels more "Fon"ish, for some reason.

comment:6 Changed 7 years ago by matthijs

I think we have the same understanding of the CCD addresses: they should not be allocated inside the dynamic pool, since the dynamic allocator is not aware of statically allocated addresses.

As for the maximum connections, I'm inclined to limit that to 64. We could of course make the subnet bigger to accomodate 1024 addresses, but I'm afraid that this would become hard to understand for most users (who don't really know how networks and netmasks work, they barely understand thinking in class A/B/C networks...). So, Saying 10.8.0.x is for dynamic addresses is probably easier to understand than saying 10.8.0.0 - 10.8.0.15.255 is for dynamic addresses. Also, I'm thinking we should assign static addresses using a dropdown in the webGUI, and a dropdown with 64 addresses is still ok-ish, 1024 is really undoable.

So, lets:

  1. Use 10.8.0.0/23 as the subnet
  2. Use 10.8.0.x for dynamic addresses
  3. Use 10.8.1.x for static addresses

Perhaps we should also change the max connections patch in #1178 to have "64" instead of "unlimited" (which isn't really unlimited right now anyway...).

Care to do a (prototype) patch?

comment:7 Changed 7 years ago by Jon "The Nice Guy" Spriggs <jon@…>

Preliminary stuff:

/usr/sbin/openvpn-client-connect-script

#!/bin/sh
CLIENT_IP=$(uci get "openvpn.$common_name.ip") 2>/dev/null
if [ -n "$CLIENT_IP" ]; then       
    PEER_IP=`echo $CLIENT_IP | awk -F "." '{print $1"."$2"."$3"."$4-1}';`
    echo ifconfig-push $CLIENT_IP $PEER_IP > "$1"                                      
fi                                                                                     
exit 0

Addition to /etc/config/openvpn

config 'openvpn' 'openvpn'
	option 'client_connect' '/usr/sbin/openvpn-client-connect-script'
	option 'script_security' '2'

Confirmed working on my home system, both with defined and pool-allocated IP addresses (AKA, it's all as predicted!!! YEY!!!).

Changed 7 years ago by matthijs

Patch for the luci part

comment:8 Changed 7 years ago by matthijs

At first glance, your scripts look good. One thing I noticed: It seems you're using the lower IP as peer IP now, instead of the client IP. I guess those should be reversed (either that, or I should update the luci patch).

I just attached a patch to get luci to play nicely and allow the user to set static IPs per client. Feel free to apply that (don't forget to svn add the new files) and build a final patch including all those changes.

comment:9 Changed 7 years ago by Jon "The Nice Guy" Spriggs <jon@…>

Sorry about the delay in getting this in. I had to reset my FON 2.0n while testing some of these scripts, and cut my wife off the network in so doing... I was not flavour of the month for a few days, and I'm on strict instructions to leave the damn thing alone for a while.

To add to that issue, I've got a project I need to get working in the next 5 days, and I've probably got about 14 days of work to do on it, so nights and some working hours have been swallowed by it... It looks like I'm not going to get this in before the end of August now :(

Sorry all.

comment:10 Changed 7 years ago by matthijs

I'm picking up this patch again, as the last of a big series of OpenVPN fixes and features (thanks Jon!).

I'm experimenting a bit with the --topology subnet option now, which allows assigning single addresses to clients (instead of /30) networks, which should make everything a bit less confusing (at the expense of requiring OpenVPN 2.1 or newer, but that's already three years old).

This means that we now have 253 addresses available in the /24 subnet, which should be enough. So, I'm thinking to stick with the existing /24, use .2 - .127 for dynamic allocations and .128 to .254 for static allocations. This means that the number of addresses is more than the maximum number of concurrent connections (64), but that's ok, since not all clients are necessarily online at the same time.

comment:11 Changed 7 years ago by matthijs

  • Milestone changed from Firmware 2.3 to Firmware 2.3.7.0
  • Severity changed from unknown to major
  • Status changed from confirmed to testing-fix

Ok, I threw everything together and it seems to be working fine. I'll commit the stuff after it received a bit more testing.

I'm leaving .254 out of the static pool, since it seems that the Windows OpenVPN client uses the .254 address as the "DHCP server address", whatever that means. Not sure if this causes any conflichts, but let's just leave out the address to be sure.

comment:12 Changed 7 years ago by matthijs

(In [2183]) openvpn: Switch to "subnet" topology.

Previously, the (default) "net30" topology was used, which allocates a /30 network to every client to work around Windows not supporting a real point-to-point topology. However, with a the "subnet" topology, each client gets assigned a single address and configures the complete /24 subnet on its tun device.

This means that OpenVPN clients now need OpenVPN version 2.1 or newer, but given that it was released nearly three years ago, that should be ok.

The main advantage of using this topology is probably that the address assignment is less confusing to novice users: The OpenVPN server gets one address and each client gets one address.

References: #1180

comment:13 Changed 7 years ago by matthijs

  • Resolution set to fixed
  • Status changed from testing-fix to closed

(In [2184]) openvpn: Allow setting static IPs for OpenVPN clients

This commit limits the automatically assigned addresses to 10.8.0.2 -> 10.8.0.127 and reserves 10.8.0.128 -> 10.8.0.253 for static assignment. These addresses can be selected from a dropdown in the webinterface (default is "automatic") and are then stored in uci.

When a client connects, the client-connect script is run, which checks for a static IP and tells OpenVPN about this. If no static IP was configured, OpenVPN falls back to automatically assigning an address from the pool.

Thanks to Jon Spriggs for parts of this patch and a lot of research for this feature.

Closes: #1180

comment:14 Changed 7 years ago by matthijs

(In [2185]) luci-openvpn: Don't allow duplicate static addresses.

This prevents the webui from saving when two clients have the same static IP address selected.

References: #1180

Add Comment

Modify Ticket

Action
as closed The ticket will remain with no owner.
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.