Пример #1
0
func (d *dht) see(key string, x *e3x.Exchange) ([]hashname.H, error) {
	c, err := x.Open(d.prefix+"see", false)
	if err != nil {
		return nil, err
	}
	defer c.Close()

	pkt := &lob.Packet{}
	pkt.Header().SetString("key", key)
	pkt.Header().SetBool("end", true)
	err = c.WritePacket(pkt)
	if err != nil {
		return nil, err
	}

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

	v, _ := pkt.Header().Get("see")
	l, ok := v.([]string)
	if !ok {
		return nil, nil
	}

	h := make([]hashname.H, len(l))
	for i, s := range l {
		h[i] = hashname.H(s)
	}

	return h, nil
}
Пример #2
0
// Gets a list of the vnodes on the box
func (t *transport) ListVnodes(hn string) ([]*chord.Vnode, error) {
	var (
		addr *e3x.Addr
		ch   *e3x.Channel
		res  []*completeVnode
		err  error
	)

	addr = t.lookupAddr(hashname.H(hn))
	if addr == nil {
		return nil, e3x.ErrNoAddress
	}

	ch, err = t.e.Open(addr, "chord.list", true)
	if err != nil {
		return nil, err
	}

	defer ch.Close()

	// ch.SetReadDeadline(time.Now().Add(30*time.Second))
	// ch.SetWriteDeadline(time.Now().Add(30*time.Second))

	err = ch.WritePacket(&lob.Packet{})
	if err != nil {
		return nil, err
	}

	err = json.NewDecoder(newStream(ch)).Decode(&res)
	if err != nil {
		return nil, err
	}

	return t.internalVnodes(res), nil
}
Пример #3
0
func (rt *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
	var (
		hashname = hashname.H(req.URL.Host)
		c        *e3x.Channel
		resp     *http.Response
		err      error
	)

	x := rt.Endpoint.GetExchange(hashname)
	if x == nil {
		return nil, e3x.UnreachableEndpointError(hashname)
	}

	c, err = x.Open("thtp", true)
	if err != nil {
		c.Close()
		return nil, err
	}

	err = rt.writeRequest(req, c)
	if err != nil {
		c.Close()
		return nil, err
	}

	resp, err = rt.readResponse(c)
	if err != nil {
		c.Close()
		return nil, err
	}

	resp.Request = req
	return resp, nil
}
Пример #4
0
func (i hashnameIdentifier) Identify(endpoint *Endpoint) (*Identity, error) {
	x := endpoint.hashnames[hashname.H(i)]
	if x == nil {
		return nil, ErrUnidentifiable
	}

	return x.RemoteIdentity(), nil
}
Пример #5
0
func init() {
	transports.RegisterAddr(&peerAddr{})

	transports.RegisterResolver("peer", func(addr string) (net.Addr, error) {
		hn := hashname.H(addr)
		if !hn.Valid() {
			return nil, transports.ErrInvalidAddr
		}
		return &peerAddr{hn}, nil
	})
}
Пример #6
0
func (a *peerAddr) UnmarshalJSON(p []byte) error {
	var desc struct {
		Type string `json:"type"`
		Hn   string `json:"hn"`
	}
	err := json.Unmarshal(p, &desc)
	if err != nil {
		return err
	}
	a.router = hashname.H(desc.Hn)
	return nil
}
Пример #7
0
func (t *transport) completeVnode(vn *chord.Vnode) *completeVnode {
	if vn == nil {
		return nil
	}

	id := hex.EncodeToString(vn.Id)

	t.mtx.Lock()
	defer t.mtx.Unlock()

	c := &completeVnode{id, t.addressTable[hashname.H(vn.Host)]}
	return c
}
Пример #8
0
func (mod *module) handle_peer(ch *e3x.Channel) {
	defer ch.Kill()

	log := mod.log.From(ch.RemoteHashname()).To(mod.e.LocalHashname())

	// MUST allow router role
	if mod.config.DisableRouter {
		log.Println("drop: router disabled")
		return
	}

	pkt, err := ch.ReadPacket()
	if err != nil {
		log.Printf("drop: failed to read packet: %s", err)
		return
	}

	peerStr, ok := pkt.Header().GetString("peer")
	if !ok {
		log.Printf("drop: no peer in packet")
		return
	}
	peer := hashname.H(peerStr)

	// MUST have link to either endpoint
	if mod.e.GetExchange(ch.RemoteHashname()) == nil && mod.e.GetExchange(peer) == nil {
		log.Printf("drop: no link to either peer")
		return
	}

	// MUST pass firewall
	if mod.config.AllowPeer != nil && !mod.config.AllowPeer(ch.RemoteHashname(), peer) {
		log.Printf("drop: blocked by firewall")
		return
	}

	ex := mod.e.GetExchange(peer)
	if ex == nil {
		log.Printf("drop: no exchange to target")
		// resolve?
		return
	}

	token := cipherset.ExtractToken(pkt.Body(nil))
	if token != cipherset.ZeroToken {
		// add bridge back to requester
		mod.RouteToken(token, ch.Exchange())
	}

	mod.connect(ex, bufpool.New().Set(pkt.Body(nil)))
}
Пример #9
0
// Find a successor
func (t *transport) FindSuccessors(vn *chord.Vnode, n int, k []byte) ([]*chord.Vnode, error) {
	var (
		addr   *e3x.Addr
		ch     *e3x.Channel
		stream io.ReadWriteCloser
		res    []*completeVnode
		err    error

		req = struct {
			Target string
			N      int
			K      []byte
		}{vn.String(), n, k}
	)

	// tracef("FindSuccessors(target:Vnode(%q))", vn.String())

	addr = t.lookupAddr(hashname.H(vn.Host))
	if addr == nil {
		return nil, e3x.ErrNoAddress
	}

	ch, err = t.e.Open(addr, "chord.successors.find", true)
	if err != nil {
		return nil, err
	}

	defer ch.Close()

	// ch.SetReadDeadline(time.Now().Add(30*time.Second))
	// ch.SetWriteDeadline(time.Now().Add(30*time.Second))

	stream = newStream(ch)

	err = json.NewEncoder(stream).Encode(&req)
	if err != nil {
		// tracef("(FindSuccessors) error: %s", err)
		return nil, err
	}

	err = json.NewDecoder(stream).Decode(&res)
	if err != nil {
		// tracef("(FindSuccessors) error: %s", err)
		return nil, err
	}

	return t.internalVnodes(res), nil
}
Пример #10
0
func (t *transport) completeVnodes(vn []*chord.Vnode) []*completeVnode {
	if len(vn) == 0 {
		return nil
	}

	t.mtx.Lock()
	defer t.mtx.Unlock()

	c := make([]*completeVnode, len(vn))
	for i, a := range vn {
		if a != nil {
			b := &completeVnode{hex.EncodeToString(a.Id), t.addressTable[hashname.H(a.Host)]}
			c[i] = b
		}
	}

	return c
}
Пример #11
0
// Notify our successor of ourselves
func (t *transport) Notify(target, self *chord.Vnode) ([]*chord.Vnode, error) {
	var (
		addr   *e3x.Addr
		ch     *e3x.Channel
		stream io.ReadWriteCloser
		res    []*completeVnode
		err    error

		req = struct {
			Target string
			Self   *completeVnode
		}{target.String(), t.completeVnode(self)}
	)

	addr = t.lookupAddr(hashname.H(target.Host))
	if addr == nil {
		return nil, e3x.ErrNoAddress
	}

	ch, err = t.e.Open(addr, "chord.notify", true)
	if err != nil {
		return nil, err
	}

	defer ch.Close()

	// ch.SetReadDeadline(time.Now().Add(30*time.Second))
	// ch.SetWriteDeadline(time.Now().Add(30*time.Second))

	stream = newStream(ch)

	err = json.NewEncoder(stream).Encode(&req)
	if err != nil {
		return nil, err
	}

	err = json.NewDecoder(stream).Decode(&res)
	if err != nil {
		return nil, err
	}

	// tracef("Notify(target:Vnode(%q), self:Vnode(%q)) => []Vnode(%v)", target.String(), self.String(), res)
	return t.internalVnodes(res), nil
}
Пример #12
0
// Request a nodes predecessor
func (t *transport) GetPredecessor(vn *chord.Vnode) (*chord.Vnode, error) {
	var (
		addr *e3x.Addr
		ch   *e3x.Channel
		pkt  *lob.Packet
		res  *completeVnode
		err  error
	)

	addr = t.lookupAddr(hashname.H(vn.Host))
	if addr == nil {
		return nil, e3x.ErrNoAddress
	}

	ch, err = t.e.Open(addr, "chord.predecessor.get", true)
	if err != nil {
		return nil, err
	}

	defer ch.Close()

	// ch.SetReadDeadline(time.Now().Add(30*time.Second))
	// ch.SetWriteDeadline(time.Now().Add(30*time.Second))

	pkt = &lob.Packet{}
	pkt.Header().SetString("vn", vn.String())
	err = ch.WritePacket(pkt)
	if err != nil {
		return nil, err
	}

	err = json.NewDecoder(newStream(ch)).Decode(&res)
	if err != nil {
		return nil, err
	}

	if res != nil {
		// tracef("GetPredecessor(Vnode(%q)) => Vnode(%q)", vn.String(), res.Id)
	}
	return t.internalVnode(res), nil
}
Пример #13
0
// Ping a Vnode, check for liveness
func (t *transport) Ping(vn *chord.Vnode) (bool, error) {
	var (
		addr  *e3x.Addr
		ch    *e3x.Channel
		pkt   *lob.Packet
		alive bool
		err   error
	)

	addr = t.lookupAddr(hashname.H(vn.Host))
	if addr == nil {
		return false, e3x.ErrNoAddress
	}

	ch, err = t.e.Open(addr, "chord.ping", true)
	if err != nil {
		return false, err
	}

	defer ch.Close()

	// ch.SetReadDeadline(time.Now().Add(30*time.Second))
	// ch.SetWriteDeadline(time.Now().Add(30*time.Second))

	pkt = &lob.Packet{}
	pkt.Header().SetString("vn", vn.String())
	err = ch.WritePacket(pkt)
	if err != nil {
		return false, err
	}

	pkt, err = ch.ReadPacket()
	if err != nil {
		return false, err
	}
	alive, _ = pkt.Header().GetBool("alive")
	// tracef("Ping(Vnode(%q)) => %v", vn.String(), alive)
	return alive, nil
}
Пример #14
0
// Instructs a node to skip a given successor. Used to leave.
func (t *transport) SkipSuccessor(target, self *chord.Vnode) error {
	var (
		addr   *e3x.Addr
		ch     *e3x.Channel
		stream io.ReadWriteCloser
		err    error

		req = struct {
			Target string
			Self   *completeVnode
		}{target.String(), t.completeVnode(self)}
	)

	addr = t.lookupAddr(hashname.H(target.Host))
	if addr == nil {
		return e3x.ErrNoAddress
	}

	ch, err = t.e.Open(addr, "chord.successor.skip", true)
	if err != nil {
		return err
	}

	defer ch.Close()

	// ch.SetReadDeadline(time.Now().Add(30*time.Second))
	// ch.SetWriteDeadline(time.Now().Add(30*time.Second))

	stream = newStream(ch)

	err = json.NewEncoder(stream).Encode(&req)
	if err != nil {
		return err
	}

	return nil
}
Пример #15
0
func resolveSRV(uri *URI, proto string) (*e3x.Identity, error) {
	// ignore port
	host, _, _ := net.SplitHostPort(uri.Canonical)
	if host == "" {
		host = uri.Canonical
	}

	// normalize
	if !strings.HasSuffix(host, ".") {
		host += "."
	}

	// ignore .public
	if strings.HasSuffix(host, ".public.") {
		return nil, &net.DNSError{Name: host, Err: "cannot resolve .public hostnames using DNS"}
	}

	// lookup SRV records
	_, srvs, err := net.LookupSRV("mesh", proto, host)
	if err != nil {
		return nil, err
	}
	if len(srvs) > 1 {
		return nil, &net.DNSError{Name: host, Err: "too many SRV records"}
	}
	if len(srvs) == 0 {
		return nil, &net.DNSError{Name: host, Err: "no SRV records"}
	}

	var (
		srv     = srvs[0]
		port    = srv.Port
		portStr = strconv.Itoa(int(port))
		hn      hashname.H
		keys    cipherset.Keys
	)

	{ // detect valid target
		parts := strings.SplitN(srv.Target, ".", 2)
		if len(parts) != 2 || len(parts[0]) != 52 || len(parts[1]) == 0 {
			return nil, &net.DNSError{Name: host, Err: "SRV must target a <hashname>.<domain> domain"}
		}

		hn = hashname.H(parts[0])
		if !hn.Valid() {
			return nil, &net.DNSError{Name: host, Err: "SRV must target a <hashname>.<domain> domain"}
		}
	}

	// detect CNAMEs (they are not allowed)
	cname, err := net.LookupCNAME(srv.Target)
	if err != nil {
		return nil, err
	}
	if cname != "" && cname != srv.Target {
		return nil, &net.DNSError{Name: host, Err: "CNAME record are not allowed"}
	}

	// lookup A AAAA records
	ips, err := net.LookupIP(srv.Target)
	if err != nil {
		return nil, err
	}
	if len(ips) == 0 {
		return nil, &net.DNSError{Name: host, Err: "no A or AAAA records"}
	}

	// lookup TXT
	txts, err := net.LookupTXT(srv.Target)
	if err != nil {
		return nil, err
	}
	if len(txts) == 0 {
		return nil, &net.DNSError{Name: host, Err: "no TXT records"}
	}

	// make addrs
	addrs := make([]net.Addr, 0, len(ips))
	for _, ip := range ips {
		var (
			addr net.Addr
		)

		switch proto {
		case "udp":
			addr, _ = transports.ResolveAddr("udp4", net.JoinHostPort(ip.String(), portStr))
			if addr == nil {
				addr, _ = transports.ResolveAddr("udp6", net.JoinHostPort(ip.String(), portStr))
			}
		case "tcp":
			addr, _ = transports.ResolveAddr("tcp4", net.JoinHostPort(ip.String(), portStr))
			if addr == nil {
				addr, _ = transports.ResolveAddr("tcp6", net.JoinHostPort(ip.String(), portStr))
			}
			// case "http":
			// 	addr, _ = http.NewAddr(ip, port)
		}

		if addr != nil {
			addrs = append(addrs, addr)
		}
	}

	{ // parse keys

		// Sort txts so they form ascending sequences of key parts
		sort.Strings(txts)

		keyData := make(map[uint8]string, 10)
		for len(txts) > 0 {
			var (
				txt   = txts[0]
				parts = strings.Split(txt, "=")
			)

			if len(parts) != 2 {
				txts = txts[1:]
				continue
			}

			var (
				label = parts[0]
				value = parts[1]
				csid  uint8
			)

			if len(label) < 2 {
				txts = txts[1:]
				continue
			}

			// parse the CSID portion of the label
			i, err := strconv.ParseUint(label[:2], 16, 8)
			if err != nil {
				txts = txts[1:]
				continue
			}
			csid = uint8(i)

			// verify the key-part portion of the label
			if len(label) > 2 {
				_, err = strconv.ParseUint(label[2:], 10, 8)
				if err != nil {
					txts = txts[1:]
					continue
				}
			}

			keyData[csid] += value
			txts = txts[1:]
		}

		keys = make(cipherset.Keys, len(keyData))
		for csid, str := range keyData {
			key, err := cipherset.DecodeKey(csid, str, "")
			if err != nil {
				continue
			}

			keys[csid] = key
		}
	}

	ident, err := e3x.NewIdentity(keys, nil, addrs)
	if err != nil {
		return nil, err
	}

	if hn != ident.Hashname() {
		return nil, &net.DNSError{Name: host, Err: "invalid keys"}
	}

	return ident, nil
}