RADIUS Load Balancing

Problem this snippet solves:

An iRule to load balance RADIUS requests.

Code :

when RULE_INIT {
  array set ::msg_types {
    1 "Access-Request"
    2 "Access-Accept"
    3 "Access-Reject"
    4 "Accounting-Request"
    5 "Accounting-Response"
    11 "Access-Challenge"
    12 "Status-Server"
    13 "Status-Client"
    255 "Reserved"
  }

  array set ::attr_types {
    1 "RADIUS_ATTR_USER_NAME"
    2 "RADIUS_ATTR_USER_PASSWORD"
    4 "RADIUS_ATTR_NAS_IP_ADDRESS"
    5 "RADIUS_ATTR_NAS_PORT"
    6 "Service-Type"
    7 "Framed-Protocol"
    8 "Framed-IP-Address"
    9 "Framed-IP-Netmask"
    10 "Framed-Routing"
    11 "Filter-Id"
    12 "RADIUS_ATTR_FRAMED_MTU"
    13 "Framed-Compression"
    14 "Login-IP-Host"
    15 "Login-Service"
    16 "Login-TCP-Port"
    24 "RADIUS_ATTR_STATE"
    25 "RADIUS_ATTR_CLASS"
    26 "RADIUS_ATTR_VENDOR_SPECIFIC"
    27 "RADIUS_ATTR_SESSION_TIMEOUT"
    28 "RADIUS_ATTR_IDLE_TIMEOUT"
    29 "RADIUS_ATTR_TERMINATION_ACTION"
    30 "RADIUS_ATTR_CALLED_STATION_ID"
    31 "RADIUS_ATTR_CALLING_STATION_ID"
    32 "RADIUS_ATTR_NAS_IDENTIFIER"
    40 "RADIUS_ATTR_ACCT_STATUS_TYPE"
    41 "RADIUS_ATTR_ACCT_DELAY_TIME"
    42 "RADIUS_ATTR_ACCT_INPUT_OCTETS"
    43 "RADIUS_ATTR_ACCT_OUTPUT_OCTETS"
    44 "RADIUS_ATTR_ACCT_SESSION_ID"
    45 "RADIUS_ATTR_ACCT_AUTHENTIC"
    46 "RADIUS_ATTR_ACCT_SESSION_TIME"
    47 "RADIUS_ATTR_ACCT_INPUT_PACKETS"
    48 "RADIUS_ATTR_ACCT_OUTPUT_PACKETS"
    49 "RADIUS_ATTR_ACCT_TERMINATE_CAUSE"
    50 "RADIUS_ATTR_ACCT_MULTI_SESSION_ID"
    51 "RADIUS_ATTR_ACCT_LINK_COUNT"
    52 "RADIUS_ATTR_ACCT_INPUT_GIGAWORDS"
    53 "RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS"
    55 "RADIUS_ATTR_EVENT_TIMESTAMP"
    61 "RADIUS_ATTR_NAS_PORT_TYPE"
    64 "RADIUS_ATTR_TUNNEL_TYPE"
    65 "RADIUS_ATTR_TUNNEL_MEDIUM_TYPE"
    77 "RADIUS_ATTR_CONNECT_INFO"
    79 "RADIUS_ATTR_EAP_MESSAGE"
    80 "RADIUS_ATTR_MESSAGE_AUTHENTICATOR"
    81 "RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID"
    85 "RADIUS_ATTR_ACCT_INTERIM_INTERVAL"
    95 "RADIUS_ATTR_NAS_IPV6_ADDRESS"
  }
}

when CLIENT_DATA {
  if { [UDP::payload length] > 4 } {
    #log "UDP::payload length [UDP::payload length]"
    binary scan [UDP::payload] c hdr_code
    log "radius type  $::msg_types($hdr_code)"
    binary scan [UDP::payload] @20a* rest_string
    while { [string length $rest_string] >4} {
      binary scan $rest_string cca* attr_id attr_length rest_string
      scan $attr_length  %i length
      set ff [format "a%da*" [expr {$length} - 2]]
      switch $attr_id {
1 { #if the type of attrbuite is RADIUS_ATTR_USER_NAME
  binary scan $rest_string $ff attr_value rest_string
          log "attribute id:  $::attr_types($attr_id); attribute length: $length; value: $attr_value"
  persist uie $attr_value
}
4 { #if the type of attrbuite is RADIUS_ATTR_NAS_IP_ADDRESS
  binary scan $rest_string c4a* IPtmp rest_string
  set IP {}
  foreach num $IPtmp {
    lappend IP [expr ($num + 0x100) % 0x100]
  }
  set attr_value [join $IP .]
  log "$::attr_types($attr_id) value $attr_value"
}
default {
  binary scan $rest_string $ff attr_value rest_string
                 #log "attribute id:  $::attr_types($attr_id); attribute length: $length; filed value: $attr_value"
}
            }   
}
    } 
}

when SERVER_DATA {
  if { [UDP::payload length] > 4 } {
    #log "UDP::payload length [UDP::payload length]"
    binary scan [UDP::payload] c hdr_code
    log "radius type  $::msg_types($hdr_code)"
    binary scan [UDP::payload] @20a* rest_string
    while { [string length $rest_string] >4} {
      binary scan $rest_string cca* attr_id attr_length rest_string
      scan $attr_length  %i length
      set ff [format "a%da*" [expr {$length} - 2]]
  switch $attr_id {
1 { #if the type of attrbuite is RADIUS_ATTR_USER_NAME
  binary scan $rest_string $ff attr_value rest_string
                  log "attribute id:  $::attr_types($attr_id); attribute length: $length; value: $attr_value"
}
4 - 
8 - 
9 { # 4 "RADIUS_ATTR_NAS_IP_ADDRESS" 8 "Framed-IP-Address"  9 "Framed-IP-Netmask"
  binary scan $rest_string c4a* IPtmp rest_string
  set IP {}
  foreach num $IPtmp {
     lappend IP [expr ($num + 0x100) % 0x100]
  }
  set attr_value [join $IP .]
  log "$::attr_types($attr_id) value $attr_value"
}
default {
  binary scan $rest_string $ff attr_value rest_string
                 #log "attribute id:  $::attr_types($attr_id); attribute length: $length; filed value: $attr_value"
}
            }   
}
    } 
}
Published Mar 18, 2015
Version 1.0
  • In version 10.x and later, the global array variables (::msg_types and ::attr_types) should instead be defined in the static:: namespace (static::msg_types and static::attr_types, respectively). This will allow CMP compatibility.