radius

package module
v2.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 22, 2026 License: MIT Imports: 24 Imported by: 0

README

a golang radius library (v2)

PkgGoDev MIT License

A feature-rich RADIUS library for Go. This is a significantly refactored version (v2) of the original library, optimized for clarity and ease of use.

This project forks from https://github.com/bronze1man/radius

Key Features

  • Simplified API: Clean and intuitive Go-native interfaces.
  • Dictionary Support: Full support for FreeRADIUS-style dictionary files.
  • Builtin Dictionary: Minimal standard attributes included out-of-the-box.
  • Template System: Pre-resolve attributes and VSAs for packet construction.
  • Lazy Decoding: Zero-allocation iterator-based decoding for high-performance use cases.
  • Allocation Pooling: Use sync.Pool for Packet structs to reach absolute zero-allocation.
  • Enhanced Testing: Comprehensive test suite including "golden data" verification.

Installation

go get github.com/sergle/radius/v2

Dictionaries: Loading External Vendor Dictionaries (Cisco, Microsoft, ...)

This library supports FreeRADIUS-style dictionary files, including $INCLUDE, VENDOR, BEGIN-VENDOR, and vendor-specific attributes (VSAs).

Create a small top-level dictionary file that includes the base dictionary plus any vendor dictionaries you need.

Example dictionary file:

$INCLUDE /path/to/freeradius/dictionary
$INCLUDE /path/to/freeradius/dictionary.cisco
$INCLUDE /path/to/freeradius/dictionary.microsoft

Then load it in Go:

dict := radius.NewDictionary()
if err := dict.LoadFile("/path/to/your/dictionary"); err != nil {
    log.Fatal(err)
}

// Optional: make this dictionary the default for package-level lookups.
radius.SetDefaultDictionary(dict)

// Example: pre-resolve a reply template with a Cisco VSA for reuse.
replyTemplate, _ := dict.CreateRequestTemplate(radius.AccessAccept, "Reply-Message")
replyTemplate.AddVSAAttribute(dict, "Cisco", "h323-remote-address")
Alternative: Load multiple files directly

You can also call dict.LoadFile(...) multiple times (for example, once per vendor file). Using a root dictionary with $INCLUDE is usually easier to manage and matches how FreeRADIUS dictionaries are commonly organized.

Quick Start (Server)

package main

import (
	"context"
	"log"
	"github.com/sergle/radius/v2"
)

func main() {
	handler := radius.HandlerFunc(func(ctx context.Context, request *radius.Packet) *radius.Packet {
		log.Printf("Received %s from %s", request.Code, request.ClientAddr)
		
		if request.Code == radius.AccessRequest {
			if request.GetUsername() == "admin" && request.GetPassword() == "secret" {
				return request.ReplyAccept()
			}
			return request.ReplyReject()
		}
		return nil
	})

	// Option A: single shared secret for all clients
	srv := radius.NewServer(":1812", "shared-secret", handler)

	// Option B: per-client shared secrets (lookup by remote host IP)
	// clients := radius.NewClientList([]radius.Client{
	// 	radius.NewClient("192.0.2.10", "secret-a"),
	// 	radius.NewClient("192.0.2.11", "secret-b"),
	// })
	// srv := radius.NewServerWithClientList(":1812", clients, handler)
	log.Fatal(srv.ListenAndServe())
}

Quick Start (Client)

package main

import (
	"context"
	"log"
	"github.com/sergle/radius/v2"
)

func main() {
	client := radius.NewRadClient("127.0.0.1:1812", "shared-secret")

	req := client.NewRequest(radius.AccessRequest)
	req.AddAVP(radius.AVP{Type: radius.AttrUserName, Value: []byte("admin")})
	req.AddPassword("secret")

	// Context-aware request with timeout
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()

	reply, err := client.SendContext(ctx, req)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("Reply: %s", reply.Code)
}

Quick Start (Client with CHAP)

CHAP sends a challenge and a response derived from the password: (response = MD5(chapID || password || challenge)).

package main

import (
	"context"
	"log"
	"time"

	"github.com/sergle/radius/v2"
)

func main() {
	client := radius.NewRadClient("127.0.0.1:1812", "shared-secret")

	req := client.NewRequest(radius.AccessRequest)
	req.AddAVP(radius.AVP{Type: radius.AttrUserName, Value: []byte("admin")})

	chapID := uint8(1)
	challenge := []byte("1234567890abcdef") // 16 bytes (RFC2865: 1..16)
	if err := req.SetCHAPPasswordFromSecret(chapID, "secret", challenge); err != nil {
		log.Fatal(err)
	}

	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel()

	reply, err := client.SendContext(ctx, req)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("Reply: %s", reply.Code)
}

High Performance: Lazy Decoding

For high-load proxies or filters where performance is critical, use lazy decoding to avoid unnecessary allocations.

// Decode without parsing attributes upfront
packet, _ := radius.DecodeRequestLazy(secret, buf)

// Attributes are parsed on-demand when using GetAVP or EachAVP
username := packet.GetUsername()

// Iterate over all attributes without heap allocations
packet.EachAVP(func(attr radius.AVP) bool {
    log.Printf("Found AVP: %d", attr.Type)
    return true
})

Security: Requiring Message-Authenticator (Optional)

RADIUS "Response Authenticator" integrity is based on an MD5 construction that is vulnerable to modern collision attacks in certain on-path (MITM) threat models (see BLAST RADIUS – Attack Details).

This library generates and verifies Message-Authenticator (HMAC-MD5, RFC 3579) when present, and automatically includes it on Access- packets it encodes*. For compatibility with legacy peers, decoding historically treated Message-Authenticator as optional.

If you want stricter behavior, you can opt-in to reject Access- packets that omit Message-Authenticator*:

packet, err := radius.DecodeRequestWithOptions(secret, buf, &radius.DecodeOptions{
	RequireMessageAuthenticator: true,
})
if err != nil {
	// err == radius.ErrMessageAuthenticatorMissing when absent on Access-*
	log.Fatal(err)
}
_ = packet

High Performance: Zero-Allocation Pooling

For the absolute highest performance, use sync.Pool and direct buffer encoding.

Pooled Decoding
// Acquire a packet from the internal pool (Zero B/op)
packet, err := radius.DecodeRequestPooled(secret, buf)
if err != nil {
    log.Fatal(err)
}
defer packet.Release() // Crucial: Return packet to the pool

log.Printf("User: %s", packet.GetUsername())
Direct Encoding
// Encode directly into a provided buffer, avoiding allocations
buf := make([]byte, 4096)
n, err := packet.EncodeTo(buf)

Migration Guide (v1 to v2)

  1. Import Path: Change github.com/sergle/radius to github.com/sergle/radius/v2.
  2. Attribute Names: Standard attributes are now prefixed with Attr (e.g., UserName -> AttrUserName).
  3. Server API: The Service interface now returns *Packet directly. Use HandlerFunc for simple closures.
  4. Packet Creation: Use client.NewRequest(code) or radius.Request(code, secret) for more control.

Documentation

References

License

MIT License. See LICENSE for details.

Documentation

Overview

Package radius implements a minimal RADIUS client/server and attribute codec.

The library supports: - Encoding and decoding RADIUS packets (with authenticator verification) - Parsing FreeRADIUS-style dictionary files for attribute typing and enums - Convenience helpers for common attributes (User-Name, User-Password, CHAP, etc.) - A simple UDP client (RadClient) and UDP server (Server)

Most applications will: - Load a dictionary and set it as the default via SetDefaultDictionary - Create request packets with RadClient.NewRequest (or Request) - Send requests with RadClient.Send / SendContext and inspect replies

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidCHAPChallengeLength = errors.New("invalid CHAP-Challenge length (must be 1..16 bytes)")
	ErrInvalidCHAPPasswordLength  = errors.New("invalid CHAP-Password length (must be 17 bytes)")
)
View Source
var ErrAuthenticatorCheckFail = fmt.Errorf("RADIUS Authenticator verification failed")
View Source
var ErrMessageAuthenticatorCheckFail = fmt.Errorf("RADIUS Message-Authenticator verification failed")
View Source
var ErrMessageAuthenticatorMissing = fmt.Errorf("RADIUS Message-Authenticator missing")

Functions

func ComputeCHAPResponse added in v2.1.0

func ComputeCHAPResponse(chapID uint8, password string, challenge []byte) ([16]byte, error)

