Example #1
0
func (mod *module) handle_connect(ch *e3x.Channel) {
	defer ch.Kill()

	var (
		from        hashname.H
		localIdent  *e3x.Identity
		remoteIdent *e3x.Identity
		handshake   cipherset.Handshake
		innerData   = bufpool.New()
		err         error
	)

	localIdent, err = mod.e.LocalIdentity()
	if err != nil {
		return
	}

	pkt, err := ch.ReadPacket()
	if err != nil {
		return
	}

	pkt.Body(innerData.SetLen(pkt.BodyLen()).RawBytes()[:0])

	inner, err := lob.Decode(innerData)
	if err != nil {
		return
	}

	innerHdr := inner.Header()
	if innerHdr.IsBinary() && len(innerHdr.Bytes) == 1 {
		// handshake
		var (
			csid = innerHdr.Bytes[0]
			key  = localIdent.Keys()[csid]
		)
		if key == nil {
			return
		}

		handshake, err = cipherset.DecryptHandshake(csid, key, inner.Body(nil))
		if err != nil {
			return
		}

		from, err = hashname.FromIntermediates(handshake.Parts())
		if err != nil {
			return
		}

		remoteIdent, err = e3x.NewIdentity(cipherset.Keys{
			handshake.CSID(): handshake.PublicKey(),
		}, handshake.Parts(), nil)
		if err != nil {
			return
		}

	} else {
		// key packet

		var parts = make(cipherset.Parts)
		var csid uint8
		for key, value := range inner.Header().Extra {
			if len(key) != 2 {
				continue
			}

			keyData, err := hex.DecodeString(key)
			if err != nil {
				continue
			}

			partCSID := keyData[0]
			switch v := value.(type) {
			case bool:
				csid = partCSID
			case string:
				parts[partCSID] = v
			}
		}

		hn, err := hashname.FromKeyAndIntermediates(csid, inner.Body(nil), parts)
		if err != nil {
			return
		}

		from = hn

		pubKey, err := cipherset.DecodeKeyBytes(csid, inner.Body(nil), nil)
		if err != nil {
			return
		}

		remoteIdent, err = e3x.NewIdentity(cipherset.Keys{csid: pubKey}, parts, nil)
		if err != nil {
			return
		}
	}

	if from == "" {
		return
	}

	if mod.config.AllowConnect != nil && !mod.config.AllowConnect(from, ch.RemoteHashname()) {
		return
	}

	x, err := mod.e.CreateExchange(remoteIdent)
	if err != nil {
		return
	}

	// when the BODY contains a handshake
	if handshake != nil {
		routerExchange := ch.Exchange()
		routerAddr := &peerAddr{
			router: routerExchange.RemoteHashname(),
		}

		conn := newConnection(x.RemoteHashname(), routerAddr, routerExchange, func() {
			mod.unregisterConnection(routerExchange, x.LocalToken())
		})

		pipe, added := x.AddPipeConnection(conn, nil)
		if added {
			mod.registerConnection(routerExchange, x.LocalToken(), conn)
		}

		resp, ok := x.ApplyHandshake(handshake, pipe)
		if !ok {
			return
		}

		if resp != nil {
			err = mod.peerVia(ch.Exchange(), from, resp)
			if err != nil {
				return
			}
		}
	}

	// when the BODY contains a key packet
	if handshake == nil {
		pkt, err := x.GenerateHandshake()
		if err != nil {
			return
		}

		err = mod.peerVia(ch.Exchange(), from, pkt)
		if err != nil {
			return
		}
	}

	// Notify on-exchange callbacks
	mod.getIntroduction(from).resolve(x, nil)
}
Example #2
0
func (e *Endpoint) accept(conn net.Conn) {
	var (
		token cipherset.Token
		msg   = bufpool.New()
		err   error
		n     int
	)
	n, err = conn.Read(msg.RawBytes()[:1500])
	if err != nil {
		msg.Free()
		conn.Close()
		return
	}
	msg.SetLen(n)

	// msg is either a handshake or a channel packet
	// when msg is a handshake decrypt it and pass it to the associated exchange
	// when msg is a channel packet lookup the exchange and pass it the msg
	// always associate the conn with the exchange

	if msg.Len() < 2 {
		if e.endpointHooks.DropPacket(msg.Get(nil), conn, nil) != ErrStopPropagation {
			conn.Close()
		}
		msg.Free()
		return // to short
	}

	token = cipherset.ExtractToken(msg.RawBytes())
	e.mtx.Lock()
	exchange := e.tokens[token]
	e.mtx.Unlock()

	if exchange != nil {
		exchange.received(newMessage(msg, newPipe(e.transport, conn, nil, exchange)))
		return
	}

	if raw := msg.RawBytes(); len(raw) < 3 || raw[0] != 0 || raw[1] != 1 {
		if e.endpointHooks.DropPacket(msg.Get(nil), conn, nil) != ErrStopPropagation {
			conn.Close()
		}
		msg.Free()
		return // to short
	}

	localIdent, err := e.LocalIdentity()
	if err != nil {
		if e.endpointHooks.DropPacket(msg.Get(nil), conn, err) != ErrStopPropagation {
			conn.Close()
		}
		e.traceDroppedPacket(msg.Get(nil), conn, err.Error())
		msg.Free()
		return // drop
	}

	// handle handshakes
	e.mtx.Lock()
	defer e.mtx.Unlock()

	var (
		csid = msg.RawBytes()[2]
		key  = e.keys[csid]
	)
	if key == nil {
		if e.endpointHooks.DropPacket(msg.Get(nil), conn, nil) != ErrStopPropagation {
			conn.Close()
		}
		msg.Free()
		return // no key for csid
	}

	handshake, err := cipherset.DecryptHandshake(csid, key, msg.RawBytes()[3:])
	if err != nil {
		if e.endpointHooks.DropPacket(msg.Get(nil), conn, err) != ErrStopPropagation {
			conn.Close()
		}
		e.traceDroppedPacket(msg.Get(nil), conn, err.Error())
		msg.Free()
		return // drop
	}

	hn, err := hashname.FromKeyAndIntermediates(csid,
		handshake.PublicKey().Public(), handshake.Parts())
	if err != nil {
		if e.endpointHooks.DropPacket(msg.Get(nil), conn, err) != ErrStopPropagation {
			conn.Close()
		}
		e.traceDroppedPacket(msg.Get(nil), conn, err.Error())
		msg.Free()
		return // drop
	}

	exchange = e.hashnames[hn]
	if exchange != nil {
		oldLocalToken := exchange.LocalToken()
		oldRemoteToken := exchange.RemoteToken()
		exchange.received(newMessage(msg, newPipe(e.transport, conn, nil, exchange)))
		newLocalToken := exchange.LocalToken()
		newRemoteToken := exchange.RemoteToken()

		if oldLocalToken != newLocalToken {
			delete(e.tokens, oldLocalToken)
			e.tokens[newLocalToken] = exchange
		}

		if oldRemoteToken != newRemoteToken {
			delete(e.tokens, oldRemoteToken)
			e.tokens[newRemoteToken] = exchange
		}

		return
	}

	exchange, err = newExchange(localIdent, nil, handshake, e.log, registerEndpoint(e))
	if err != nil {
		if e.endpointHooks.DropPacket(msg.Get(nil), conn, err) != ErrStopPropagation {
			conn.Close()
		}
		e.traceDroppedPacket(msg.Get(nil), conn, err.Error())
		msg.Free()
		return // drop
	}

	e.hashnames[hn] = exchange
	e.tokens[exchange.LocalToken()] = exchange
	e.tokens[exchange.RemoteToken()] = exchange
	exchange.state = ExchangeDialing
	exchange.received(newMessage(msg, newPipe(e.transport, conn, nil, exchange)))
}