networking n stuff

Saturday, October 14, 2017

Configuring CoA: Juniper MX + FreeRADIUS

Recently I had to configure CoA on Juniper and was surprised by how vague the coverage of this topic is. Juniper's Day One on CoA is not bad, however, in my opinion, sometimes it's focusing on unnecessary details while missing the important ones.

As you probably already know, CoA, or Change of Authorization allows you to modify subscribers sessions "on the flight", without having to disrupt the session. CoA is usually used together with some kind of billing software, so you can implement all kinds of things - for example, implement time-scheduled rate-limiting (imagine, for example, that you as ISP provide a tariff that allows unlimited speed at particular hours and lower speeds at all other time), or abrupting internet access as soon as there's no money left on client's account...and so on.


My topology is as simple as possible and looks like this:





Note I'm using one server as both authorization and accounting server, but this is NOT a requirement. You can as well have one server for accounting and another one for authorization. I'll cover the difference and show you in detail what each part is responsible for later.

I'm going to use CoA the same way they do it in Day One: simply change client's rate, so here's a basic configuration I'll need: dynamic profile, DHCP server, RADIUS accounting & authorization and two policers:

root# show interfaces ge-0/0/0 
unit 0 {
    demux-source inet;
    family inet {
        unnumbered-address lo0.0;
    }
}

root# show access-profile 

Access-Profile-1;

root# show access 
profile Access-Profile-1 {
    accounting-order radius;
    authentication-order radius;
    }
    radius {
        authentication-server 172.20.30.3;
        accounting-server 172.20.30.3;
    }
    radius-server {
        172.20.30.3 {
            secret  ## SECRET-DATA
            timeout 2;
            retry 3;
            max-outstanding-requests 200;
            source-address 172.20.30.1;
        }
    }
    accounting {
        order radius;
        immediate-update;
        coa-immediate-update;
        update-interval 10;
        statistics volume-time;
        send-acct-status-on-config-change;
    }
}

root# show dynamic-profiles DHCP 
interfaces {
    demux0 {
        unit "$junos-interface-unit" {
            demux-options {
                underlying-interface "$junos-underlying-interface";
            }
            family inet {
                demux-source {
                    $junos-subscriber-ip-address;
                }
                filter {
                    output "$junos-output-filter";
                }
                unnumbered-address "$junos-loopback-interface";
            }
        }
    }
}

root# show system services dhcp-local-server 
authentication {
    password iamsecret;
    username-include {
        mac-address;
    }
}
group 1 {
    dynamic-profile DHCP;
    interface ge-0/0/0.0;

}

root# show access address-assignment 
pool mypool {
    family inet {
        network 100.64.0.0/14;
        range R1 {
            low 100.64.0.10;
            high 100.65.200.255;
        }
        dhcp-attributes {
            maximum-lease-time 600;
            name-server {
                8.8.8.8;
            }
            router {
                100.64.0.1;
            }
        }
    }

}

root# show firewall 
family inet {
    filter limit2m {
        interface-specific;
        term limit {
            then policer police2m;
        }
    }
    filter limit5m {
        interface-specific;
        term limit {
            then policer police5m;
        }
    }
}
policer police2m {
    if-exceeding {
        bandwidth-limit 2m;
        burst-size-limit 100k;
    }
    then discard;
}
policer police5m {
    if-exceeding {
        bandwidth-limit 5m;             
        burst-size-limit 500k;
    }
    then discard;
}

This is my very basic config for RADIUS: users

0050.0000.0a00 Cleartext-Password := "iamsecret"
            ERX-Egress-Policy-Name := limit2m

and clients.conf:

client 172.30.3.0/24 {
            secret = iamsecret
       }

You don't have to configure CoA on server, we're going to use radclient for sending CoA requests.

Let's ensure our client is up and running, the policer is applied:

root# run show subscribers 
Interface           IP Address/VLAN ID                      User Name                      LS:RI
demux0.3221232096   100.64.0.10                             0050.0000.0a00            default:default      

root# run show subscribers interface demux0.3221232096 extensive 
Type: DHCP
User Name: 0050.0000.0a00
IP Address: 100.64.0.10
IP Netmask: 255.252.0.0
Domain name server inet: 8.8.8.8 
Logical System: default
Routing Instance: default
Interface: demux0.3221232096
Interface type: Dynamic
Underlying Interface: ge-0/0/0.0
Dynamic Profile Name: DHCP
Dynamic Profile Version: 2
MAC Address: 00:50:00:00:0a:00
Idle Timeout (seconds): 3600
Idle Timeout Ingress Only: FALSE
State: Active
Radius Accounting ID: 11728
Session ID: 11728
PFE Flow ID: 6849
Login Time: 2017-10-14 18:26:17 UTC
DHCP Options: len 37
35 01 01 32 04 64 40 00 0a 0c 0b 73 65 72 76 65 72 2d 75 62
6e 74 37 0d 01 1c 02 03 0f 06 77 0c 2c 2f 1a 79 2a 
IP Address Pool: mypool             
IPv4 Output Filter Name: limit2m-demux0.3221232096-out
Accounting interval: 600
Dynamic configuration: 
  junos-output-filter: limit2m