ComputeCHAPResponse computes the CHAP response as MD5(chapID || password || challenge).

func MSCHAPv2ChallengeHash added in v2.1.0

func MSCHAPv2ChallengeHash(peerChallenge, authChallenge []byte, username string) []byte

MSCHAPv2ChallengeHash computes SHA1(peerChallenge||authChallenge||username)[0:8] (RFC 2759 §8.3). authChallenge is the server-generated challenge.

func MSCHAPv2NTHash added in v2.1.0

func MSCHAPv2NTHash(password string) []byte

MSCHAPv2NTHash computes NT-Hash = MD4(UTF-16LE(password)) (RFC 2759 §8.2).

func MSCHAPv2NTResponse added in v2.1.0

func MSCHAPv2NTResponse(authChallenge, peerChallenge []byte, username, password string) ([]byte, error)

MSCHAPv2NTResponse computes the 24-byte NT-Response (RFC 2759 §8.1). authChallenge is the server-generated challenge; peerChallenge is client-generated.

func SetDefaultDictionary

func SetDefaultDictionary(d *Dictionary)

SetDefaultDictionary sets the dictionary used for package-level lookups (like AVP.Decode)

Types

type AVP

type AVP struct {
	Type  AttributeType
	Value []byte
}

AVP represents a RADIUS Attribute-Value Pair.

The on-the-wire attribute format is: Type (1 byte), Length (1 byte), Value (Length-2 bytes).

func (AVP) Copy

func (a AVP) Copy() AVP

Copy returns a deep copy of the AVP (including its Value bytes).

func (AVP) Decode

func (a AVP) Decode(p *Packet) interface{}

Decode decodes the AVP value using the current default dictionary.

func (AVP) Encode

func (a AVP) Encode(b []byte) (n int, err error)

Encode writes the AVP to b and returns the number of bytes written.

The caller must ensure b is large enough to hold the encoded AVP.

func (AVP) String

func (a AVP) String() string

String returns a human-readable representation of the AVP.

func (AVP) StringWithPacket

func (a AVP) StringWithPacket(p *Packet) string

StringWithPacket returns a human-readable representation of the AVP that may depend on packet context (for example User-Password decryption).

type AVPTemplate

type AVPTemplate interface {
	Add(p *Packet, value string)
}

AVPTemplate is an interface for both standard attributes and VSAs.

type AcctStatusTypeEnum

type AcctStatusTypeEnum uint32

AcctStatusTypeEnum is the decoded form of Acct-Status-Type.

const (
	AcctStatusTypeEnumStart         AcctStatusTypeEnum = 1
	AcctStatusTypeEnumStop          AcctStatusTypeEnum = 2
	AcctStatusTypeEnumInterimUpdate AcctStatusTypeEnum = 3
	AcctStatusTypeEnumAccountingOn  AcctStatusTypeEnum = 7
	AcctStatusTypeEnumAccountingOff AcctStatusTypeEnum = 8
	// RFC 2867 - tunnel accounting status types
	AcctStatusTypeEnumTunnelStart      AcctStatusTypeEnum = 9
	AcctStatusTypeEnumTunnelStop       AcctStatusTypeEnum = 10
	AcctStatusTypeEnumTunnelReject     AcctStatusTypeEnum = 11
	AcctStatusTypeEnumTunnelLinkStart  AcctStatusTypeEnum = 12
	AcctStatusTypeEnumTunnelLinkStop   AcctStatusTypeEnum = 13
	AcctStatusTypeEnumTunnelLinkReject AcctStatusTypeEnum = 14
)

func (AcctStatusTypeEnum) String

func (e AcctStatusTypeEnum) String() string

String returns the standard name for the accounting status value.

type AcctTerminateCauseEnum

type AcctTerminateCauseEnum uint32

AcctTerminateCauseEnum is the decoded form of Acct-Terminate-Cause.

const (
	AcctTerminateCauseEnumUserRequest             AcctTerminateCauseEnum = 1
	AcctTerminateCauseEnumLostCarrier             AcctTerminateCauseEnum = 2
	AcctTerminateCauseEnumLostService             AcctTerminateCauseEnum = 3
	AcctTerminateCauseEnumIdleTimeout             AcctTerminateCauseEnum = 4
	AcctTerminateCauseEnumSessionTimeout          AcctTerminateCauseEnum = 5
	AcctTerminateCauseEnumAdminReset              AcctTerminateCauseEnum = 6
	AcctTerminateCauseEnumAdminReboot             AcctTerminateCauseEnum = 7
	AcctTerminateCauseEnumPortError               AcctTerminateCauseEnum = 8
	AcctTerminateCauseEnumNASError                AcctTerminateCauseEnum = 9
	AcctTerminateCauseEnumNASRequest              AcctTerminateCauseEnum = 10
	AcctTerminateCauseEnumNASReboot               AcctTerminateCauseEnum = 11
	AcctTerminateCauseEnumPortUnneeded            AcctTerminateCauseEnum = 12
	AcctTerminateCauseEnumPortPreempted           AcctTerminateCauseEnum = 13
	AcctTerminateCauseEnumPortSuspended           AcctTerminateCauseEnum = 14
	AcctTerminateCauseEnumServiceUnavailable      AcctTerminateCauseEnum = 15
	AcctTerminateCauseEnumCallback                AcctTerminateCauseEnum = 16
	AcctTerminateCauseEnumUserError               AcctTerminateCauseEnum = 17
	AcctTerminateCauseEnumHostRequest             AcctTerminateCauseEnum = 18
	AcctTerminateCauseEnumSupplicantRestart       AcctTerminateCauseEnum = 19
	AcctTerminateCauseEnumReauthenticationFailure AcctTerminateCauseEnum = 20
	AcctTerminateCauseEnumPortReinitialized       AcctTerminateCauseEnum = 21
	AcctTerminateCauseEnumPortAdminDisabled       AcctTerminateCauseEnum = 22
)

func (AcctTerminateCauseEnum) String

func (e AcctTerminateCauseEnum) String() string

String returns the standard name for the accounting terminate cause value.

type AttributeTemplate

type AttributeTemplate struct {
	// contains filtered or unexported fields
}

AttributeTemplate stores a pre-resolved attribute definition for reuse.

func (*AttributeTemplate) Add

func (t *AttributeTemplate) Add(p *Packet, value string)

Add encodes the value and adds it to the provided packet.

type AttributeType

type AttributeType uint8

AttributeType is the RADIUS attribute Type field.

