Server-side crypt resync. Properly store ping stats.

This commit is contained in:
Mikkel Krautz 2011-05-13 22:26:15 +02:00
parent 0b086d6f57
commit a2c9a15386
4 changed files with 131 additions and 59 deletions

View file

@ -16,6 +16,7 @@ import (
"grumble/blobstore" "grumble/blobstore"
"io" "io"
"packetdatastream" "packetdatastream"
"time"
) )
// A client connection // A client connection
@ -39,9 +40,18 @@ type Client struct {
disconnected bool disconnected bool
crypt *cryptstate.CryptState lastResync int64
codecs []int32 crypt *cryptstate.CryptState
udp bool 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, // If the client is a registered user on the server,
// the user field will point to the registration record. // the user field will point to the registration record.
@ -573,3 +583,19 @@ func (client *Client) sendChannelTree(channel *Channel) {
client.sendChannelTree(subchannel) 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)
}
}
}
}

View file

@ -113,8 +113,39 @@ func (server *Server) handlePingMessage(client *Client, msg *Message) {
return return
} }
// Phony response for ping messages. We don't keep stats if ping.Good != nil {
// for this yet. 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{ client.sendProtoMessage(MessagePing, &mumbleproto.Ping{
Timestamp: ping.Timestamp, Timestamp: ping.Timestamp,
Good: proto.Uint32(uint32(client.crypt.Good)), Good: proto.Uint32(uint32(client.crypt.Good)),

View file

@ -9,6 +9,7 @@ import (
"crypto/aes" "crypto/aes"
"crypto/rand" "crypto/rand"
"os" "os"
"time"
) )
const AESBlockSize = 16 const AESBlockSize = 16
@ -20,15 +21,16 @@ type CryptState struct {
DecryptIV [AESBlockSize]byte DecryptIV [AESBlockSize]byte
decryptHistory [DecryptHistorySize]byte decryptHistory [DecryptHistorySize]byte
Good int LastGoodTime int64
Late int
Lost int
Resync int
RemoteGood int Good uint32
RemoteLate int Late uint32
RemoteLost int Lost uint32
RemoteResync int Resync uint32
RemoteGood uint32
RemoteLate uint32
RemoteLost uint32
RemoteResync uint32
cipher *aes.Cipher cipher *aes.Cipher
} }
@ -196,10 +198,18 @@ func (cs *CryptState) Decrypt(dst, src []byte) (err os.Error) {
} }
cs.Good += 1 cs.Good += 1
cs.Late += late if late > 0 {
cs.Lost += lost 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 return
} }

View file

@ -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, // Send CryptState information to the client so it can establish an UDP connection,
// if it wishes. // if it wishes.
client.lastResync = time.Seconds()
err = client.sendProtoMessage(MessageCryptSetup, &mumbleproto.CryptSetup{ err = client.sendProtoMessage(MessageCryptSetup, &mumbleproto.CryptSetup{
Key: client.crypt.RawKey[0:], Key: client.crypt.RawKey[0:],
ClientNonce: client.crypt.DecryptIV[0:], ClientNonce: client.crypt.DecryptIV[0:],
@ -923,53 +924,57 @@ func (server *Server) ListenUDP() {
address: udpaddr, address: udpaddr,
} }
} else { } else {
var match *Client server.handleUdpPacket(udpaddr, buf, nread)
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
} }
} }
} }
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 // Clear the ACL cache
func (s *Server) ClearACLCache() { func (s *Server) ClearACLCache() {
s.aclcache = NewACLCache() s.aclcache = NewACLCache()