Modifying accounting request with vendor-specific attribute

Kruz Gaffaney GaffaneyK at rconnects.net
Wed Jan 17 23:07:14 UTC 2024


Hi Alan, thanks for your patience. Using regex makes a lot of sense. I removed my custom policy and replaced it with what you sent over, I double checked it with a regex tester online and looks like it matches correctly, though I'm see a new issue with the debug saying the condition is false.

Canonicalization file:

[root at ces-vs-isp-radius3 policy.d]# cat canonicalization
#
#       Split User-Name in NAI format (RFC 4282) into components
#
#  This policy writes the Username and Domain portions of the
#  NAI into the Stripped-User-Name and Stripped-User-Domain
#  attributes.
#
#  The regular expression to do this is not strictly compliant
#  with the standard, but it is not possible to write a
#  compliant regexp without perl style regular expressions (or
#  at least not a legible one).
#
nai_regexp = '^([^@]*)(@([-[:alnum:]]+\.[-[:alnum:].]+))?$'

split_username_nai {
        if (&User-Name && (&User-Name =~ /${policy.nai_regexp}/)) {
                update request {
                        &Stripped-User-Name := "%{1}"
                }

                # Only add the Stripped-User-Domain attribute if
                # we have a domain. This means presence checks
                # for Stripped-User-Domain work.
                if ("%{3}" != '') {
                        update request {
                                &Stripped-User-Domain = "%{3}"
                        }
                }

                # If any of the expansions result in a null
                # string, the update section may return
                # something other than updated...
                updated
        }
        else {
                noop
        }
}

#
#  If called in post-proxy we modify the proxy-reply message
#
split_username_nai.post-proxy {
        if (&proxy-reply:User-Name && (&proxy-reply:User-Name =~ /${policy.nai_regexp}/)) {
                update proxy-reply {
                        &Stripped-User-Name := "%{1}"
                }

                # Only add the Stripped-User-Domain attribute if
                # we have a domain. This means presence checks
                # for Stripped-User-Domain work.
                if ("%{3}" != '') {
                        update proxy-reply {
                                &Stripped-User-Domain = "%{3}"
                        }
                }
                updated
        }
        else {
                noop
        }
}

#
#  Normalize the MAC Addresses in the Calling/Called-Station-Id
#
mac-addr-regexp = '([0-9a-f]{2})[^0-9a-f]?([0-9a-f]{2})[^0-9a-f]?([0-9a-f]{2})[^0-9a-f]?([0-9a-f]{2})[^0-9a-f]?([0-9a-f]{2})[^0-9a-f]?([0-9a-f]{2})'

#
#  Add "rewrite_called_station_id" in the "authorize" and
#  "preacct" sections.
#
#  Makes Called-Station-ID conform to what RFC3580 says should
#  be provided by 802.1X authenticators.
#
rewrite_called_station_id {
        if (&Called-Station-Id && (&Called-Station-Id =~ /^${policy.mac-addr-regexp}([^0-9a-f](.+))?$/i)) {
                update request {
                        &Called-Station-Id := "%{toupper:%{1}-%{2}-%{3}-%{4}-%{5}-%{6}}"
                }

                # SSID component?
                if ("%{8}") {
                        update request {
                                &Called-Station-SSID := "%{8}"
                        }
                }
                updated
        }
        else {
                noop
        }
}

#
#  Add "rewrite_calling_station_id" in the "authorize" and
#  "preacct" sections.
#
#  Makes Calling-Station-ID conform to what RFC3580 says should
#  be provided by 802.1X authenticators.
#
rewrite_calling_station_id {
        if (&Calling-Station-Id && (&Calling-Station-Id =~ /^${policy.mac-addr-regexp}$/i)) {
                update request {
                        &Calling-Station-Id := "%{toupper:%{1}-%{2}-%{3}-%{4}-%{5}-%{6}}"
                }
                updated
        }
        else {
                noop
        }
}

custom_rewrite_calling_station_id {
        if (Cisco-AVPair =~ /client-mac-address=(.*)/) {
                update request {
                        Calling-Station-Id = "%{1}"
                }
        }
}

Debug:

(0) Received Accounting-Request Id 185 from 72.19.55.73:61651 to 216.155.208.69:1813 length 802
(0)   Acct-Interim-Interval = 60
(0)   Acct-Session-Time = 163500
(0)   Acct-Status-Type = Interim-Update
(0)   Event-Timestamp = "Jan 17 2024 14:51:11 PST"
(0)   NAS-Port-Type = Wireless-XGP
(0)   Cisco-AVPair = "pppoe-session-id=17305"
(0)   Cisco-AVPair = "client-mac-address=d8b6.b7e8.b2ee"
(0)   ADSL-Agent-Circuit-Id = 0x4e33362d312d352d38
(0)   Cisco-AVPair = "circuit-id-tag=N36-1-5-8"
(0)   Acct-Session-Id = "0046013c"
(0)   NAS-Port-Id = "0/0/10/3111"
(0)   Cisco-NAS-Port = "0/0/10/3111"
(0)   Called-Station-Id = "N36-1-5-8"
(0)   User-Name = "modem905496"
(0)   Acct-Authentic = RADIUS
(0)   Framed-IP-Address = 216.155.211.154
(0)   Cisco-AVPair = "vrf-id=default"
(0)   Cisco-AVPair = "accounting-list=AAA-GROUP-BNG-RADIUS-SERVERS"
(0)   Cisco-AVPair = "srg-group-id=10"
(0)   Framed-Protocol = PPP
(0)   Service-Type = Framed-User
(0)   X-Ascend-Connect-Progress = IPNCP-Opened
(0)   Cisco-AVPair = "connect-progress=IPCP Open"
(0)   Acct-Input-Octets = 1842870865
(0)   Acct-Input-Packets = 14378033
(0)   Acct-Output-Octets = 791579294
(0)   Acct-Output-Gigawords = 8
(0)   Acct-Output-Packets = 25259638
(0)   Cisco-AVPair = "acct-input-octets-ipv4=1468938988"
(0)   Cisco-AVPair = "acct-input-packets-ipv4=14375306"
(0)   Cisco-AVPair = "acct-output-octets-ipv4=134738370"
(0)   Cisco-AVPair = "acct-output-gigawords-ipv4=8"
(0)   Cisco-AVPair = "acct-output-packets-ipv4=25256876"
(0)   Cisco-AVPair = "acct-input-octets-ipv6=0"
(0)   Cisco-AVPair = "acct-input-packets-ipv6=0"
(0)   Cisco-AVPair = "acct-output-octets-ipv6=0"
(0)   Cisco-AVPair = "acct-output-packets-ipv6=0"
(0)   NAS-Identifier = "ASR9006A-EST"
(0)   NAS-IP-Address = 72.19.55.73
(0)   NAS-IPv6-Address = ::
(0)   Acct-Delay-Time = 44
(0) # Executing section preacct from file /etc/raddb/sites-enabled/default
(0)   preacct {
(0) preprocess: EXPAND ([0-9a-f]{2})[-:]?([0-9a-f]{2})[-:.]?([0-9a-f]{2})[-:]?([0-9a-f]{2})[-:.]?([0-9a-f]{2})[-:]?([0-9a-f]{2})
(0) preprocess:    --> ([0-9a-f]{2})[-:]?([0-9a-f]{2})[-:.]?([0-9a-f]{2})[-:]?([0-9a-f]{2})[-:.]?([0-9a-f]{2})[-:]?([0-9a-f]{2})
(0)     [preprocess] = ok
(0)     policy custom_rewrite_calling_station_id {
(0)       if (Cisco-AVPair =~ /client-mac-address=(.*)/) {
(0)       if (Cisco-AVPair =~ /client-mac-address=(.*)/)  -> FALSE
(0)     } # policy custom_rewrite_calling_station_id = ok
(0)     policy acct_unique {
(0)       update request {
(0)         &Tmp-String-9 := "ai:"
(0)       } # update request = noop
(0)       if (("%{hex:&Class}" =~ /^%{hex:&Tmp-String-9}/) &&       ("%{string:&Class}" =~ /^ai:([0-9a-f]{32})/i)) {
(0)       EXPAND %{hex:&Class}
(0)          -->
(0)       EXPAND ^%{hex:&Tmp-String-9}
(0)          --> ^61693a
(0)       if (("%{hex:&Class}" =~ /^%{hex:&Tmp-String-9}/) &&       ("%{string:&Class}" =~ /^ai:([0-9a-f]{32})/i))  -> FALSE
(0)       else {
(0)         update request {
(0)           EXPAND %{md5:%{User-Name},%{Acct-Session-ID},%{%{NAS-IPv6-Address}:-%{NAS-IP-Address}},%{NAS-Identifier},%{NAS-Port-ID},%{NAS-Port}}
(0)              --> 6d3022986abcd942249c2c0c95f42ffa
(0)           &Acct-Unique-Session-Id := 6d3022986abcd942249c2c0c95f42ffa
(0)         } # update request = noop
(0)       } # else = noop
(0)     } # policy acct_unique = noop
(0) suffix: Checking for suffix after "@"
(0) suffix: No '@' in User-Name = "modem905496", looking up realm NULL
(0) suffix: Found realm "NULL"
(0) suffix: Adding Stripped-User-Name = "modem905496"
(0) suffix: Adding Realm = "NULL"
(0) suffix: Proxying request from user modem905496 to realm NULL
(0) suffix: Preparing to proxy accounting request to realm "NULL"
(0)     [suffix] = updated
(0)     [files] = noop
(0)     update {
(0)       control:Replicate-To-Realm := plixer
(0)     } # update = noop
(0) replicate: Replicating list 'request' to Realm 'plixer'
(0)     [replicate] = ok
(0)   } # preacct = updated
(0) # Executing section accounting from file /etc/raddb/sites-enabled/default
(0)   accounting {
(0) detail: EXPAND /var/log/radius/radacct/%{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}}/detail-%Y%m%d
(0) detail:    --> /var/log/radius/radacct/72.19.55.73/detail-20240117
(0) detail: /var/log/radius/radacct/%{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}}/detail-%Y%m%d expands to /var/log/radius/radacct/72.19.55.73/detail-20240117
(0) detail: EXPAND %t
(0) detail:    --> Wed Jan 17 14:51:56 2024
(0)     [detail] = ok
(0)     [unix] = noop
(0) sql: EXPAND %{tolower:type.%{Acct-Status-Type}.query}
(0) sql:    --> type.interim-update.query
(0) sql: Using query template 'query'
rlm_sql (sql): Reserved connection (1)
(0) sql: EXPAND %{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}}
(0) sql:    --> modem905496
(0) sql: SQL-User-Name set to 'modem905496'
(0) sql: EXPAND UPDATE radacct SET acctupdatetime  = (@acctupdatetime_old:=acctupdatetime), acctupdatetime  = FROM_UNIXTIME(%{integer:Event-Timestamp}), acctinterval    = %{integer:Event-Timestamp} - UNIX_TIMESTAMP(@acctupdatetime_old), framedipaddress = '%{Framed-IP-Address}', acctsessiontime = %{%{Acct-Session-Time}:-NULL}, acctinputoctets = '%{%{Acct-Input-Gigawords}:-0}' << 32 | '%{%{Acct-Input-Octets}:-0}', acctoutputoctets = '%{%{Acct-Output-Gigawords}:-0}' << 32 | '%{%{Acct-Output-Octets}:-0}' WHERE AcctUniqueId = '%{Acct-Unique-Session-Id}'
(0) sql:    --> UPDATE radacct SET acctupdatetime  = (@acctupdatetime_old:=acctupdatetime), acctupdatetime  = FROM_UNIXTIME(1705531871), acctinterval    = 1705531871 - UNIX_TIMESTAMP(@acctupdatetime_old), framedipaddress = '216.155.211.154', acctsessiontime = 163500, acctinputoctets = '0' << 32 | '1842870865', acctoutputoctets = '8' << 32 | '791579294' WHERE AcctUniqueId = '6d3022986abcd942249c2c0c95f42ffa'
(0) sql: Executing query: UPDATE radacct SET acctupdatetime  = (@acctupdatetime_old:=acctupdatetime), acctupdatetime  = FROM_UNIXTIME(1705531871), acctinterval    = 1705531871 - UNIX_TIMESTAMP(@acctupdatetime_old), framedipaddress = '216.155.211.154', acctsessiontime = 163500, acctinputoctets = '0' << 32 | '1842870865', acctoutputoctets = '8' << 32 | '791579294' WHERE AcctUniqueId = '6d3022986abcd942249c2c0c95f42ffa'
rlm_sql_mysql: Rows matched: 1  Changed: 1  Warnings: 0
(0) sql: SQL query returned: success
(0) sql: 1 record(s) updated
rlm_sql (sql): Released connection (1)
Need 4 more connections to reach 10 spares
rlm_sql (sql): Opening additional connection (6), 1 of 26 pending slots used
rlm_sql_mysql: Starting connect to MySQL server
rlm_sql_mysql: Connected to database 'radius' on Localhost via UNIX socket, server version 10.4.18-MariaDB, protocol version 10
(0)     [sql] = ok
(0)     [exec] = noop
(0) attr_filter.accounting_response: EXPAND %{User-Name}
(0) attr_filter.accounting_response:    --> modem905496
(0) attr_filter.accounting_response: Matched entry DEFAULT at line 12
(0)     [attr_filter.accounting_response] = updated
(0)   } # accounting = updated
(0) Starting proxy to home server 52.38.74.115 port 1813
(0) server home.calix {
(0) }
(0) Proxying request to home server 52.38.74.115 port 1813 timeout 30.000000
(0) Sent Accounting-Request Id 68 from 0.0.0.0:60398 to 52.38.74.115:1813 length 807
(0)   Acct-Interim-Interval = 60
(0)   Acct-Session-Time = 163500
(0)   Acct-Status-Type = Interim-Update
(0)   Event-Timestamp = "Jan 17 2024 14:51:11 PST"
(0)   NAS-Port-Type = Wireless-XGP
(0)   Cisco-AVPair = "pppoe-session-id=17305"
(0)   Cisco-AVPair = "client-mac-address=d8b6.b7e8.b2ee"
(0)   ADSL-Agent-Circuit-Id = 0x4e33362d312d352d38
(0)   Cisco-AVPair = "circuit-id-tag=N36-1-5-8"
(0)   Acct-Session-Id = "0046013c"
(0)   NAS-Port-Id = "0/0/10/3111"
(0)   Cisco-NAS-Port = "0/0/10/3111"
(0)   Called-Station-Id = "N36-1-5-8"
(0)   User-Name = "modem905496"
(0)   Acct-Authentic = RADIUS
(0)   Framed-IP-Address = 216.155.211.154
(0)   Cisco-AVPair = "vrf-id=default"
(0)   Cisco-AVPair = "accounting-list=AAA-GROUP-BNG-RADIUS-SERVERS"
(0)   Cisco-AVPair = "srg-group-id=10"
(0)   Framed-Protocol = PPP
(0)   Service-Type = Framed-User
(0)   X-Ascend-Connect-Progress = IPNCP-Opened
(0)   Cisco-AVPair = "connect-progress=IPCP Open"
(0)   Acct-Input-Octets = 1842870865
(0)   Acct-Input-Packets = 14378033
(0)   Acct-Output-Octets = 791579294
(0)   Acct-Output-Gigawords = 8
(0)   Acct-Output-Packets = 25259638
(0)   Cisco-AVPair = "acct-input-octets-ipv4=1468938988"
(0)   Cisco-AVPair = "acct-input-packets-ipv4=14375306"
(0)   Cisco-AVPair = "acct-output-octets-ipv4=134738370"
(0)   Cisco-AVPair = "acct-output-gigawords-ipv4=8"
(0)   Cisco-AVPair = "acct-output-packets-ipv4=25256876"
(0)   Cisco-AVPair = "acct-input-octets-ipv6=0"
(0)   Cisco-AVPair = "acct-input-packets-ipv6=0"
(0)   Cisco-AVPair = "acct-output-octets-ipv6=0"
(0)   Cisco-AVPair = "acct-output-packets-ipv6=0"
(0)   NAS-Identifier = "ASR9006A-EST"
(0)   NAS-IP-Address = 72.19.55.73
(0)   NAS-IPv6-Address = ::
(0)   Acct-Delay-Time = 44
(0)   Proxy-State = 0x313835
Waking up in 0.2 seconds.