const (
	AttrUserName            AttributeType = 1
	AttrUserPassword        AttributeType = 2
	AttrCHAPPassword        AttributeType = 3
	AttrNASIPAddress        AttributeType = 4
	AttrNASPort             AttributeType = 5
	AttrServiceType         AttributeType = 6
	AttrFramedIPAddress     AttributeType = 8
	AttrFilterId            AttributeType = 11
	AttrFramedMTU           AttributeType = 12
	AttrReplyMessage        AttributeType = 18
	AttrState               AttributeType = 24
	AttrClass               AttributeType = 25
	AttrVendorSpecific      AttributeType = 26
	AttrSessionTimeout      AttributeType = 27
	AttrIdleTimeout         AttributeType = 28
	AttrTerminationAction   AttributeType = 29
	AttrCalledStationId     AttributeType = 30
	AttrCallingStationId    AttributeType = 31
	AttrNASIdentifier       AttributeType = 32
	AttrAcctStatusType      AttributeType = 40
	AttrAcctDelayTime       AttributeType = 41
	AttrAcctInputOctets     AttributeType = 42
	AttrAcctOutputOctets    AttributeType = 43
	AttrAcctSessionId       AttributeType = 44
	AttrAcctSessionTime     AttributeType = 46
	AttrAcctInputPackets    AttributeType = 47
	AttrAcctOutputPackets   AttributeType = 48
	AttrAcctTerminateCause  AttributeType = 49
	AttrAcctMultiSessionId  AttributeType = 50
	AttrAcctLinkCount       AttributeType = 51
	AttrAcctInputGigawords  AttributeType = 52
	AttrAcctOutputGigawords AttributeType = 53
	AttrEventTimestamp      AttributeType = 55
	AttrCHAPChallenge       AttributeType = 60
	AttrNASPortType         AttributeType = 61
	AttrPortLimit           AttributeType = 62

	// RFC 2868 - RADIUS Attributes for Tunnel Protocol Support
	AttrTunnelType           AttributeType = 64
	AttrTunnelMediumType     AttributeType = 65
	AttrTunnelClientEndpoint AttributeType = 66
	AttrTunnelServerEndpoint AttributeType = 67

	// RFC 2867 - RADIUS Accounting Modifications for Tunnel Protocol Support
	AttrAcctTunnelConnection AttributeType = 68

	// RFC 2868 (continued)
	AttrTunnelPassword AttributeType = 69

	// RFC 2869 - RADIUS Extensions
	AttrPrompt      AttributeType = 76
	AttrConnectInfo AttributeType = 77

	AttrEAPMessage           AttributeType = 79
	AttrMessageAuthenticator AttributeType = 80

	// RFC 2868 (continued)
	AttrTunnelPrivateGroupID AttributeType = 81
	AttrTunnelAssignmentID   AttributeType = 82
	AttrTunnelPreference     AttributeType = 83

	AttrNASPortId  AttributeType = 87
	AttrFramedPool AttributeType = 88

	// RFC 2867 (continued)
	AttrAcctTunnelPacketsLost AttributeType = 86

	// RFC 2869 (continued)
	AttrAcctInterimInterval AttributeType = 85

	// RFC 4372 - Chargeable User Identity
	AttrChargeableUserIdentity AttributeType = 89

	// RFC 2868 (continued)
	AttrTunnelClientAuthID AttributeType = 90
	AttrTunnelServerAuthID AttributeType = 91

	// RFC 4849 - RADIUS Filter Rule Attribute
	AttrNASFilterRule AttributeType = 92

	// RFC 3162 - RADIUS and IPv6
	AttrNASIPv6Address    AttributeType = 95
	AttrFramedInterfaceId AttributeType = 96
	AttrFramedIPv6Prefix  AttributeType = 97
	AttrLoginIPv6Host     AttributeType = 98
	AttrFramedIPv6Route   AttributeType = 99
	AttrFramedIPv6Pool    AttributeType = 100

	// RFC 5176 - Dynamic Authorization Extensions to RADIUS
	AttrErrorCause AttributeType = 101

	// RFC 5090 - RADIUS Extension for Digest Authentication
	AttrDigestResponse       AttributeType = 103
	AttrDigestRealm          AttributeType = 104
	AttrDigestNonce          AttributeType = 105
	AttrDigestResponseAuth   AttributeType = 106
	AttrDigestNextnonce      AttributeType = 107
	AttrDigestMethod         AttributeType = 108
	AttrDigestURI            AttributeType = 109
	AttrDigestQop            AttributeType = 110
	AttrDigestAlgorithm      AttributeType = 111
	AttrDigestEntityBodyHash AttributeType = 112
	AttrDigestCNonce         AttributeType = 113
	AttrDigestNonceCount     AttributeType = 114
	AttrDigestUsername       AttributeType = 115
	AttrDigestOpaque         AttributeType = 116
	AttrDigestAuthParam      AttributeType = 117
	AttrDigestAKAAuts        AttributeType = 118
	AttrDigestDomain         AttributeType = 119
	AttrDigestStale          AttributeType = 120
	AttrDigestHA1            AttributeType = 121
	AttrSIPAOR               AttributeType = 122
)

func (AttributeType) String

func (a AttributeType) String() string

String returns the attribute name from the current default dictionary when available. If no dictionary is loaded or the attribute is unknown, it returns a fallback name.

type AvpBinary

type AvpBinary struct{}

func (AvpBinary) FromString

func (s AvpBinary) FromString(v string) []byte

func (AvpBinary) String

func (s AvpBinary) String(p *Packet, a AVP) string

func (AvpBinary) Value

func (s AvpBinary) Value(p *Packet, a AVP) interface{}

type AvpEapMessage

type AvpEapMessage struct{}

func (AvpEapMessage) FromString

func (s AvpEapMessage) FromString(v string) []byte

func (AvpEapMessage) String

func (s AvpEapMessage) String(p *Packet, a AVP) string

func (AvpEapMessage) Value

func (s AvpEapMessage) Value(p *Packet, a AVP) interface{}

type AvpIP

type AvpIP struct{}

func (AvpIP) FromString

func (s AvpIP) FromString(v string) []byte

func (AvpIP) String

func (s AvpIP) String(p *Packet, a AVP) string

func (AvpIP) Value

func (s AvpIP) Value(p *Packet, a AVP) interface{}

type AvpPassword

type AvpPassword struct{}

func (AvpPassword) Encode

func (s AvpPassword) Encode(password, secret string, authenticator []byte) []byte

Encode the password according to RFC 2865.

func (AvpPassword) FromString

func (s AvpPassword) FromString(v string) []byte

func (AvpPassword) String

func (s AvpPassword) String(p *Packet, a AVP) string

func (AvpPassword) Value

func (s AvpPassword) Value(p *Packet, a AVP) interface{}

type AvpString

type AvpString struct{}

func (AvpString) FromString

func (s AvpString) FromString(v string) []byte

func (AvpString) String

func (s AvpString) String(p *Packet, a AVP) string

func (AvpString) Value

func (s AvpString) Value(p *Packet, a AVP) interface{}

type AvpUint32

type AvpUint32 struct{}

func (AvpUint32) FromString

func (s AvpUint32) FromString(value string) []byte

func (AvpUint32) String

func (s AvpUint32) String(p *Packet, a AVP) string

func (AvpUint32) Value

func (s AvpUint32) Value(p *Packet, a AVP) interface{}

type AvpUint32Enum

type AvpUint32Enum struct {
	// contains filtered or unexported fields
}

func (AvpUint32Enum) FromString

func (s AvpUint32Enum) FromString(v string) []byte

TODO

func (AvpUint32Enum) String

func (s AvpUint32Enum) String(p *Packet, a AVP) string

func (AvpUint32Enum) Value

func (s AvpUint32Enum) Value(p *Packet, a AVP) interface{}

type AvpUint32EnumList

type AvpUint32EnumList []string

not used?

func (AvpUint32EnumList) FromString

func (s AvpUint32EnumList) FromString(v string) []byte

func (AvpUint32EnumList) String

func (s AvpUint32EnumList) String(p *Packet, a AVP) string

func (AvpUint32EnumList) Value

func (s AvpUint32EnumList) Value(p *Packet, a AVP) interface{}

type AvpVendor

type AvpVendor struct{}

func (AvpVendor) FromString

func (s AvpVendor) FromString(v string) []byte

func (AvpVendor) String

func (s AvpVendor) String(p *Packet, a AVP) string

func (AvpVendor) Value

func (s AvpVendor) Value(p *Packet, a AVP) interface{}

type CHAPPassword added in v2.1.0

type CHAPPassword struct {
	ID       uint8
	Response [16]byte
}

CHAPPassword is the decoded form of the CHAP-Password attribute (RFC 2865).

The on-the-wire value is 17 bytes: 1 byte CHAP ID followed by 16 bytes response.

type Client

type Client interface {
	// GetHost get the client host
	GetHost() string
	// GetSecret get shared secret
	GetSecret() string
}

Client represents a RADIUS peer with a host and a shared secret.

func NewClient

func NewClient(host, secret string) Client

NewClient returns a default Client implementation for the given host and secret.

type ClientList

type ClientList struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

ClientList is a concurrency-safe set of RADIUS clients indexed by host.

func NewClientList

func NewClientList(cs []Client) *ClientList

NewClientList returns a ClientList initialized with cs.

func (*ClientList) AddOrUpdate

func (cls *ClientList) AddOrUpdate(cl Client)

AddOrUpdate adds a new client or replaces an existing client with the same host.

func (*ClientList) Get

func (cls *ClientList) Get(host string) Client

Get returns a client by host, or nil if not present.

func (*ClientList) GetHerd

func (cls *ClientList) GetHerd() []Client

GetHerd returns a snapshot of the current clients.

func (*ClientList) Remove

func (cls *ClientList) Remove(host string)

Remove deletes a client by host.

func (*ClientList) SetHerd

func (cls *ClientList) SetHerd(herd []Client)

SetHerd replaces the current client set with herd.

type DecodeOptions added in v2.1.0

type DecodeOptions struct {
	// RequireMessageAuthenticator rejects Access-* packets that do not contain
	// a Message-Authenticator attribute (RFC 3579).
	//
	// Default: false (accept packets without Message-Authenticator).
	RequireMessageAuthenticator bool
}

DecodeOptions controls optional decode-time security checks.

The zero value preserves historical behavior for compatibility.

