All, I've just become aware of a rather annoying problem with our PPTP VPN server. Sometimes, a client will connect, disconnect and reconnect in quick succession. In these circumstances, there seems to be a window which an IP can remain allocated to a live VPN session, but is marked as free in the SQL table, causing subsequent clients to connect, be allocated the IP, and fail to get any connectivity. Unfortunately at this time I don't have a debug trace or even detail logs of the accounting traffic for an instance of this, but I was wondering if anyone had seen something similar. We're running FreeRadius 2.1.4 on RHEL5 against a postgres 8.3 database. I am wondering if I've got a logic error in my sqlippool queries; however, they're the stock ones for postgres that come with the distribution with two additions: 1. Any time a row is updated, two extra columns are added to the update: updatedby = '%{localopts.server}', updatedat = now() 2. I've made the WHERE clause on the stop-clear and alive-update more specific, changing it from: WHERE nasipaddress = '%{NAS-IP-Address}' \ AND pool_key = '${pool-key}'" ...to: WHERE nasipaddress = '%{Nas-IP-Address}' \ AND pool_key = '${pool-key}' \ AND username = '%{SQL-User-Name}' \ AND callingstationid = '%{Calling-Station-Id}' \ AND framedipaddress = '%{Framed-IP-Address}'" Obviously the stock queries will try to allocate the same IP to subsequent connections for the same username, which is good and desired for us, but in this case it seems to be somehow allocating the IP, allocating the *same* IP to the 2nd connection, then marking it as unused when the first, short-lived client dies (and the accounting stop presumably comes in late) I can't see how this is happening, since the postgres module has proper transaction support and rlm_sqlippool issues the "START TRANSACTION" queries around every allocate/update/free query, unless it's the postgres isolation level being wrong - in which case I'd expect others to see it. Yours, baffled...
Phil Mayers wrote:
All,
I've just become aware of a rather annoying problem with our PPTP VPN server. Sometimes, a client will connect, disconnect and reconnect in quick succession. In these circumstances, there seems to be a window which an IP can remain allocated to a live VPN session, but is marked as free in the SQL table, causing subsequent clients to connect, be allocated the IP, and fail to get any connectivity.
ACK! Shortly after sending this email, we found the problem and it's truly vile. It's nothing to do with FreeRadius at all, except tangentially - what's actually happening is that the PPTP client is closing the PPP LCP layer and re-opening it on the same PPTP control/data channel. This results in a very rapid set of: 1. access-request nas-port-id = 100 2. access-accept framedipaddress = 192.168.1.100 3. acct-start acctsessionid = 4B151C655A0000 nas-port-id = 100 framedipaddress = 192.168.1.100 4. acct-stop nas-port-id = 100 framedipaddress = 192.168.1.100 acctterminatecause = user-request 5. access-request nas-port-id = 100 6. access-accept framedipaddress = 192.168.1.100 7. acct-start acctsessionid = 4B151C685A0001 nas-port-id = 100 framedipaddress = 192.168.1.100 I am assuming the radius packet for #5 actually arrives before the accounting stop in #4, thus the accounting-stop then marks the IP free, and the problem occurs. Bah. I can probably work around this by unallocating the "allocate-clear" query in rlm_sqlippool. Sick..
Phil Mayers wrote:
Phil Mayers wrote:
All,
I've just become aware of a rather annoying problem with our PPTP VPN server. Sometimes, a client will connect, disconnect and reconnect in quick succession. In these circumstances, there seems to be a window which an IP can remain allocated to a live VPN session, but is marked as free in the SQL table, causing subsequent clients to connect, be allocated the IP, and fail to get any connectivity.
ACK!
Shortly after sending this email, we found the problem and it's truly vile. It's nothing to do with FreeRadius at all, except tangentially - what's actually happening is that the PPTP client is closing the PPP LCP layer and re-opening it on the same PPTP control/data channel.
This results in a very rapid set of:
Ugh. Even worse, it doesn't actually re-authenticate the user; it actually just tears down the IPCP layer, and then brings it back up again USING THE SAME IP. Of course, since the "stop-clear" query has run at that point and re-set the pool_key column to "0", so the 2nd accounting start doesn't re-allocate the IP. That is, it does: access-request allocate-ip update pool set nas=%{NAS},pool_key=${pool-key} where ip=%I accounting-start update pool set expires=now()+x where nas=%{NAS} and pool_key=${pool-key} accounting-stop update pool set expires=now()-1,pool_key=0 where nas=%{NAS} and pool_key=${pool-key} accounting-start update pool set expires=now()+x where nas=%{NAS} and pool_key=${pool-key} FAILS because pool_key=0 now Bah. Bah bah bah.
Phil Mayers wrote:
Ugh. Even worse, it doesn't actually re-authenticate the user; it actually just tears down the IPCP layer, and then brings it back up again USING THE SAME IP. Of course, since the "stop-clear" query has run at that point and re-set the pool_key column to "0", so the 2nd accounting start doesn't re-allocate the IP.
Is there a MAC in the Access-Request? If so, the IPPool module *should* save "last allocated MAC". The preference for allocation should be: 1) previously unallocated IP (no MAC associated with it) 2) unused (MAC associated with it), ordered by last time it was released (prefer older IPs) That will maximize the re-use, and minimize the conflict. Surprisingly enough, the same algorithm is useful for DHCP, too. :) Alan DeKok.
Alan DeKok wrote:
Phil Mayers wrote:
Ugh. Even worse, it doesn't actually re-authenticate the user; it actually just tears down the IPCP layer, and then brings it back up again USING THE SAME IP. Of course, since the "stop-clear" query has run at that point and re-set the pool_key column to "0", so the 2nd accounting start doesn't re-allocate the IP.
Is there a MAC in the Access-Request? If so, the IPPool module
Sadly not. It's from pptp (pppd) radius.so plugin, so the requests basically only contain: User-Name NAS-IP-Address NAS-Port = pppd_pty# Calling-Station-Id = the.vpn.client.ip Framed-IP-Address For the moment I've worked around it by changing the stop-clear query from: UPDATE ${ippool_table} SET \ nasipaddress = '', pool_key = 0, callingstationid = '' \ expiry_time = 'now'::timestamp(0) - '1 second'::interval ...to: UPDATE ${ippool_table} SET \ expiry_time = 'now'::timestamp(0) - '1 second'::interval This allows the start-update query to "re-claim" the IP allocation. It should also be safe, since in my case the pool-key option is "NAS-Port" and the allocate-clear query will zero out any spurious / dead sessions before the accounting gets a chance to "eat" them. Still - I'll admit to finding it a bit worrying. There are clearly cases when IPs can get lost. The other options are to base the "WHERE" clause on the framedipaddress, which in my case is always present in the accounting.
Phil Mayers wrote:
Is there a MAC in the Access-Request? If so, the IPPool module
Sadly not. It's from pptp (pppd) radius.so plugin, so the requests basically only contain:
Ugh. We should fix that to send the MAC in the Calling-Station-Id, rather than sending the IP address. Alan DeKok.
participants (2)
-
Alan DeKok -
Phil Mayers