radius

package module
v0.0.0-...-1006025 Latest Latest
Warning

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

Go to latest
Published: Dec 13, 2023 License: MPL-2.0 Imports: 13 Imported by: 370

README

radius

a Go (golang) RADIUS client and server implementation

Go Reference

Installation

go get -u layeh.com/radius

Client example

package main

import (
	"context"
	"log"

	"layeh.com/radius"
	"layeh.com/radius/rfc2865"
)

func main() {
	packet := radius.New(radius.CodeAccessRequest, []byte(`secret`))
	rfc2865.UserName_SetString(packet, "tim")
	rfc2865.UserPassword_SetString(packet, "12345")
	response, err := radius.Exchange(context.Background(), packet, "localhost:1812")
	if err != nil {
		log.Fatal(err)
	}

	log.Println("Code:", response.Code)
}

Server example

package main

import (
	"log"

	"layeh.com/radius"
	"layeh.com/radius/rfc2865"
)

func main() {
	handler := func(w radius.ResponseWriter, r *radius.Request) {
		username := rfc2865.UserName_GetString(r.Packet)
		password := rfc2865.UserPassword_GetString(r.Packet)

		var code radius.Code
		if username == "tim" && password == "12345" {
			code = radius.CodeAccessAccept
		} else {
			code = radius.CodeAccessReject
		}
		log.Printf("Writing %v to %v", code, r.RemoteAddr)
		w.Write(r.Response(code))
	}

	server := radius.PacketServer{
		Handler:      radius.HandlerFunc(handler),
		SecretSource: radius.StaticSecretSource([]byte(`secret`)),
	}

	log.Printf("Starting server on :1812")
	if err := server.ListenAndServe(); err != nil {
		log.Fatal(err)
	}
}

RADIUS Dictionaries

Included in this package is the command line program radius-dict-gen. It can be installed with:

go get -u layeh.com/radius/cmd/radius-dict-gen

Given a FreeRADIUS dictionary, the program will generate helper functions and types for reading and manipulating RADIUS attributes in a packet. It is recommended that generated code be used for any RADIUS dictionary you would like to consume.

Included in this repository are sub-packages of generated helpers for commonly used RADIUS attributes, including rfc2865 and rfc2866.

License

MPL 2.0

Author

Tim Cooper (tim.cooper@layeh.com)

Documentation

Overview

Package radius provides a RADIUS client and server (RFC 2865, RFC 2866).

Example (Client)
package main

import (
	"context"
	"log"

	"layeh.com/radius"
	"layeh.com/radius/rfc2865"
)

var (
	ClientUsername = "tim"
	ClientPassword = "12345"
)

func main() {
	packet := radius.New(radius.CodeAccessRequest, []byte(`secret`))
	rfc2865.UserName_SetString(packet, ClientUsername)
	rfc2865.UserPassword_SetString(packet, ClientPassword)
	response, err := radius.Exchange(context.Background(), packet, "localhost:1812")
	if err != nil {
		log.Fatal(err)
	}

	log.Println("Code:", response.Code)
}
Output:

Example (PacketServer)
package main

import (
	"log"

	"layeh.com/radius"
	"layeh.com/radius/rfc2865"
)

var (
	ServerUsername = "tim"
	ServerPassword = "12345"
)

func main() {
	handler := func(w radius.ResponseWriter, r *radius.Request) {
		username := rfc2865.UserName_GetString(r.Packet)
		password := rfc2865.UserPassword_GetString(r.Packet)

		var code radius.Code
		if username == ServerUsername && password == ServerPassword {
			code = radius.CodeAccessAccept
		} else {
			code = radius.CodeAccessReject
		}
		log.Printf("Writing %v to %v", code, r.RemoteAddr)
		w.Write(r.Response(code))
	}

	server := radius.PacketServer{
		Handler:      radius.HandlerFunc(handler),
		SecretSource: radius.StaticSecretSource([]byte(`secret`)),
	}

	log.Printf("Starting server on :1812")
	if err := server.ListenAndServe(); err != nil {
		log.Fatal(err)
	}
}
Output:

Index

Examples

Constants

View Source
const MaxPacketLength = 4096

MaxPacketLength is the maximum wire length of a RADIUS packet.

Variables

View Source
var DefaultClient = &Client{
	Retry:           time.Second,
	MaxPacketErrors: 10,
}

DefaultClient is the RADIUS client used by the Exchange function.

View Source
var ErrNoAttribute = errors.New("radius: attribute not found")

ErrNoAttribute is returned when an attribute was not found when one was expected.

View Source
var ErrServerShutdown = errors.New("radius: server shutdown")

ErrServerShutdown is returned from server Serve methods when Shutdown has been called and handlers are still completing.