type DefaultClient

type DefaultClient struct {
	Host   string
	Secret string
}

DefaultClient is the default Client implementation.

func (*DefaultClient) GetHost

func (cl *DefaultClient) GetHost() string

GetHost returns the client's host.

func (*DefaultClient) GetSecret

func (cl *DefaultClient) GetSecret() string

GetSecret returns the client's shared secret.

type Dictionary

type Dictionary struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

Dictionary parses and stores FreeRADIUS-style dictionary files.

A Dictionary provides name/type mappings for standard attributes and Vendor-Specific Attributes (VSAs), and is used by AVP decoding/formatting.

func GetDefaultDictionary

func GetDefaultDictionary() *Dictionary

GetDefaultDictionary returns the current default dictionary

func NewDictionary

func NewDictionary() *Dictionary

NewDictionary returns an empty dictionary ready to load dictionary files.

func (*Dictionary) CreateRequestTemplate

func (d *Dictionary) CreateRequestTemplate(code PacketCode, names ...string) (*RequestTemplate, error)

CreateRequestTemplate creates a RequestTemplate for the given packet code and list of attribute names.

func (*Dictionary) DecodeAVPValue

func (d *Dictionary) DecodeAVPValue(p *Packet, a AVP) string

DecodeAVPValue returns a human-readable string for the given AVP.

When possible, DecodeAVPValue uses dictionary type information and enum mappings (including VSA enums) to format values.

func (*Dictionary) GetAttributeID

func (d *Dictionary) GetAttributeID(attrName string) AttributeType

GetAttributeID returns the AttributeType for an attribute name.

func (*Dictionary) GetAttributeName

func (d *Dictionary) GetAttributeName(attrID AttributeType) string

GetAttributeName returns the attribute name for an AttributeType.

func (*Dictionary) GetAttributeType

func (d *Dictionary) GetAttributeType(attrName string) string

GetAttributeType returns the type name (for example "string" or "integer") for an attribute name.

func (*Dictionary) GetTemplate

func (d *Dictionary) GetTemplate(name string) (*AttributeTemplate, error)

GetTemplate creates an AttributeTemplate for the given attribute name.

func (*Dictionary) GetVSAAttributeID

func (d *Dictionary) GetVSAAttributeID(vendorID VendorID, attrName string) VendorAttr

GetVSAAttributeID returns the vendor-specific attribute ID for a vendor and attribute name.

func (*Dictionary) GetVSAAttributeName

func (d *Dictionary) GetVSAAttributeName(vendorID VendorID, attrID VendorAttr) string

GetVSAAttributeName returns the attribute name for a vendor-specific attribute ID.

func (*Dictionary) GetVSAAttributeType

func (d *Dictionary) GetVSAAttributeType(vendorID VendorID, attrName string) string

GetVSAAttributeType returns the type name (for example "string" or "integer") for a vendor-specific attribute.

func (*Dictionary) GetVendorID

func (d *Dictionary) GetVendorID(vendorName string) VendorID

GetVendorID returns the VendorID for a vendor name.

func (*Dictionary) GetVendorName

func (d *Dictionary) GetVendorName(vendorID VendorID) string

GetVendorName returns the vendor name for a VendorID.

func (*Dictionary) HasAttribute

func (d *Dictionary) HasAttribute(attrName string) bool

HasAttribute reports whether the dictionary defines the given attribute name.

func (*Dictionary) HasVSAAttribute

func (d *Dictionary) HasVSAAttribute(vendorID VendorID, attrName string) bool

HasVSAAttribute reports whether the dictionary defines the given vendor-specific attribute.

func (*Dictionary) LoadBuiltin added in v2.2.0

func (d *Dictionary) LoadBuiltin() error

LoadBuiltin loads the embedded built-in dictionary into d.

func (*Dictionary) LoadFile

func (d *Dictionary) LoadFile(fname string) error

LoadFile loads and parses a dictionary file.

The file format is compatible with FreeRADIUS dictionary files and supports $INCLUDE recursion (with internal/unsupported files skipped).

func (*Dictionary) NewAVP

func (d *Dictionary) NewAVP(attrName string, attrValue string) AVP

NewAVP constructs an AVP from the attribute name and a string value using the attribute type defined in the dictionary.

func (*Dictionary) NewVSA

func (d *Dictionary) NewVSA(vendorName string, attrName string, attrValue string) VSA

NewVSA constructs a Vendor-Specific Attribute from the vendor name, attribute name, and a string value using the VSA type defined in the dictionary.

type DigestAuthRequest added in v2.2.0

type DigestAuthRequest struct {
	// contains filtered or unexported fields
}

DigestAuthRequest wraps an incoming Access-Request packet that carries RFC 5090 Digest Authentication attributes, providing typed getters for each field.

It is the entry point for RADIUS server handlers processing Digest auth. Use IsNonceRequest to distinguish the two-round flow, then construct the appropriate reply via Challenge, Accept, or Reject.

func NewDigestAuthRequest added in v2.2.0

func NewDigestAuthRequest(p *Packet) *DigestAuthRequest

NewDigestAuthRequest wraps p for reading its RFC 5090 Digest attributes.

func (*DigestAuthRequest) AKAAuts added in v2.2.0

func (r *DigestAuthRequest) AKAAuts() string

AKAAuts returns Digest-AKA-Auts (118), the re-sync token for Digest AKA.

func (*DigestAuthRequest) Accept added in v2.2.0

func (r *DigestAuthRequest) Accept(rspauth string) *DigestAuthResponse

Accept constructs an Access-Accept DigestAuthResponse from this request. rspauth is the Digest-Response-Auth value (required for qop=auth; pass "" when qop=auth-int, where SetHA1 is used instead, or when qop is absent).

func (*DigestAuthRequest) Algorithm added in v2.2.0

func (r *DigestAuthRequest) Algorithm() string

Algorithm returns Digest-Algorithm (111). Defaults to "MD5" when the attribute is absent, per RFC 5090 §3.

func (*DigestAuthRequest) AuthParams added in v2.2.0

func (r *DigestAuthRequest) AuthParams() []string

AuthParams returns all Digest-Auth-Param (117) values. Each is a full "name=value" pair for extension parameters.

func (*DigestAuthRequest) CNonce added in v2.2.0

func (r *DigestAuthRequest) CNonce() string

CNonce returns Digest-CNonce (113), the client nonce.

func (*DigestAuthRequest) Challenge added in v2.2.0

func (r *DigestAuthRequest) Challenge(realm, nonce string) *DigestAuthResponse

Challenge constructs an Access-Challenge DigestAuthResponse with the required fields pre-populated: Nonce, Realm, Qop ("auth"), Algorithm ("MD5"), and State (set to nonce bytes per RFC 5090 §5 note [4]). Use the setter methods to override or add optional fields (e.g. SetOpaque, AddDomain).

func (*DigestAuthRequest) DigestUsername added in v2.2.0

func (r *DigestAuthRequest) DigestUsername() string

DigestUsername returns Digest-Username (115). This is the username used in the HA1 digest calculation. Credential lookup must use Username() (User-Name attr) instead.

func (*DigestAuthRequest) EntityBodyHash added in v2.2.0

func (r *DigestAuthRequest) EntityBodyHash() string

EntityBodyHash returns Digest-Entity-Body-Hash (112), hex H(entity-body). Present only when qop=auth-int.

func (*DigestAuthRequest) IsNonceRequest added in v2.2.0

func (r *DigestAuthRequest) IsNonceRequest() bool

IsNonceRequest reports whether the packet is a bare nonce-request: Digest-Method is present but Digest-Nonce is absent. The RADIUS server should respond with Access-Challenge containing a fresh nonce.

func (*DigestAuthRequest) Method added in v2.2.0

func (r *DigestAuthRequest) Method() string

Method returns Digest-Method (108), e.g. "INVITE" or "GET".

func (*DigestAuthRequest) Nonce added in v2.2.0

func (r *DigestAuthRequest) Nonce() string

Nonce returns Digest-Nonce (105).

func (*DigestAuthRequest) NonceCount added in v2.2.0

func (r *DigestAuthRequest) NonceCount() string

NonceCount returns Digest-Nonce-Count (114) as an 8-char hex string, e.g. "00000001".

func (*DigestAuthRequest) Opaque added in v2.2.0

func (r *DigestAuthRequest) Opaque() string

Opaque returns Digest-Opaque (116).

