Documentation
¶
Index ¶
- Constants
- func NewState(c protocol.Context) any
- func Protocol() protocol.Payload
- type BuffConn
- func (c *BuffConn) Close() error
- func (c *BuffConn) FeedFlight(data []byte)
- func (c *BuffConn) HarvestFlight() []byte
- func (c *BuffConn) InboundLen() int
- func (c *BuffConn) LocalAddr() net.Addr
- func (c *BuffConn) OutboundLen() int
- func (c *BuffConn) PeekInbound() []byte
- func (c *BuffConn) Read(p []byte) (int, error)
- func (c *BuffConn) ReadWaiting() bool
- func (c *BuffConn) RemoteAddr() net.Addr
- func (c *BuffConn) ResetInbound()
- func (c *BuffConn) ResetOutbound()
- func (c *BuffConn) SetDeadline(t time.Time) error
- func (c *BuffConn) SetReadDeadline(t time.Time) error
- func (c *BuffConn) SetWriteDeadline(t time.Time) error
- func (c *BuffConn) WaitOutbound(done, errc <-chan struct{}) WaitOutcome
- func (c *BuffConn) Write(p []byte) (int, error)
- type Flag
- type Payload
- func (p *Payload) Decode(raw []byte) error
- func (p *Payload) Encode() ([]byte, error)
- func (p *Payload) Handle(ctx protocol.Context) protocol.Payload
- func (p *Payload) HasInner() protocol.Payload
- func (p *Payload) ModifyRADIUSResponse(r *radius.Packet, q *radius.Packet) error
- func (p *Payload) Offerable() bool
- func (p *Payload) String() string
- func (p *Payload) Type() protocol.Type
- type Settings
- type State
- type TLSConfig
- type WaitOutcome
Constants ¶
const TypeTLS protocol.Type = 13
Variables ¶
This section is empty.
Functions ¶
Types ¶
type BuffConn ¶
type BuffConn struct {
// contains filtered or unexported fields
}
BuffConn is an in-memory net.Conn that bridges a sequence of short-lived EAP handler invocations with the single long-lived crypto/tls handshake goroutine started in tlsInit.
Threading model:
- The TLS goroutine is the SOLE caller of Read/Write/Close/deadline setters.
- Handler goroutines are the SOLE callers of FeedFlight/WaitOutbound/ HarvestFlight and the inspection helpers.
Every field is guarded by mu. State changes are published by replacing the notify channel (broadcastLocked), which both Read and WaitOutbound select on; this gives condition-variable semantics that also compose with context cancellation and deadlines. The previous implementation shared two *bytes.Buffer values and a pair of non-atomic counters across both goroutines and relied on retry/backoff timing for correctness, which is a data race.
func NewBuffConn ¶
NewBuffConn creates an empty conn. Peer data (including the first ClientHello flight) is delivered exclusively through FeedFlight so there is a single ingestion path.
func (*BuffConn) FeedFlight ¶ added in v0.2.0
FeedFlight delivers one complete, reassembled peer flight (EAP fragmentation already stripped by the payload layer) and wakes a parked Read. It resets the read-waiting state because it provides exactly the data the TLS goroutine was waiting for, which prevents a later WaitOutbound from observing a stale "waiting" signal from before this flight.
func (*BuffConn) HarvestFlight ¶ added in v0.2.0
HarvestFlight atomically drains and returns the accumulated outbound bytes.
func (*BuffConn) InboundLen ¶ added in v0.2.0
InboundLen reports how many inbound bytes are buffered (unconsumed by TLS).
func (*BuffConn) OutboundLen ¶ added in v0.2.0
OutboundLen reports how many outbound bytes are buffered.
func (*BuffConn) PeekInbound ¶ added in v0.2.0
PeekInbound returns a copy of the unconsumed inbound bytes.
func (*BuffConn) Read ¶
Read implements net.Conn for the TLS goroutine. It returns buffered inbound bytes immediately (supporting short reads); otherwise it records that it is waiting, wakes any pending WaitOutbound, and parks until more data arrives, the conn is closed, the context is cancelled, or the read deadline fires.
func (*BuffConn) ReadWaiting ¶ added in v0.2.0
ReadWaiting reports whether the TLS goroutine is currently parked waiting for more peer data. Intended for tests.
func (*BuffConn) RemoteAddr ¶
func (*BuffConn) ResetInbound ¶ added in v0.2.0
func (c *BuffConn) ResetInbound()
ResetInbound discards any unconsumed inbound bytes.
func (*BuffConn) ResetOutbound ¶ added in v0.2.0
func (c *BuffConn) ResetOutbound()
ResetOutbound discards any unharvested outbound bytes.
func (*BuffConn) WaitOutbound ¶ added in v0.2.0
func (c *BuffConn) WaitOutbound(done, errc <-chan struct{}) WaitOutcome
WaitOutbound blocks until the TLS goroutine has produced outbound bytes, is parked waiting for the next peer flight, the handshake finished (done), the handshake errored (errc), the context expired, or the conn closed. It never busy-polls. done and errc may be nil (those arms simply never fire).
type Payload ¶
type Payload struct {
Flags Flag
Length uint32
Data []byte
Inner protocol.Payload
// contains filtered or unexported fields
}
func (*Payload) Handle ¶
Handle advances the EAP-TLS exchange by one RADIUS round-trip: on first call it starts the TLS handshake (tlsInit), then on each call it feeds the reassembled peer flight to the background handshake goroutine, waits for the goroutine's response without polling, fragments and returns the outbound flight, and on completion resolves the final status — or, when wrapped by PEAP, delegates the protected channel to the inner protocol. See _RFC.md for the concurrency model.
func (*Payload) ModifyRADIUSResponse ¶
type Settings ¶
type Settings struct {
Config *tls.Config
// VerifyPeerCertificate mirrors tls.Config.VerifyPeerCertificate while adding
// protocol.Context. Note that Go does not invoke this callback on resumed
// connections.
VerifyPeerCertificate func(ctx protocol.Context, rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
// VerifyConnection mirrors tls.Config.VerifyConnection while adding
// protocol.Context. Prefer this hook for production-critical validation that
// must also run on resumed connections.
VerifyConnection func(ctx protocol.Context, cs tls.ConnectionState) error
// HandshakeSuccessful runs after the TLS handshake has completed and the EAP
// layer is ready to decide whether the authenticated client should proceed.
HandshakeSuccessful func(ctx protocol.Context, certs []*x509.Certificate) protocol.Status
// MaxMessageSize bounds a single reassembled EAP-TLS message (one peer
// flight). Zero selects the package default (64 KiB). It guards against a
// malicious peer declaring an enormous fragmented message (RFC 5216 Section 3.1).
MaxMessageSize int
}
Settings defines the reusable TLS extension points for EAP-TLS/PEAP consumers.
Consumers that only need native Go TLS client-certificate enforcement can keep Config.ClientAuth at tls.RequireAndVerifyClientCert and leave the hooks nil.
Consumers that need identity-aware inspection or application-specific policy decisions during the handshake can instead require certificate presence (typically tls.RequireAnyClientCert) and perform their own validation in VerifyConnection. That hook runs for all connections, including resumptions.
func (Settings) MaxTLSMessageSize ¶ added in v0.2.0
MaxTLSMessageSize exposes the configured reassembly bound to the TLS layer.
type State ¶
type State struct {
// TLS is the server side of the in-memory TLS connection; Conn is the
// byte pipe it reads from / writes to. Context (with ContextCancel) bounds
// the whole handshake to staleConnectionTimeout and is cancelled when the
// exchange ends. ClientHello captures the peer's hello for inspection.
TLS *tls.Conn
Conn *BuffConn
Context context.Context
ContextCancel context.CancelFunc
ClientHello *tls.ClientHelloInfo
HandshakeDone bool
FinalStatus protocol.Status
HandshakeDoneCh chan struct{}
HandshakeErrCh chan struct{}
// --- Outbound fragmentation (server -> peer) ---
//
// A TLS flight larger than maxChunkSize is split into RemainingChunks and
// sent across several EAP-TLS fragments. TotalPayloadSize is the original
// size advertised in the first fragment's Length field, and
// IncludeLengthInNextFragment marks that first fragment.
RemainingChunks [][]byte
TotalPayloadSize int
IncludeLengthInNextFragment bool
// MPPEKey is the exported keying material (RFC 5216) used to derive the
// MS-MPPE-Recv/Send keys returned on Access-Accept.
MPPEKey []byte
// HandshakeCtx is the protocol.Context handed to the handshake-completion
// callbacks; Logger is the session logger.
HandshakeCtx protocol.Context
Logger protocol.Logger
// contains filtered or unexported fields
}
State is the per-session state for the EAP-TLS / PEAP outer layer. One State lives for the whole TLS exchange of a single EAP session and is persisted between RADIUS round-trips by the StateManager.
Concurrency model: the TLS handshake runs on a dedicated background goroutine (started in tlsInit) while each RADIUS packet is processed on a separate handler goroutine. The two communicate through Conn (a race-free BuffConn) and through the synchronization fields below. Every field that both goroutines may touch is accessed only through the helper methods on State, never directly, so the locking stays in one place.
func (*State) FinalStatusValue ¶ added in v0.1.4
func (*State) HandshakeDoneValue ¶ added in v0.1.4
func (*State) SetFinalStatus ¶ added in v0.1.4
func (*State) SetHandshakeDone ¶ added in v0.1.4
type WaitOutcome ¶ added in v0.2.0
type WaitOutcome int
WaitOutcome reports why WaitOutbound returned.
const ( // WaitFlightBoundary: the TLS goroutine produced outbound data and/or is // parked waiting for the next peer flight. The caller should harvest. WaitFlightBoundary WaitOutcome = iota // WaitHandshakeDone: the handshake completed successfully. WaitHandshakeDone // WaitError: the handshake goroutine reported an error. WaitError // WaitTimeout: the stale-connection context expired. WaitTimeout // WaitClosed: the conn was closed. WaitClosed )