Pritunl server not accessible through VPN with more than 1 connection

I wanted to say this is still happening to me on the latest version of Pritunl in Ubuntu 24.04 (1.32.4181.41-0ubuntu1~noble), although it’s been happening for quite some time. On one server, I have 84 total users. It is a /25, so it should support close to 128 users. There should be approximately 44 IP addresses (128-84) in the dynamic pool (let’s just say 40).

At any given time, there are some users that have more than one connection, but those are usually in the single digits. Any time I see the dreaded “Unable to assign ip address”, the total devices online (as shown on the servers page) is well below the number of users + dynamic IP addresses. I did have Wireguard enabled at one point (cutting the OpenVPN range down to a /26), but I disabled that long ago. I’m not sure if that had any lingering effects.

I’m not well versed with MongoDB (I’m an SQL guy), but I’ve tried looking around in the database for clues (I could be way off here). I noticed that servers_ip_pool has 159 entries in it. Only six of these records have a blank value for user_id. For one server with five users, I have 20 IP addresses listed, many are linked to unique records in the users collection (I assume that’s how user_id is used). The “type” for non-users varies between ca, client_pool, server, and server_pool. The users collection has 126 rows. I have no idea if these records hang around after a user has disconnected or if this means anything significant.

If I add the two other servers we have in Pritunl (with Wireguard, so double the IPs), we should have a total of 104 static IP address assignments (but this is across multiple subnets).

The servers_ip_pool is used for assigning static addresses, the issue would be in the clients_pool this collection is used to store addresses for active clients and available dynamic addresses. When a user connects if it is the first device it will use that users static address and store this record in clients_pool with static set to true. Any secondary devices will be assigned a dynamic address, this is done by iterating from the end of the subnet using the last addresses first. As these dynamic addresses are assigned they are stored in clients_pool with static unset. The pool_cursor in the server document stores the current position in this iteration to allow all hosts running the server to start assigning from where the last address was. When a client disconnects or times out the document in clients_pool is deleted if it is a static address or the user_id field is set to null for non-static addresses to mark that address as available. Future connections will first attempt to find those unused addresses before assigning a new one. The likely issue is the pool cursor losing track of the correct position in the subnet iteration or dynamic address documents being deleted.

If running db.servers.updateMany({}, {"$set": {"pool_cursor": null}}) fixes the issue it is likely dynamic address documents being incorrectly removed. This can be safely run at any time it will trigger the server to start from the back of the subnet again and iterate through until finding an available address.

In older releases dynamic addresses were being inadvertently deleted by a left over TTL index that would remove any address not recently updated. This was changed to only remove static addresses that have expired timestamps.

It happened to me yesterday, at that moment on the server only 11 users were connected. People were unable to login with multiple devices to the same profile but were able to login with new profiles. The exact error message was:

ERROR User auth failed “Unable to assign ip address”

I am running v1.32.3602.80 1830ca with Enterprise plan activated.

The option for Allow Multiple Devices was enabled and Max Devices was set to 0 which I assume it’s unlimited?

Today I restarted the server and was able to connect with multiple devices with the exact same configuration.

The latest commit to pritunl/clients/clients.py may fix the issue. This will reset the cursor when an address can’t be acquired and retry. This will be included in the next release. It can be tested now by editing /usr/lib/pritunl/usr/lib/python3.9/site-packages/pritunl/clients/clients.py and applying the changes. Then run sudo systemctl restart pritunl.

Thanks, will try that.