forked from layeh/radius
-
Notifications
You must be signed in to change notification settings - Fork 0
/
client.go
92 lines (77 loc) · 1.94 KB
/
client.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package radius
import (
"context"
"net"
"time"
)
// Client is a RADIUS client that can exchange packets with a RADIUS server.
type Client struct {
// Network on which to make the connection. Defaults to "udp".
Net string
// Dialer to use when making the outgoing connections.
Dialer net.Dialer
// Interval on which to resend packet (zero or negative value means no
// retry).
Retry time.Duration
InsecureSkipVerify bool
}
// DefaultClient is the RADIUS client used by the Exchange function.
var DefaultClient = &Client{}
// 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")
}
wire, err := packet.Encode()
if err != nil {
return nil, err
}
connNet := c.Net
if connNet == "" {
connNet = "udp"
}
conn, err := c.Dialer.DialContext(ctx, connNet, addr)
if err != nil {
return nil, err
}
defer conn.Close()
if deadline, deadlineSet := ctx.Deadline(); deadlineSet {
conn.SetDeadline(deadline)
}
conn.Write(wire)
if c.Retry > 0 {
retry := time.NewTicker(c.Retry)
defer retry.Stop()
end := make(chan struct{})
defer close(end)
go func() {
for {
select {
case <-retry.C:
conn.Write(wire)
case <-ctx.Done():
return
case <-end:
return
}
}
}()
}
var incoming [MaxPacketLength]byte
for {
n, err := conn.Read(incoming[:])
if err != nil {
return nil, err
}
received, err := Parse(incoming[:n], packet.Secret)
if err == nil && (!c.InsecureSkipVerify && IsAuthenticResponse(incoming[:n], wire, packet.Secret)) {
return received, nil
}
}
}