Functions

func AttributesEncodedLen

func AttributesEncodedLen(a Attributes) (int, error)

AttributesEncodedLen returns the encoded length of all attributes in a. An error is returned if any attribute in a exceeds the permitted size.

func Bytes

func Bytes(a Attribute) []byte

Bytes returns the given Attribute as a byte slice.

func Date

func Date(a Attribute) (time.Time, error)

Date returns the given Attribute as time.Time. An error is returned if the attribute is not 4 bytes long.

func IFID

func IFID(a Attribute) (net.HardwareAddr, error)

IFID returns the given attribute as a 8-byte hardware address. An error is return if the attribute is not 8 bytes long.

func IPAddr

func IPAddr(a Attribute) (net.IP, error)

IPAddr returns the given Attribute as an IPv4 IP address. An error is returned if the attribute is not 4 bytes long.

func IPv6Addr

func IPv6Addr(a Attribute) (net.IP, error)

IPv6Addr returns the given Attribute as an IPv6 IP address. An error is returned if the attribute is not 16 bytes long.

func IPv6Prefix

func IPv6Prefix(a Attribute) (*net.IPNet, error)

func Integer

func Integer(a Attribute) (uint32, error)

Integer returns the given attribute as an integer. An error is returned if the attribute is not 4 bytes long.

func Integer64

func Integer64(a Attribute) (uint64, error)

Integer64 returns the given attribute as an integer. An error is returned if the attribute is not 8 bytes long.

func IsAuthenticRequest

func IsAuthenticRequest(request, secret []byte) bool

IsAuthenticRequest returns if the given RADIUS request is an authentic request using the given secret.

func IsAuthenticResponse

func IsAuthenticResponse(response, request, secret []byte) bool

IsAuthenticResponse returns if the given RADIUS response is an authentic response to the given request.

func Short

func Short(a Attribute) (uint16, error)

Short returns the given attribute as an integer. An error is returned if the attribute is not 2 bytes long.

func String

func String(a Attribute) string

String returns the given attribute as a string.

func TunnelPassword

func TunnelPassword(a Attribute, secret, requestAuthenticator []byte) (password, salt []byte, err error)

TunnelPassword decrypts an RFC 2868 encrypted Tunnel-Password. The Attribute must not be prefixed with a tag. The requestAuthenticator must be from the Access-Request packet.

func UserPassword

func UserPassword(a Attribute, secret, requestAuthenticator []byte) ([]byte, error)

UserPassword decrypts the given "User-Password"-encrypted (as defined in RFC 2865) Attribute, and returns the plaintext. An error is returned if the attribute length is invalid, the secret is empty, or the requestAuthenticator length is invalid.

Types

type AVP

type AVP struct {
	Type
	Attribute
}

AVP is an attribute-value pair. It contains an attribute type and its wire data.

type Attribute

type Attribute []byte

Attribute is a wire encoded RADIUS attribute value.

func NewBytes

func NewBytes(b []byte) (Attribute, error)

NewBytes returns a new Attribute from the given byte slice. An error is returned if the slice is longer than 253.

func NewDate

func NewDate(t time.Time) (Attribute, error)

NewDate returns a new Attribute from the given time.Time.

func NewIFID

func NewIFID(addr net.HardwareAddr) (Attribute, error)

NewIFID returns a new Attribute from the given hardware address. An error is returned if the address is not 8 bytes long.

func NewIPAddr

func NewIPAddr(a net.IP) (Attribute, error)

NewIPAddr returns a new Attribute from the given IP address. An error is returned if the given address is not an IPv4 address.

func NewIPv6Addr

func NewIPv6Addr(a net.IP) (Attribute, error)

NewIPv6Addr returns a new Attribute from the given IP address. An error is returned if the given address is not an IPv6 address.

func NewIPv6Prefix

func NewIPv6Prefix(prefix *net.IPNet) (Attribute, error)

func NewInteger

func NewInteger(i uint32) Attribute

NewInteger creates a new Attribute from the given integer value.

func NewInteger64

func NewInteger64(i uint64) Attribute

NewInteger64 creates a new Attribute from the given integer value.

func NewShort

func NewShort(i uint16) Attribute

NewShort creates a new Attribute from the given integer value.

func NewString

func NewString(s string) (Attribute, error)

NewString returns a new Attribute from the given string. An error is returned if the string length is greater than 253.

func NewTLV

func NewTLV(tlvType byte, tlvValue Attribute) (Attribute, error)

NewTLV returns a new TLV attribute.

func NewTunnelPassword

func NewTunnelPassword(password, salt, secret, requestAuthenticator []byte) (Attribute, error)

NewTunnelPassword returns an RFC 2868 encrypted Tunnel-Password. A tag must be added on to the returned Attribute.

