radius

package
v1.4.1 Latest Latest
Warning

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

Go to latest
Published: Oct 24, 2026 License: AGPL-3.0 Imports: 30 Imported by: 0

Documentation

Overview

Package radius terminates RADIUS Access-Request for switch and router login. The worker listens on UDP, checks the packet with the NAS shared secret, and binds to LDAP itself. factum2 is where the policy is edited and where accept/reject lines are stored; it is not on the login path.

Index

Constants

View Source
const (
	// Role is the worker.commands name that starts the UDP listener and
	// may fetch /api/radius-config.
	Role = "radius"

	DefaultListen = ":1812"
)
View Source
const DefaultReply = `` /* 684-byte string literal not displayed */

DefaultReply is sent on Access-Accept until an administrator saves a different set. Devices ignore vendor attributes that are not theirs. Each line is one attribute. A leading # skips the line. A # after the value, outside quotes, is a comment and is not sent. =, := and += all add one attribute, so a repeated name is a second copy (FreeRADIUS +=). An unknown name can be written as 26.<vendor>.<type> = value.

Variables

View Source
var ErrBadCredentials = errors.New("bad credentials")

ErrBadCredentials is a wrong username or password. Callers must not treat it as a directory outage.

Functions

func EncodeReply

func EncodeReply(text string) ([]byte, error)

EncodeReply turns reply lines into RADIUS attribute bytes. Message-Authenticator is not included; the caller puts that first.

func ReplyText

func ReplyText(stored *string) string

ReplyText returns the reply lines to send. A nil stored value means the built-in set. An empty string sends no vendor attributes.

func Run

func Run(ctx context.Context, opt Options) error

Run refreshes config, ships the login log, and serves UDP until ctx ends.

func StatePath

func StatePath(override string) string

StatePath is the on-disk config cache. Empty uses the default under /var/lib/factum2. The file holds directory and NAS secrets.

func ValidateListen

func ValidateListen(s string) error

ValidateListen accepts an empty address (the worker uses :1812) or a host:port string such as ":1812" or "10.0.0.5:1812".

func ValidateReply

func ValidateReply(text string) error

ValidateReply reports whether text can be encoded into an Access-Accept.

Types

type Client

type Client struct {
	Name    string `json:"name"`
	Address string `json:"address"`
	Secret  string `json:"secret"`
}

Client is one NAS (router or switch) allowed to send Access-Request.

type Config

type Config struct {
	Enabled  bool            `json:"enabled"`
	Listen   string          `json:"listen"`
	LDAP     ldapauth.Config `json:"ldap"`
	Clients  []Client        `json:"clients"`
	Policies []Policy        `json:"policies"`
	Devices  []Device        `json:"devices"`
	// Reply is the Access-Accept attribute text. Empty sends none.
	Reply string `json:"reply"`
	// Machine is the AD computer account used to check MS-CHAPv2.
	Machine Machine `json:"machine"`
}

Config is the snapshot a worker persists and serves from. LDAP is the directory the worker binds to; it is not read at request time from factum2.

type Device

type Device struct {
	Name      string   `json:"name"`
	Role      string   `json:"role"`
	Enabled   bool     `json:"enabled"`
	Addresses []string `json:"addresses"`
}

Device is one NetBox device the worker can name from an address.

type Event

type Event struct {
	ReportedAt string `json:"reported_at"`
	Username   string `json:"username,omitempty"`
	NASIP      string `json:"nas_ip,omitempty"`
	DeviceName string `json:"device_name,omitempty"`
	DeviceRole string `json:"device_role,omitempty"`
	Result     string `json:"result"`
	Reason     string `json:"reason"`
	Worker     string `json:"worker,omitempty"`
}

Event is one login attempt safe to store. Password is never included.

type Index

type Index struct {
	Enabled bool
	Listen  string
	LDAP    ldapauth.Config
	// contains filtered or unexported fields
}

Index is the lookup form of Config. Ambiguous addresses (two devices, or two clients) are omitted so a login against them fails closed.

func BuildIndex

func BuildIndex(cfg Config) *Index

BuildIndex indexes clients and devices by canonical IP.

type Machine

type Machine struct {
	Account  string `json:"account"`
	Password string `json:"password"`
	Domain   string `json:"domain"`
}

Machine is the Active Directory computer account that opens the NETLOGON channel used to check MS-CHAPv2. Account is the SAM name, including the trailing $.

type Options

type Options struct {
	StatePath string
	Worker    string
	Fetch     func(ctx context.Context) ([]byte, error)
	Report    func(ctx context.Context, body []byte) error
	// Authenticate overrides the LDAP bind. Tests set it. Nil uses ldapauth.
	Authenticate func(cfg ldapauth.Config, username, password string) (groups []string, ok bool, err error)
	// VerifyMSCHAP overrides the Active Directory NETLOGON check. Nil uses
	// verifyMSCHAP. A nil error and a 16-byte session key means the response
	// was accepted. ErrBadCredentials is a wrong password.
	VerifyMSCHAP func(ctx context.Context, cfg ldapauth.Config, machine Machine, username string, challenge, ntResponse []byte) ([]byte, error)
	// LookupGroups overrides the directory group search used after MS-CHAPv2.
	LookupGroups func(cfg ldapauth.Config, username string) (groups []string, found bool, err error)
}

Options wires the listener to the hub. Fetch and Report may fail while factum2 is down; the last Config on disk keeps answering.

type Packet

type Packet struct {
	Code byte
	ID   byte
	Auth [16]byte
	Raw  []byte
}

Packet is a parsed RADIUS message. Raw is the on-wire bytes of Length, which is what the Message-Authenticator covers.

type Policy

type Policy struct {
	GroupDN    string   `json:"group_dn"`
	AllDevices bool     `json:"all_devices"`
	Roles      []string `json:"roles"`
}

Policy maps one LDAP group to NetBox device roles. AllDevices permits every role, including a device whose role is blank.

type Server

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

Server answers RADIUS on UDP. The snapshot is swapped as a whole.

Jump to

Keyboard shortcuts

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