func (*DigestAuthRequest) Qop added in v2.2.0

func (r *DigestAuthRequest) Qop() string

Qop returns Digest-Qop (110), e.g. "auth" or "auth-int".

func (*DigestAuthRequest) Realm added in v2.2.0

func (r *DigestAuthRequest) Realm() string

Realm returns Digest-Realm (104).

func (*DigestAuthRequest) Reject added in v2.2.0

Reject constructs an Access-Reject DigestAuthResponse from this request.

func (*DigestAuthRequest) Response added in v2.2.0

func (r *DigestAuthRequest) Response() string

Response returns Digest-Response (103), the hex digest from the client.

func (*DigestAuthRequest) SIPAOR added in v2.2.0

func (r *DigestAuthRequest) SIPAOR() string

SIPAOR returns SIP-AOR (122), the SIP Address-of-Record being authenticated.

func (*DigestAuthRequest) State added in v2.2.0

func (r *DigestAuthRequest) State() []byte

State returns the State attribute bytes, or nil if absent. The NAS copies State from the Access-Challenge into the follow-up Access-Request so the server can correlate the two rounds.

func (*DigestAuthRequest) URI added in v2.2.0

func (r *DigestAuthRequest) URI() string

URI returns Digest-URI (109).

func (*DigestAuthRequest) Username added in v2.2.0

func (r *DigestAuthRequest) Username() string

Username returns User-Name (attr 1) used for credential lookup. Per RFC 5090 §2.2.2 the server looks up credentials using User-Name, not DigestUsername.

func (*DigestAuthRequest) Verify added in v2.2.0

func (r *DigestAuthRequest) Verify(ha1 string) bool

Verify reports whether the Digest-Response in the packet is valid for the given ha1 (hex H(A1), e.g. pre-stored or computed for the relevant algorithm). Returns false if any required attribute is missing.

type DigestAuthResponse added in v2.2.0

type DigestAuthResponse struct {
	// contains filtered or unexported fields
}

DigestAuthResponse builds an RFC 5090 reply packet. Obtain one via DigestAuthRequest.Challenge, Accept, or Reject. All setter methods return the receiver for fluent chaining. Call Packet to retrieve the finished reply.

func (*DigestAuthResponse) AddAuthParam added in v2.2.0

func (r *DigestAuthResponse) AddAuthParam(v string) *DigestAuthResponse

AddAuthParam appends a Digest-Auth-Param (117) extension value. Valid in Access-Request, Access-Challenge, Access-Accept, and Accounting-Request.

func (*DigestAuthResponse) AddDomain added in v2.2.0

func (r *DigestAuthResponse) AddDomain(v string) *DigestAuthResponse

AddDomain appends a Digest-Domain (119) URI, defining a protection space component. Multiple Domain attributes may appear in Access-Challenge.

func (*DigestAuthResponse) AddQop added in v2.2.0

AddQop appends a Digest-Qop (110) value. Multiple Qop attributes may appear in Access-Challenge.

func (*DigestAuthResponse) Packet added in v2.2.0

func (r *DigestAuthResponse) Packet() *Packet

Packet returns the fully constructed reply packet, ready for returning from a RADIUS server handler.

func (*DigestAuthResponse) SetAlgorithm added in v2.2.0

func (r *DigestAuthResponse) SetAlgorithm(v string) *DigestAuthResponse

SetAlgorithm sets Digest-Algorithm (111), e.g. "MD5" or "MD5-sess".

func (*DigestAuthResponse) SetHA1 added in v2.2.0

SetHA1 sets Digest-HA1 (121), the hex H(A1) value. Used in Access-Accept when qop=auth-int so the NAS can compute rspauth locally. MUST NOT be sent when qop=auth — use SetResponseAuth instead.

func (*DigestAuthResponse) SetNextnonce added in v2.2.0

func (r *DigestAuthResponse) SetNextnonce(v string) *DigestAuthResponse

SetNextnonce sets Digest-Nextnonce (107), pre-supplying a nonce for the client's next request via the Authentication-Info nextnonce directive.

func (*DigestAuthResponse) SetNonce added in v2.2.0

SetNonce sets Digest-Nonce (105). Required in Access-Challenge.

func (*DigestAuthResponse) SetOpaque added in v2.2.0

func (r *DigestAuthResponse) SetOpaque(v string) *DigestAuthResponse

SetOpaque sets Digest-Opaque (116).

func (*DigestAuthResponse) SetQop added in v2.2.0

SetQop sets a single Digest-Qop (110), replacing any prior values. Use AddQop when the challenge should advertise multiple supported options.

func (*DigestAuthResponse) SetRealm added in v2.2.0

SetRealm sets Digest-Realm (104). Required in Access-Challenge.

func (*DigestAuthResponse) SetResponseAuth added in v2.2.0

func (r *DigestAuthResponse) SetResponseAuth(v string) *DigestAuthResponse

SetResponseAuth sets Digest-Response-Auth (106), the server's rspauth value. MUST be included in Access-Accept when qop=auth; the NAS puts it in the Authentication-Info rspauth directive. MUST NOT be sent when qop=auth-int — use SetHA1 instead.

func (*DigestAuthResponse) SetStale added in v2.2.0

func (r *DigestAuthResponse) SetStale(stale bool) *DigestAuthResponse

SetStale sets Digest-Stale (120) to "true" or "false". Indicates whether the client's nonce was stale but the credentials are otherwise valid.

func (*DigestAuthResponse) SetState added in v2.2.0

func (r *DigestAuthResponse) SetState(v []byte) *DigestAuthResponse

SetState sets the State attribute (24). State MUST be present in Access-Challenge (RFC 5090 §5 note [4]) and MUST be copied back by the NAS in the follow-up Access-Request.

type EapCode

type EapCode uint8
const (
	EapCodeRequest  EapCode = 1
	EapCodeResponse EapCode = 2
	EapCodeSuccess  EapCode = 3
	EapCodeFailure  EapCode = 4
)

func (EapCode) String

func (c EapCode) String() string

type EapPacket

type EapPacket struct {
	Code       EapCode
	Identifier uint8
	Type       EapType
	Data       []byte
}

func EapDecode

func EapDecode(b []byte) (eap *EapPacket, err error)

func (*EapPacket) Copy

func (a *EapPacket) Copy() *EapPacket

func (*EapPacket) Encode

func (a *EapPacket) Encode() (b []byte)

func (*EapPacket) String

func (a *EapPacket) String() string

func (*EapPacket) ToEAPMessage

func (a *EapPacket) ToEAPMessage() *AVP

type EapType

type EapType uint8
const (
	EapTypeIdentity         EapType = 1
	EapTypeNotification     EapType = 2
	EapTypeNak              EapType = 3 //Response only
	EapTypeMd5Challenge     EapType = 4
	EapTypeOneTimePassword  EapType = 5 //otp
	EapTypeGenericTokenCard EapType = 6 //gtc
	EapTypeMSCHAPV2         EapType = 26
	EapTypeExpandedTypes    EapType = 254
	EapTypeExperimentalUse  EapType = 255
)

func (EapType) String

func (c EapType) String() string

type HandlerFunc

type HandlerFunc func(ctx context.Context, request *Packet) *Packet

HandlerFunc adapts a function to the Service interface.

func (HandlerFunc) RadiusHandle

func (f HandlerFunc) RadiusHandle(ctx context.Context, request *Packet) *Packet

RadiusHandle calls f(ctx, request).

type MsChapV2OpCode

type MsChapV2OpCode uint8
const (
	MsChapV2OpCodeChallenge      MsChapV2OpCode = 1
	MsChapV2OpCodeResponse       MsChapV2OpCode = 2
	MsChapV2OpCodeSuccess        MsChapV2OpCode = 3
	MsChapV2OpCodeFailure        MsChapV2OpCode = 4
	MsChapV2OpCodeChangePassword MsChapV2OpCode = 7
)

func (MsChapV2OpCode) String

func (c MsChapV2OpCode) String() string

type MsChapV2Packet

type MsChapV2Packet struct {
	Eap    *EapPacket //The eap information when decrypting, does not use the data inside
	OpCode MsChapV2OpCode
	Data   []byte
}

func MsChapV2PacketFromEap

func MsChapV2PacketFromEap(eap *EapPacket) (p *MsChapV2Packet, err error)

func (*MsChapV2Packet) String

func (p *MsChapV2Packet) String() string

Does not include eap information

func (*MsChapV2Packet) ToEap

