2017-12-12 02:51:45 +00:00
package quic
import (
"bytes"
2018-01-03 19:19:49 +00:00
"context"
"crypto/tls"
2017-12-12 02:51:45 +00:00
"errors"
"net"
2018-01-03 19:19:49 +00:00
"reflect"
2017-12-12 02:51:45 +00:00
"time"
2018-01-03 19:19:49 +00:00
"github.com/lucas-clemente/quic-go/internal/crypto"
"github.com/lucas-clemente/quic-go/internal/handshake"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/testdata"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/internal/wire"
2017-12-12 02:51:45 +00:00
"github.com/lucas-clemente/quic-go/qerr"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
type mockSession struct {
2018-01-03 19:19:49 +00:00
connectionID protocol . ConnectionID
packetCount int
closed bool
closeReason error
closedRemote bool
stopRunLoop chan struct { } // run returns as soon as this channel receives a value
handshakeChan chan handshakeEvent
handshakeComplete chan error // for WaitUntilHandshakeComplete
2017-12-12 02:51:45 +00:00
}
func ( s * mockSession ) handlePacket ( * receivedPacket ) {
s . packetCount ++
}
2018-01-03 19:19:49 +00:00
func ( s * mockSession ) run ( ) error {
<- s . stopRunLoop
return s . closeReason
}
func ( s * mockSession ) WaitUntilHandshakeComplete ( ) error {
return <- s . handshakeComplete
}
2017-12-12 02:51:45 +00:00
func ( s * mockSession ) Close ( e error ) error {
2018-01-03 19:19:49 +00:00
if s . closed {
return nil
}
2017-12-12 02:51:45 +00:00
s . closeReason = e
s . closed = true
2018-01-03 19:19:49 +00:00
close ( s . stopRunLoop )
2017-12-12 02:51:45 +00:00
return nil
}
2018-01-03 19:19:49 +00:00
func ( s * mockSession ) closeRemote ( e error ) {
s . closeReason = e
s . closed = true
s . closedRemote = true
close ( s . stopRunLoop )
2017-12-12 02:51:45 +00:00
}
func ( s * mockSession ) OpenStream ( ) ( Stream , error ) {
return & stream { streamID : 1337 } , nil
}
2018-01-03 19:19:49 +00:00
func ( s * mockSession ) AcceptStream ( ) ( Stream , error ) { panic ( "not implemented" ) }
func ( s * mockSession ) OpenStreamSync ( ) ( Stream , error ) { panic ( "not implemented" ) }
func ( s * mockSession ) LocalAddr ( ) net . Addr { panic ( "not implemented" ) }
func ( s * mockSession ) RemoteAddr ( ) net . Addr { panic ( "not implemented" ) }
func ( * mockSession ) Context ( ) context . Context { panic ( "not implemented" ) }
func ( * mockSession ) GetVersion ( ) protocol . VersionNumber { return protocol . VersionWhatever }
func ( s * mockSession ) handshakeStatus ( ) <- chan handshakeEvent { return s . handshakeChan }
func ( * mockSession ) getCryptoStream ( ) cryptoStream { panic ( "not implemented" ) }
2017-12-12 02:51:45 +00:00
var _ Session = & mockSession { }
2018-01-03 19:19:49 +00:00
var _ NonFWSession = & mockSession { }
func newMockSession (
_ connection ,
_ protocol . VersionNumber ,
connectionID protocol . ConnectionID ,
_ * handshake . ServerConfig ,
_ * tls . Config ,
_ * Config ,
) ( packetHandler , error ) {
s := mockSession {
connectionID : connectionID ,
handshakeChan : make ( chan handshakeEvent ) ,
handshakeComplete : make ( chan error ) ,
stopRunLoop : make ( chan struct { } ) ,
}
return & s , nil
2017-12-12 02:51:45 +00:00
}
var _ = Describe ( "Server" , func ( ) {
var (
conn * mockPacketConn
config * Config
udpAddr = & net . UDPAddr { IP : net . IPv4 ( 192 , 168 , 100 , 200 ) , Port : 1337 }
)
BeforeEach ( func ( ) {
2018-01-03 19:19:49 +00:00
conn = newMockPacketConn ( )
conn . addr = & net . UDPAddr { }
config = & Config { Versions : protocol . SupportedVersions }
2017-12-12 02:51:45 +00:00
} )
Context ( "with mock session" , func ( ) {
var (
serv * server
firstPacket [ ] byte // a valid first packet for a new connection with connectionID 0x4cfa9f9b668619f6 (= connID)
connID = protocol . ConnectionID ( 0x4cfa9f9b668619f6 )
)
BeforeEach ( func ( ) {
serv = & server {
2018-01-03 19:19:49 +00:00
sessions : make ( map [ protocol . ConnectionID ] packetHandler ) ,
newSession : newMockSession ,
conn : conn ,
config : config ,
sessionQueue : make ( chan Session , 5 ) ,
errorChan : make ( chan struct { } ) ,
2017-12-12 02:51:45 +00:00
}
b := & bytes . Buffer { }
2018-01-03 19:19:49 +00:00
utils . BigEndian . WriteUint32 ( b , uint32 ( protocol . SupportedVersions [ 0 ] ) )
firstPacket = [ ] byte { 0x09 , 0x4c , 0xfa , 0x9f , 0x9b , 0x66 , 0x86 , 0x19 , 0xf6 }
2017-12-12 02:51:45 +00:00
firstPacket = append ( append ( firstPacket , b . Bytes ( ) ... ) , 0x01 )
2018-01-03 19:19:49 +00:00
firstPacket = append ( firstPacket , bytes . Repeat ( [ ] byte { 0 } , protocol . MinClientHelloSize ) ... ) // add padding
2017-12-12 02:51:45 +00:00
} )
It ( "returns the address" , func ( ) {
conn . addr = & net . UDPAddr {
IP : net . IPv4 ( 192 , 168 , 13 , 37 ) ,
Port : 1234 ,
}
Expect ( serv . Addr ( ) . String ( ) ) . To ( Equal ( "192.168.13.37:1234" ) )
} )
It ( "creates new sessions" , func ( ) {
err := serv . handlePacket ( nil , nil , firstPacket )
Expect ( err ) . ToNot ( HaveOccurred ( ) )
Expect ( serv . sessions ) . To ( HaveLen ( 1 ) )
sess := serv . sessions [ connID ] . ( * mockSession )
Expect ( sess . connectionID ) . To ( Equal ( connID ) )
Expect ( sess . packetCount ) . To ( Equal ( 1 ) )
} )
2018-01-03 19:19:49 +00:00
It ( "accepts a session once the connection it is forward secure" , func ( done Done ) {
var acceptedSess Session
go func ( ) {
defer GinkgoRecover ( )
var err error
acceptedSess , err = serv . Accept ( )
Expect ( err ) . ToNot ( HaveOccurred ( ) )
} ( )
err := serv . handlePacket ( nil , nil , firstPacket )
Expect ( err ) . ToNot ( HaveOccurred ( ) )
Expect ( serv . sessions ) . To ( HaveLen ( 1 ) )
sess := serv . sessions [ connID ] . ( * mockSession )
sess . handshakeChan <- handshakeEvent { encLevel : protocol . EncryptionSecure }
Consistently ( func ( ) Session { return acceptedSess } ) . Should ( BeNil ( ) )
sess . handshakeChan <- handshakeEvent { encLevel : protocol . EncryptionForwardSecure }
Eventually ( func ( ) Session { return acceptedSess } ) . Should ( Equal ( sess ) )
close ( done )
} , 0.5 )
It ( "doesn't accept session that error during the handshake" , func ( done Done ) {
var accepted bool
go func ( ) {
defer GinkgoRecover ( )
serv . Accept ( )
accepted = true
} ( )
err := serv . handlePacket ( nil , nil , firstPacket )
Expect ( err ) . ToNot ( HaveOccurred ( ) )
Expect ( serv . sessions ) . To ( HaveLen ( 1 ) )
sess := serv . sessions [ connID ] . ( * mockSession )
sess . handshakeChan <- handshakeEvent { err : errors . New ( "handshake failed" ) }
Consistently ( func ( ) bool { return accepted } ) . Should ( BeFalse ( ) )
close ( done )
2017-12-12 02:51:45 +00:00
} )
It ( "assigns packets to existing sessions" , func ( ) {
err := serv . handlePacket ( nil , nil , firstPacket )
Expect ( err ) . ToNot ( HaveOccurred ( ) )
2018-01-03 19:19:49 +00:00
err = serv . handlePacket ( nil , nil , [ ] byte { 0x08 , 0x4c , 0xfa , 0x9f , 0x9b , 0x66 , 0x86 , 0x19 , 0xf6 , 0x01 } )
2017-12-12 02:51:45 +00:00
Expect ( err ) . ToNot ( HaveOccurred ( ) )
Expect ( serv . sessions ) . To ( HaveLen ( 1 ) )
Expect ( serv . sessions [ connID ] . ( * mockSession ) . connectionID ) . To ( Equal ( connID ) )
Expect ( serv . sessions [ connID ] . ( * mockSession ) . packetCount ) . To ( Equal ( 2 ) )
} )
It ( "closes and deletes sessions" , func ( ) {
serv . deleteClosedSessionsAfter = time . Second // make sure that the nil value for the closed session doesn't get deleted in this test
2018-01-03 19:19:49 +00:00
nullAEAD , err := crypto . NewNullAEAD ( protocol . PerspectiveServer , connID , protocol . VersionWhatever )
Expect ( err ) . ToNot ( HaveOccurred ( ) )
err = serv . handlePacket ( nil , nil , append ( firstPacket , nullAEAD . Seal ( nil , nil , 0 , firstPacket ) ... ) )
2017-12-12 02:51:45 +00:00
Expect ( err ) . ToNot ( HaveOccurred ( ) )
Expect ( serv . sessions ) . To ( HaveLen ( 1 ) )
Expect ( serv . sessions [ connID ] ) . ToNot ( BeNil ( ) )
2018-01-03 19:19:49 +00:00
// make session.run() return
serv . sessions [ connID ] . ( * mockSession ) . stopRunLoop <- struct { } { }
2017-12-12 02:51:45 +00:00
// The server should now have closed the session, leaving a nil value in the sessions map
2018-01-03 19:19:49 +00:00
Consistently ( func ( ) map [ protocol . ConnectionID ] packetHandler { return serv . sessions } ) . Should ( HaveLen ( 1 ) )
2017-12-12 02:51:45 +00:00
Expect ( serv . sessions [ connID ] ) . To ( BeNil ( ) )
} )
It ( "deletes nil session entries after a wait time" , func ( ) {
serv . deleteClosedSessionsAfter = 25 * time . Millisecond
2018-01-03 19:19:49 +00:00
nullAEAD , err := crypto . NewNullAEAD ( protocol . PerspectiveServer , connID , protocol . VersionWhatever )
Expect ( err ) . ToNot ( HaveOccurred ( ) )
err = serv . handlePacket ( nil , nil , append ( firstPacket , nullAEAD . Seal ( nil , nil , 0 , firstPacket ) ... ) )
2017-12-12 02:51:45 +00:00
Expect ( err ) . ToNot ( HaveOccurred ( ) )
Expect ( serv . sessions ) . To ( HaveLen ( 1 ) )
Expect ( serv . sessions ) . To ( HaveKey ( connID ) )
2018-01-03 19:19:49 +00:00
// make session.run() return
serv . sessions [ connID ] . ( * mockSession ) . stopRunLoop <- struct { } { }
2017-12-12 02:51:45 +00:00
Eventually ( func ( ) bool {
serv . sessionsMutex . Lock ( )
_ , ok := serv . sessions [ connID ]
serv . sessionsMutex . Unlock ( )
return ok
} ) . Should ( BeFalse ( ) )
} )
It ( "closes sessions and the connection when Close is called" , func ( ) {
2018-01-03 19:19:49 +00:00
session , _ := newMockSession ( nil , 0 , 0 , nil , nil , nil )
2017-12-12 02:51:45 +00:00
serv . sessions [ 1 ] = session
err := serv . Close ( )
Expect ( err ) . NotTo ( HaveOccurred ( ) )
2018-01-03 19:19:49 +00:00
Expect ( session . ( * mockSession ) . closed ) . To ( BeTrue ( ) )
2017-12-12 02:51:45 +00:00
Expect ( conn . closed ) . To ( BeTrue ( ) )
} )
It ( "ignores packets for closed sessions" , func ( ) {
serv . sessions [ connID ] = nil
2018-01-03 19:19:49 +00:00
err := serv . handlePacket ( nil , nil , [ ] byte { 0x08 , 0x4c , 0xfa , 0x9f , 0x9b , 0x66 , 0x86 , 0x19 , 0xf6 , 0x01 } )
2017-12-12 02:51:45 +00:00
Expect ( err ) . ToNot ( HaveOccurred ( ) )
Expect ( serv . sessions ) . To ( HaveLen ( 1 ) )
Expect ( serv . sessions [ connID ] ) . To ( BeNil ( ) )
} )
2018-01-03 19:19:49 +00:00
It ( "works if no quic.Config is given" , func ( done Done ) {
ln , err := ListenAddr ( "127.0.0.1:0" , testdata . GetTLSConfig ( ) , nil )
Expect ( err ) . ToNot ( HaveOccurred ( ) )
Expect ( ln . Close ( ) ) . To ( Succeed ( ) )
close ( done )
} , 1 )
2017-12-12 02:51:45 +00:00
It ( "closes properly" , func ( ) {
2018-01-03 19:19:49 +00:00
ln , err := ListenAddr ( "127.0.0.1:0" , testdata . GetTLSConfig ( ) , config )
2017-12-12 02:51:45 +00:00
Expect ( err ) . ToNot ( HaveOccurred ( ) )
var returned bool
go func ( ) {
defer GinkgoRecover ( )
2018-01-03 19:19:49 +00:00
_ , err := ln . Accept ( )
2017-12-12 02:51:45 +00:00
Expect ( err ) . To ( HaveOccurred ( ) )
Expect ( err . Error ( ) ) . To ( ContainSubstring ( "use of closed network connection" ) )
returned = true
} ( )
ln . Close ( )
Eventually ( func ( ) bool { return returned } ) . Should ( BeTrue ( ) )
} )
2018-01-03 19:19:49 +00:00
It ( "errors when encountering a connection error" , func ( done Done ) {
2017-12-12 02:51:45 +00:00
testErr := errors . New ( "connection error" )
conn . readErr = testErr
2018-01-03 19:19:49 +00:00
go serv . serve ( )
_ , err := serv . Accept ( )
2017-12-12 02:51:45 +00:00
Expect ( err ) . To ( MatchError ( testErr ) )
2018-01-03 19:19:49 +00:00
Expect ( serv . Close ( ) ) . To ( Succeed ( ) )
close ( done )
} , 0.5 )
It ( "closes all sessions when encountering a connection error" , func ( ) {
session , _ := newMockSession ( nil , 0 , 0 , nil , nil , nil )
serv . sessions [ 0x12345 ] = session
Expect ( serv . sessions [ 0x12345 ] . ( * mockSession ) . closed ) . To ( BeFalse ( ) )
testErr := errors . New ( "connection error" )
conn . readErr = testErr
go serv . serve ( )
Eventually ( func ( ) Session { return serv . sessions [ connID ] } ) . Should ( BeNil ( ) )
Eventually ( func ( ) bool { return session . ( * mockSession ) . closed } ) . Should ( BeTrue ( ) )
Expect ( serv . Close ( ) ) . To ( Succeed ( ) )
2017-12-12 02:51:45 +00:00
} )
It ( "ignores delayed packets with mismatching versions" , func ( ) {
err := serv . handlePacket ( nil , nil , firstPacket )
Expect ( err ) . ToNot ( HaveOccurred ( ) )
Expect ( serv . sessions [ connID ] . ( * mockSession ) . packetCount ) . To ( Equal ( 1 ) )
b := & bytes . Buffer { }
// add an unsupported version
2018-01-03 19:19:49 +00:00
data := [ ] byte { 0x09 , 0x4c , 0xfa , 0x9f , 0x9b , 0x66 , 0x86 , 0x19 , 0xf6 }
utils . BigEndian . WriteUint32 ( b , uint32 ( protocol . SupportedVersions [ 0 ] + 1 ) )
2017-12-12 02:51:45 +00:00
data = append ( append ( data , b . Bytes ( ) ... ) , 0x01 )
err = serv . handlePacket ( nil , nil , data )
Expect ( err ) . ToNot ( HaveOccurred ( ) )
// if we didn't ignore the packet, the server would try to send a version negotation packet, which would make the test panic because it doesn't have a udpConn
Expect ( conn . dataWritten . Bytes ( ) ) . To ( BeEmpty ( ) )
// make sure the packet was *not* passed to session.handlePacket()
Expect ( serv . sessions [ connID ] . ( * mockSession ) . packetCount ) . To ( Equal ( 1 ) )
} )
It ( "errors on invalid public header" , func ( ) {
err := serv . handlePacket ( nil , nil , nil )
Expect ( err . ( * qerr . QuicError ) . ErrorCode ) . To ( Equal ( qerr . InvalidPacketHeader ) )
} )
It ( "ignores public resets for unknown connections" , func ( ) {
2018-01-03 19:19:49 +00:00
err := serv . handlePacket ( nil , nil , wire . WritePublicReset ( 999 , 1 , 1337 ) )
2017-12-12 02:51:45 +00:00
Expect ( err ) . ToNot ( HaveOccurred ( ) )
Expect ( serv . sessions ) . To ( BeEmpty ( ) )
} )
It ( "ignores public resets for known connections" , func ( ) {
err := serv . handlePacket ( nil , nil , firstPacket )
Expect ( serv . sessions ) . To ( HaveLen ( 1 ) )
Expect ( serv . sessions [ connID ] . ( * mockSession ) . packetCount ) . To ( Equal ( 1 ) )
2018-01-03 19:19:49 +00:00
err = serv . handlePacket ( nil , nil , wire . WritePublicReset ( connID , 1 , 1337 ) )
2017-12-12 02:51:45 +00:00
Expect ( err ) . ToNot ( HaveOccurred ( ) )
Expect ( serv . sessions ) . To ( HaveLen ( 1 ) )
Expect ( serv . sessions [ connID ] . ( * mockSession ) . packetCount ) . To ( Equal ( 1 ) )
} )
It ( "ignores invalid public resets for known connections" , func ( ) {
err := serv . handlePacket ( nil , nil , firstPacket )
Expect ( serv . sessions ) . To ( HaveLen ( 1 ) )
Expect ( serv . sessions [ connID ] . ( * mockSession ) . packetCount ) . To ( Equal ( 1 ) )
2018-01-03 19:19:49 +00:00
data := wire . WritePublicReset ( connID , 1 , 1337 )
2017-12-12 02:51:45 +00:00
err = serv . handlePacket ( nil , nil , data [ : len ( data ) - 2 ] )
Expect ( err ) . ToNot ( HaveOccurred ( ) )
Expect ( serv . sessions ) . To ( HaveLen ( 1 ) )
Expect ( serv . sessions [ connID ] . ( * mockSession ) . packetCount ) . To ( Equal ( 1 ) )
} )
It ( "doesn't respond with a version negotiation packet if the first packet is too small" , func ( ) {
b := & bytes . Buffer { }
2018-01-03 19:19:49 +00:00
hdr := wire . Header {
2017-12-12 02:51:45 +00:00
VersionFlag : true ,
ConnectionID : 0x1337 ,
PacketNumber : 1 ,
PacketNumberLen : protocol . PacketNumberLen2 ,
}
2018-01-03 19:19:49 +00:00
hdr . Write ( b , protocol . PerspectiveClient , 13 /* not a valid QUIC version */ )
b . Write ( bytes . Repeat ( [ ] byte { 0 } , protocol . MinClientHelloSize - 1 ) ) // this packet is 1 byte too small
2017-12-12 02:51:45 +00:00
err := serv . handlePacket ( conn , udpAddr , b . Bytes ( ) )
Expect ( err ) . To ( MatchError ( "dropping small packet with unknown version" ) )
Expect ( conn . dataWritten . Len ( ) ) . Should ( BeZero ( ) )
} )
} )
It ( "setups with the right values" , func ( ) {
2018-01-03 19:19:49 +00:00
supportedVersions := [ ] protocol . VersionNumber { 1 , 3 , 5 }
acceptCookie := func ( _ net . Addr , _ * Cookie ) bool { return true }
2017-12-12 02:51:45 +00:00
config := Config {
2018-01-03 19:19:49 +00:00
Versions : supportedVersions ,
AcceptCookie : acceptCookie ,
HandshakeTimeout : 1337 * time . Hour ,
IdleTimeout : 42 * time . Minute ,
KeepAlive : true ,
2017-12-12 02:51:45 +00:00
}
2018-01-03 19:19:49 +00:00
ln , err := Listen ( conn , & tls . Config { } , & config )
2017-12-12 02:51:45 +00:00
Expect ( err ) . ToNot ( HaveOccurred ( ) )
2018-01-03 19:19:49 +00:00
server := ln . ( * server )
2017-12-12 02:51:45 +00:00
Expect ( server . deleteClosedSessionsAfter ) . To ( Equal ( protocol . ClosedSessionDeleteTimeout ) )
Expect ( server . sessions ) . ToNot ( BeNil ( ) )
Expect ( server . scfg ) . ToNot ( BeNil ( ) )
2018-01-03 19:19:49 +00:00
Expect ( server . config . Versions ) . To ( Equal ( supportedVersions ) )
Expect ( server . config . HandshakeTimeout ) . To ( Equal ( 1337 * time . Hour ) )
Expect ( server . config . IdleTimeout ) . To ( Equal ( 42 * time . Minute ) )
Expect ( reflect . ValueOf ( server . config . AcceptCookie ) ) . To ( Equal ( reflect . ValueOf ( acceptCookie ) ) )
Expect ( server . config . KeepAlive ) . To ( BeTrue ( ) )
} )
It ( "fills in default values if options are not set in the Config" , func ( ) {
ln , err := Listen ( conn , & tls . Config { } , & Config { } )
Expect ( err ) . ToNot ( HaveOccurred ( ) )
server := ln . ( * server )
Expect ( server . config . Versions ) . To ( Equal ( protocol . SupportedVersions ) )
Expect ( server . config . HandshakeTimeout ) . To ( Equal ( protocol . DefaultHandshakeTimeout ) )
Expect ( server . config . IdleTimeout ) . To ( Equal ( protocol . DefaultIdleTimeout ) )
Expect ( reflect . ValueOf ( server . config . AcceptCookie ) ) . To ( Equal ( reflect . ValueOf ( defaultAcceptCookie ) ) )
Expect ( server . config . KeepAlive ) . To ( BeFalse ( ) )
2017-12-12 02:51:45 +00:00
} )
It ( "listens on a given address" , func ( ) {
addr := "127.0.0.1:13579"
2018-01-03 19:19:49 +00:00
ln , err := ListenAddr ( addr , nil , config )
2017-12-12 02:51:45 +00:00
Expect ( err ) . ToNot ( HaveOccurred ( ) )
serv := ln . ( * server )
Expect ( serv . Addr ( ) . String ( ) ) . To ( Equal ( addr ) )
} )
It ( "errors if given an invalid address" , func ( ) {
addr := "127.0.0.1"
2018-01-03 19:19:49 +00:00
_ , err := ListenAddr ( addr , nil , config )
2017-12-12 02:51:45 +00:00
Expect ( err ) . To ( BeAssignableToTypeOf ( & net . AddrError { } ) )
} )
It ( "errors if given an invalid address" , func ( ) {
addr := "1.1.1.1:1111"
2018-01-03 19:19:49 +00:00
_ , err := ListenAddr ( addr , nil , config )
2017-12-12 02:51:45 +00:00
Expect ( err ) . To ( BeAssignableToTypeOf ( & net . OpError { } ) )
} )
It ( "setups and responds with version negotiation" , func ( ) {
2018-01-03 19:19:49 +00:00
config . Versions = [ ] protocol . VersionNumber { 99 }
2017-12-12 02:51:45 +00:00
b := & bytes . Buffer { }
2018-01-03 19:19:49 +00:00
hdr := wire . Header {
2017-12-12 02:51:45 +00:00
VersionFlag : true ,
ConnectionID : 0x1337 ,
PacketNumber : 1 ,
PacketNumberLen : protocol . PacketNumberLen2 ,
}
2018-01-03 19:19:49 +00:00
hdr . Write ( b , protocol . PerspectiveClient , 13 /* not a valid QUIC version */ )
b . Write ( bytes . Repeat ( [ ] byte { 0 } , protocol . MinClientHelloSize ) ) // add a fake CHLO
conn . dataToRead <- b . Bytes ( )
2017-12-12 02:51:45 +00:00
conn . dataReadFrom = udpAddr
2018-01-03 19:19:49 +00:00
ln , err := Listen ( conn , nil , config )
2017-12-12 02:51:45 +00:00
Expect ( err ) . ToNot ( HaveOccurred ( ) )
2018-01-03 19:19:49 +00:00
done := make ( chan struct { } )
2017-12-12 02:51:45 +00:00
go func ( ) {
2018-01-03 19:19:49 +00:00
ln . Accept ( )
close ( done )
2017-12-12 02:51:45 +00:00
} ( )
Eventually ( func ( ) int { return conn . dataWritten . Len ( ) } ) . ShouldNot ( BeZero ( ) )
Expect ( conn . dataWrittenTo ) . To ( Equal ( udpAddr ) )
2018-01-03 19:19:49 +00:00
r := bytes . NewReader ( conn . dataWritten . Bytes ( ) )
packet , err := wire . ParseHeaderSentByServer ( r , protocol . VersionUnknown )
Expect ( err ) . ToNot ( HaveOccurred ( ) )
Expect ( packet . VersionFlag ) . To ( BeTrue ( ) )
Expect ( packet . ConnectionID ) . To ( Equal ( protocol . ConnectionID ( 0x1337 ) ) )
Expect ( r . Len ( ) ) . To ( BeZero ( ) )
Consistently ( done ) . ShouldNot ( BeClosed ( ) )
} )
It ( "sends an IETF draft style Version Negotaion Packet, if the client sent a IETF draft style header" , func ( ) {
config . Versions = [ ] protocol . VersionNumber { 99 , protocol . VersionTLS }
b := & bytes . Buffer { }
hdr := wire . Header {
Type : protocol . PacketTypeInitial ,
IsLongHeader : true ,
ConnectionID : 0x1337 ,
PacketNumber : 0x55 ,
Version : 0x1234 ,
}
err := hdr . Write ( b , protocol . PerspectiveClient , protocol . VersionTLS )
Expect ( err ) . ToNot ( HaveOccurred ( ) )
b . Write ( bytes . Repeat ( [ ] byte { 0 } , protocol . MinInitialPacketSize ) ) // add a fake CHLO
conn . dataToRead <- b . Bytes ( )
conn . dataReadFrom = udpAddr
ln , err := Listen ( conn , testdata . GetTLSConfig ( ) , config )
Expect ( err ) . ToNot ( HaveOccurred ( ) )
done := make ( chan struct { } )
go func ( ) {
ln . Accept ( )
close ( done )
} ( )
Eventually ( func ( ) int { return conn . dataWritten . Len ( ) } ) . ShouldNot ( BeZero ( ) )
Expect ( conn . dataWrittenTo ) . To ( Equal ( udpAddr ) )
r := bytes . NewReader ( conn . dataWritten . Bytes ( ) )
packet , err := wire . ParseHeaderSentByServer ( r , protocol . VersionUnknown )
Expect ( err ) . ToNot ( HaveOccurred ( ) )
Expect ( packet . IsVersionNegotiation ) . To ( BeTrue ( ) )
Expect ( packet . ConnectionID ) . To ( Equal ( protocol . ConnectionID ( 0x1337 ) ) )
Expect ( packet . PacketNumber ) . To ( Equal ( protocol . PacketNumber ( 0x55 ) ) )
Expect ( r . Len ( ) ) . To ( BeZero ( ) )
Consistently ( done ) . ShouldNot ( BeClosed ( ) )
} )
It ( "ignores IETF draft style Initial packets, if it doesn't support TLS" , func ( ) {
version := protocol . VersionNumber ( 99 )
Expect ( version . UsesTLS ( ) ) . To ( BeFalse ( ) )
config . Versions = [ ] protocol . VersionNumber { version }
b := & bytes . Buffer { }
hdr := wire . Header {
Type : protocol . PacketTypeInitial ,
IsLongHeader : true ,
ConnectionID : 0x1337 ,
PacketNumber : 0x55 ,
Version : protocol . VersionTLS ,
}
err := hdr . Write ( b , protocol . PerspectiveClient , protocol . VersionTLS )
Expect ( err ) . ToNot ( HaveOccurred ( ) )
b . Write ( bytes . Repeat ( [ ] byte { 0 } , protocol . MinClientHelloSize ) ) // add a fake CHLO
conn . dataToRead <- b . Bytes ( )
conn . dataReadFrom = udpAddr
ln , err := Listen ( conn , testdata . GetTLSConfig ( ) , config )
defer ln . Close ( )
Expect ( err ) . ToNot ( HaveOccurred ( ) )
Consistently ( func ( ) int { return conn . dataWritten . Len ( ) } ) . Should ( BeZero ( ) )
2017-12-12 02:51:45 +00:00
} )
It ( "sends a PublicReset for new connections that don't have the VersionFlag set" , func ( ) {
conn . dataReadFrom = udpAddr
2018-01-03 19:19:49 +00:00
conn . dataToRead <- [ ] byte { 0x08 , 0x4c , 0xfa , 0x9f , 0x9b , 0x66 , 0x86 , 0x19 , 0xf6 , 0x01 }
ln , err := Listen ( conn , nil , config )
2017-12-12 02:51:45 +00:00
Expect ( err ) . ToNot ( HaveOccurred ( ) )
go func ( ) {
defer GinkgoRecover ( )
2018-01-03 19:19:49 +00:00
_ , err := ln . Accept ( )
2017-12-12 02:51:45 +00:00
Expect ( err ) . ToNot ( HaveOccurred ( ) )
} ( )
Eventually ( func ( ) int { return conn . dataWritten . Len ( ) } ) . ShouldNot ( BeZero ( ) )
Expect ( conn . dataWrittenTo ) . To ( Equal ( udpAddr ) )
Expect ( conn . dataWritten . Bytes ( ) [ 0 ] & 0x02 ) . ToNot ( BeZero ( ) ) // check that the ResetFlag is set
Expect ( ln . ( * server ) . sessions ) . To ( BeEmpty ( ) )
} )
} )
2018-01-03 19:19:49 +00:00
var _ = Describe ( "default source address verification" , func ( ) {
It ( "accepts a token" , func ( ) {
remoteAddr := & net . UDPAddr { IP : net . IPv4 ( 192 , 168 , 0 , 1 ) }
cookie := & Cookie {
RemoteAddr : "192.168.0.1" ,
SentTime : time . Now ( ) . Add ( - protocol . CookieExpiryTime ) . Add ( time . Second ) , // will expire in 1 second
}
Expect ( defaultAcceptCookie ( remoteAddr , cookie ) ) . To ( BeTrue ( ) )
} )
It ( "requests verification if no token is provided" , func ( ) {
remoteAddr := & net . UDPAddr { IP : net . IPv4 ( 192 , 168 , 0 , 1 ) }
Expect ( defaultAcceptCookie ( remoteAddr , nil ) ) . To ( BeFalse ( ) )
} )
It ( "rejects a token if the address doesn't match" , func ( ) {
remoteAddr := & net . UDPAddr { IP : net . IPv4 ( 192 , 168 , 0 , 1 ) }
cookie := & Cookie {
RemoteAddr : "127.0.0.1" ,
SentTime : time . Now ( ) ,
}
Expect ( defaultAcceptCookie ( remoteAddr , cookie ) ) . To ( BeFalse ( ) )
} )
It ( "accepts a token for a remote address is not a UDP address" , func ( ) {
remoteAddr := & net . TCPAddr { IP : net . IPv4 ( 192 , 168 , 0 , 1 ) , Port : 1337 }
cookie := & Cookie {
RemoteAddr : "192.168.0.1:1337" ,
SentTime : time . Now ( ) ,
}
Expect ( defaultAcceptCookie ( remoteAddr , cookie ) ) . To ( BeTrue ( ) )
} )
It ( "rejects an invalid token for a remote address is not a UDP address" , func ( ) {
remoteAddr := & net . TCPAddr { IP : net . IPv4 ( 192 , 168 , 0 , 1 ) , Port : 1337 }
cookie := & Cookie {
RemoteAddr : "192.168.0.1:7331" , // mismatching port
SentTime : time . Now ( ) ,
}
Expect ( defaultAcceptCookie ( remoteAddr , cookie ) ) . To ( BeFalse ( ) )
} )
It ( "rejects an expired token" , func ( ) {
remoteAddr := & net . UDPAddr { IP : net . IPv4 ( 192 , 168 , 0 , 1 ) }
cookie := & Cookie {
RemoteAddr : "192.168.0.1" ,
SentTime : time . Now ( ) . Add ( - protocol . CookieExpiryTime ) . Add ( - time . Second ) , // expired 1 second ago
}
Expect ( defaultAcceptCookie ( remoteAddr , cookie ) ) . To ( BeFalse ( ) )
} )
} )