-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathradiuspacket.go
128 lines (113 loc) · 3.39 KB
/
radiuspacket.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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package goradius
import (
"bytes"
"crypto/md5"
"encoding/binary"
"fmt"
"io"
"math/rand"
"net"
)
var (
packetCodes map[uint]string = map[uint]string{
1: "Access-Request",
2: "Access-Accept",
3: "Access-Reject",
4: "Accounting-Request",
5: "Accounting-Response",
6: "Accounting-Status",
7: "Password-Request",
8: "Password-Ack",
9: "Password-Reject",
10: "Accounting-Message",
11: "Access-Challenge",
12: "Status-Server",
13: "Status-Client",
28: "Reserved",
29: "Next-Passcode",
30: "New-Pin",
255: "Reserved",
}
)
type RadiusPacket struct {
Originator *net.UDPAddr // The origin IP address of the packet
SharedSecret string // Shared Secret
Code uint // Packet Code
PacketType string // Packet Type, based on Code
PacketId uint // Packet Identifier
Authenticator []byte // Authenticator Signature
AVPS []AttributeValuePair // A list of Attribute-value Pairs
Raw []byte // A buffer with the original raw data
}
// Attribute-Value Pair structure
type AttributeValuePair struct {
Name string
Type string
Length uint8
Content interface{}
}
func (p *RadiusPacket) String() string {
return fmt.Sprintf("Radius Packet %s (%d) ID: %d - %d AVPs", p.PacketType, p.Code, p.PacketId, len(p.AVPS))
}
// Verifies the Authenticator Field if it matches our shared-secret
func (p *RadiusPacket) VerifyAuthenticator() bool {
// Calculate the Request Authenticator Hash
h := md5.New()
h.Write(p.Raw[0:4]) // Code + Identifier + Length
h.Write([]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) // 16 Zero Octets
h.Write(p.Raw[20:]) // Request Attributes
h.Write([]byte(p.SharedSecret)) // Shared-Secret, as retrieved by SharedSecret Callback
ours := h.Sum(nil)
// Loop & compare byte-by-byte
for i := 0; i < 16; i++ {
if p.Raw[4+i] != ours[i] {
return false
}
}
return true
}
func (p *RadiusPacket) Marshal() []byte {
packetBuffer := make([]byte, 0, 1500)
packet := bytes.NewBuffer(packetBuffer)
// Write Packet Code & ID
packet.WriteByte(byte(p.Code))
packet.WriteByte(byte(p.PacketId))
avpBuffer := make([]byte, 0, 1500)
avps := bytes.NewBuffer(avpBuffer)
if len(p.AVPS) > 0 {
for _, avp := range p.AVPS {
if m, ok := marshalMap[avp.Name]; ok {
avpBytes := m(avp, p)
avps.Write(avpBytes)
} else {
l.Debug("No Marshaller found for AVP %s (%d)\n", avp.Name, avp.Type)
}
}
}
var packetLen uint16 = 4 + 16 + uint16(avps.Len())
// Write packet length
l.Debug("AVPs Length: %d\n", avps.Len())
binary.Write(packet, binary.BigEndian, packetLen)
// If authenticator is empty, we assume that we'll be generating one
if p.Authenticator == nil {
l.Debug("Nil authenticator, generating one\n")
// generate 16 random ints
randInts := rand.Perm(16)
p.Authenticator = make([]byte, 16)
for i := 0; i < 16; i++ {
p.Authenticator[0] = byte(randInts[i])
}
} else {
// Calculate Response Authenticator
h := md5.New()
temp := packet.Bytes()
h.Write(temp[0:4])
h.Write(p.Authenticator)
h.Write(avps.Bytes())
io.WriteString(h, p.SharedSecret)
p.Authenticator = h.Sum(nil)
}
packet.Write(p.Authenticator)
packet.Write(avps.Bytes())
return packet.Bytes()
}