func (p *MsChapV2Packet) ToEap() *EapPacket

type NASPortTypeEnum

type NASPortTypeEnum uint32

NASPortTypeEnum is the decoded form of NAS-Port-Type.

const (
	NASPortTypeEnumAsync            NASPortTypeEnum = 0
	NASPortTypeEnumSync             NASPortTypeEnum = 1
	NASPortTypeEnumISDNSync         NASPortTypeEnum = 2
	NASPortTypeEnumISDNSyncV120     NASPortTypeEnum = 3
	NASPortTypeEnumISDNSyncV110     NASPortTypeEnum = 4
	NASPortTypeEnumVirtual          NASPortTypeEnum = 5
	NASPortTypeEnumPIAFS            NASPortTypeEnum = 6
	NASPortTypeEnumHDLCClearChannel NASPortTypeEnum = 7
	NASPortTypeEnumEthernet         NASPortTypeEnum = 15
	NASPortTypeEnumxDSL             NASPortTypeEnum = 16
	NASPortTypeEnumCable            NASPortTypeEnum = 17
	NASPortTypeEnumWirelessOther    NASPortTypeEnum = 18
	NASPortTypeEnumWireless80211    NASPortTypeEnum = 19
	NASPortTypeEnumTokenRing        NASPortTypeEnum = 20
	NASPortTypeEnumFDDI             NASPortTypeEnum = 21
)

func (NASPortTypeEnum) String

func (e NASPortTypeEnum) String() string

String returns the standard name for the NAS port type value.

type Packet

type Packet struct {
	Secret        string
	Code          PacketCode
	Identifier    uint8
	Authenticator [16]byte
	AVPs          []AVP
	RawAVPs       []byte // Unparsed attributes for lazy decoding
	ClientAddr    string
}

Packet represents a RADIUS packet as defined by RFC 2865/RFC 2866.

A Packet can be encoded for sending over the network and decoded from bytes. When decoding lazily, AVPs may be available via RawAVPs instead of AVPs; helper methods (for example GetAVP/EachAVP/HasAVP) work with either representation.

func DecodePacket deprecated

func DecodePacket(secret string, buf []byte) (p *Packet, err error)

DecodePacket decodes a request packet from buf using the shared secret.

Deprecated: kept for backward compatibility; use DecodeRequest.

func DecodeReply

func DecodeReply(secret string, buf []byte, requestAuth []byte) (p *Packet, err error)

DecodeReply decodes a reply packet from buf using the shared secret and requestAuth (the 16-byte Authenticator from the corresponding request).

func DecodeReplyLazy added in v2.1.0

func DecodeReplyLazy(secret string, buf []byte, requestAuth []byte) (p *Packet, err error)

DecodeReplyLazy decodes only the packet header and keeps attributes in raw form for lazy access via RawAVPs.

func DecodeReplyLazyWithOptions added in v2.1.0

func DecodeReplyLazyWithOptions(secret string, buf []byte, requestAuth []byte, opts *DecodeOptions) (p *Packet, err error)

DecodeReplyLazyWithOptions is like DecodeReplyLazy but allows options.

func DecodeReplyPooled added in v2.1.0

func DecodeReplyPooled(secret string, buf []byte, requestAuth []byte) (p *Packet, err error)

DecodeReplyPooled decodes a reply packet and returns a packet from an internal pool. The returned packet must be released with (*Packet).Release.

func DecodeReplyPooledWithOptions added in v2.1.0

func DecodeReplyPooledWithOptions(secret string, buf []byte, requestAuth []byte, opts *DecodeOptions) (p *Packet, err error)

DecodeReplyPooledWithOptions is like DecodeReplyPooled but allows options.

func DecodeReplyWithOptions added in v2.1.0

func DecodeReplyWithOptions(secret string, buf []byte, requestAuth []byte, opts *DecodeOptions) (p *Packet, err error)

DecodeReplyWithOptions decodes a reply packet from buf using the shared secret, requestAuth (the 16-byte Authenticator from the corresponding request), and options.

func DecodeRequest

func DecodeRequest(secret string, buf []byte) (p *Packet, err error)

DecodeRequest decodes a request packet from buf using the shared secret.

func DecodeRequestLazy added in v2.1.0

func DecodeRequestLazy(secret string, buf []byte) (p *Packet, err error)

DecodeRequestLazy decodes only the packet header and keeps attributes in raw form for lazy access via RawAVPs.

func DecodeRequestLazyWithOptions added in v2.1.0

func DecodeRequestLazyWithOptions(secret string, buf []byte, opts *DecodeOptions) (p *Packet, err error)

DecodeRequestLazyWithOptions is like DecodeRequestLazy but allows options.

func DecodeRequestPooled added in v2.1.0

func DecodeRequestPooled(secret string, buf []byte) (p *Packet, err error)

DecodeRequestPooled decodes a request packet and returns a packet from an internal pool. The returned packet must be released with (*Packet).Release.

func DecodeRequestPooledWithOptions added in v2.1.0

func DecodeRequestPooledWithOptions(secret string, buf []byte, opts *DecodeOptions) (p *Packet, err error)

DecodeRequestPooledWithOptions is like DecodeRequestPooled but allows options.

func DecodeRequestWithOptions added in v2.1.0

func DecodeRequestWithOptions(secret string, buf []byte, opts *DecodeOptions) (p *Packet, err error)

DecodeRequestWithOptions decodes a request packet from buf using the shared secret and the provided options.

func Request

func Request(code PacketCode, secret string) *Packet

Request constructs a new request packet with a random Identifier.

For Access-Request packets, a new request Authenticator is also generated and is later used for User-Password encryption and reply validation.

func (*Packet) AddAVP

func (p *Packet) AddAVP(avps ...AVP)

AddAVP appends avp to the packet's attribute list.

func (*Packet) AddPassword

func (p *Packet) AddPassword(password string)

AddPassword adds (or replaces) the User-Password attribute, encrypting it as required by the RADIUS protocol using the packet Secret and Authenticator.

func (*Packet) AddVSA

func (p *Packet) AddVSA(vsa VSA)

AddVSA adds a Vendor-Specific Attribute (VSA) to the packet.

func (*Packet) Copy

func (p *Packet) Copy() *Packet

Copy returns a deep copy of the packet and all currently decoded AVPs.

Note: when the packet was decoded lazily (RawAVPs is set and AVPs is empty), Copy copies only the header fields; RawAVPs is not currently copied.

func (*Packet) DeleteAVP

func (p *Packet) DeleteAVP(avp *AVP)

DeleteAVP removes the specific AVP instance from the packet, if present.

func (*Packet) DeleteOneType

func (p *Packet) DeleteOneType(attrType AttributeType)

DeleteOneType removes the first attribute with the given type from the packet.

func (*Packet) EachAVP added in v2.1.0

func (p *Packet) EachAVP(fn func(a AVP) bool)

EachAVP iterates over attributes in the packet, calling fn for each.

If fn returns false, iteration stops early.

func (*Packet) Encode

func (p *Packet) Encode() (b []byte, err error)

Encode serializes the packet into a new byte slice.

If the packet Code requires it, Encode will compute and include Message-Authenticator and/or update the packet Authenticator.

func (*Packet) EncodeTo added in v2.1.0

func (p *Packet) EncodeTo(b []byte) (n int, err error)

EncodeTo serializes the packet into b and returns the number of bytes written.

The provided buffer must be large enough for the full packet; this package commonly uses 4096 bytes (the RADIUS maximum packet size).

func (*Packet) GetAVP

func (p *Packet) GetAVP(attrType AttributeType) *AVP

GetAVP returns the first attribute of the given type, or nil if not present.

For lazily decoded packets, GetAVP returns a pointer to a newly allocated AVP.

func (*Packet) GetAcctSessionId

func (p *Packet) GetAcctSessionId() string

GetAcctSessionId returns Acct-Session-Id as a string, if present.

func (*Packet) GetAcctStatusType

func (p *Packet) GetAcctStatusType() AcctStatusTypeEnum

GetAcctStatusType returns Acct-Status-Type if present, or 0 otherwise.

func (*Packet) GetAcctTotalInputOctets

func (p *Packet) GetAcctTotalInputOctets() uint64

GetAcctTotalInputOctets returns the total input octets by combining Acct-Input-Octets and Acct-Input-Gigawords when present.

func (*Packet) GetAcctTotalOutputOctets

func (p *Packet) GetAcctTotalOutputOctets() uint64

GetAcctTotalOutputOctets returns the total output octets by combining Acct-Output-Octets and Acct-Output-Gigawords when present.

func (*Packet) GetCHAPChallenge added in v2.1.0

func (p *Packet) GetCHAPChallenge() []byte

GetCHAPChallenge returns CHAP-Challenge value bytes, if present.

The returned slice is a copy and is safe to keep.

func (*Packet) GetCHAPPassword added in v2.1.0

func (p *Packet) GetCHAPPassword() (CHAPPassword, bool)

GetCHAPPassword returns the decoded CHAP-Password value if present and well-formed.

func (*Packet) GetEAPMessage

func (p *Packet) GetEAPMessage() *EapPacket

GetEAPMessage reassembles and decodes the EAP-Message from the packet. Per RFC 3579 §3.1, a single EAP packet may be split across multiple consecutive EAP-Message attributes (each carrying at most 253 bytes). All fragments are concatenated in order before decoding.

func (*Packet) GetNASIdentifier

func (p *Packet) GetNASIdentifier() string

GetNASIdentifier returns NAS-Identifier, if present.

func (*Packet) GetNASPort

func (p *Packet) GetNASPort() uint32

GetNASPort returns NAS-Port, if present.

Note: some clients (for example strongSwan) use this to carry an IKE identity.

func (*Packet) GetNASPortType

func (p *Packet) GetNASPortType() NASPortTypeEnum

GetNASPortType returns NAS-Port-Type if present, or 0 otherwise.

func (*Packet) GetNasIpAddress

func (p *Packet) GetNasIpAddress() (ip net.IP)

GetNasIpAddress returns NAS-IP-Address as a net.IP, if present.

func (*Packet) GetPassword

func (p *Packet) GetPassword() (password string)

GetPassword returns the decrypted User-Password, if present.

func (*Packet) GetServiceType

func (p *Packet) GetServiceType() ServiceTypeEnum

GetServiceType returns Service-Type if present, or 0 otherwise.

func (*Packet) GetUsername

func (p *Packet) GetUsername() (username string)

GetUsername returns the value of User-Name as a string, if present.

func (*Packet) GetVLAN added in v2.2.0

func (p *Packet) GetVLAN() (uint16, bool)

GetVLAN returns the VLAN ID from the packet if the RFC 3580 §3.31 tunnel attribute combination is present and valid (Tunnel-Type=VLAN, Tunnel-Medium-Type=802, Tunnel-Private-Group-ID parseable as 1–4094). Returns 0, false if the combination is absent or invalid.

func (*Packet) HasAVP

func (p *Packet) HasAVP(attrType AttributeType) bool

HasAVP reports whether the packet contains at least one attribute of the given type.

func (*Packet) Release added in v2.1.0

func (p *Packet) Release()

Release returns the packet to the pool. The packet should not be used after being released.

func (*Packet) Reply

func (p *Packet) Reply() *Packet

Reply constructs a response packet initialized with the request's Authenticator and Identifier.

func (*Packet) ReplyAccept added in v2.2.0

func (p *Packet) ReplyAccept() *Packet

ReplyAccept creates an Access-Accept reply to this packet.

func (*Packet) ReplyAccountingResponse added in v2.2.0

func (p *Packet) ReplyAccountingResponse() *Packet

ReplyAccountingResponse creates an Accounting-Response reply to this packet.

func (*Packet) ReplyChallenge added in v2.2.0

func (p *Packet) ReplyChallenge() *Packet

ReplyChallenge creates an Access-Challenge reply to this packet.

func (*Packet) ReplyCoAAccept added in v2.2.0

func (p *Packet) ReplyCoAAccept() *Packet

ReplyCoAAccept creates a CoA-Accept reply to this packet.

func (*Packet) ReplyCoAReject added in v2.2.0

func (p *Packet) ReplyCoAReject() *Packet

ReplyCoAReject creates a CoA-Reject reply to this packet.

func (*Packet) ReplyDisconnectAccept added in v2.2.0

func (p *Packet) ReplyDisconnectAccept() *Packet

ReplyDisconnectAccept creates a Disconnect-Accept reply to this packet.

func (*Packet) ReplyDisconnectReject added in v2.2.0

func (p *Packet) ReplyDisconnectReject() *Packet

ReplyDisconnectReject creates a Disconnect-Reject reply to this packet.

func (*Packet) ReplyReject added in v2.2.0

func (p *Packet) ReplyReject() *Packet

ReplyReject creates an Access-Reject reply to this packet.

func (*Packet) Reset added in v2.1.0

func (p *Packet) Reset()

Reset clears the packet state for reuse.

func (*Packet) Send

func (p *Packet) Send(c net.PacketConn, addr net.Addr) error

Send encodes the packet and writes it to addr using the provided PacketConn.

func (*Packet) SetAVP

func (p *Packet) SetAVP(avp AVP)

SetAVP removes all attributes of the same type and then adds avp.

func (*Packet) SetCHAPChallenge added in v2.1.0

func (p *Packet) SetCHAPChallenge(challenge []byte) error

SetCHAPChallenge adds or replaces the CHAP-Challenge attribute.

func (*Packet) SetCHAPPassword added in v2.1.0

func (p *Packet) SetCHAPPassword(chapID uint8, response16 [16]byte)

SetCHAPPassword adds or replaces the CHAP-Password attribute using the provided CHAP ID and 16-byte response.

func (*Packet) SetCHAPPasswordFromSecret added in v2.1.0

func (p *Packet) SetCHAPPasswordFromSecret(chapID uint8, password string, challenge []byte) error

SetCHAPPasswordFromSecret computes and sets both CHAP-Password and CHAP-Challenge.

func (*Packet) SetVLAN added in v2.2.0

func (p *Packet) SetVLAN(vlanID uint16)

SetVLAN adds the three-attribute combination required for dynamic VLAN assignment per RFC 3580 §3.31: Tunnel-Type=VLAN, Tunnel-Medium-Type=802, and Tunnel-Private-Group-ID set to the decimal VLAN ID string.

func (*Packet) String

func (p *Packet) String() string

type PacketCode

type PacketCode uint8

PacketCode is the RADIUS packet Code field.

const (
	AccessRequest      PacketCode = 1
	AccessAccept       PacketCode = 2
	AccessReject       PacketCode = 3
	AccountingRequest  PacketCode = 4
	AccountingResponse PacketCode = 5
	AccessChallenge    PacketCode = 11
	StatusServer       PacketCode = 12 //(experimental)
	StatusClient       PacketCode = 13 //(experimental)
	DisconnectRequest  PacketCode = 40
	DisconnectAccept   PacketCode = 41
	DisconnectReject   PacketCode = 42
	CoARequest         PacketCode = 43
	CoAAccept          PacketCode = 44
	CoAReject          PacketCode = 45
	Reserved           PacketCode = 255
)

func (PacketCode) IsAccess

func (p PacketCode) IsAccess() bool

IsAccess reports whether the code is in the Access-* family.

func (PacketCode) IsRequest

func (p PacketCode) IsRequest() bool

IsRequest reports whether the code is a request (as opposed to a reply).

func (PacketCode) String

func (p PacketCode) String() string

String returns the canonical name of the packet code.

type PromptEnum added in v2.1.0

type PromptEnum uint32

PromptEnum is the decoded form of Prompt (RFC 2869).

const (
	PromptEnumNoEcho PromptEnum = 0
	PromptEnumEcho   PromptEnum = 1
)

func (PromptEnum) String added in v2.1.0

func (e PromptEnum) String() string

String returns the standard name for the prompt value.

type RadClient

type RadClient struct {
	// contains filtered or unexported fields
}

RadClient is a simple UDP RADIUS client.

It encodes requests, sends them to the configured server, reads a reply, and validates the reply authenticator using the shared secret.

func NewRadClient

func NewRadClient(server string, secret string) *RadClient

NewRadClient constructs a client for a server address (for example "host:1812") and a shared secret.

func (*RadClient) NewAccessRequest added in v2.2.0

func (c *RadClient) NewAccessRequest() *Packet

NewAccessRequest constructs an Access-Request packet.

func (*RadClient) NewAccountingRequest added in v2.2.0

func (c *RadClient) NewAccountingRequest() *Packet

NewAccountingRequest constructs an Accounting-Request packet.

func (*RadClient) NewCoARequest added in v2.2.0

func (c *RadClient) NewCoARequest() *Packet