func NewUserPassword

func NewUserPassword(plaintext, secret, requestAuthenticator []byte) (Attribute, error)

NewUserPassword returns a new "User-Password"-encrypted attribute from the given plaintext, secret, and requestAuthenticator. An error is returned if the plaintext is too long, the secret is empty, or the requestAuthenticator is an invalid length.

func NewVendorSpecific

func NewVendorSpecific(vendorID uint32, value Attribute) (Attribute, error)

NewVendorSpecific returns a new vendor specific attribute with the given vendor ID and value.

func TLV

func TLV(a Attribute) (tlvType byte, tlvValue Attribute, err error)

TLV returns a components of a Type-Length-Value (TLV) attribute.

func VendorSpecific

func VendorSpecific(a Attribute) (vendorID uint32, value Attribute, err error)

VendorSpecific returns the vendor ID and value from the given attribute. An error is returned if the attribute is less than 5 bytes long.

type Attributes

type Attributes []*AVP

Attributes is a list of RADIUS attributes.

func ParseAttributes

func ParseAttributes(b []byte) (Attributes, error)

ParseAttributes parses the wire-encoded RADIUS attributes and returns a new Attributes value. An error is returned if the buffer is malformed.

func (*Attributes) Add

func (a *Attributes) Add(key Type, value Attribute)

Add appends the given Attribute to the list of attributes.

func (*Attributes) Del

func (a *Attributes) Del(key Type)

Del removes all Attributes of the given type from a.

func (*Attributes) Get

func (a *Attributes) Get(key Type) Attribute

Get returns the first Attribute of Type key. nil is returned if no Attribute of Type key exists in a.

func (*Attributes) Lookup

func (a *Attributes) Lookup(key Type) (Attribute, bool)

Lookup returns the first Attribute of Type key. nil and false is returned if no Attribute of Type key exists in a.

func (*Attributes) Set

func (a *Attributes) Set(key Type, value Attribute)

Set removes all Attributes of Type key and appends value.

type Client

type Client struct {
	// Network on which to make the connection. Defaults to "udp".
	Net string

	// Dialer to use when making the outgoing connections.
	Dialer net.Dialer

	// Interval on which to resend packet (zero or negative value means no
	// retry).
	Retry time.Duration

	// MaxPacketErrors controls how many packet parsing and validation errors
	// the client will ignore before returning the error from Exchange.
	//
	// If zero, Exchange will drop all packet parsing errors.
	MaxPacketErrors int

	// InsecureSkipVerify controls whether the client should skip verifying
	// response packets received.
	InsecureSkipVerify bool
}

Client is a RADIUS client that can exchange packets with a RADIUS server.

func (*Client) Exchange

func (c *Client) Exchange(ctx context.Context, packet *Packet, addr string) (*Packet, error)

Exchange sends the packet to the given server and waits for a response. ctx must be non-nil.

type Code

type Code int

Code defines the RADIUS packet type.

const (
	CodeAccessRequest      Code = 1
	CodeAccessAccept       Code = 2
	CodeAccessReject       Code = 3
	CodeAccountingRequest  Code = 4
	CodeAccountingResponse Code = 5
	CodeAccessChallenge    Code = 11
	CodeStatusServer       Code = 12
	CodeStatusClient       Code = 13
	CodeDisconnectRequest  Code = 40
	CodeDisconnectACK      Code = 41
	CodeDisconnectNAK      Code = 42
	CodeCoARequest         Code = 43
	CodeCoAACK             Code = 44
	CodeCoANAK             Code = 45
	CodeReserved           Code = 255
)

Standard RADIUS packet codes.

func (Code) String

func (c Code) String() string

String returns a string representation of the code.

type Handler

type Handler interface {
	ServeRADIUS(w ResponseWriter, r *Request)
}

Handler provides a handler to RADIUS server requests. When a RADIUS request is received, ServeRADIUS is called.

type HandlerFunc

type HandlerFunc func(w ResponseWriter, r *Request)

HandlerFunc allows a function to implement Handler.

func (HandlerFunc) ServeRADIUS

func (h HandlerFunc) ServeRADIUS(w ResponseWriter, r *Request)

ServeRADIUS calls h(w, p).

type NonAuthenticResponseError

type NonAuthenticResponseError struct {
}

NonAuthenticResponseError is returned when a client was expecting a valid response but did not receive one.

func (*NonAuthenticResponseError) Error

func (e *NonAuthenticResponseError) Error() string

type Packet

type Packet struct {
	Code          Code
	Identifier    byte
	Authenticator [16]byte
	Secret        []byte
	Attributes
}

Packet is a RADIUS packet.

func Exchange

