eap

package module
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Sep 3, 2026 License: MIT Imports: 15 Imported by: 0

README

Go Report Card pkg.go.dev

radius-eap

A production-oriented implementation of common EAP methods for RADIUS in Go — race-free, state-safe, and tested clause-by-clause against the relevant RFCs.

Supported methods

EAP method Type Specification
Identity 1 RFC 3748 Section 5.1
Legacy Nak 3 RFC 3748 Section 5.3.1
GTC (OTP, in-tunnel) 6 RFC 3748 Section 5.6
EAP-TLS 13 RFC 5216 / RFC 9190
PEAP (PEAPv0) 25 draft-josefsson / draft-kamath
MS-CHAP-v2 (in-tunnel or standalone) 26 RFC 2759 / RFC 3079 / draft-kamath

Documentation

Architecture and per-protocol RFC references live in _RFC.md, which indexes a detailed document (with diagrams) for each protocol. Start there to see how a protocol works and which file/function implements which RFC clause.

Usage

Implement protocol.StateManager (or use the bundled eap.NewMemoryStateManager, a concurrency-safe store with TTL eviction), then decode the EAP-Message from each RADIUS request and let the library drive the exchange:

sm := eap.NewMemoryStateManager(settings, 5*time.Minute)
defer sm.Close()

func (s *Server) ServeRADIUS(w radius.ResponseWriter, r *radius.Request) {
    raw := rfc2869.EAPMessage_Get(r.Packet)
    if len(raw) == 0 {
        return
    }
    pkt, err := eap.Decode(sm, raw)
    if err != nil {
        return
    }
    pkt.HandleRadiusPacket(w, r) // writes Access-Challenge/Accept/Reject
}

See examples/server for a complete EAP-TLS + PEAP-MSCHAPv2 server.

Testing

make test       # unit tests + eapol_test integration
make test-race  # the full suite under the race detector

Integration tests use eapol_test (sudo apt install eapoltest) and a minimal PKI (a CA, a server certificate, and — for EAP-TLS — a client certificate). Run a client against the server with:

eapol_test -c peap.conf -s foo -a <radius-server-ip>
PEAP (phase 2: MS-CHAP-v2)
network={
    ssid="DoesNotMatterForThisTest"
    key_mgmt=WPA-EAP
    eap=PEAP
    identity="foo"
    password="bar"
    ca_cert="ca.pem"
    phase2="auth=MSCHAPV2"
}
EAP-TLS
network={
    ssid="DoesNotMatterForThisTest"
    key_mgmt=WPA-EAP
    eap=TLS
    identity="foo"
    ca_cert="ca.pem"
    client_cert="cert_client.pem"
    private_key="cert_client.key"
    eapol_flags=3
    eap_workaround=0
}

Acknowledgements

Originally forked from BeryJu/radius-eap; see BeryJu's write-up Implementing EAP. This fork has since been substantially reworked (race-free EAP-TLS transport, session-safe state handling, DoS hardening, RFC documentation, and expanded tests).

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DefaultLogger

func DefaultLogger() *stdLogger

Types

type MemoryStateManager added in v0.2.0

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

MemoryStateManager is a ready-to-use, concurrency-safe protocol.StateManager backed by an in-memory map with time-based eviction. It exists so consumers do not have to re-implement the same map+mutex+TTL boilerplate (and so they avoid the unbounded-growth bug of a naive map that never evicts abandoned EAP sessions).

A single MemoryStateManager serves one EAP configuration (protocol.Settings). Construct it once at startup and share it across requests.

func NewMemoryStateManager added in v0.2.0

func NewMemoryStateManager(settings protocol.Settings, ttl time.Duration) *MemoryStateManager

NewMemoryStateManager returns a MemoryStateManager for the given settings. If ttl > 0 a background goroutine evicts sessions whose last access is older than ttl; ttl <= 0 disables eviction (sessions live until the process exits). Call Close to stop the eviction goroutine when the manager is no longer needed.

func (*MemoryStateManager) AcceptNewSession added in v0.5.0

func (m *MemoryStateManager) AcceptNewSession() bool

AcceptNewSession implements protocol.SessionLimiter.

func (*MemoryStateManager) Close added in v0.2.0

func (m *MemoryStateManager) Close()

Close stops the background eviction goroutine. It is safe to call more than once.

func (*MemoryStateManager) Delete added in v0.2.0

func (m *MemoryStateManager) Delete(key string)

Delete removes a session immediately, e.g. once authentication has resolved.

func (*MemoryStateManager) GetEAPSettings added in v0.2.0

func (m *MemoryStateManager) GetEAPSettings() protocol.Settings

func (*MemoryStateManager) GetEAPState added in v0.2.0

func (m *MemoryStateManager) GetEAPState(key string) *protocol.State

func (*MemoryStateManager) Len added in v0.2.0

func (m *MemoryStateManager) Len() int

Len reports the number of live sessions. Primarily useful for tests/metrics.

func (*MemoryStateManager) SetEAPState added in v0.2.0

func (m *MemoryStateManager) SetEAPState(key string, state *protocol.State)

func (*MemoryStateManager) SetMaxSessions added in v0.5.0

func (m *MemoryStateManager) SetMaxSessions(n int)

SetMaxSessions bounds the number of live sessions. Once the bound is reached AcceptNewSession reports false and the handler rejects requests that would start another conversation; existing sessions continue. Zero removes the bound.

The bound is soft: AcceptNewSession and the insert that follows it are not one atomic step, so concurrent starts can overshoot by up to the number of requests in flight. That is enough for its purpose, which is to stop unbounded growth rather than to hold an exact number.

type Packet

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

func Decode

func Decode(stm protocol.StateManager, raw []byte) (*Packet, error)

Decode parses the raw EAP-Message bytes from a RADIUS Access-Request into a Packet ready for HandleRadiusPacket. The StateManager supplies the method settings used to resolve the inner method payload. It returns an error if the bytes are not a well-formed EAP packet.

func (*Packet) Encode

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

Encode serializes the packet's EAP payload into the bytes to place in the outbound EAP-Message attribute.

func (*Packet) HandleRadiusPacket

func (p *Packet) HandleRadiusPacket(w radius.ResponseWriter, r *radius.Request)

HandleRadiusPacket processes one decoded EAP Access-Request and writes the RADIUS response. It resolves the session State, runs the EAP method state machine (handleEAP), maps the resulting EAP Code to a RADIUS code (Request→Access-Challenge, Success→Access-Accept, Failure→Access-Reject), applies any registered response modifiers, attaches the State on challenges, and finally sets the RFC 2869 Message-Authenticator. It never returns an error: failures are turned into an Access-Reject.

Directories

Path Synopsis
examples
server command
eap
gtc
tls

Jump to

Keyboard shortcuts

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