-----Original Message-----
From: Freeradius-Users <freeradius-users-bounces+gaffaneyk=rconnects.net at lists.freeradius.org> On Behalf Of Alan DeKok
Sent: Wednesday, January 17, 2024 1:24 PM
To: FreeRadius users mailing list <freeradius-users at lists.freeradius.org>
Subject: Re: Modifying accounting request with vendor-specific attribute

On Jan 17, 2024, at 4:11 PM, Kruz Gaffaney <GaffaneyK at rconnects.net> wrote:
> I've updated the policy to be the following;
> 
> custom_rewrite_calling_station_id {
>        update request {
>                Calling-Station-Id := &request:client-mac-address
>                }
>        }
> 
> Although now I'm running into a new error when running radius in debug;
> 
> /etc/raddb/policy.d/canonicalization[116]: Unknown attribute 'client-mac-address'

  i.e. you didn't see that attribute name show up in the debug output, but you put it into the "update" section anyways.

  It helps to follow instructions correctly.  It's also good to be familiar with how RADIUS works, and what it does.  i.e. what is an "attribute", versus the value for an attribute.

  When the server prints:

	User-Name = "foo"

  The "User-Name" string is the attribute name

  The "foo" string is the value of the User-Name attribute.

> ...
> (0) Received Accounting-Request Id 26 from 72.19.55.73:16444 to 216.155.208.69:1813 length 834

  This packet lists a bunch of attributes.  Which one needs to go into Calling-Station-ID?

  Let's read the debug output.

