-
Notifications
You must be signed in to change notification settings - Fork 40
/
server.go
189 lines (171 loc) · 4.65 KB
/
server.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
package rcon
import (
"crypto"
"crypto/rsa"
"crypto/sha256"
"crypto/tls"
"crypto/x509"
"encoding/pem"
"github.com/RoboCup-SSL/ssl-game-controller/pkg/refproto"
"github.com/golang/protobuf/proto"
"io/ioutil"
"log"
"net"
"os"
"strings"
)
type Server struct {
Clients map[string]*Client
TrustedKeys map[string]*rsa.PublicKey
ConnectionHandler func(net.Conn)
ClientsChangedObservers []func()
}
type Client struct {
Id string
Conn net.Conn
Token string
PubKey *rsa.PublicKey
VerifiedConnection bool
}
func NewServer() (s *Server) {
s = new(Server)
s.Clients = map[string]*Client{}
s.TrustedKeys = map[string]*rsa.PublicKey{}
return
}
func (s *Server) Listen(address string) {
listener, err := net.Listen("tcp", address)
if err != nil {
log.Print("Failed to listen on ", address)
return
}
log.Print("Listening on ", address)
for {
conn, err := listener.Accept()
if err != nil {
log.Print("Could not accept connection: ", err)
} else {
go s.ConnectionHandler(conn)
}
}
}
func (s *Server) ListenTls(address string) {
if _, err := os.Stat("server.crt"); os.IsNotExist(err) {
log.Println("Missing certificate for TLS endpoint. Put a server.crt in the working dir.")
return
}
if _, err := os.Stat("server.key"); os.IsNotExist(err) {
log.Println("Missing certificate key for TLS endpoint. Put a server.key in the working dir.")
return
}
cer, err := tls.LoadX509KeyPair("server.crt", "server.key")
if err != nil {
log.Printf("Could not load X509 key pair: %v", err)
return
}
config := &tls.Config{Certificates: []tls.Certificate{cer}}
listener, err := tls.Listen("tcp", address, config)
if err != nil {
log.Printf("Failed to listen on %v: %v", address, err)
return
}
log.Print("Listening on ", address)
for {
conn, err := listener.Accept()
if err != nil {
log.Print("Could not accept connection: ", err)
} else {
go s.ConnectionHandler(conn)
}
}
}
func (s *Server) CloseConnection(conn net.Conn, id string) {
delete(s.Clients, id)
log.Printf("Connection to %v closed", id)
for _, observer := range s.ClientsChangedObservers {
observer()
}
}
func (c *Client) Ok() (reply refproto.ControllerReply) {
reply.StatusCode = new(refproto.ControllerReply_StatusCode)
*reply.StatusCode = refproto.ControllerReply_OK
c.addVerification(&reply)
return
}
func (c *Client) addVerification(reply *refproto.ControllerReply) {
reply.Verification = new(refproto.ControllerReply_Verification)
if c.Token != "" {
reply.NextToken = new(string)
*reply.NextToken = c.Token
*reply.Verification = refproto.ControllerReply_VERIFIED
c.VerifiedConnection = true
} else {
*reply.Verification = refproto.ControllerReply_UNVERIFIED
c.VerifiedConnection = false
}
}
func (c *Client) Reject(reason string) (reply refproto.ControllerReply) {
log.Print("Reject connection: " + reason)
reply.StatusCode = new(refproto.ControllerReply_StatusCode)
*reply.StatusCode = refproto.ControllerReply_REJECTED
reply.Reason = new(string)
*reply.Reason = reason
c.addVerification(&reply)
return
}
func (s *Server) LoadTrustedKeys(trustedKeysDir string) {
files, err := ioutil.ReadDir(trustedKeysDir)
if err != nil {
log.Print("Could not read trusted keys: ", err)
return
}
for _, file := range files {
if !file.IsDir() && strings.HasSuffix(file.Name(), ".pub.pem") {
pubKey := readPublicKey(trustedKeysDir + "/" + file.Name())
if pubKey != nil {
name := strings.Replace(file.Name(), ".pub.pem", "", 1)
s.TrustedKeys[name] = pubKey
log.Printf("Loaded public key for %v", name)
}
}
}
log.Printf("Loaded %v public keys", len(s.TrustedKeys))
}
func readPublicKey(filename string) *rsa.PublicKey {
b, err := ioutil.ReadFile(filename)
if err != nil {
log.Print("Could not find private key at ", filename)
return nil
}
p, rest := pem.Decode(b)
if p == nil {
log.Print("Could not decode public key. Remaining data: ", string(rest))
return nil
}
if p.Type != "PUBLIC KEY" {
log.Print("Public key type is wrong: ", p.Type)
return nil
}
publicKey, err := x509.ParsePKIXPublicKey(p.Bytes)
if err != nil {
log.Print("Failed to parse public key: ", err)
return nil
}
switch pub := publicKey.(type) {
case *rsa.PublicKey:
return pub
default:
log.Print("Unsupported public key: ", pub)
return nil
}
}
func VerifySignature(key *rsa.PublicKey, message proto.Message, signature []byte) error {
messageBytes, err := proto.Marshal(message)
if err != nil {
log.Fatal("Failed to marshal message: ", err)
}
hash := sha256.New()
hash.Write(messageBytes)
d := hash.Sum(nil)
return rsa.VerifyPKCS1v15(key, crypto.SHA256, d, signature)
}