예제 #1
0
func TestPingPong(t *testing.T) {
	// t.Parallel()
	logs.ResetLogger()

	withTwoEndpoints(t, func(A, B *Endpoint) {
		var (
			assert = assert.New(t)
			c      *Channel
			ident  *Identity
			pkt    *lob.Packet
			err    error
		)

		go func() {
			c, err := A.Listen("ping", false).AcceptChannel()

			c.SetDeadline(time.Now().Add(10 * time.Second))

			if assert.NoError(err) && assert.NotNil(c) {
				defer c.Close()

				pkt, err = c.ReadPacket()
				if assert.NoError(err) && assert.NotNil(pkt) {
					assert.Equal("ping", string(pkt.Body(nil)))

					err = c.WritePacket(lob.New([]byte("pong")))
					assert.NoError(err)
				}
			}
		}()

		ident, err = A.LocalIdentity()
		assert.NoError(err)

		c, err = B.Open(ident, "ping", false)
		assert.NoError(err)
		if assert.NotNil(c) {
			defer c.Close()

			c.SetDeadline(time.Now().Add(10 * time.Second))

			err = c.WritePacket(lob.New([]byte("ping")))
			assert.NoError(err)

			pkt, err = c.ReadPacket()
			if assert.NoError(err) && assert.NotNil(pkt) {
				assert.Equal("pong", string(pkt.Body(nil)))
			}
		}
	})
}
예제 #2
0
func (mod *module) introduceVia(router *e3x.Exchange, to hashname.H) error {
	localIdent, err := mod.e.LocalIdentity()
	if err != nil {
		return err
	}

	keys := localIdent.Keys()
	parts := hashname.PartsFromKeys(keys)

	for csid, key := range keys {
		inner := lob.New(key.Public())
		for partCSID, part := range parts {
			if partCSID == csid {
				inner.Header().SetBool(hex.EncodeToString([]byte{partCSID}), true)
			} else {
				inner.Header().SetString(hex.EncodeToString([]byte{partCSID}), part)
			}
		}

		body, err := lob.Encode(inner)
		if err != nil {
			return err
		}

		err = mod.peerVia(router, to, body)
		if err != nil {
			return err
		}
	}

	return nil
}
예제 #3
0
func (s *state) EncryptHandshake(at uint32, compact cipherset.Parts) ([]byte, error) {
	pkt := lob.New(s.localKey.Public())
	compact.ApplyToHeader(pkt.Header())
	pkt.Header().SetUint32("at", at)
	data, err := lob.Encode(pkt)
	if err != nil {
		return nil, err
	}
	return s.EncryptMessage(data.Get(nil))
}
예제 #4
0
// Write implements the net.Conn Write method.
func (c *Channel) Write(b []byte) (int, error) {
	n := len(b)
	pkt := lob.New(b)

	err := c.WritePacket(pkt)
	if err != nil {
		return 0, err
	}

	return n, nil
}
예제 #5
0
func (s *state) EncryptPacket(pkt *lob.Packet) (*lob.Packet, error) {
	s.mtx.RLock()
	defer s.mtx.RUnlock()

	var (
		outer   *lob.Packet
		inner   *bufpool.Buffer
		body    *bufpool.Buffer
		bodyRaw []byte
		nonce   [lenNonce]byte
		ctLen   int
		err     error
	)

	if !s.CanEncryptPacket() {
		return nil, cipherset.ErrInvalidState
	}
	if pkt == nil {
		return nil, nil
	}

	// encode inner packet
	inner, err = lob.Encode(pkt)
	if err != nil {
		return nil, err
	}

	// make nonce
	copy(nonce[:], s.pktNoncePrefix[:])
	nonceSuffix := atomic.AddUint64(&s.pktNonceSuffix, 1)
	binary.BigEndian.PutUint64(nonce[16:], nonceSuffix)

	// alloc enough space
	body = bufpool.New().SetLen(lenToken + lenNonce + inner.Len() + box.Overhead)
	bodyRaw = body.RawBytes()

	// copy token
	copy(bodyRaw[:lenToken], s.remoteToken[:])

	// copy nonce
	copy(bodyRaw[lenToken:lenToken+lenNonce], nonce[:])

	// encrypt inner packet
	ctLen = len(box.SealAfterPrecomputation(
		bodyRaw[lenToken+lenNonce:lenToken+lenNonce], inner.RawBytes(), &nonce, s.lineEncryptionKey))
	body.SetLen(lenToken + lenNonce + ctLen)

	outer = lob.New(body.RawBytes())
	inner.Free()
	body.Free()

	return outer, nil
}
예제 #6
0
func (mod *module) peerVia(router *e3x.Exchange, to hashname.H, body *bufpool.Buffer) error {
	ch, err := router.Open("peer", false)
	if err != nil {
		return err
	}
	defer ch.Kill()

	pkt := lob.New(body.RawBytes())
	pkt.Header().SetString("peer", string(to))
	ch.WritePacket(pkt)

	return nil
}
예제 #7
0
func (c *connection) sendHandshake(body []byte) error {
	ch, err := c.ex.Open("peer", false)
	if err != nil {
		return err
	}

	// defer e3x.ForgetterFromEndpoint(c.ex.).ForgetChannel(ch)

	pkt := lob.New(body)
	pkt.Header().SetString("peer", string(c.target))
	ch.WritePacket(pkt)

	return nil
}
예제 #8
0
func (mod *module) connect(ex *e3x.Exchange, inner *bufpool.Buffer) error {
	ch, err := ex.Open("connect", false)
	if err != nil {
		return err
	}

	defer ch.Kill()

	err = ch.WritePacket(lob.New(inner.RawBytes()))
	if err != nil {
		return err
	}

	return nil
}
예제 #9
0
func (s *state) EncryptPacket(pkt *lob.Packet) (*lob.Packet, error) {
	s.mtx.RLock()
	defer s.mtx.RUnlock()

	var (
		outer   *lob.Packet
		inner   *bufpool.Buffer
		body    *bufpool.Buffer
		bodyRaw []byte
		nonce   [16]byte
		ctLen   int
		err     error
	)

	if !s.CanEncryptPacket() {
		return nil, cipherset.ErrInvalidState
	}
	if pkt == nil {
		return nil, nil
	}

	// encode inner packet
	inner, err = lob.Encode(pkt)
	if err != nil {
		return nil, err
	}

	ctLen = inner.Len()

	// make nonce
	_, err = io.ReadFull(rand.Reader, nonce[:4])
	if err != nil {
		return nil, err
	}

	// alloc enough space
	body = bufpool.New().SetLen(16 + 4 + ctLen + 4)
	bodyRaw = body.RawBytes()

	// copy token
	copy(bodyRaw[:16], (*s.remoteToken)[:])

	// copy nonce
	copy(bodyRaw[16:16+4], nonce[:])

	{ // encrypt inner
		aesBlock, err := aes.NewCipher(s.lineEncryptionKey)
		if err != nil {
			return nil, err
		}

		aes := Cipher.NewCTR(aesBlock, nonce[:])
		if aes == nil {
			return nil, cipherset.ErrInvalidMessage
		}

		aes.XORKeyStream(bodyRaw[16+4:16+4+ctLen], inner.RawBytes())
	}

	{ // compute HMAC
		macKey := append(s.lineEncryptionKey, bodyRaw[16:16+4]...)

		h := hmac.New(sha256.New, macKey)
		h.Write(bodyRaw[16+4 : 16+4+ctLen])
		sum := h.Sum(nil)
		copy(bodyRaw[16+4+ctLen:], fold(sum, 4))
	}

	outer = lob.New(body.RawBytes())
	inner.Free()
	body.Free()

	return outer, nil
}
예제 #10
0
func BenchmarkPacketDecryption(b *testing.B, c cipherset.Cipher) {
	pkt := lob.New(bytes.Repeat([]byte{'x'}, 1024))

	lkey, err := c.GenerateKey()
	if err != nil {
		b.Fatal(err)
	}

	rkey, err := c.GenerateKey()
	if err != nil {
		b.Fatal(err)
	}

	lstate, err := c.NewState(lkey)
	if err != nil {
		b.Fatal(err)
	}

	rstate, err := c.NewState(rkey)
	if err != nil {
		b.Fatal(err)
	}

	err = lstate.SetRemoteKey(rkey)
	if err != nil {
		b.Fatal(err)
	}

	hs, err := lstate.EncryptHandshake(1, nil)
	if err != nil {
		b.Fatal(err)
	}

	hsMsg, err := c.DecryptHandshake(rkey, hs)
	if err != nil {
		b.Fatal(err)
	}

	ok := rstate.ApplyHandshake(hsMsg)
	if !ok {
		b.Fatal("handshake failed")
	}

	hs, err = rstate.EncryptHandshake(1, nil)
	if err != nil {
		b.Fatal(err)
	}

	hsMsg, err = c.DecryptHandshake(lkey, hs)
	if err != nil {
		b.Fatal(err)
	}

	ok = lstate.ApplyHandshake(hsMsg)
	if !ok {
		b.Fatal("handshake failed")
	}

	pkt, err = rstate.EncryptPacket(pkt)
	if err != nil {
		b.Fatal(err)
	}

	b.SetBytes(1024)
	b.ResetTimer()

	for i := 0; i < b.N; i++ {
		epkt, err := lstate.DecryptPacket(pkt)
		epkt.Free()
		if err != nil {
			b.Fatal(err)
		}
	}
}
예제 #11
0
func (s *cipherTestSuite) TestPacketEncryption() {
	var (
		assert = s.Assertions
		c      = s.cipher
	)

	var (
		ka  cipherset.Key
		kb  cipherset.Key
		sa  cipherset.State
		sb  cipherset.State
		ha  cipherset.Handshake
		hb  cipherset.Handshake
		pkt *lob.Packet
		box []byte
		err error
		ok  bool
	)

	ka, err = c.GenerateKey()
	assert.NoError(err)
	kb, err = c.GenerateKey()
	assert.NoError(err)

	sa, err = c.NewState(ka)
	assert.NoError(err)
	sb, err = c.NewState(kb)
	assert.NoError(err)

	err = sa.SetRemoteKey(kb)
	assert.NoError(err)
	box, err = sa.EncryptHandshake(1, nil)
	assert.NoError(err)
	hb, err = c.DecryptHandshake(kb, box)
	assert.NoError(err)
	ok = sb.ApplyHandshake(hb)
	assert.True(ok)
	box, err = sb.EncryptHandshake(1, nil)
	assert.NoError(err)
	ha, err = c.DecryptHandshake(ka, box)
	assert.NoError(err)
	ok = sa.ApplyHandshake(ha)
	assert.True(ok)

	pkt = lob.New([]byte("Hello world!"))
	pkt.Header().SetInt("foo", 0xbeaf)
	pkt, err = sa.EncryptPacket(pkt)
	assert.NoError(err)
	assert.NotNil(pkt)
	assert.Nil(pkt.Header().Bytes)
	assert.True(pkt.Header().IsZero())
	assert.NotEmpty(pkt.Body)

	pkt, err = sb.DecryptPacket(pkt)
	assert.NoError(err)
	assert.NotNil(pkt)
	assert.Nil(pkt.Header().Bytes)
	assert.Equal(&lob.Header{Extra: map[string]interface{}{"foo": 0xbeaf}}, pkt.Header())
	assert.Equal([]byte("Hello world!"), pkt.Body(nil))

	pkt = lob.New([]byte("Bye world!"))
	pkt.Header().SetInt("bar", 0xdead)
	pkt, err = sb.EncryptPacket(pkt)
	assert.NoError(err)
	assert.NotNil(pkt)
	assert.Nil(pkt.Header().Bytes)
	assert.True(pkt.Header().IsZero())
	assert.NotEmpty(pkt.Body)

	pkt, err = sa.DecryptPacket(pkt)
	assert.NoError(err)
	assert.NotNil(pkt)
	assert.Nil(pkt.Header().Bytes)
	assert.Equal(&lob.Header{Extra: map[string]interface{}{"bar": 0xdead}}, pkt.Header())
	assert.Equal([]byte("Bye world!"), pkt.Body(nil))
}
예제 #12
0
func BenchmarkChannelsReliable(b *testing.B) {
	defer dumpExpVar(b)
	logs.ResetLogger()

	var (
		ping = []byte("ping")
		pong = []byte("pong")
	)

	client := func(x *Exchange) {
		c, err := x.Open("ping", true)
		if err != nil {
			b.Fatal(err)
		}

		defer c.Close()

		pkt := lob.New(ping)
		err = c.WritePacket(pkt)
		if err != nil {
			b.Fatal(err)
		}

		pkt, err = c.ReadPacket()
		if err != nil {
			b.Fatal(err)
		}
		pkt.Free()
	}

	server := func(c *Channel) {
		defer c.Close()

		pkt, err := c.ReadPacket()
		if err != nil {
			b.Fatal(err)
		}
		pkt.Free()

		pkt = lob.New(pong)
		err = c.WritePacket(pkt)
		if err != nil {
			b.Fatal(err)
		}
	}

	accept := func(l *Listener) {
		for {
			c, err := l.AcceptChannel()
			if err == io.EOF {
				break
			}
			if err != nil {
				b.Fatal(err)
			}
			go server(c)
		}
	}

	withTwoEndpoints(b, func(A, B *Endpoint) {
		A.setOptions(DisableLog())
		B.setOptions(DisableLog())

		var (
			ident *Identity
			err   error
		)

		b.ResetTimer()

		l := A.Listen("ping", true)
		defer l.Close()
		go accept(l)

		ident, err = A.LocalIdentity()
		if err != nil {
			b.Fatal(err)
		}

		x, err := B.Dial(ident)
		if err != nil {
			b.Fatal(err)
		}

		b.ResetTimer()

		for i := 0; i < b.N; i++ {
			client(x)
		}

		b.StopTimer()
	})
}
예제 #13
0
func BenchmarkReadWriteUnreliable(b *testing.B) {
	defer dumpExpVar(b)
	logs.ResetLogger()

	withTwoEndpoints(b, func(A, B *Endpoint) {
		A.setOptions(DisableLog())
		B.setOptions(DisableLog())

		var (
			c     *Channel
			ident *Identity
			pkt   *lob.Packet
			err   error
			body  = bytes.Repeat([]byte{'x'}, 1300)
		)

		b.SetBytes(int64(len(body)))
		b.ResetTimer()

		go func() {
			c, err := A.Listen("flood", false).AcceptChannel()
			if err != nil {
				b.Fatal(err)
			}

			defer c.Close()

			pkt, err = c.ReadPacket()
			if err != nil {
				b.Fatal(err)
			}

			for i := 0; i < b.N; i++ {
				pkt := lob.New(body)
				err = c.WritePacket(pkt)
				if err != nil {
					b.Fatal(err)
				}

				// Give the other go routines some room to breath when GOMAXPROCS=1
				runtime.Gosched()
			}
		}()

		ident, err = A.LocalIdentity()
		if err != nil {
			b.Fatal(err)
		}

		c, err = B.Open(ident, "flood", false)
		if err != nil {
			b.Fatal(err)
		}

		defer c.Close()

		err = c.WritePacket(lob.New(nil))
		if err != nil {
			b.Fatal(err)
		}

		for {
			pkt, err = c.ReadPacket()
			if err == io.EOF {
				break
			}
			if err != nil {
				b.Fatal(err)
			}
			pkt.Free()
		}

		b.StopTimer()
	})
}
예제 #14
0
func TestFloodReliable(t *testing.T) {
	if testing.Short() {
		t.Skip("this is a long running test.")
	}

	withTwoEndpoints(t, func(A, B *Endpoint) {
		A.setOptions(DisableLog())
		B.setOptions(DisableLog())

		var (
			assert = assert.New(t)
			c      *Channel
			ident  *Identity
			pkt    *lob.Packet
			err    error
		)

		go func() {
			c, err := A.Listen("flood", true).AcceptChannel()
			if assert.NoError(err) && assert.NotNil(c) {
				defer c.Close()

				pkt, err = c.ReadPacket()
				assert.NoError(err)
				assert.NotNil(pkt)

				for i := 0; i < 100000; i++ {
					pkt := lob.New(nil)
					pkt.Header().SetInt("flood_id", i)
					err = c.WritePacket(pkt)
					assert.NoError(err)
				}
			}
		}()

		ident, err = A.LocalIdentity()
		assert.NoError(err)

		c, err = B.Open(ident, "flood", true)
		assert.NoError(err)
		assert.NotNil(c)

		defer c.Close()

		err = c.WritePacket(lob.New(nil))
		assert.NoError(err)

		lastID := -1
		for {
			pkt, err = c.ReadPacket()
			if err == io.EOF {
				break
			}
			assert.NoError(err)
			assert.NotNil(pkt)
			if err != nil {
				break
			}
			if pkt != nil {
				id, _ := pkt.Header().GetInt("flood_id")
				assert.True(lastID < id)
				lastID = id
			}
		}
	})
}