> (0)   Cisco-AVPair = "client-mac-address=5483.3a9a.f1d7"

  That seems relevant.  Except the attribute name isn't "client-mac-address", it's Cisco-AVPair.  This can be discovered by reading the debug output, and seeing what's there.

  So the problem statement is really:

a) find the Cisco-AVPair attribute

b) where the value contains client-mac-address

c) take text after the "=", and then

d) copy it to Calling-Station-Id.

  A methodical approach is likely to fix issues like this.  Trying random things, or inventing syntax is not likely to help.

  What you want do is to use a regular expression:

	if (Cisco-AVPair =~ /client-mac-address=(.*)/)  {
		update request {
			Calling-Station-Id = "%{1}"
		}
	}

  That's going to work.

  Alan DeKok.

-
List info/subscribe/unsubscribe? See http://www.freeradius.org/list/users.html

----------

This email has been scanned for spam and viruses by Proofpoint Essentials. Visit the following link to report this email as spam:
https://us2.proofpointessentials.com/app/report_spam.php?mod_id=11&mod_option=logitem&report=1&type=easyspam&k=k1&payload=53616c7465645f5f385347135a4d11d0829814aa4461684f6b3a0f07651d3ffc3b74a646da1ebfaad9ae54d94615575e3ca6e7464a9fde1d5bfa64aaaa064d1562e053c37f8b878d6a1dbf5406315d78f90f1331a2092b736474707b6274704148149cf01bbc952baaffd7c605c9b3c193b58615ff9ebd13185a8c597885630f682cbbf59ce5ad0206fc5f206514f2b844d935f3fe42b5f9bdc05f68900e4219



More information about the Freeradius-Users mailing list