forked from FreeRADIUS/freeradius-server
-
Notifications
You must be signed in to change notification settings - Fork 0
Coa Single Tunnel feature. #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
vcargats
wants to merge
14
commits into
v3.0.x
Choose a base branch
from
coa_single_tunnel
base: v3.0.x
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Added two new types: auth+coa and auth+acct+coa. For listen section added CoA retransmission config same way it is done for home_server. So that TCP server is able to send/retransmit CoA requests with some pattern. For home_server section, coa subsection added a virtual_server option to be able to process coa messages in unlang config.
-) If a listener is a TCP server, then I am reversing it at dual_tcp_accept function. -) If a listener is a TCP client, then I am reversing it at proxy_new_listener function. To reverse I am duplicating original listener, change its type to RAD_LISTEN_PROXY or RAD_LISTEN_COA and change the write callback. Reading is always performed on the original listener. The new write functions are in the following commit. For RAD_LISTEN_PROXY reversed listener we need additionally create home_server to be used later while originating CoA. For RAD_LISTEN_COA reversed listener we need additionally create client to be used later while receiving CoA/Disconnect requests.
Once I have a 'reverse' listener I need to be able to store that. That is done either by key (TCP-Session-Key) or by address. An address means just an IP here. Note I store a list in the tree, so that several listeners may share the same key or IP address. If this is the case and several listeners share the same key or IP address then I select a next listener to be used (to send CoA request) in a round-robin fashion. So that if switch has several tunnels (and they all are exactly equal for us) we will evenly split the load between them. For IP use case I have added an option to explicitly specify port number, in which case it is possible to select exact listener without any round-robin.
I am able to store the listener by address as soon as I have it reversed (because I know an IP right away). At the same time, I need to wait for a special attribute (and special packet optionally (Status-Server)) to be able to store reverse listener by its key. I need to add internal attribute here as well so that to be able to configure the key.
First the original flow tries to find a home_server where to send a CoA. It is done either by IP(port) or by Home-Server/Home-Pool reference. If that failed we are trying to find a reverse tunnel to send the CoA to. That is done either by IP and optionally port or by a key that may be set from TCP-Session-Key earlier. If such reverse tunnel is found we may get a home_server from this reversed listener. Home-Server has been previously created when we have reversed the listener. From now on original flow continues as if the home_server has been found with the old approach. The difference is in insert_into_proxy_hash function where we are trying to allocate an ID for the request *and* to setup a proxy listener to be used to actually send the CoA. Since we already have known this proxy listener to be used (this is our 'reversed' listener) we don't need to setup it. We need just to allocate an ID. The limitation here is that we *must* use a specific tunnel only. Hence, we cannot send more than 256 CoA request at the same time. In the original flow freeRADIUS may open another connection if all IDs are allocated for a particular listener/connection. We have no such option within this feature since by definition we *must* use single tunnel to send CoAs. Potential workaround is the case when *switch* opens several tunnels. If these tunnels are equal and may process all CoAs interchangeably, then if all IDs have been already allocated for the current reversed listener we may try another reverse listener if available. In the end of the flow a send function pointer is called. This send callback is different for the reversed listener compared to the original listener. This is specified in the next commit. Stay tuned.
TCP Server (RAD_LISTEN_AUTH type) had a pair of functions
-) dual_tls_recv - receives requests
-) dual_tls_send - sends *responses*
So we need to make sure we may *send* requests as well. For that a new function is introduced: dual_tls_send_req.
For recv part - we simply cannot differentiate a packet until we actually read it, so the receiving is always happening
on the original listener. Once a packet is received we may check its type and if required (for CoA/Disconnect process it with the reversed
listener.
The similar logic applies for TCP Client (RAD_LISTEN_PROXY). So it had a pair:
-) proxy_tls_recv - receives responses
-) proxy_tls_send - sends *requests*
So new function is introduced to send *responses* instead of requests: proxy_tls_send_reply.
At the same time original proxy_tls_recv should be able to receive not just responses but also requests. If
CoA/Disconnect request packet type is detected we run the request flow with the reversed listener. Not that in that case
(since we are working with the reversed listener) at the time the flow ends and ready to send a "response", a new
version of send is called: proxy_tls_send_reply.
Good thing here is that read/write is protected by mutex that belongs to socket struct which is exactly the same for
main(original) and reversed listeners.
Minor caveat here. I has to delete/revert your changes. Some time ago you have removed unused variable sockfd, since
that may be obtained from the request argument. Now the sockfd would be different for dual_tls_send_req. At first
I wanted to delete *request argument, but it it is used for debug printing. Some other option would be to set sockfd in
request->packet->sockfd, but I have decided that would not be clean... well with all pros and cons I have just returned
sockfd as a third argument.
Each listener has its own lifecycle enum state assigned. Now we have a reversed listener. We need to make sure the states of these two are in sync. That also means that if some actions are required to be done as lifecycle state is changed similar actions should be made for both main(original) and reversed listeners (check event_new_fd function).
With that RADSEC is not working at all. The issue is in this commit: FreeRADIUS@b6d7249 it pretends to revert erroneously deleted lines from another commit: FreeRADIUS@f9c2f5a The thing is that it is not only reverting deleted lines, it also adds fr_nonblock(fd) call in tls_new_client_session. Was that done by mistake? With that SSL_connect exits immediately while we are trying to send initial Access-Request packet in proxy_tls_send. Of course at the this time the handshake is not yet finished and SSL_connect returns with an error. SSL_connect will return success just on the following reads in proxy_tls_recv. But here we are in the recv callback, handlshake is done... so what, we don't have any packet to send. I have deleted this fr_nonblock(fd) call meanwhile.
Some other stuff: -) Add version information -) Add feature reference in Doxygen
vcargats
commented
Mar 30, 2021
Comment on lines
+404
to
+409
| coa { | ||
| irt = 2 | ||
| mrt = 16 | ||
| mrc = 5 | ||
| mrd = 30 | ||
| } |
Owner
Author
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment out by default
Instead of using reverse listeners, replace all send/encode/decode with send_proxy/encode_proxy/decode_proxy for the 'proxy' flows. Regularly only a one of this callback will be set. For example either send or send_proxy. For 'with_coa' listeners both will be set.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The flow is like follows:
Radclient sends plain RADIUS Access-Request to Proxy Server. Proxy Server then proxies this authentication request with
RADSEC to Home Server. While Sending Access-Request Proxy Server opens a TLS tunnel. This tunnel will be used later to
accept CoA requests from Home Server.
Radclient sends plain RADIUS CoA request to Home Server. Home Server originates CoA request to Proxy Server with RADSEC.
This is the new flow where Proxy Server can accept CoA requests from Home Server within the same tunnel that it
has opened to send Access-Request. And of course, Home Server can send CoA requests within the same tunnel. In this
case, the Proxy Server is still a TCP client yet in terms of RADIUS protocol it acts as a CoA Server.
Home Server may select a tunnel to send a CoA either by new internal attribute TCP-Session-Key, or by source IP address and possibly port.
Then Proxy Server forwards a CoA request to CoA Server to complete the flow. To be precise CoA Server responds with
CoA-ACK, then in turn Proxy Server responds with CoA-ACK to Home Server within the same TLS tunnel once opened for
initial Access-Request. Here the flow completes.
The main idea is to 'reverse' a listener (rad_listen_t) and then use it in the 'reversed' flows. Say if we are the
TCP server and
(a) processing requests, and (b) sending replies,
then a 'reversed' listener is responsible for:
(a) sending requests (CoA/Disconnect-Request), and (b) processing replies (CoA/Disconnect-ACK/NAK).
On the contrary, if we are the TCP client and
(a) sending requests and (b) processing replies,
then a 'reversed' listener is responsible for
(a) processing requests (CoA/Disconnect-Request), and (b) sending replies (CoA/Disconnect-ACK/NAK).