forked from External/grumble
Server-side crypt resync. Properly store ping stats.
This commit is contained in:
parent
0b086d6f57
commit
a2c9a15386
4 changed files with 131 additions and 59 deletions
32
client.go
32
client.go
|
|
@ -16,6 +16,7 @@ import (
|
|||
"grumble/blobstore"
|
||||
"io"
|
||||
"packetdatastream"
|
||||
"time"
|
||||
)
|
||||
|
||||
// A client connection
|
||||
|
|
@ -39,9 +40,18 @@ type Client struct {
|
|||
|
||||
disconnected bool
|
||||
|
||||
crypt *cryptstate.CryptState
|
||||
codecs []int32
|
||||
udp bool
|
||||
lastResync int64
|
||||
crypt *cryptstate.CryptState
|
||||
codecs []int32
|
||||
udp bool
|
||||
|
||||
// Ping stats
|
||||
UdpPingAvg float32
|
||||
UdpPingVar float32
|
||||
UdpPackets uint32
|
||||
TcpPingAvg float32
|
||||
TcpPingVar float32
|
||||
TcpPackets uint32
|
||||
|
||||
// If the client is a registered user on the server,
|
||||
// the user field will point to the registration record.
|
||||
|
|
@ -573,3 +583,19 @@ func (client *Client) sendChannelTree(channel *Channel) {
|
|||
client.sendChannelTree(subchannel)
|
||||
}
|
||||
}
|
||||
|
||||
// Try to do a crypto resync
|
||||
func (client *Client) cryptResync() {
|
||||
goodElapsed := time.Seconds() - client.crypt.LastGoodTime
|
||||
if goodElapsed > 5 {
|
||||
requestElapsed := time.Seconds() - client.lastResync
|
||||
if requestElapsed > 5 {
|
||||
client.lastResync = time.Seconds()
|
||||
cryptsetup := &mumbleproto.CryptSetup{}
|
||||
err := client.sendProtoMessage(MessageCryptSetup, cryptsetup)
|
||||
if err != nil {
|
||||
client.Panicf("%v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
35
message.go
35
message.go
|
|
@ -113,8 +113,39 @@ func (server *Server) handlePingMessage(client *Client, msg *Message) {
|
|||
return
|
||||
}
|
||||
|
||||
// Phony response for ping messages. We don't keep stats
|
||||
// for this yet.
|
||||
if ping.Good != nil {
|
||||
client.crypt.RemoteGood = uint32(*ping.Good)
|
||||
}
|
||||
if ping.Late != nil {
|
||||
client.crypt.RemoteLate = *ping.Late
|
||||
}
|
||||
if ping.Lost != nil {
|
||||
client.crypt.RemoteLost = *ping.Lost
|
||||
}
|
||||
if ping.Resync != nil {
|
||||
client.crypt.RemoteResync = *ping.Resync
|
||||
}
|
||||
|
||||
if ping.UdpPingAvg != nil {
|
||||
client.UdpPingAvg = *ping.UdpPingAvg
|
||||
}
|
||||
if ping.UdpPingVar != nil {
|
||||
client.UdpPingVar = *ping.UdpPingVar
|
||||
}
|
||||
if ping.UdpPackets != nil {
|
||||
client.UdpPackets = *ping.UdpPackets
|
||||
}
|
||||
|
||||
if ping.TcpPingAvg != nil {
|
||||
client.TcpPingAvg = *ping.TcpPingAvg
|
||||
}
|
||||
if ping.TcpPingVar != nil {
|
||||
client.TcpPingVar = *ping.TcpPingVar
|
||||
}
|
||||
if ping.TcpPackets != nil {
|
||||
client.TcpPackets = *ping.TcpPackets
|
||||
}
|
||||
|
||||
client.sendProtoMessage(MessagePing, &mumbleproto.Ping{
|
||||
Timestamp: ping.Timestamp,
|
||||
Good: proto.Uint32(uint32(client.crypt.Good)),
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"crypto/aes"
|
||||
"crypto/rand"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
const AESBlockSize = 16
|
||||
|
|
@ -20,15 +21,16 @@ type CryptState struct {
|
|||
DecryptIV [AESBlockSize]byte
|
||||
decryptHistory [DecryptHistorySize]byte
|
||||
|
||||
Good int
|
||||
Late int
|
||||
Lost int
|
||||
Resync int
|
||||
LastGoodTime int64
|
||||
|
||||
RemoteGood int
|
||||
RemoteLate int
|
||||
RemoteLost int
|
||||
RemoteResync int
|
||||
Good uint32
|
||||
Late uint32
|
||||
Lost uint32
|
||||
Resync uint32
|
||||
RemoteGood uint32
|
||||
RemoteLate uint32
|
||||
RemoteLost uint32
|
||||
RemoteResync uint32
|
||||
|
||||
cipher *aes.Cipher
|
||||
}
|
||||
|
|
@ -196,10 +198,18 @@ func (cs *CryptState) Decrypt(dst, src []byte) (err os.Error) {
|
|||
}
|
||||
|
||||
cs.Good += 1
|
||||
cs.Late += late
|
||||
cs.Lost += lost
|
||||
if late > 0 {
|
||||
cs.Late += uint32(late)
|
||||
} else {
|
||||
cs.Late -= uint32(-late)
|
||||
}
|
||||
if lost > 0 {
|
||||
cs.Lost = uint32(lost)
|
||||
} else {
|
||||
cs.Lost = uint32(-lost)
|
||||
}
|
||||
|
||||
// restart timer
|
||||
cs.LastGoodTime = time.Seconds()
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
|||
91
server.go
91
server.go
|
|
@ -492,6 +492,7 @@ func (server *Server) handleAuthenticate(client *Client, msg *Message) {
|
|||
|
||||
// Send CryptState information to the client so it can establish an UDP connection,
|
||||
// if it wishes.
|
||||
client.lastResync = time.Seconds()
|
||||
err = client.sendProtoMessage(MessageCryptSetup, &mumbleproto.CryptSetup{
|
||||
Key: client.crypt.RawKey[0:],
|
||||
ClientNonce: client.crypt.DecryptIV[0:],
|
||||
|
|
@ -923,53 +924,57 @@ func (server *Server) ListenUDP() {
|
|||
address: udpaddr,
|
||||
}
|
||||
} else {
|
||||
var match *Client
|
||||
plain := make([]byte, nread-4)
|
||||
|
||||
// Determine which client sent the the packet. First, we
|
||||
// check the map 'hpclients' in the server struct. It maps
|
||||
// a hort-post combination to a client.
|
||||
//
|
||||
// If we don't find any matches, we look in the 'hclients',
|
||||
// which maps a host address to a slice of clients.
|
||||
server.hmutex.Lock()
|
||||
client, ok := server.hpclients[udpaddr.String()]
|
||||
if ok {
|
||||
err = client.crypt.Decrypt(plain[0:], buf[0:nread])
|
||||
if err != nil {
|
||||
server.Panicf("Unable to decrypt incoming packet for client %v (host-port matched)", client)
|
||||
}
|
||||
match = client
|
||||
} else {
|
||||
host := udpaddr.IP.String()
|
||||
hostclients := server.hclients[host]
|
||||
for _, client := range hostclients {
|
||||
err = client.crypt.Decrypt(plain[0:], buf[0:nread])
|
||||
if err != nil {
|
||||
continue
|
||||
} else {
|
||||
match = client
|
||||
}
|
||||
}
|
||||
if match != nil {
|
||||
match.udpaddr = udpaddr
|
||||
server.hpclients[udpaddr.String()] = match
|
||||
}
|
||||
}
|
||||
server.hmutex.Unlock()
|
||||
|
||||
// No client found.
|
||||
if match == nil {
|
||||
server.Printf("Sender of UDP packet could not be determined. Packet dropped.")
|
||||
continue
|
||||
}
|
||||
|
||||
match.udp = true
|
||||
match.udprecv <- plain
|
||||
server.handleUdpPacket(udpaddr, buf, nread)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (server *Server) handleUdpPacket(udpaddr *net.UDPAddr, buf []byte, nread int) {
|
||||
var match *Client
|
||||
plain := make([]byte, nread-4)
|
||||
|
||||
// Determine which client sent the the packet. First, we
|
||||
// check the map 'hpclients' in the server struct. It maps
|
||||
// a hort-post combination to a client.
|
||||
//
|
||||
// If we don't find any matches, we look in the 'hclients',
|
||||
// which maps a host address to a slice of clients.
|
||||
server.hmutex.Lock()
|
||||
defer server.hmutex.Unlock()
|
||||
client, ok := server.hpclients[udpaddr.String()]
|
||||
if ok {
|
||||
err := client.crypt.Decrypt(plain[0:], buf[0:nread])
|
||||
if err != nil {
|
||||
client.cryptResync()
|
||||
return
|
||||
}
|
||||
match = client
|
||||
} else {
|
||||
host := udpaddr.IP.String()
|
||||
hostclients := server.hclients[host]
|
||||
for _, client := range hostclients {
|
||||
err := client.crypt.Decrypt(plain[0:], buf[0:nread])
|
||||
if err != nil {
|
||||
client.cryptResync()
|
||||
return
|
||||
} else {
|
||||
match = client
|
||||
}
|
||||
}
|
||||
if match != nil {
|
||||
match.udpaddr = udpaddr
|
||||
server.hpclients[udpaddr.String()] = match
|
||||
}
|
||||
}
|
||||
|
||||
if match == nil {
|
||||
return
|
||||
}
|
||||
|
||||
match.udp = true
|
||||
match.udprecv <- plain
|
||||
}
|
||||
|
||||
// Clear the ACL cache
|
||||
func (s *Server) ClearACLCache() {
|
||||
s.aclcache = NewACLCache()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue