Documentation
¶
Overview ¶
Package gotacacs implements the TACACS+ protocol as defined in RFC8907. It provides both client and server SDK interfaces for Authentication, Authorization, and Accounting (AAA) services.
TACACS+ is a security protocol that provides centralized access control for network devices. This package supports TCP and TLS transports with body obfuscation using MD5-based pseudo-pad generation.
Client Usage ¶
Create a client to connect to a TACACS+ server:
client := gotacacs.NewClient(
gotacacs.WithAddress("tacacs.example.com:49"),
gotacacs.WithSecret("sharedsecret"),
gotacacs.WithTimeout(30*time.Second),
)
// Authenticate a user
reply, err := client.Authenticate(ctx, "username", "password")
if err != nil {
log.Fatal(err)
}
if reply.IsPass() {
fmt.Println("Authentication successful")
}
// Authorize a user
resp, err := client.Authorize(ctx, "username", []string{"service=shell", "cmd=show"})
if err != nil {
log.Fatal(err)
}
if resp.IsPass() {
fmt.Println("Authorization granted")
}
// Send accounting records
acctReply, err := client.Accounting(ctx, gotacacs.AcctFlagStart, "username", []string{"task_id=123"})
if err != nil {
log.Fatal(err)
}
if acctReply.IsSuccess() {
fmt.Println("Accounting recorded")
}
Server Usage ¶
Create a server with custom handlers:
ln, err := gotacacs.ListenTCP(":49")
if err != nil {
log.Fatal(err)
}
server := gotacacs.NewServer(
gotacacs.WithServerListener(ln),
gotacacs.WithServerSecret("sharedsecret"),
gotacacs.WithHandler(&myHandler{}),
)
if err := server.Serve(); err != nil {
log.Fatal(err)
}
Handler Implementation ¶
Implement the Handler interface to process requests:
type myHandler struct{}
func (h *myHandler) HandleAuthenStart(_ context.Context, req *gotacacs.AuthenRequest) *gotacacs.AuthenReply {
if string(req.Start.User) == "admin" && string(req.Start.Data) == "password" {
return &gotacacs.AuthenReply{Status: gotacacs.AuthenStatusPass}
}
return &gotacacs.AuthenReply{Status: gotacacs.AuthenStatusFail}
}
func (h *myHandler) HandleAuthenContinue(_ context.Context, _ *gotacacs.AuthenContinueRequest) *gotacacs.AuthenReply {
return &gotacacs.AuthenReply{Status: gotacacs.AuthenStatusPass}
}
func (h *myHandler) HandleAuthorRequest(_ context.Context, req *gotacacs.AuthorRequestContext) *gotacacs.AuthorResponse {
return &gotacacs.AuthorResponse{
Status: gotacacs.AuthorStatusPassAdd,
Args: [][]byte{[]byte("priv-lvl=15")},
}
}
func (h *myHandler) HandleAcctRequest(_ context.Context, req *gotacacs.AcctRequestContext) *gotacacs.AcctReply {
return &gotacacs.AcctReply{Status: gotacacs.AcctStatusSuccess}
}
Per-Client Secret Provider ¶
Use SecretProviderFunc to return different secrets and custom user data per client:
secretProvider := gotacacs.SecretProviderFunc(func(ctx context.Context, req gotacacs.SecretRequest) gotacacs.SecretResponse {
return gotacacs.SecretResponse{
Secret: []byte("sharedsecret"),
UserData: map[string]string{
"client_ip": req.RemoteAddr.String(),
"local_ip": req.LocalAddr.String(),
},
}
})
server := gotacacs.NewServer(
gotacacs.WithServerListener(ln),
gotacacs.WithSecretProvider(secretProvider),
gotacacs.WithHandler(&myHandler{}),
)
The UserData map is available in all handler request contexts via req.UserData.
TLS Support (RFC 9887) RFC 9887)" aria-label="Go to TLS Support (RFC 9887)">¶
Both client and server support TLS 1.3 for secure communication. When using TLS, the shared secret is not needed as TLS provides encryption:
// Client with TLS
tlsConfig := &tls.Config{
RootCAs: certPool,
}
client := gotacacs.NewClient(
gotacacs.WithAddress("tacacs.example.com:300"),
gotacacs.WithTLSConfig(tlsConfig),
)
// Server with TLS
ln, err := gotacacs.ListenTLS(":300", tlsConfig)
Single-Connect Mode ¶
Enable single-connect mode to reuse connections for multiple requests:
client := gotacacs.NewClient(
gotacacs.WithAddress("tacacs.example.com:49"),
gotacacs.WithSecret("sharedsecret"),
gotacacs.WithSingleConnect(true),
)
defer client.Close()
For more information about the TACACS+ protocol, see RFC8907: https://datatracker.ietf.org/doc/html/rfc8907
Index ¶
- Constants
- Variables
- func IsClientPacket(p Packet) bool
- func IsServerPacket(p Packet) bool
- func IsTLSConn(conn Conn) bool
- func Obfuscate(header *Header, secret, body []byte) []byte
- func PacketType(p Packet) uint8
- type AccountingHandler
- type AcctHandlerFunc
- type AcctReply
- type AcctRequest
- func (p *AcctRequest) AddArg(arg string)
- func (p *AcctRequest) GetArgs() []string
- func (p *AcctRequest) IsStart() bool
- func (p *AcctRequest) IsStop() bool
- func (p *AcctRequest) IsWatchdog() bool
- func (p *AcctRequest) MarshalBinary() ([]byte, error)
- func (p *AcctRequest) UnmarshalBinary(data []byte) error
- type AcctRequestContext
- type AuthenContinue
- type AuthenContinueRequest
- type AuthenHandlerFunc
- type AuthenReply
- type AuthenRequest
- type AuthenStart
- type AuthenticateContext
- type AuthenticationHandler
- type AuthorHandlerFunc
- type AuthorRequest
- type AuthorRequestContext
- type AuthorResponse
- func (p *AuthorResponse) AddArg(arg string)
- func (p *AuthorResponse) GetArgs() []string
- func (p *AuthorResponse) IsError() bool
- func (p *AuthorResponse) IsFail() bool
- func (p *AuthorResponse) IsPass() bool
- func (p *AuthorResponse) IsPassAdd() bool
- func (p *AuthorResponse) IsPassRepl() bool
- func (p *AuthorResponse) MarshalBinary() ([]byte, error)
- func (p *AuthorResponse) UnmarshalBinary(data []byte) error
- type AuthorizationHandler
- type Client
- func (c *Client) Accounting(ctx context.Context, flags uint8, username string, args []string) (*AcctReply, error)
- func (c *Client) Address() string
- func (c *Client) Authenticate(ctx context.Context, username, password string) (*AuthenReply, error)
- func (c *Client) AuthenticateASCII(ctx context.Context, username string, ...) (*AuthenReply, error)
- func (c *Client) AuthenticateWithContext(ctx context.Context, authCtx *AuthenticateContext) (*AuthenReply, error)
- func (c *Client) Authorize(ctx context.Context, username string, args []string) (*AuthorResponse, error)
- func (c *Client) Close() error
- func (c *Client) Connect(ctx context.Context) error
- func (c *Client) IsConnected() bool
- func (c *Client) IsTLSConnection() bool
- func (c *Client) IsTLSMode() bool
- func (c *Client) LocalAddr() net.Addr
- func (c *Client) RemoteAddr() net.Addr
- type ClientOption
- func WithAddress(address string) ClientOption
- func WithDialer(dialer Dialer) ClientOption
- func WithMaxBodyLength(maxLength uint32) ClientOption
- func WithSecret(secret string) ClientOption
- func WithSecretBytes(secret []byte) ClientOption
- func WithSingleConnect(enabled bool) ClientOption
- func WithTLSConfig(config *tls.Config) ClientOption
- func WithTimeout(timeout time.Duration) ClientOption
- type Conn
- type Dialer
- type Handler
- type Header
- func (h *Header) IsSingleConnect() bool
- func (h *Header) IsUnencrypted() bool
- func (h *Header) MajorVersionNumber() uint8
- func (h *Header) MarshalBinary() ([]byte, error)
- func (h *Header) MinorVersionNumber() uint8
- func (h *Header) SetSingleConnect(singleConnect bool)
- func (h *Header) SetUnencrypted(unencrypted bool)
- func (h *Header) UnmarshalBinary(data []byte) error
- func (h *Header) Validate() error
- type Listener
- type MemorySessionStore
- type Packet
- type SecretProvider
- type SecretProviderFunc
- type SecretRequest
- type SecretResponse
- type Server
- type ServerOption
- func WithAccountingHandler(handler AccountingHandler) ServerOption
- func WithAuthenticationHandler(handler AuthenticationHandler) ServerOption
- func WithAuthorizationHandler(handler AuthorizationHandler) ServerOption
- func WithHandler(handler Handler) ServerOption
- func WithSecretProvider(provider SecretProvider) ServerOption
- func WithServerListener(ln Listener) ServerOption
- func WithServerMaxBodyLength(maxLength uint32) ServerOption
- func WithServerReadTimeout(timeout time.Duration) ServerOption
- func WithServerSecret(secret string) ServerOption
- func WithServerSecretBytes(secret []byte) ServerOption
- func WithServerSessionStore(store SessionStore) ServerOption
- func WithServerWriteTimeout(timeout time.Duration) ServerOption
- type Session
- func (s *Session) Created() time.Time
- func (s *Session) ID() uint32
- func (s *Session) IsClient() bool
- func (s *Session) LastActivity() time.Time
- func (s *Session) NextSeqNo() (uint8, error)
- func (s *Session) SeqNo() uint8
- func (s *Session) SetState(state SessionState)
- func (s *Session) State() SessionState
- func (s *Session) Touch()
- func (s *Session) UpdateSeqNo(seqNo uint8)
- func (s *Session) ValidateSeqNo(seqNo uint8) bool
- type SessionState
- type SessionStore
- type TCPDialer
- type TLSConn
- type TLSDialer
Constants ¶
const ( // MajorVersion is the TACACS+ major version (0x0c). MajorVersion = 0x0c // MinorVersionDefault is the default minor version. MinorVersionDefault = 0x00 // MinorVersionOne indicates minor version 1. MinorVersionOne = 0x01 )
TACACS+ protocol version constants as defined in RFC8907.
const ( // PacketTypeAuthen indicates an authentication packet. PacketTypeAuthen = 0x01 // PacketTypeAuthor indicates an authorization packet. PacketTypeAuthor = 0x02 // PacketTypeAcct indicates an accounting packet. PacketTypeAcct = 0x03 )
Packet type constants as defined in RFC8907 Section 4.1.
const ( // FlagUnencrypted indicates the packet body is not obfuscated. FlagUnencrypted = 0x01 // FlagSingleConnect indicates the client wants to use single-connection mode. FlagSingleConnect = 0x04 )
Header flag constants as defined in RFC8907 Section 4.1.
const ( // AuthenActionLogin indicates a login action. AuthenActionLogin = 0x01 // AuthenActionChPass indicates a password change action. AuthenActionChPass = 0x02 // AuthenActionSendAuth indicates a send authentication action. AuthenActionSendAuth = 0x04 )
Authentication action types as defined in RFC8907 Section 5.1.
const ( // AuthenTypeASCII indicates ASCII authentication. AuthenTypeASCII = 0x01 // AuthenTypePAP indicates PAP authentication. AuthenTypePAP = 0x02 // AuthenTypeCHAP indicates CHAP authentication. AuthenTypeCHAP = 0x03 // AuthenTypeMSCHAP indicates MS-CHAP v1 authentication. AuthenTypeMSCHAP = 0x05 // AuthenTypeMSCHAPV2 indicates MS-CHAP v2 authentication. AuthenTypeMSCHAPV2 = 0x06 )
Authentication types as defined in RFC8907 Section 5.1.
const ( // AuthenServiceNone indicates no service. AuthenServiceNone = 0x00 // AuthenServiceLogin indicates login service. AuthenServiceLogin = 0x01 // AuthenServiceEnable indicates enable service. AuthenServiceEnable = 0x02 // AuthenServicePPP indicates PPP service. AuthenServicePPP = 0x03 // AuthenServicePT indicates PT service. AuthenServicePT = 0x05 // AuthenServiceRCMD indicates RCMD service. AuthenServiceRCMD = 0x06 // AuthenServiceX25 indicates X25 service. AuthenServiceX25 = 0x07 // AuthenServiceNASI indicates NASI service. AuthenServiceNASI = 0x08 )
Authentication service types as defined in RFC8907 Section 5.1.
const ( // AuthenStatusPass indicates authentication passed. AuthenStatusPass = 0x01 // AuthenStatusFail indicates authentication failed. AuthenStatusFail = 0x02 // AuthenStatusGetData indicates server needs more data. AuthenStatusGetData = 0x03 // AuthenStatusGetUser indicates server needs the username. AuthenStatusGetUser = 0x04 // AuthenStatusGetPass indicates server needs the password. AuthenStatusGetPass = 0x05 // AuthenStatusRestart indicates authentication should restart. AuthenStatusRestart = 0x06 // AuthenStatusError indicates an error occurred. AuthenStatusError = 0x07 // AuthenStatusFollow indicates the client should follow to another server. AuthenStatusFollow = 0x21 )
Authentication status codes as defined in RFC8907 Section 5.2.
const ( // AuthenMethodNotSet indicates the authentication method was not set. AuthenMethodNotSet = 0x00 // AuthenMethodNone indicates no authentication was performed. AuthenMethodNone = 0x01 // AuthenMethodKRB5 indicates Kerberos 5 authentication. AuthenMethodKRB5 = 0x02 // AuthenMethodLine indicates line authentication (e.g., console password). AuthenMethodLine = 0x03 // AuthenMethodEnable indicates enable authentication. AuthenMethodEnable = 0x04 // AuthenMethodLocal indicates local database authentication. AuthenMethodLocal = 0x05 // AuthenMethodTACACSPlus indicates TACACS+ authentication. AuthenMethodTACACSPlus = 0x06 // AuthenMethodGuest indicates guest authentication. AuthenMethodGuest = 0x08 // AuthenMethodRadius indicates RADIUS authentication. AuthenMethodRadius = 0x10 // AuthenMethodKRB4 indicates Kerberos 4 authentication. AuthenMethodKRB4 = 0x11 // AuthenMethodRCMD indicates RCMD authentication. AuthenMethodRCMD = 0x20 )
Authentication method constants as defined in RFC8907 Section 6.1. These indicate how the user was authenticated in authorization/accounting requests.
const ( // AuthorStatusPassAdd indicates authorization passed with additional arguments. AuthorStatusPassAdd = 0x01 // AuthorStatusPassRepl indicates authorization passed with replacement arguments. AuthorStatusPassRepl = 0x02 // AuthorStatusFail indicates authorization failed. AuthorStatusFail = 0x10 // AuthorStatusError indicates an error occurred. AuthorStatusError = 0x11 // AuthorStatusFollow indicates the client should follow to another server. AuthorStatusFollow = 0x21 )
Authorization status codes as defined in RFC8907 Section 6.2.
const ( // AcctFlagStart indicates the start of a task. AcctFlagStart = 0x02 // AcctFlagStop indicates the end of a task. AcctFlagStop = 0x04 // AcctFlagWatchdog indicates an update for an ongoing task. AcctFlagWatchdog = 0x08 )
Accounting flags as defined in RFC8907 Section 7.1.
const ( // AcctStatusSuccess indicates the accounting record was accepted. AcctStatusSuccess = 0x01 // AcctStatusError indicates an error occurred. AcctStatusError = 0x02 // AcctStatusFollow indicates the client should follow to another server. AcctStatusFollow = 0x21 )
Accounting status codes as defined in RFC8907 Section 7.2.
const (
// AuthenContinueFlagAbort indicates the client wants to abort authentication.
AuthenContinueFlagAbort = 0x01
)
Authentication continue flags as defined in RFC8907 Section 5.3.
const (
// AuthenReplyFlagNoEcho indicates the server wants no echo of user input.
AuthenReplyFlagNoEcho = 0x01
)
Authentication reply flags as defined in RFC8907 Section 5.2.
const DefaultMaxBodyLength = 256 * 1024
DefaultMaxBodyLength is the default maximum allowed body length (256KB). This prevents memory exhaustion attacks from malicious peers.
const DefaultPort = 49
DefaultPort is the default TACACS+ port as defined in RFC8907.
const DefaultTLSPort = 300
DefaultTLSPort is the default TACACS+ over TLS port as defined in RFC9887. RFC 9887 specifies port 300 for TLS-secured TACACS+ connections (service name "tacacss").
const HeaderLength = 12
HeaderLength is the fixed size of a TACACS+ header in bytes.
const MinPSKLength = 16
MinPSKLength is the minimum Pre-Shared Key length required by RFC 9887. RFC 9887 specifies a minimum of 16 octets for PSK.
const TLSSessionTicketKeyLength = 32
TLSSessionTicketKeyLength is the required length for TLS session ticket keys. Go's TLS implementation requires 32 bytes for session ticket keys.
Variables ¶
var ( // ErrInvalidHeader indicates the packet header is malformed or invalid. ErrInvalidHeader = errors.New("invalid header") // ErrInvalidPacket indicates the packet body is malformed or invalid. ErrInvalidPacket = errors.New("invalid packet") // ErrInvalidVersion indicates an unsupported protocol version. ErrInvalidVersion = errors.New("invalid version") // ErrInvalidType indicates an unsupported packet type. ErrInvalidType = errors.New("invalid packet type") // ErrInvalidSequence indicates a sequence number violation. ErrInvalidSequence = errors.New("invalid sequence number") // ErrSessionNotFound indicates the session ID is unknown. ErrSessionNotFound = errors.New("session not found") // ErrConnectionClosed indicates the connection was terminated. ErrConnectionClosed = errors.New("connection closed") // ErrTimeout indicates an operation timed out. ErrTimeout = errors.New("operation timeout") // ErrAuthenticationFailed indicates authentication failed. ErrAuthenticationFailed = errors.New("authentication failed") // ErrAuthorizationDenied indicates authorization was denied. ErrAuthorizationDenied = errors.New("authorization denied") // ErrAccountingFailed indicates accounting operation failed. ErrAccountingFailed = errors.New("accounting failed") // ErrBufferTooShort indicates the buffer is too short for the operation. ErrBufferTooShort = errors.New("buffer too short") // ErrBodyTooLarge indicates the packet body exceeds maximum size. ErrBodyTooLarge = errors.New("body too large") // ErrAuthenFollow indicates the server requested authentication follow. // The client should connect to an alternate server specified in ServerMsg. ErrAuthenFollow = errors.New("authentication follow requested") // ErrAuthenRestart indicates the server requested authentication restart. // The client should restart authentication from the beginning. ErrAuthenRestart = errors.New("authentication restart requested") // ErrSequenceOverflow indicates the sequence number would overflow. // This happens after 255 packets in a session. ErrSequenceOverflow = errors.New("sequence number overflow") // ErrBadSecret indicates the shared secret may be incorrect. // This error is returned when packet parsing fails in a way that // suggests the body was deobfuscated with the wrong secret, // resulting in garbage length fields. ErrBadSecret = errors.New("bad secret") )
Protocol errors for TACACS+ operations.
Functions ¶
func IsClientPacket ¶
IsClientPacket returns true if the packet is sent by the client.
func IsServerPacket ¶
IsServerPacket returns true if the packet is sent by the server.
func Obfuscate ¶
Obfuscate obfuscates or deobfuscates the body using the TACACS+ pseudo-pad algorithm. The operation is symmetric (XOR), so the same function is used for both operations. As defined in RFC8907 Section 4.5, the pseudo-pad is computed as:
pseudo_pad = {MD5(session_id + secret + version + seq_no) +
MD5(session_id + secret + version + seq_no + pseudo_pad[0..15]) +
MD5(session_id + secret + version + seq_no + pseudo_pad[0..31]) + ...}
The body is XORed with the pseudo-pad to produce the obfuscated/deobfuscated result.
If secret is empty or the header has FlagUnencrypted set, the body is returned unchanged.
func PacketType ¶
PacketType returns the packet type constant for a given packet.
Types ¶
type AccountingHandler ¶
type AccountingHandler interface {
// HandleAcctRequest handles an accounting REQUEST packet.
HandleAcctRequest(ctx context.Context, req *AcctRequestContext) *AcctReply
}
AccountingHandler handles accounting requests.
type AcctHandlerFunc ¶
type AcctHandlerFunc func(ctx context.Context, req *AcctRequestContext) *AcctReply
AcctHandlerFunc is an adapter for simple accounting handlers.
func (AcctHandlerFunc) HandleAcctRequest ¶
func (f AcctHandlerFunc) HandleAcctRequest(ctx context.Context, req *AcctRequestContext) *AcctReply
HandleAcctRequest implements AccountingHandler.
type AcctReply ¶
type AcctReply struct {
Status uint8 // Accounting status
ServerMsg []byte // Server message (optional)
Data []byte // Additional data (optional)
}
AcctReply represents a TACACS+ accounting REPLY packet as defined in RFC8907 Section 7.2. This packet is sent by the server in response to an accounting request.
func NewAcctReply ¶
NewAcctReply creates a new AcctReply packet with the specified status.
func (*AcctReply) MarshalBinary ¶
MarshalBinary encodes the AcctReply packet to binary format.
func (*AcctReply) UnmarshalBinary ¶
UnmarshalBinary decodes the AcctReply packet from binary format.
type AcctRequest ¶
type AcctRequest struct {
Flags uint8 // Accounting flags (START, STOP, WATCHDOG)
AuthenMethod uint8 // Authentication method used
PrivLevel uint8 // Privilege level
AuthenType uint8 // Authentication type
Service uint8 // Authentication service
User []byte // Username
Port []byte // Port identifier
RemoteAddr []byte // Remote address
Args [][]byte // Accounting arguments
}
AcctRequest represents a TACACS+ accounting REQUEST packet as defined in RFC8907 Section 7.1. This packet is sent by the client to send accounting records to the server.
func NewAcctRequest ¶
func NewAcctRequest(flags, authenMethod, authenType, service uint8, user string) *AcctRequest
NewAcctRequest creates a new AcctRequest packet with the specified parameters.
func (*AcctRequest) AddArg ¶
func (p *AcctRequest) AddArg(arg string)
AddArg adds an argument to the accounting request.
func (*AcctRequest) GetArgs ¶
func (p *AcctRequest) GetArgs() []string
GetArgs returns the arguments as strings.
func (*AcctRequest) IsStart ¶
func (p *AcctRequest) IsStart() bool
IsStart returns true if the START flag is set.
func (*AcctRequest) IsStop ¶
func (p *AcctRequest) IsStop() bool
IsStop returns true if the STOP flag is set.
func (*AcctRequest) IsWatchdog ¶
func (p *AcctRequest) IsWatchdog() bool
IsWatchdog returns true if the WATCHDOG flag is set.
func (*AcctRequest) MarshalBinary ¶
func (p *AcctRequest) MarshalBinary() ([]byte, error)
MarshalBinary encodes the AcctRequest packet to binary format.
func (*AcctRequest) UnmarshalBinary ¶
func (p *AcctRequest) UnmarshalBinary(data []byte) error
UnmarshalBinary decodes the AcctRequest packet from binary format.
type AcctRequestContext ¶
type AcctRequestContext struct {
SessionID uint32
RemoteAddr net.Addr
Header *Header
Request *AcctRequest
UserData map[string]string
}
AcctRequestContext represents an accounting request context.
type AuthenContinue ¶
type AuthenContinue struct {
Flags uint8 // Continue flags (ABORT)
UserMsg []byte // User message/response (optional)
Data []byte // Authentication data (optional)
}
AuthenContinue represents a TACACS+ authentication CONTINUE packet as defined in RFC8907 Section 5.3. This packet is sent by the client in response to a REPLY requesting more data.
func NewAuthenContinue ¶
func NewAuthenContinue(userMsg string) *AuthenContinue
NewAuthenContinue creates a new AuthenContinue packet with the specified user message.
func (*AuthenContinue) IsAbort ¶
func (p *AuthenContinue) IsAbort() bool
IsAbort returns true if the ABORT flag is set.
func (*AuthenContinue) MarshalBinary ¶
func (p *AuthenContinue) MarshalBinary() ([]byte, error)
MarshalBinary encodes the AuthenContinue packet to binary format.
func (*AuthenContinue) SetAbort ¶
func (p *AuthenContinue) SetAbort(abort bool)
SetAbort sets or clears the ABORT flag.
func (*AuthenContinue) UnmarshalBinary ¶
func (p *AuthenContinue) UnmarshalBinary(data []byte) error
UnmarshalBinary decodes the AuthenContinue packet from binary format.
type AuthenContinueRequest ¶
type AuthenContinueRequest struct {
SessionID uint32
RemoteAddr net.Addr
Header *Header
Continue *AuthenContinue
UserData map[string]string
}
AuthenContinueRequest represents an authentication continue request context.
type AuthenHandlerFunc ¶
type AuthenHandlerFunc func(ctx context.Context, req *AuthenRequest) *AuthenReply
AuthenHandlerFunc is an adapter for simple authentication handlers.
func (AuthenHandlerFunc) HandleAuthenContinue ¶
func (f AuthenHandlerFunc) HandleAuthenContinue(_ context.Context, _ *AuthenContinueRequest) *AuthenReply
HandleAuthenContinue implements AuthenticationHandler (returns ERROR by default).
func (AuthenHandlerFunc) HandleAuthenStart ¶
func (f AuthenHandlerFunc) HandleAuthenStart(ctx context.Context, req *AuthenRequest) *AuthenReply
HandleAuthenStart implements AuthenticationHandler.
type AuthenReply ¶
type AuthenReply struct {
Status uint8 // Authentication status (PASS, FAIL, GETDATA, etc.)
Flags uint8 // Reply flags (NOECHO)
ServerMsg []byte // Server message to display (optional)
Data []byte // Authentication data (optional)
}
AuthenReply represents a TACACS+ authentication REPLY packet as defined in RFC8907 Section 5.2. This packet is sent by the server in response to START or CONTINUE packets.
func NewAuthenReply ¶
func NewAuthenReply(status uint8) *AuthenReply
NewAuthenReply creates a new AuthenReply packet with the specified status.
func (*AuthenReply) IsError ¶
func (p *AuthenReply) IsError() bool
IsError returns true if the status indicates an error occurred.
func (*AuthenReply) IsFail ¶
func (p *AuthenReply) IsFail() bool
IsFail returns true if the status indicates authentication failed.
func (*AuthenReply) IsPass ¶
func (p *AuthenReply) IsPass() bool
IsPass returns true if the status indicates authentication passed.
func (*AuthenReply) MarshalBinary ¶
func (p *AuthenReply) MarshalBinary() ([]byte, error)
MarshalBinary encodes the AuthenReply packet to binary format.
func (*AuthenReply) NeedsInput ¶
func (p *AuthenReply) NeedsInput() bool
NeedsInput returns true if the server is requesting more input.
func (*AuthenReply) NoEcho ¶
func (p *AuthenReply) NoEcho() bool
NoEcho returns true if the NOECHO flag is set.
func (*AuthenReply) UnmarshalBinary ¶
func (p *AuthenReply) UnmarshalBinary(data []byte) error
UnmarshalBinary decodes the AuthenReply packet from binary format.
type AuthenRequest ¶
type AuthenRequest struct {
SessionID uint32
RemoteAddr net.Addr
Header *Header
Start *AuthenStart
UserData map[string]string
}
AuthenRequest represents an authentication request context.
type AuthenStart ¶
type AuthenStart struct {
Action uint8 // Authentication action (LOGIN, CHPASS, SENDAUTH)
PrivLevel uint8 // Privilege level
AuthenType uint8 // Authentication type (ASCII, PAP, CHAP, etc.)
Service uint8 // Authentication service (LOGIN, ENABLE, etc.)
User []byte // Username (optional)
Port []byte // Port identifier (optional)
RemoteAddr []byte // Remote address (optional)
Data []byte // Authentication data (optional)
}
AuthenStart represents a TACACS+ authentication START packet as defined in RFC8907 Section 5.1. This packet is sent by the client to initiate an authentication session.
func NewAuthenStart ¶
func NewAuthenStart(action, authenType, service uint8, user string) *AuthenStart
NewAuthenStart creates a new AuthenStart packet with the specified parameters.
func (*AuthenStart) MarshalBinary ¶
func (p *AuthenStart) MarshalBinary() ([]byte, error)
MarshalBinary encodes the AuthenStart packet to binary format.
func (*AuthenStart) UnmarshalBinary ¶
func (p *AuthenStart) UnmarshalBinary(data []byte) error
UnmarshalBinary decodes the AuthenStart packet from binary format.
type AuthenticateContext ¶
type AuthenticateContext struct {
Session *Session
Username string
Password string
Port string
RemoteAddr string
}
AuthenticateContext holds the context for multi-step authentication.
type AuthenticationHandler ¶
type AuthenticationHandler interface {
// HandleAuthenStart handles an authentication START packet.
HandleAuthenStart(ctx context.Context, req *AuthenRequest) *AuthenReply
// HandleAuthenContinue handles an authentication CONTINUE packet.
HandleAuthenContinue(ctx context.Context, req *AuthenContinueRequest) *AuthenReply
}
AuthenticationHandler handles authentication requests.
type AuthorHandlerFunc ¶
type AuthorHandlerFunc func(ctx context.Context, req *AuthorRequestContext) *AuthorResponse
AuthorHandlerFunc is an adapter for simple authorization handlers.
func (AuthorHandlerFunc) HandleAuthorRequest ¶
func (f AuthorHandlerFunc) HandleAuthorRequest(ctx context.Context, req *AuthorRequestContext) *AuthorResponse
HandleAuthorRequest implements AuthorizationHandler.
type AuthorRequest ¶
type AuthorRequest struct {
AuthenMethod uint8 // Authentication method used
PrivLevel uint8 // Privilege level
AuthenType uint8 // Authentication type
Service uint8 // Authentication service
User []byte // Username
Port []byte // Port identifier
RemoteAddr []byte // Remote address
Args [][]byte // Authorization arguments
}
AuthorRequest represents a TACACS+ authorization REQUEST packet as defined in RFC8907 Section 6.1. This packet is sent by the client to request authorization for a specific action.
func NewAuthorRequest ¶
func NewAuthorRequest(authenMethod, authenType, service uint8, user string) *AuthorRequest
NewAuthorRequest creates a new AuthorRequest packet with the specified parameters.
func (*AuthorRequest) AddArg ¶
func (p *AuthorRequest) AddArg(arg string)
AddArg adds an argument to the authorization request.
func (*AuthorRequest) GetArgs ¶
func (p *AuthorRequest) GetArgs() []string
GetArgs returns the arguments as strings.
func (*AuthorRequest) MarshalBinary ¶
func (p *AuthorRequest) MarshalBinary() ([]byte, error)
MarshalBinary encodes the AuthorRequest packet to binary format.
func (*AuthorRequest) UnmarshalBinary ¶
func (p *AuthorRequest) UnmarshalBinary(data []byte) error
UnmarshalBinary decodes the AuthorRequest packet from binary format.
type AuthorRequestContext ¶
type AuthorRequestContext struct {
SessionID uint32
RemoteAddr net.Addr
Header *Header
Request *AuthorRequest
UserData map[string]string
}
AuthorRequestContext represents an authorization request context.
type AuthorResponse ¶
type AuthorResponse struct {
Status uint8 // Authorization status
Args [][]byte // Authorization arguments (may be modified from request)
ServerMsg []byte // Server message (optional)
Data []byte // Additional data (optional)
}
AuthorResponse represents a TACACS+ authorization RESPONSE packet as defined in RFC8907 Section 6.2. This packet is sent by the server in response to an authorization request.
func NewAuthorResponse ¶
func NewAuthorResponse(status uint8) *AuthorResponse
NewAuthorResponse creates a new AuthorResponse packet with the specified status.
func (*AuthorResponse) AddArg ¶
func (p *AuthorResponse) AddArg(arg string)
AddArg adds an argument to the authorization response.
func (*AuthorResponse) GetArgs ¶
func (p *AuthorResponse) GetArgs() []string
GetArgs returns the arguments as strings.
func (*AuthorResponse) IsError ¶
func (p *AuthorResponse) IsError() bool
IsError returns true if an error occurred.
func (*AuthorResponse) IsFail ¶
func (p *AuthorResponse) IsFail() bool
IsFail returns true if the authorization failed.
func (*AuthorResponse) IsPass ¶
func (p *AuthorResponse) IsPass() bool
IsPass returns true if the authorization passed (either PASS_ADD or PASS_REPL).
func (*AuthorResponse) IsPassAdd ¶
func (p *AuthorResponse) IsPassAdd() bool
IsPassAdd returns true if the status is PASS_ADD.
func (*AuthorResponse) IsPassRepl ¶
func (p *AuthorResponse) IsPassRepl() bool
IsPassRepl returns true if the status is PASS_REPL.
func (*AuthorResponse) MarshalBinary ¶
func (p *AuthorResponse) MarshalBinary() ([]byte, error)
MarshalBinary encodes the AuthorResponse packet to binary format.
func (*AuthorResponse) UnmarshalBinary ¶
func (p *AuthorResponse) UnmarshalBinary(data []byte) error
UnmarshalBinary decodes the AuthorResponse packet from binary format.
type AuthorizationHandler ¶
type AuthorizationHandler interface {
// HandleAuthorRequest handles an authorization REQUEST packet.
HandleAuthorRequest(ctx context.Context, req *AuthorRequestContext) *AuthorResponse
}
AuthorizationHandler handles authorization requests.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client represents a TACACS+ client for communicating with a TACACS+ server.
func NewClient ¶
func NewClient(opts ...ClientOption) *Client
NewClient creates a new TACACS+ client.
func (*Client) Accounting ¶
func (c *Client) Accounting(ctx context.Context, flags uint8, username string, args []string) (*AcctReply, error)
Accounting sends an accounting record to the TACACS+ server.
func (*Client) Authenticate ¶
Authenticate performs authentication with the TACACS+ server. It handles the complete authentication flow including multi-step interactions.
func (*Client) AuthenticateASCII ¶
func (c *Client) AuthenticateASCII(ctx context.Context, username string, promptHandler func(prompt string, noEcho bool) (string, error)) (*AuthenReply, error)
AuthenticateASCII performs ASCII authentication with interactive prompts. The promptHandler is called for each GETDATA/GETUSER/GETPASS request.
func (*Client) AuthenticateWithContext ¶
func (c *Client) AuthenticateWithContext(ctx context.Context, authCtx *AuthenticateContext) (*AuthenReply, error)
AuthenticateWithContext performs authentication with additional context.
func (*Client) Authorize ¶
func (c *Client) Authorize(ctx context.Context, username string, args []string) (*AuthorResponse, error)
Authorize performs authorization with the TACACS+ server.
func (*Client) IsConnected ¶
IsConnected returns true if the client has an active connection.
func (*Client) IsTLSConnection ¶
IsTLSConnection returns true if the current connection is TLS-secured.
func (*Client) RemoteAddr ¶
RemoteAddr returns the remote address of the connection.
type ClientOption ¶
type ClientOption func(*Client)
ClientOption is a function that configures a Client.
func WithAddress ¶
func WithAddress(address string) ClientOption
WithAddress sets the server address to connect to.
func WithDialer ¶
func WithDialer(dialer Dialer) ClientOption
WithDialer sets a custom dialer for connections. If dialer is nil, the default TCP dialer is retained.
func WithMaxBodyLength ¶
func WithMaxBodyLength(maxLength uint32) ClientOption
WithMaxBodyLength sets the maximum allowed body length for incoming packets. This prevents memory exhaustion attacks from malicious servers.
func WithSecret ¶
func WithSecret(secret string) ClientOption
WithSecret sets the shared secret for packet obfuscation.
func WithSecretBytes ¶
func WithSecretBytes(secret []byte) ClientOption
WithSecretBytes sets the shared secret as bytes for packet obfuscation.
func WithSingleConnect ¶
func WithSingleConnect(enabled bool) ClientOption
WithSingleConnect enables single-connect mode. In this mode, the connection is reused across multiple sessions.
func WithTLSConfig ¶
func WithTLSConfig(config *tls.Config) ClientOption
WithTLSConfig sets the TLS 1.3 configuration for RFC 9887 compliant connections. When using TLS mode, the unencrypted flag is automatically set and packet obfuscation is disabled since TLS provides encryption. This function enforces TLS 1.3 as required by RFC 9887. If config is nil, a default TLS 1.3 configuration is used.
func WithTimeout ¶
func WithTimeout(timeout time.Duration) ClientOption
WithTimeout sets the connection and operation timeout.
type Conn ¶
Conn represents a network connection for TACACS+ communication. It extends net.Conn with additional context awareness.
type Dialer ¶
type Dialer interface {
// Dial connects to the address on the named network.
Dial(ctx context.Context, network, address string) (Conn, error)
}
Dialer represents a dialer for establishing TACACS+ connections.
type Handler ¶
type Handler interface {
AuthenticationHandler
AuthorizationHandler
AccountingHandler
}
Handler combines all handler interfaces.
type Header ¶
type Header struct {
Version uint8
Type uint8
SeqNo uint8
Flags uint8
SessionID uint32
Length uint32
}
Header represents a TACACS+ packet header as defined in RFC8907 Section 4.1. The header is 12 bytes and contains the following fields:
- Version (1 byte): major version (high nibble) and minor version (low nibble)
- Type (1 byte): packet type (authentication, authorization, or accounting)
- SeqNo (1 byte): sequence number for the session
- Flags (1 byte): various flags (unencrypted, single-connect)
- SessionID (4 bytes): session identifier
- Length (4 bytes): length of the packet body
func NewHeader ¶
NewHeader creates a new Header with the specified packet type and session ID. It sets the default version and initializes sequence number to 1.
func (*Header) IsSingleConnect ¶
IsSingleConnect returns true if the single-connect flag is set.
func (*Header) IsUnencrypted ¶
IsUnencrypted returns true if the unencrypted flag is set.
func (*Header) MajorVersionNumber ¶
MajorVersionNumber returns the major version from the version byte.
func (*Header) MarshalBinary ¶
MarshalBinary encodes the header to binary format (big-endian).
func (*Header) MinorVersionNumber ¶
MinorVersionNumber returns the minor version from the version byte.
func (*Header) SetSingleConnect ¶
SetSingleConnect sets or clears the single-connect flag.
func (*Header) SetUnencrypted ¶
SetUnencrypted sets or clears the unencrypted flag.
func (*Header) UnmarshalBinary ¶
UnmarshalBinary decodes the header from binary format.
type Listener ¶
type Listener interface {
// Accept waits for and returns the next connection to the listener.
Accept() (Conn, error)
// Close closes the listener.
Close() error
// Addr returns the listener's network address.
Addr() net.Addr
}
Listener represents a network listener for accepting TACACS+ connections.
type MemorySessionStore ¶
type MemorySessionStore struct {
// contains filtered or unexported fields
}
MemorySessionStore is an in-memory implementation of SessionStore.
func NewMemorySessionStore ¶
func NewMemorySessionStore() *MemorySessionStore
NewMemorySessionStore creates a new in-memory session store.
func (*MemorySessionStore) Cleanup ¶
func (s *MemorySessionStore) Cleanup(maxAge time.Duration) int
Cleanup removes expired sessions older than the given duration. Returns the number of sessions removed.
func (*MemorySessionStore) Count ¶
func (s *MemorySessionStore) Count() int
Count returns the number of sessions in the store.
func (*MemorySessionStore) Delete ¶
func (s *MemorySessionStore) Delete(id uint32)
Delete removes a session by ID.
func (*MemorySessionStore) Get ¶
func (s *MemorySessionStore) Get(id uint32) (*Session, bool)
Get retrieves a session by ID.
func (*MemorySessionStore) Put ¶
func (s *MemorySessionStore) Put(session *Session)
Put stores a session.
type Packet ¶
type Packet interface {
encoding.BinaryMarshaler
encoding.BinaryUnmarshaler
}
Packet is the interface that all TACACS+ packet types implement.
func ParseAcctPacket ¶
ParseAcctPacket parses an accounting packet body based on the sequence number. Sequence number 1 indicates a REQUEST. Sequence number 2 indicates a REPLY.
func ParseAuthenPacket ¶
ParseAuthenPacket parses an authentication packet body based on the sequence number. Odd sequence numbers indicate client packets (START, CONTINUE). Even sequence numbers indicate server packets (REPLY).
func ParseAuthorPacket ¶
ParseAuthorPacket parses an authorization packet body based on the sequence number. Sequence number 1 indicates a REQUEST. Sequence number 2 indicates a RESPONSE.
type SecretProvider ¶
type SecretProvider interface {
// GetSecret returns the shared secret and optional user data for the given request.
GetSecret(ctx context.Context, req SecretRequest) SecretResponse
}
SecretProvider provides per-client shared secrets and optional user data.
type SecretProviderFunc ¶
type SecretProviderFunc func(ctx context.Context, req SecretRequest) SecretResponse
SecretProviderFunc is an adapter to allow ordinary functions to be used as SecretProvider.
func (SecretProviderFunc) GetSecret ¶
func (f SecretProviderFunc) GetSecret(ctx context.Context, req SecretRequest) SecretResponse
GetSecret implements SecretProvider.
type SecretRequest ¶
type SecretRequest struct {
// RemoteAddr is the remote address of the client.
RemoteAddr net.Addr
// LocalAddr is the local address of the server connection.
LocalAddr net.Addr
// Attempt is the 0-based secret attempt index for secret rotation.
// The server calls GetSecret multiple times with increasing Attempt values
// when the first secret fails to deobfuscate the packet.
Attempt int
}
SecretRequest contains information about the client connection for secret lookup.
type SecretResponse ¶
type SecretResponse struct {
// Secret is the shared secret for packet obfuscation.
// If nil, packets will not be obfuscated.
Secret []byte
// UserData is optional metadata passed to handlers.
UserData map[string]string
// Attempts is the total number of secrets available for rotation.
// A value of 0 or 1 means no rotation (single secret).
// When greater than 1, the server will try each secret in order
// on the first packet of a connection until one succeeds.
Attempts int
}
SecretResponse contains the secret and optional user data for a client.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is a TACACS+ server.
func NewServer ¶
func NewServer(opts ...ServerOption) *Server
NewServer creates a new TACACS+ server with the given options.
type ServerOption ¶
type ServerOption func(*Server)
ServerOption configures a Server.
func WithAccountingHandler ¶
func WithAccountingHandler(handler AccountingHandler) ServerOption
WithAccountingHandler sets the accounting handler.
func WithAuthenticationHandler ¶
func WithAuthenticationHandler(handler AuthenticationHandler) ServerOption
WithAuthenticationHandler sets the authentication handler.
func WithAuthorizationHandler ¶
func WithAuthorizationHandler(handler AuthorizationHandler) ServerOption
WithAuthorizationHandler sets the authorization handler.
func WithHandler ¶
func WithHandler(handler Handler) ServerOption
WithHandler sets a combined handler for all request types.
func WithSecretProvider ¶
func WithSecretProvider(provider SecretProvider) ServerOption
WithSecretProvider sets the secret provider for the server.
func WithServerListener ¶
func WithServerListener(ln Listener) ServerOption
WithServerListener sets the listener for the server.
func WithServerMaxBodyLength ¶
func WithServerMaxBodyLength(maxLength uint32) ServerOption
WithServerMaxBodyLength sets the maximum allowed body length for incoming packets.
func WithServerReadTimeout ¶
func WithServerReadTimeout(timeout time.Duration) ServerOption
WithServerReadTimeout sets the read timeout for client connections.
func WithServerSecret ¶
func WithServerSecret(secret string) ServerOption
WithServerSecret sets a static secret for all clients.
func WithServerSecretBytes ¶
func WithServerSecretBytes(secret []byte) ServerOption
WithServerSecretBytes sets a static secret for all clients.
func WithServerSessionStore ¶
func WithServerSessionStore(store SessionStore) ServerOption
WithServerSessionStore sets the session store. If store is nil, the default memory session store is retained.
func WithServerWriteTimeout ¶
func WithServerWriteTimeout(timeout time.Duration) ServerOption
WithServerWriteTimeout sets the write timeout for client connections.
type Session ¶
type Session struct {
// contains filtered or unexported fields
}
Session represents a TACACS+ session. A session is identified by a unique session ID and tracks the sequence of packets.
func NewSession ¶
NewSession creates a new session with a randomly generated session ID. If isClient is true, the session is for a client (odd sequence numbers). If isClient is false, the session is for a server (even sequence numbers).
func NewSessionWithID ¶
NewSessionWithID creates a new session with the specified session ID.
func (*Session) LastActivity ¶
LastActivity returns the time of the last activity on this session.
func (*Session) NextSeqNo ¶
NextSeqNo returns the next sequence number and increments the internal counter. For clients: 1, 3, 5, ... (odd numbers) For servers: 2, 4, 6, ... (even numbers) Returns ErrSequenceOverflow if the sequence number would wrap around.
func (*Session) SetState ¶
func (s *Session) SetState(state SessionState)
SetState sets the session state.
func (*Session) State ¶
func (s *Session) State() SessionState
State returns the current session state.
func (*Session) UpdateSeqNo ¶
UpdateSeqNo updates the sequence number after receiving a packet.
func (*Session) ValidateSeqNo ¶
ValidateSeqNo validates an incoming sequence number. Returns true if the sequence number is valid for the current session state.
type SessionState ¶
type SessionState uint8
SessionState represents the current state of a TACACS+ session.
const ( // SessionStateNew indicates a newly created session. SessionStateNew SessionState = iota // SessionStateActive indicates an active session with ongoing communication. SessionStateActive // SessionStateComplete indicates a successfully completed session. SessionStateComplete // SessionStateError indicates a session that ended with an error. SessionStateError )
func (SessionState) String ¶
func (s SessionState) String() string
String returns a string representation of the session state.
type SessionStore ¶
type SessionStore interface {
// Get retrieves a session by ID.
Get(id uint32) (*Session, bool)
// Put stores a session.
Put(session *Session)
// Delete removes a session by ID.
Delete(id uint32)
// Cleanup removes expired sessions older than the given duration.
Cleanup(maxAge time.Duration) int
}
SessionStore is the interface for session storage.
type TCPDialer ¶
type TCPDialer struct {
// Timeout is the maximum duration for the dial to complete.
// If zero, no timeout is applied.
Timeout time.Duration
// LocalAddr is the local address to use when dialing.
// If nil, a local address is automatically chosen.
LocalAddr *net.TCPAddr
}
TCPDialer implements Dialer for TCP connections.
type TLSConn ¶
type TLSConn interface {
Conn
// ConnectionState returns the TLS connection state.
ConnectionState() tls.ConnectionState
}
TLSConn represents a TLS-secured connection. Use IsTLSConn to check if a Conn is TLS-secured.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
tacacs-client
command
Package main provides an example TACACS+ client.
|
Package main provides an example TACACS+ client. |
|
tacacs-client-tls
command
Package main provides an example TACACS+ client using TLS 1.3 (RFC 9887).
|
Package main provides an example TACACS+ client using TLS 1.3 (RFC 9887). |
|
tacacs-server
command
Package main provides an example TACACS+ server.
|
Package main provides an example TACACS+ server. |
|
tacacs-server-tls
command
Package main provides an example TACACS+ server using TLS 1.3 (RFC 9887).
|
Package main provides an example TACACS+ server using TLS 1.3 (RFC 9887). |