Search code examples
freeradiusradius

How to add/copy VSAs (Vendor-Specific attributes) to outer channel of EAP reply in FreeRADIUS C module


I am adding VSAs programmatically to Access-Accept reply in my FreeRADIUS C module (More details here).

For debugging/troubleshooting purpose, I need a way to visually inspect the VSAs on the receiving end. The issue is that my clients are using inner tunnel protocols (PEAP and TTLS) over EAP outer channel, and the traffic sniffer tools, such as WireShark, show only outer channel data.

I understand there is a way to copy the attributes to the outer channel for this purpose but was unable to find the instructions or samples on how to do this.

UPDATE: This is to address Arran's answer below. While I'm sure that Arran is right in saying that unlang is the preferred method, it is not applicable to my situation - the set of VSAs I need to send to NAS in my reply is defined outside of FreeRADIUS server, and is passed on to the C module at run time based on the user being authenticated. This is why I'm looking for a way to do this programmatically.


Solution

  • I wouldn't recommend doing this programatically within your module, unless for some reason it can only over be called within the inner-tunnel server. Instead, you should place your attributes in the request or reply list of the inner tunnel request and then copy them to the outer request using unlang.

    The easiest way to copy attributes from the inner to outer tunnels is using the outer.session-state list. This list persists throughout the multiple Access-Request/Access-Challenge rounds of an EAP authentication attempt.

    If you want to return attributes in the final Access-Accept, place them in the outer.session-state list using the unlang update keyword from within the inner-tunnel virtual server.

    In the outer virtual server in the Post-Auth section, copy the attributes from the outer request's session-state list over to the reply list. This will ensure your VSAs are only sent in the final Access-Accept/Access-Reject and not in any of the intermediary Access-Challenge packets.

    The inner virtual server:

    server inner {
        post-auth {
            <your_custom_module>
            update outer.session-state {
                <custom attribute> := &reply:<custom attribute>
            }
        }
    }
    

    The outer virtual server:

    server {
        post-auth {
            update reply {
                <custom attribute> := &session-state:<custom attribute>
            }
        }
    }
    

    UPDATE - If you don't know which attributes you'll be returning in advance you can do a whole list copy.

    server inner {
        post-auth {
            <your_custom_module>
            update {
                &outer.session-state: += &reply:[*]
            }
        }
    }