Cool. Now, I suggest you don't need clarification on what exactly authentication server is doing, but you might be unclear about what MX sends to accounting server. Let's take a look at Accounting-Request (this output is cut):


Some of the fields are similar to what you'd see in authentication Access-Request, but there's also other fields like input octets and session time (their names are self-explanatory, I guess). According to our configuration MX will send this requests to accounting server at every 10 minutes. Now, we don't really need to dig into it to implement CoA request, that's just to show you what is this thing even for and what it contains.

Now, to sending CoA.
There's three required attributes without which MX will not accept CoA-request. These attributes are:
  • username
  • nas-identifier
  • accounting-session ID.
Don't be confused by the last one.  You can see it in the output of the show subscribers extensive.

This is what my final request which I issue on server looks like:

echo User-Name="0050.0000.0a00", Nas-Identifier="172.20.30.1", Acct-Session-Id="11728", ERX-Egress-Policy-Name="limit5m" | radclient -d /usr/share/freeradius/ -sx 172.20.30.1 coa iamsecret

Radclient allows to see results immediately:

Sending CoA-Request of id 24 to 172.20.30.1 port 3799
        User-Name = "0050.0000.0a00"
        NAS-Identifier = "172.20.30.1"
        Acct-Session-Id = "11728"
        ERX-Egress-Policy-Name = "limit5m"

rad_recv: CoA-ACK from host 172.20.30.1 port 3799, id=139, length=20
           Total approved auths:  1
           Total denied auths:  0
           Total lost auths:  0

Let's perform a check on client:

root# run show subscribers interface demux0.3221232096 extensive    
Type: DHCP
User Name: 0050.0000.0a00
IP Address: 100.64.0.10
IP Netmask: 255.252.0.0
Domain name server inet: 8.8.8.8 
Logical System: default
Routing Instance: default
Interface: demux0.3221232096
Interface type: Dynamic
Underlying Interface: ge-0/0/0.0
Dynamic Profile Name: DHCP
Dynamic Profile Version: 2
MAC Address: 00:50:00:00:0a:00
Idle Timeout (seconds): 3600
Idle Timeout Ingress Only: FALSE
State: Active
Radius Accounting ID: 11728
Session ID: 11728
PFE Flow ID: 6849
Login Time: 2017-10-14 18:26:17 UTC
DHCP Options: len 37
35 01 01 32 04 64 40 00 0a 0c 0b 73 65 72 76 65 72 2d 75 62
6e 74 37 0d 01 1c 02 03 0f 06 77 0c 2c 2f 1a 79 2a 
IP Address Pool: mypool                
IPv4 Output Filter Name: limit5m-demux0.3221232096-out
Accounting interval: 600
Dynamic configuration: 
  junos-output-filter: limit5m

Great.

Note that although here for the sake of simplicity I use CoA to change policy name, noone really implements it that way in a real networks. In a real world this is done with dynamic-profiles - you create several dynamic profiles (which can contain policers, or access-lists, or redirection rules..) for each case and when you need to change them you send CoA request with a name of profile.

In case something goes wrong traceoptions is your best friend:

root# show system processes 
general-authentication-service {
    traceoptions {
        file RADD;
        flag all;
    }
}

For instance:
run show log RADD | last 500

<...>

 ============ CoA/Disconnect Callback =================
Oct 14 19:23:53.089623 dyn_req_disconnect_cb attributes remote_addr:(172.20.30.3) remote_port:(58841), rtbl_idx:(0)
Oct 14 19:23:53.089648 authd_extract_identifier_avps received AVP type:1 val:0050.0000.0a00 len:14
Oct 14 19:23:53.089658 authd_extract_identifier_avps: User-Name=0050.0000.0a00
Oct 14 19:23:53.089665 authd_extract_identifier_avps received AVP type:32 val:172.20.30.1 len:11
Oct 14 19:23:53.089673 authd_extract_identifier_avps received AVP type:44 val:1178 len:4
Oct 14 19:23:53.089681 authd_extract_identifier_avps: Acct-Session-Id=1178
Oct 14 19:23:53.089688 authd_extract_identifier_avps received AVP type:26 val: len:13
Oct 14 19:23:53.089799 findSession AST-Table couldn't find the session-id:1178
Oct 14 19:23:53.089821 authd_lookup_session_entry: No session entry found for acct-session-id:1178
Oct 14 19:23:53.089847 nak_error_cause 503 ret_val 0
Oct 14 19:23:53.090149 authd_auth_aaa_msg_destruct auth_aaa_msg: 0x94f95d8

No comments:

Post a Comment