1
0
Fork 0
forked from External/grumble

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,10 +40,19 @@ type Client struct {
disconnected bool disconnected bool
lastResync int64
crypt *cryptstate.CryptState crypt *cryptstate.CryptState
codecs []int32 codecs []int32
udp bool 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.
user *User user *User
@ -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,6 +924,12 @@ func (server *Server) ListenUDP() {
address: udpaddr, address: udpaddr,
} }
} else { } else {
server.handleUdpPacket(udpaddr, buf, nread)
}
}
}
func (server *Server) handleUdpPacket(udpaddr *net.UDPAddr, buf []byte, nread int) {
var match *Client var match *Client
plain := make([]byte, nread-4) plain := make([]byte, nread-4)
@ -933,20 +940,23 @@ func (server *Server) ListenUDP() {
// If we don't find any matches, we look in the 'hclients', // If we don't find any matches, we look in the 'hclients',
// which maps a host address to a slice of clients. // which maps a host address to a slice of clients.
server.hmutex.Lock() server.hmutex.Lock()
defer server.hmutex.Unlock()
client, ok := server.hpclients[udpaddr.String()] client, ok := server.hpclients[udpaddr.String()]
if ok { if ok {
err = client.crypt.Decrypt(plain[0:], buf[0:nread]) err := client.crypt.Decrypt(plain[0:], buf[0:nread])
if err != nil { if err != nil {
server.Panicf("Unable to decrypt incoming packet for client %v (host-port matched)", client) client.cryptResync()
return
} }
match = client match = client
} else { } else {
host := udpaddr.IP.String() host := udpaddr.IP.String()
hostclients := server.hclients[host] hostclients := server.hclients[host]
for _, client := range hostclients { for _, client := range hostclients {
err = client.crypt.Decrypt(plain[0:], buf[0:nread]) err := client.crypt.Decrypt(plain[0:], buf[0:nread])
if err != nil { if err != nil {
continue client.cryptResync()
return
} else { } else {
match = client match = client
} }
@ -956,19 +966,14 @@ func (server *Server) ListenUDP() {
server.hpclients[udpaddr.String()] = match server.hpclients[udpaddr.String()] = match
} }
} }
server.hmutex.Unlock()
// No client found.
if match == nil { if match == nil {
server.Printf("Sender of UDP packet could not be determined. Packet dropped.") return
continue
} }
match.udp = true match.udp = true
match.udprecv <- plain match.udprecv <- plain
} }
}
}
// Clear the ACL cache // Clear the ACL cache
func (s *Server) ClearACLCache() { func (s *Server) ClearACLCache() {