func Exchange(ctx context.Context, packet *Packet, addr string) (*Packet, error)

Exchange uses DefaultClient to send the given RADIUS packet to the server at address addr and waits for a response.

func New

func New(code Code, secret []byte) *Packet

New creates a new packet with the Code, Secret fields set to the given values. The returned packet's Identifier and Authenticator fields are filled with random values.

The function panics if not enough random data could be generated.

func Parse

func Parse(b, secret []byte) (*Packet, error)

Parse parses an encoded RADIUS packet b. An error is returned if the packet is malformed.

func (*Packet) Encode

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

Encode encodes the RADIUS packet to wire format that can then be sent to a RADIUS client.

If the RADIUS packet code requires it, the authenticator in the returned data will be a hash calculation based off of the packet data and secret. Use MarshalBinary() to get the packet in wire format without the hash calculation.

An error is returned if the encoded packet is too long (due to its Attributes), or if the packet has an unknown Code.

func (*Packet) MarshalBinary

func (p *Packet) MarshalBinary() ([]byte, error)

MarshalBinary returns the packet in wire format.

The authenticator in the returned data is copied from p.Authenticator without any hash calculation. Use Encode() if the packet is intended to be sent to a RADIUS client and requires the authenticator to be calculated.

func (*Packet) Response

func (p *Packet) Response(code Code) *Packet

Response returns a new packet that has the same identifier, secret, and authenticator as the current packet.

type PacketServer

type PacketServer struct {
	// The address on which the server listens. Defaults to :1812.
	Addr string

	// The network on which the server listens. Defaults to udp.
	Network string

	// The source from which the secret is obtained for parsing and validating
	// the request.
	SecretSource SecretSource

	// Handler which is called to process the request.
	Handler Handler

	// Skip incoming packet authenticity validation.
	// This should only be set to true for debugging purposes.
	InsecureSkipVerify bool

	// ErrorLog specifies an optional logger for errors
	// around packet accepting, processing, and validation.
	// If nil, logging is done via the log package's standard logger.
	ErrorLog *log.Logger
	// contains filtered or unexported fields
}

PacketServer listens for RADIUS requests on a packet-based protocols (e.g. UDP).

func (*PacketServer) ListenAndServe

func (s *PacketServer) ListenAndServe() error

ListenAndServe starts a RADIUS server on the address given in s.

func (*PacketServer) Serve

func (s *PacketServer) Serve(conn net.PacketConn) error

Serve accepts incoming connections on conn.

func (*PacketServer) Shutdown

func (s *PacketServer) Shutdown(ctx context.Context) error

Shutdown gracefully stops the server. It first closes all listeners and then waits for any running handlers to complete.

Shutdown returns after nil all handlers have completed. ctx.Err() is returned if ctx is canceled.

Any Serve methods return ErrShutdown after Shutdown is called.

type Request

type Request struct {
	// LocalAddr is the local address on which the incoming RADIUS request
	// was received.
	LocalAddr net.Addr
	// RemoteAddr is the address from which the incoming RADIUS request
	// was sent.
	RemoteAddr net.Addr

	// Packet is the RADIUS packet sent in the request.
	*Packet
	// contains filtered or unexported fields
}

Request is an incoming RADIUS request that is being handled by the server.

func (*Request) Context

func (r *Request) Context() context.Context

Context returns the context of the request. If a context has not been set using WithContext, the Background context is returned.

func (*Request) WithContext

func (r *Request) WithContext(ctx context.Context) *Request

WithContext returns a shallow copy of the request with the new request's context set to the given context.

type ResponseWriter

type ResponseWriter interface {
	Write(packet *Packet) error
}

ResponseWriter is used by RADIUS servers when replying to a RADIUS request.

type SecretSource

type SecretSource interface {
	RADIUSSecret(ctx context.Context, remoteAddr net.Addr) ([]byte, error)
}

SecretSource supplies RADIUS servers with the secret that should be used for authorizing and decrypting packets.

ctx is canceled if the server's Shutdown method is called.

Returning an empty secret will discard the incoming packet.

func StaticSecretSource

func StaticSecretSource(secret []byte) SecretSource

StaticSecretSource returns a SecretSource that uses secret for all requests.

type Type

type Type int

Type is the RADIUS attribute type.

const TypeInvalid Type = -1

TypeInvalid is a Type that can be used to represent an invalid RADIUS attribute type.

Directories

Path Synopsis
cmd
Package debug contains utilities for debugging RADIUS packets.
Package debug contains utilities for debugging RADIUS packets.
Package dictionary parses FreeRADIUS dictionary files.
Package dictionary parses FreeRADIUS dictionary files.
internal
vendors

Jump to

Keyboard shortcuts

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