restructured contexts in mitm tests

This commit is contained in:
Tatiana Bradley
2019-08-01 14:35:15 +00:00
parent db645f3336
commit 179d445778

View File

@@ -72,53 +72,100 @@ var _ = Describe("MITM test", func() {
Expect(err).ToNot(HaveOccurred())
})
AfterEach(func() {
Eventually(serverSess.Context().Done()).Should(BeClosed())
// Test shutdown is tricky due to the proxy. Just wait for a bit.
time.Sleep(50 * time.Millisecond)
Expect(clientConn.Close()).To(Succeed())
Expect(serverConn.Close()).To(Succeed())
Expect(proxy.Close()).To(Succeed())
})
Context("unsuccessful attacks", func() {
AfterEach(func() {
Eventually(serverSess.Context().Done()).Should(BeClosed())
// Test shutdown is tricky due to the proxy. Just wait for a bit.
time.Sleep(50 * time.Millisecond)
Expect(clientConn.Close()).To(Succeed())
Expect(serverConn.Close()).To(Succeed())
Expect(proxy.Close()).To(Succeed())
})
Context("injecting invalid packets", func() {
const rtt = 20 * time.Millisecond
Context("injecting invalid packets", func() {
const rtt = 20 * time.Millisecond
sendRandomPacketsOfSameType := func(conn net.PacketConn, remoteAddr net.Addr, raw []byte) {
defer GinkgoRecover()
hdr, _, _, err := wire.ParsePacket(raw, connIDLen)
Expect(err).ToNot(HaveOccurred())
replyHdr := &wire.ExtendedHeader{
Header: wire.Header{
IsLongHeader: hdr.IsLongHeader,
DestConnectionID: hdr.DestConnectionID,
SrcConnectionID: hdr.SrcConnectionID,
Type: hdr.Type,
Version: hdr.Version,
},
PacketNumber: protocol.PacketNumber(mrand.Int31n(math.MaxInt32 / 4)),
PacketNumberLen: protocol.PacketNumberLen(mrand.Int31n(4) + 1),
}
const numPackets = 10
ticker := time.NewTicker(rtt / numPackets)
for i := 0; i < numPackets; i++ {
payloadLen := mrand.Int31n(100)
replyHdr.Length = protocol.ByteCount(mrand.Int31n(payloadLen + 1))
buf := &bytes.Buffer{}
Expect(replyHdr.Write(buf, v)).To(Succeed())
b := make([]byte, payloadLen)
mrand.Read(b)
buf.Write(b)
if _, err := conn.WriteTo(buf.Bytes(), remoteAddr); err != nil {
return
sendRandomPacketsOfSameType := func(conn net.PacketConn, remoteAddr net.Addr, raw []byte) {
defer GinkgoRecover()
hdr, _, _, err := wire.ParsePacket(raw, connIDLen)
Expect(err).ToNot(HaveOccurred())
replyHdr := &wire.ExtendedHeader{
Header: wire.Header{
IsLongHeader: hdr.IsLongHeader,
DestConnectionID: hdr.DestConnectionID,
SrcConnectionID: hdr.SrcConnectionID,
Type: hdr.Type,
Version: hdr.Version,
},
PacketNumber: protocol.PacketNumber(mrand.Int31n(math.MaxInt32 / 4)),
PacketNumberLen: protocol.PacketNumberLen(mrand.Int31n(4) + 1),
}
<-ticker.C
}
}
runTest := func(delayCb quicproxy.DelayCallback) {
startServerAndProxy(delayCb, nil)
const numPackets = 10
ticker := time.NewTicker(rtt / numPackets)
for i := 0; i < numPackets; i++ {
payloadLen := mrand.Int31n(100)
replyHdr.Length = protocol.ByteCount(mrand.Int31n(payloadLen + 1))
buf := &bytes.Buffer{}
Expect(replyHdr.Write(buf, v)).To(Succeed())
b := make([]byte, payloadLen)
mrand.Read(b)
buf.Write(b)
if _, err := conn.WriteTo(buf.Bytes(), remoteAddr); err != nil {
return
}
<-ticker.C
}
}
runTest := func(delayCb quicproxy.DelayCallback) {
startServerAndProxy(delayCb, nil)
raddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("localhost:%d", proxy.LocalPort()))
Expect(err).ToNot(HaveOccurred())
sess, err := quic.Dial(
clientConn,
raddr,
fmt.Sprintf("localhost:%d", proxy.LocalPort()),
getTLSClientConfig(),
&quic.Config{
Versions: []protocol.VersionNumber{version},
ConnectionIDLength: connIDLen,
},
)
Expect(err).ToNot(HaveOccurred())
str, err := sess.AcceptUniStream(context.Background())
Expect(err).ToNot(HaveOccurred())
data, err := ioutil.ReadAll(str)
Expect(err).ToNot(HaveOccurred())
Expect(data).To(Equal(testserver.PRData))
Expect(sess.Close()).To(Succeed())
}
It("downloads a message when the packets are injected towards the server", func() {
delayCb := func(dir quicproxy.Direction, raw []byte) time.Duration {
if dir == quicproxy.DirectionIncoming {
defer GinkgoRecover()
go sendRandomPacketsOfSameType(clientConn, serverConn.LocalAddr(), raw)
}
return rtt / 2
}
runTest(delayCb)
})
It("downloads a message when the packets are injected towards the client", func() {
delayCb := func(dir quicproxy.Direction, raw []byte) time.Duration {
if dir == quicproxy.DirectionOutgoing {
defer GinkgoRecover()
go sendRandomPacketsOfSameType(serverConn, clientConn.LocalAddr(), raw)
}
return rtt / 2
}
runTest(delayCb)
})
})
runTest := func(dropCb quicproxy.DropCallback) {
startServerAndProxy(nil, dropCb)
raddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("localhost:%d", proxy.LocalPort()))
Expect(err).ToNot(HaveOccurred())
sess, err := quic.Dial(
@@ -140,130 +187,89 @@ var _ = Describe("MITM test", func() {
Expect(sess.Close()).To(Succeed())
}
It("downloads a message when the packets are injected towards the server", func() {
delayCb := func(dir quicproxy.Direction, raw []byte) time.Duration {
if dir == quicproxy.DirectionIncoming {
Context("duplicating packets", func() {
It("downloads a message when packets are duplicated towards the server", func() {
dropCb := func(dir quicproxy.Direction, raw []byte) bool {
defer GinkgoRecover()
go sendRandomPacketsOfSameType(clientConn, serverConn.LocalAddr(), raw)
if dir == quicproxy.DirectionIncoming {
_, err := clientConn.WriteTo(raw, serverConn.LocalAddr())
Expect(err).ToNot(HaveOccurred())
}
return false
}
return rtt / 2
}
runTest(delayCb)
runTest(dropCb)
})
It("downloads a message when packets are duplicated towards the client", func() {
dropCb := func(dir quicproxy.Direction, raw []byte) bool {
defer GinkgoRecover()
if dir == quicproxy.DirectionOutgoing {
_, err := serverConn.WriteTo(raw, clientConn.LocalAddr())
Expect(err).ToNot(HaveOccurred())
}
return false
}
runTest(dropCb)
})
})
It("downloads a message when the packets are injected towards the client", func() {
delayCb := func(dir quicproxy.Direction, raw []byte) time.Duration {
if dir == quicproxy.DirectionOutgoing {
Context("corrupting packets", func() {
const interval = 10 // corrupt every 10th packet (stochastically)
const idleTimeout = time.Second
var numCorrupted int32
BeforeEach(func() {
numCorrupted = 0
serverConfig.IdleTimeout = idleTimeout
})
AfterEach(func() {
num := atomic.LoadInt32(&numCorrupted)
fmt.Fprintf(GinkgoWriter, "Corrupted %d packets.", num)
Expect(num).To(BeNumerically(">=", 1))
// If the packet containing the CONNECTION_CLOSE is corrupted,
// we have to wait for the session to time out.
Eventually(serverSess.Context().Done(), 3*idleTimeout).Should(BeClosed())
})
It("downloads a message when packet are corrupted towards the server", func() {
dropCb := func(dir quicproxy.Direction, raw []byte) bool {
defer GinkgoRecover()
go sendRandomPacketsOfSameType(serverConn, clientConn.LocalAddr(), raw)
if dir == quicproxy.DirectionIncoming && mrand.Intn(interval) == 0 {
pos := mrand.Intn(len(raw))
raw[pos] = byte(mrand.Intn(256))
_, err := clientConn.WriteTo(raw, serverConn.LocalAddr())
Expect(err).ToNot(HaveOccurred())
atomic.AddInt32(&numCorrupted, 1)
return true
}
return false
}
return rtt / 2
}
runTest(delayCb)
runTest(dropCb)
})
It("downloads a message when packet are corrupted towards the client", func() {
dropCb := func(dir quicproxy.Direction, raw []byte) bool {
defer GinkgoRecover()
isRetry := raw[0]&0xc0 == 0xc0 // don't corrupt Retry packets
if dir == quicproxy.DirectionOutgoing && mrand.Intn(interval) == 0 && !isRetry {
pos := mrand.Intn(len(raw))
raw[pos] = byte(mrand.Intn(256))
_, err := serverConn.WriteTo(raw, clientConn.LocalAddr())
Expect(err).ToNot(HaveOccurred())
atomic.AddInt32(&numCorrupted, 1)
return true
}
return false
}
runTest(dropCb)
})
})
})
runTest := func(dropCb quicproxy.DropCallback) {
startServerAndProxy(nil, dropCb)
raddr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("localhost:%d", proxy.LocalPort()))
Expect(err).ToNot(HaveOccurred())
sess, err := quic.Dial(
clientConn,
raddr,
fmt.Sprintf("localhost:%d", proxy.LocalPort()),
getTLSClientConfig(),
&quic.Config{
Versions: []protocol.VersionNumber{version},
ConnectionIDLength: connIDLen,
},
)
Expect(err).ToNot(HaveOccurred())
str, err := sess.AcceptUniStream(context.Background())
Expect(err).ToNot(HaveOccurred())
data, err := ioutil.ReadAll(str)
Expect(err).ToNot(HaveOccurred())
Expect(data).To(Equal(testserver.PRData))
Expect(sess.Close()).To(Succeed())
}
Context("duplicating packets", func() {
It("downloads a message when packets are duplicated towards the server", func() {
dropCb := func(dir quicproxy.Direction, raw []byte) bool {
defer GinkgoRecover()
if dir == quicproxy.DirectionIncoming {
_, err := clientConn.WriteTo(raw, serverConn.LocalAddr())
Expect(err).ToNot(HaveOccurred())
}
return false
}
runTest(dropCb)
})
It("downloads a message when packets are duplicated towards the client", func() {
dropCb := func(dir quicproxy.Direction, raw []byte) bool {
defer GinkgoRecover()
if dir == quicproxy.DirectionOutgoing {
_, err := serverConn.WriteTo(raw, clientConn.LocalAddr())
Expect(err).ToNot(HaveOccurred())
}
return false
}
runTest(dropCb)
})
})
Context("corrupting packets", func() {
const interval = 10 // corrupt every 10th packet (stochastically)
const idleTimeout = time.Second
var numCorrupted int32
BeforeEach(func() {
numCorrupted = 0
serverConfig.IdleTimeout = idleTimeout
})
AfterEach(func() {
num := atomic.LoadInt32(&numCorrupted)
fmt.Fprintf(GinkgoWriter, "Corrupted %d packets.", num)
Expect(num).To(BeNumerically(">=", 1))
// If the packet containing the CONNECTION_CLOSE is corrupted,
// we have to wait for the session to time out.
Eventually(serverSess.Context().Done(), 3*idleTimeout).Should(BeClosed())
})
It("downloads a message when packet are corrupted towards the server", func() {
dropCb := func(dir quicproxy.Direction, raw []byte) bool {
defer GinkgoRecover()
if dir == quicproxy.DirectionIncoming && mrand.Intn(interval) == 0 {
pos := mrand.Intn(len(raw))
raw[pos] = byte(mrand.Intn(256))
_, err := clientConn.WriteTo(raw, serverConn.LocalAddr())
Expect(err).ToNot(HaveOccurred())
atomic.AddInt32(&numCorrupted, 1)
return true
}
return false
}
runTest(dropCb)
})
It("downloads a message when packet are corrupted towards the client", func() {
dropCb := func(dir quicproxy.Direction, raw []byte) bool {
defer GinkgoRecover()
isRetry := raw[0]&0xc0 == 0xc0 // don't corrupt Retry packets
if dir == quicproxy.DirectionOutgoing && mrand.Intn(interval) == 0 && !isRetry {
pos := mrand.Intn(len(raw))
raw[pos] = byte(mrand.Intn(256))
_, err := serverConn.WriteTo(raw, clientConn.LocalAddr())
Expect(err).ToNot(HaveOccurred())
atomic.AddInt32(&numCorrupted, 1)
return true
}
return false
}
runTest(dropCb)
})
Context("successful injection attacks", func() {
// TODO(tatianab): add successful injection attacks
})
})
}