// applyDeltaOnce pushes one piece of info into the network func (srv *Server) applyDeltaOnce(key ChordKey, meta Neighbor) { kilog.Debug("directory: beginning push to %x", key.ToBytes()) rawsok, err := kiricom.EasyDial(fmt.Sprintf("%v:%v", meta.Address, meta.Port), nil, meta.Secret) if err != nil { kilog.Debug("directory: push to %x failed due to %v", key.ToBytes(), err.Error()) return } defer rawsok.Close() sok, err := kiss.KiSSAnonHandshake(kiss.NewDirectVerifier(meta.PubKey), rawsok) if err != nil { kilog.Debug("directory: push to %x failed in KiSS due to %v", key.ToBytes(), err.Error()) return } defer sok.Close() srv.Lock() neighs, err := srv.crd.Neighs(key) if err != nil { panic("WTF is going on here") } srv.Unlock() var msg textprot.NeighInfo // expires 1hr from now msg.Json.Expires = int(time.Now().Add(time.Hour).Unix()) msg.Json.IssuedTo = meta.PubKey for _, nay := range neighs { msg.Json.NeighList = append(msg.Json.NeighList, nay.ToBytes()) } msg.Signat = srv.prv.Sign(msg.Json.HashValue()) // send the message req := textprot.TextReq{ Verb: "NEIGH_PUSH", Blob: msg.ToString(), } err = req.WriteTo(sok) if err != nil { kilog.Debug("directory: push to %x failed while pushing due to %v", key.ToBytes(), err.Error()) return } //fmt.Println(msg.ToString()) // get msg back err = req.ReadFrom(sok) if err != nil { kilog.Debug("directory: push to %x failed at the final stage", key.ToBytes()) return } kilog.Debug("directory: push to %x succeeded", key.ToBytes()) }
// NewClient creates a client from the given first-node information. func NewClient(first directory.Neighbor) (toret *Client, err error) { // kissless kiricom sok, err := kiricom.EasyDial( fmt.Sprintf("%v:%v", first.Address, first.Port), nil, first.Secret) if err != nil { return } // negotiate KiSS secsok, err := kiss.KiSSAnonHandshake(kiss.NewDirectVerifier(first.PubKey), sok) if err != nil { return } // return the client toret = &Client{ sok: secsok, pklst: []natrium.EdDSAPublic{first.PubKey}, } return }
// ConnectNext connects to the next hop, identified by public key func (clnt *Client) ConnectNext(nxpub natrium.EdDSAPublic) error { req := textprot.TextReq{ Verb: "NEIGH_CONNECT", Args: []string{hex.EncodeToString(nxpub)}, } _, err := clnt.execCmd(req) if err != nil { return err } // now negotiate KiSS newsok, err := kiss.KiSSAnonHandshake(kiss.NewDirectVerifier(nxpub), clnt.sok) if err != nil { clnt.sok.Close() return ErrBadSocket } clnt.sok = newsok clnt.pklst = append(clnt.pklst, nxpub) clnt.circlen++ return nil }
// EasyDial dials to a target address (in `host:port` form) using Kiricom over hlObfs. // `secret` may be specified, or it may be nil, in which case the default secret is implied. // // When `verify` is nil, KiSS is not used at all. func EasyDial(targetAddr string, verify kiss.Verifier, secret []byte) (io.ReadWriteCloser, error) { dialState.Lock() res, ok := dialState.table[targetAddr] if !ok { raw, err := net.Dial("tcp", targetAddr) if err != nil { dialState.Unlock() return nil, err } raw.(*net.TCPConn).SetNoDelay(true) sec, err := kiss.LLObfsClientHandshake(secret, raw) if err != nil { dialState.Unlock() return nil, err } if verify != nil { sec, err = kiss.KiSSAnonHandshake(verify, sec) if err != nil { dialState.Unlock() return nil, err } } state := NewClientCtx(32768, sec) dialState.table[targetAddr] = state dialState.Unlock() return state.Dial() } dialState.Unlock() toret, err := res.Dial() if err != nil { kilog.Debug("kiricom: EasyDial error: %v", err.Error()) dialState.Lock() delete(dialState.table, targetAddr) dialState.Unlock() return nil, err } return toret, nil }
// connect to the service identified by the public key func dialPubKey(pub natrium.EdDSAPublic) (io.ReadWriteCloser, error) { kilog.Debug("circ: beginning to dial %v", pub) var key directory.ChordKey key.FromBytes(pub) circPool.Lock() if len(circPool.neighs) == 0 { circPool.Unlock() return nil, ErrNoRoute } once, ok := circPool.onceTab[key] if !ok { kilog.Debug("circ: %v is a new destination, will have to build a fresh one", pub) once = new(sync.Once) circPool.onceTab[key] = once } circPool.Unlock() once.Do(func() { kilog.Debug("circ: entered atomic action for %v", pub) defer kilog.Debug("circ: leaving atomic action for %v", pub) thing, err := newCircGroup(pub) if err != nil { kilog.Debug("circ: rolling back %v due to %v", pub, err.Error()) circPool.Lock() delete(circPool.onceTab, key) circPool.Unlock() return } circPool.Lock() circPool.dialTab[key] = thing circPool.Unlock() }) circPool.Lock() thing, ok := circPool.dialTab[key] circPool.Unlock() if !ok { return nil, ErrNoRoute } raah, err := thing.Dial() if err != nil { thing.Destroy() circPool.Lock() if circPool.onceTab[key] != nil { delete(circPool.onceTab, key) } if circPool.dialTab[key] != nil { delete(circPool.dialTab, key) } circPool.Unlock() return nil, err } toret, err := kiss.KiSSAnonHandshake(kiss.NewDirectVerifier(pub), raah) if err != nil { thing.Destroy() circPool.Lock() if circPool.onceTab[key] != nil { delete(circPool.onceTab, key) } if circPool.dialTab[key] != nil { delete(circPool.dialTab, key) } circPool.Unlock() return nil, err } return toret, nil }