open-vault/vendor/layeh.com/radius/client.go

131 lines
2.8 KiB
Go
Raw Normal View History

2017-09-05 22:06:47 +00:00
package radius
2017-02-07 21:04:27 +00:00
import (
2017-09-05 22:06:47 +00:00
"context"
2017-02-07 21:04:27 +00:00
"net"
"time"
)
2017-09-05 22:06:47 +00:00
// Client is a RADIUS client that can exchange packets with a RADIUS server.
2017-02-07 21:04:27 +00:00
type Client struct {
// Network on which to make the connection. Defaults to "udp".
Net string
2017-09-05 22:06:47 +00:00
// Dialer to use when making the outgoing connections.
Dialer net.Dialer
2017-02-07 21:04:27 +00:00
2017-09-05 22:06:47 +00:00
// Interval on which to resend packet (zero or negative value means no
// retry).
2017-02-07 21:04:27 +00:00
Retry time.Duration
2017-09-05 22:06:47 +00:00
2018-02-11 00:29:52 +00:00
// 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.
2017-09-05 22:06:47 +00:00
InsecureSkipVerify bool
2017-02-07 21:04:27 +00:00
}
2017-09-05 22:06:47 +00:00
// DefaultClient is the RADIUS client used by the Exchange function.
var DefaultClient = &Client{
Retry: time.Second,
MaxPacketErrors: 10,
}
2017-09-05 22:06:47 +00:00
// Exchange uses DefaultClient to send the given RADIUS packet to the server at
// address addr and waits for a response.
func Exchange(ctx context.Context, packet *Packet, addr string) (*Packet, error) {
return DefaultClient.Exchange(ctx, packet, addr)
}
// Exchange sends the packet to the given server and waits for a response. ctx
// must be non-nil.
func (c *Client) Exchange(ctx context.Context, packet *Packet, addr string) (*Packet, error) {
if ctx == nil {
panic("nil context")
}
2017-02-07 21:04:27 +00:00
wire, err := packet.Encode()
if err != nil {
return nil, err
}
connNet := c.Net
if connNet == "" {
connNet = "udp"
}
2017-09-05 22:06:47 +00:00
conn, err := c.Dialer.DialContext(ctx, connNet, addr)
2017-02-07 21:04:27 +00:00
if err != nil {
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
}
2017-02-07 21:04:27 +00:00
return nil, err
}
2017-09-05 22:06:47 +00:00
defer conn.Close()
2017-02-07 21:04:27 +00:00
conn.Write(wire)
var cancel context.CancelFunc
ctx, cancel = context.WithCancel(ctx)
defer cancel()
var retryTimer <-chan time.Time
2017-02-07 21:04:27 +00:00
if c.Retry > 0 {
retry := time.NewTicker(c.Retry)
2017-09-05 22:06:47 +00:00
defer retry.Stop()
retryTimer = retry.C
2017-02-07 21:04:27 +00:00
}
go func() {
defer conn.Close()
for {
select {
case <-retryTimer:
conn.Write(wire)
case <-ctx.Done():
return
}
}
}()
2018-02-11 00:29:52 +00:00
var packetErrorCount int
2017-09-05 22:06:47 +00:00
var incoming [MaxPacketLength]byte
2017-02-07 21:04:27 +00:00
for {
n, err := conn.Read(incoming[:])
if err != nil {
select {
case <-ctx.Done():
return nil, ctx.Err()
default:
}
2017-02-07 21:04:27 +00:00
return nil, err
}
2018-02-11 00:29:52 +00:00
2017-09-05 22:06:47 +00:00
received, err := Parse(incoming[:n], packet.Secret)
2018-02-11 00:29:52 +00:00
if err != nil {
packetErrorCount++
if c.MaxPacketErrors > 0 && packetErrorCount >= c.MaxPacketErrors {
return nil, err
}
continue
2017-02-07 21:04:27 +00:00
}
2018-02-11 00:29:52 +00:00
if !c.InsecureSkipVerify && !IsAuthenticResponse(incoming[:n], wire, packet.Secret) {
packetErrorCount++
if c.MaxPacketErrors > 0 && packetErrorCount >= c.MaxPacketErrors {
return nil, &NonAuthenticResponseError{}
}
continue
}
return received, nil
2017-02-07 21:04:27 +00:00
}
}