NewCoARequest constructs a Change-of-Authorization Request (RFC 3576) packet.

func (*RadClient) NewDisconnectRequest added in v2.2.0

func (c *RadClient) NewDisconnectRequest() *Packet

NewDisconnectRequest constructs a Disconnect-Request (RFC 3576) packet.

func (*RadClient) NewRequest

func (c *RadClient) NewRequest(code PacketCode) *Packet

NewRequest constructs a new request packet with the given code using the client's shared secret.

func (*RadClient) Send

func (c *RadClient) Send(request *Packet) (*Packet, error)

Send is a convenience wrapper around SendContext that uses context.Background().

func (*RadClient) SendContext added in v2.1.0

func (c *RadClient) SendContext(ctx context.Context, request *Packet) (*Packet, error)

SendContext sends a RADIUS packet using the provided context, allowing callers to control cancellation and deadlines. For most callers, use Send, which wraps this with context.Background().

func (*RadClient) SetTimeout

func (c *RadClient) SetTimeout(t time.Duration)

SetTimeout sets the fallback timeout used by Send/SendContext when the context has no deadline.

type RequestTemplate

type RequestTemplate struct {
	// contains filtered or unexported fields
}

RequestTemplate defines a reusable structure for RADIUS requests.

func (*RequestTemplate) AddAttributeTypes added in v2.2.0

func (t *RequestTemplate) AddAttributeTypes(attrTypes ...AttributeType)

AddAttributeTypes appends one or more attributes by their AttributeType ID to the request template. The handler is resolved from the default dictionary; unknown attributes fall back to binary encoding.

func (*RequestTemplate) AddAttributes added in v2.2.0

func (t *RequestTemplate) AddAttributes(d *Dictionary, names ...string) error

AddAttributes appends one or more attributes by name to the request template. Returns an error if any attribute is not found in the dictionary.

func (*RequestTemplate) AddVLAN added in v2.2.0

func (t *RequestTemplate) AddVLAN()

AddVLAN appends a vlanTemplate to the request template.

func (*RequestTemplate) AddVSAAttribute added in v2.2.0

func (t *RequestTemplate) AddVSAAttribute(d *Dictionary, vendorName, attrName string) error

AddVSAAttribute appends a VSA attribute by vendor and attribute name to the request template. Returns an error if the vendor or attribute is not found in the dictionary.

func (*RequestTemplate) CreateRequest

func (t *RequestTemplate) CreateRequest(client *RadClient, values ...string) *Packet

CreateRequest generates a new packet from the template with the provided values.

func (*RequestTemplate) Fill

func (t *RequestTemplate) Fill(p *Packet, values ...string)

Fill populates an existing packet with values according to the template.

type Server

type Server struct {
	// contains filtered or unexported fields
}

Server is a simple UDP RADIUS server.

func NewServer

func NewServer(addr string, secret string, service Service) *Server

NewServer constructs a UDP RADIUS server bound to addr with the given shared secret.

func NewServerWithClientList added in v2.1.0

func NewServerWithClientList(addr string, clients *ClientList, service Service) *Server

NewServerWithClientList constructs a UDP RADIUS server bound to addr that resolves shared secrets per client using clients.

If a request comes from a host not present in the list, it is dropped.

func (*Server) ListenAndServe

func (s *Server) ListenAndServe() error

ListenAndServe listens on UDP and processes RADIUS requests until stopped.

Each request is handled in its own goroutine; the server reuses internal buffers to reduce allocations.

func (*Server) SetClientList added in v2.1.0

func (s *Server) SetClientList(clients *ClientList)

SetClientList sets the client list used to resolve per-client shared secrets. When set, the server will prefer the list over the Server.secret field.

func (*Server) Stop

func (s *Server) Stop()

Stop cancels the server context and closes the UDP listener.

type Service

type Service interface {
	RadiusHandle(ctx context.Context, request *Packet) *Packet
}

Service handles inbound RADIUS requests and returns a reply packet.

type ServiceTypeEnum

type ServiceTypeEnum uint32

ServiceTypeEnum is the decoded form of Service-Type.

const (
	ServiceTypeEnumLogin            ServiceTypeEnum = 1
	ServiceTypeEnumFramed           ServiceTypeEnum = 2
	ServiceTypeEnumCallbackLogin    ServiceTypeEnum = 3
	ServiceTypeEnumCallbackFramed   ServiceTypeEnum = 4
	ServiceTypeEnumOutbound         ServiceTypeEnum = 5
	ServiceTypeEnumAdministrative   ServiceTypeEnum = 6
	ServiceTypeEnumNASPrompt        ServiceTypeEnum = 7
	ServiceTypeEnumAuthenticateOnly ServiceTypeEnum = 8
	ServiceTypeEnumCallCheck        ServiceTypeEnum = 10
)

func (ServiceTypeEnum) String

func (e ServiceTypeEnum) String() string

String returns the standard name for the service type value.

type TunnelMediumTypeEnum added in v2.1.0

type TunnelMediumTypeEnum uint32

TunnelMediumTypeEnum is the decoded form of Tunnel-Medium-Type (RFC 2868).

const (
	TunnelMediumTypeEnumIPv4        TunnelMediumTypeEnum = 1
	TunnelMediumTypeEnumIPv6        TunnelMediumTypeEnum = 2
	TunnelMediumTypeEnumNSAP        TunnelMediumTypeEnum = 3
	TunnelMediumTypeEnumHDLC        TunnelMediumTypeEnum = 4
	TunnelMediumTypeEnumBBN1822     TunnelMediumTypeEnum = 5
	TunnelMediumTypeEnum802         TunnelMediumTypeEnum = 6
	TunnelMediumTypeEnumE163        TunnelMediumTypeEnum = 7
	TunnelMediumTypeEnumE164        TunnelMediumTypeEnum = 8
	TunnelMediumTypeEnumF69         TunnelMediumTypeEnum = 9
	TunnelMediumTypeEnumX121        TunnelMediumTypeEnum = 10
	TunnelMediumTypeEnumIPX         TunnelMediumTypeEnum = 11
	TunnelMediumTypeEnumAppletalk   TunnelMediumTypeEnum = 12
	TunnelMediumTypeEnumDecnetIV    TunnelMediumTypeEnum = 13
	TunnelMediumTypeEnumBanyanVines TunnelMediumTypeEnum = 14
	TunnelMediumTypeEnumE164NSAP    TunnelMediumTypeEnum = 15
)

func (TunnelMediumTypeEnum) String added in v2.1.0

func (e TunnelMediumTypeEnum) String() string

String returns the standard name for the tunnel medium type value.

type TunnelTypeEnum added in v2.1.0

type TunnelTypeEnum uint32

TunnelTypeEnum is the decoded form of Tunnel-Type (RFC 2868).

const (
	TunnelTypeEnumPPTP    TunnelTypeEnum = 1
	TunnelTypeEnumL2F     TunnelTypeEnum = 2
	TunnelTypeEnumL2TP    TunnelTypeEnum = 3
	TunnelTypeEnumATMP    TunnelTypeEnum = 4
	TunnelTypeEnumVTP     TunnelTypeEnum = 5
	TunnelTypeEnumAH      TunnelTypeEnum = 6
	TunnelTypeEnumIPIP    TunnelTypeEnum = 7
	TunnelTypeEnumMinIPIP TunnelTypeEnum = 8
	TunnelTypeEnumESP     TunnelTypeEnum = 9
	TunnelTypeEnumGRE     TunnelTypeEnum = 10
	TunnelTypeEnumDVS     TunnelTypeEnum = 11
	TunnelTypeEnumIPInIP  TunnelTypeEnum = 12
	TunnelTypeEnumVLAN    TunnelTypeEnum = 13
)

func (TunnelTypeEnum) String added in v2.1.0

func (e TunnelTypeEnum) String() string

String returns the standard name for the tunnel type value.

type VSA

type VSA struct {
	Vendor VendorID
	Type   VendorAttr
	Value  []byte
}

Vendor

func ToVSA

func ToVSA(a AVP) *VSA

decode AVP value to VSA

func (VSA) ToAVP

func (vsa VSA) ToAVP() AVP

encode VSA attribute under Vendor-Specific AVP

type VendorAttr

type VendorAttr uint8

TODO some VSA has uint16 type (Lucent)

type VendorID

type VendorID uint32

Directories

Path Synopsis
examples
chap_client command
client command
server command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL