2020-03-02 23:30:09 +01:00
|
|
|
package radius
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Type is the RADIUS attribute type.
|
|
|
|
type Type int
|
|
|
|
|
|
|
|
// TypeInvalid is a Type that can be used to represent an invalid RADIUS
|
|
|
|
// attribute type.
|
|
|
|
const TypeInvalid Type = -1
|
|
|
|
|
2021-01-26 00:00:53 +01:00
|
|
|
// AVP is an attribute-value pair.
|
|
|
|
// It contains an attribute type and its wire data.
|
|
|
|
type AVP struct {
|
|
|
|
Type
|
|
|
|
Attribute
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attributes is a list of RADIUS attributes.
|
|
|
|
type Attributes []*AVP
|
2020-03-02 23:30:09 +01:00
|
|
|
|
|
|
|
// ParseAttributes parses the wire-encoded RADIUS attributes and returns a new
|
|
|
|
// Attributes value. An error is returned if the buffer is malformed.
|
|
|
|
func ParseAttributes(b []byte) (Attributes, error) {
|
2021-01-26 00:00:53 +01:00
|
|
|
var attrs Attributes
|
2020-03-02 23:30:09 +01:00
|
|
|
|
|
|
|
for len(b) > 0 {
|
|
|
|
if len(b) < 2 {
|
|
|
|
return nil, errors.New("short buffer")
|
|
|
|
}
|
|
|
|
length := int(b[1])
|
|
|
|
if length > len(b) || length < 2 || length > 255 {
|
|
|
|
return nil, errors.New("invalid attribute length")
|
|
|
|
}
|
|
|
|
|
2021-01-26 00:00:53 +01:00
|
|
|
avp := &AVP{
|
|
|
|
Type: Type(b[0]),
|
|
|
|
}
|
2020-03-02 23:30:09 +01:00
|
|
|
if length > 2 {
|
2021-01-26 00:00:53 +01:00
|
|
|
avp.Attribute = append(Attribute(nil), b[2:length]...)
|
2020-03-02 23:30:09 +01:00
|
|
|
}
|
2021-01-26 00:00:53 +01:00
|
|
|
attrs = append(attrs, avp)
|
2020-03-02 23:30:09 +01:00
|
|
|
|
|
|
|
b = b[length:]
|
|
|
|
}
|
|
|
|
|
|
|
|
return attrs, nil
|
|
|
|
}
|
|
|
|
|
2021-01-26 00:00:53 +01:00
|
|
|
// Add appends the given Attribute to the list of attributes.
|
|
|
|
func (a *Attributes) Add(key Type, value Attribute) {
|
|
|
|
*a = append(*a, &AVP{
|
|
|
|
Type: key,
|
|
|
|
Attribute: value,
|
|
|
|
})
|
2020-03-02 23:30:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Del removes all Attributes of the given type from a.
|
2021-01-26 00:00:53 +01:00
|
|
|
func (a *Attributes) Del(key Type) {
|
|
|
|
for i := 0; i < len(*a); {
|
|
|
|
if (*a)[i].Type == key {
|
|
|
|
*a = append((*a)[:i], (*a)[i+1:]...)
|
|
|
|
} else {
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
}
|
2020-03-02 23:30:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get returns the first Attribute of Type key. nil is returned if no Attribute
|
|
|
|
// of Type key exists in a.
|
2021-01-26 00:00:53 +01:00
|
|
|
func (a *Attributes) Get(key Type) Attribute {
|
2020-03-02 23:30:09 +01:00
|
|
|
attr, _ := a.Lookup(key)
|
|
|
|
return attr
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lookup returns the first Attribute of Type key. nil and false is returned if
|
|
|
|
// no Attribute of Type key exists in a.
|
2021-01-26 00:00:53 +01:00
|
|
|
func (a *Attributes) Lookup(key Type) (Attribute, bool) {
|
|
|
|
for _, attr := range *a {
|
|
|
|
if attr.Type == key {
|
|
|
|
return attr.Attribute, true
|
|
|
|
}
|
2020-03-02 23:30:09 +01:00
|
|
|
}
|
2021-01-26 00:00:53 +01:00
|
|
|
return nil, false
|
2020-03-02 23:30:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set removes all Attributes of Type key and appends value.
|
2021-01-26 00:00:53 +01:00
|
|
|
func (a *Attributes) Set(key Type, value Attribute) {
|
|
|
|
foundKey := false
|
|
|
|
for i := 0; i < len(*a); {
|
|
|
|
if (*a)[i].Type == key {
|
|
|
|
if foundKey {
|
|
|
|
*a = append((*a)[:i], (*a)[i+1:]...)
|
|
|
|
} else {
|
|
|
|
(*a)[i] = &AVP{
|
|
|
|
Type: key,
|
|
|
|
Attribute: value,
|
|
|
|
}
|
|
|
|
foundKey = true
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
i++
|
2020-03-02 23:30:09 +01:00
|
|
|
}
|
|
|
|
}
|
2021-01-26 00:00:53 +01:00
|
|
|
if !foundKey {
|
|
|
|
a.Add(key, value)
|
|
|
|
}
|
|
|
|
}
|
2020-03-02 23:30:09 +01:00
|
|
|
|
2021-01-26 00:00:53 +01:00
|
|
|
func (a Attributes) encodeTo(b []byte) {
|
|
|
|
for _, attr := range a {
|
|
|
|
if attr.Type < 0 || 255 < attr.Type || len(attr.Attribute) > 253 {
|
|
|
|
continue
|
2020-03-02 23:30:09 +01:00
|
|
|
}
|
2021-01-26 00:00:53 +01:00
|
|
|
size := 1 + 1 + len(attr.Attribute)
|
|
|
|
b[0] = byte(attr.Type)
|
|
|
|
b[1] = byte(size)
|
|
|
|
copy(b[2:], attr.Attribute)
|
|
|
|
b = b[size:]
|
2020-03-02 23:30:09 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-26 00:00:53 +01:00
|
|
|
// AttributesEncodedLen returns the encoded length of all attributes in a. An error is
|
|
|
|
// returned if any attribute in a exceeds the permitted size.
|
|
|
|
func AttributesEncodedLen(a Attributes) (int, error) {
|
|
|
|
var n int
|
|
|
|
for _, attr := range a {
|
|
|
|
if attr.Type < 0 || 255 < attr.Type {
|
2020-03-02 23:30:09 +01:00
|
|
|
continue
|
|
|
|
}
|
2021-01-26 00:00:53 +01:00
|
|
|
if len(attr.Attribute) > 253 {
|
|
|
|
return 0, errors.New("radius: attribute too large")
|
2020-03-02 23:30:09 +01:00
|
|
|
}
|
2021-01-26 00:00:53 +01:00
|
|
|
n += 1 + 1 + len(attr.Attribute)
|
2020-03-02 23:30:09 +01:00
|
|
|
}
|
2021-01-26 00:00:53 +01:00
|
|
|
return n, nil
|
2020-03-02 23:30:09 +01:00
|
|
|
}
|