func (cc *ClientCtx) thrMain() { defer cc.Close() // thrMain only handles incoming segments for { select { case <-cc.cmn.deadch: return case seg := <-cc.cmn.dnch: switch seg.Flag { case kcOPEN: kilog.Warning("kiricom: severe protocol violation: kcOPEN on client") return case kcDATA: fallthrough case kcCLOS: cc.tablock.Lock() tgt, ok := cc.conntab[seg.ConnID] cc.tablock.Unlock() if !ok { kilog.FineDebug("kiricom: %v to invalid connid", seg) continue } select { case tgt.inbox <- seg: default: kilog.Warning("kiricom: severe protocol violation: overfull flow control buffer") return } if seg.Flag == kcCLOS { cc.tablock.Lock() delete(cc.conntab, seg.ConnID) cc.tablock.Unlock() } case kcMORE: cc.tablock.Lock() tgt, ok := cc.conntab[seg.ConnID] cc.tablock.Unlock() if !ok { kilog.FineDebug("kiricom: %v to invalid connid", seg) continue } select { case tgt.morech <- true: kilog.FineDebug("kiricom: sent MORE to connid %v", tgt.connid) default: kilog.Warning("kiricom: severe protocol violation: duplicate MORE") return } } } } }
func run_monitor_loop() { onionstew.DownloadIncrement = incr_down_bytes onionstew.DownloadOverheadIncrement = incr_down_overhead_bytes onionstew.UploadIncrement = incr_up_bytes onionstew.UploadOverheadIncrement = incr_up_overhead_bytes listener, err := net.Listen("tcp", "127.0.0.1:9221") if err != nil { panic(err.Error()) } for { client, err := listener.Accept() if err != nil { kilog.Warning(err.Error()) continue } func() { defer client.Close() for { thing := <-global_monitor_chan _, err := client.Write(thing) if err != nil { return } } }() } }
func (sg *servGroup) connAmb(i int) (*kiricom.ServerCtx, error) { nonce := make([]byte, 8) binary.BigEndian.PutUint64(nonce, uint64(i)) hash := natrium.SecureHash(sg.aidee.PublicKey(), nonce) kilog.Debug("serv: building circuit %v -> %x for %v", i, hash, sg.aidee.PublicKey()) var tgt directory.ChordKey tgt.FromBytes(hash) // build circuit to each and every one of them thingy, err := buildCirc(tgt) if err != nil { //thingy.Destroy() return nil, err } haha, err := thingy.RegAmbassador(sg.aidee.PublicKey()) if err != nil { thingy.Destroy() if err == core2core.ErrRejectedReq { kilog.Warning("serv: circuit number %v for %v rejected", i, sg.aidee.PublicKey()) return nil, err } else { return nil, err } } return haha, nil }
func tcpLoop() { listener, err := net.ListenTCP("tcp", transThis) if err != nil { kilog.Critical("%v", err.Error()) os.Exit(-1) } for { clnt, err := listener.AcceptTCP() if err != nil { kilog.Critical("%v", err.Error()) os.Exit(-1) } go func() { defer clnt.Close() defer clnt.CloseRead() defer clnt.CloseWrite() lol, err := clnt.File() if err != nil { panic(err.Error()) } haha := C.getdestaddr_iptables(C.int(lol.Fd())) lol.Close() sdf := make([]byte, 4) binary.LittleEndian.PutUint32(sdf, uint32(haha.sin_addr.s_addr)) port := binary.BigEndian.Uint16((*[2]byte)(unsafe.Pointer(&haha.sin_port))[:]) rmAddr := &net.TCPAddr{sdf, int(port), ""} dnsLock.Lock() rmName, ok := ipToName[rmAddr.IP.String()] dnsLock.Unlock() var rmConn io.ReadWriteCloser // see if we should connect IP or name if !ok { kilog.Warning("unmapped IP received (%v), misconfig?", rmAddr) rmConn, err = socksConnectIP(socksNext, rmAddr) } else { kilog.Debug("mapped IP received (%v -> %v)", rmAddr, rmName) rmConn, err = socksConnectName(socksNext, rmName, rmAddr.Port) } if err != nil { kilog.Debug("%v", err) return } defer rmConn.Close() go func() { defer rmConn.Close() defer clnt.Close() defer clnt.CloseRead() defer clnt.CloseWrite() io.Copy(rmConn, clnt) }() io.Copy(clnt, rmConn) kilog.Debug("closing client") }() } }
func (dpv dftProv) getSock(clnt Client) io.ReadWriteCloser { sock, err := net.Dial("tcp", dpv.url) if err != nil { kilog.Warning("directory: default provider failed: %v", err.Error()) return nil } /*obsok, err := kiss.LLObfsClientHandshake(dpv.PublicKey(), sock) if err != nil { kilog.Warning("directory: default provider failed: %v", err.Error()) sock.Close() return nil }*/ secsok, err := kiss.KiSSNamedHandshake(clnt.private, kiss.NewDirectVerifier(dpv.PublicKey()), sock) if err != nil { kilog.Warning("directory: default provider failed: %v", err.Error()) sock.Close() return nil } return secsok }
func runCore(id directory.Client) { state := core2core.NewNodeState(dirProvider, id) addr := id.GetAddress() srv, err := kiricom.EasyListen(fmt.Sprintf("0.0.0.0:%v", addr.Port), nil, id.GetSecret()) if err != nil { panic(err.Error()) } err = dirProvider.JoinCore(id) if err != nil { panic(err.Error()) } go func() { for { time.Sleep(time.Minute * 5) err = dirProvider.JoinCore(id) if err != nil { kilog.Warning("core: error while joining %v", err.Error()) } } }() fmt.Println(id.GetAddress()) kilog.Info("started core service on %v", addr) for { client, err := srv.Accept() if err != nil { panic(err.Error()) } kilog.Debug("core: accepted a client") go func() { err := state.HandleClient(client) if err != nil { kilog.Warning("core: error %v", err) } }() } }
func getNeighs(id directory.Client) { var neighs []directory.Neighbor for len(neighs) == 0 { var err error neighs, err = dirProvider.JoinEdge(id) if err != nil { kilog.Warning("failure in getNeighs(): %v", err) time.Sleep(time.Second) continue } fmt.Println(neighs) } circPool.Lock() defer circPool.Unlock() circPool.neighs = neighs }
func (sg *servGroup) revAmbass(num int) { retry: noo, err := sg.connAmb(num) if err != nil { kilog.Warning("serv: ambassador %v of %v has problems resurrecting: %v", num, sg.aidee.PublicKey(), err.Error()) getNeighs(dirClient) if err != core2core.ErrRejectedReq { time.Sleep(time.Second) goto retry } sg.ambass[num] = nil } else { sg.ambass[num] = noo go sg.runAmbass(num, noo) } }
func (cg *circGroup) Dial() (io.ReadWriteCloser, error) { req := make(chan io.ReadWriteCloser) select { case <-cg.dedchan: return nil, ErrDeadCG case cg.inchan <- req: select { case wire := <-req: if wire == nil { return nil, ErrDeadCG } else { return wire, nil } case <-cg.dedchan: return nil, ErrDeadCG } case <-time.After(time.Second * 5): kilog.Warning("circ: bad circuit group") cg.Destroy() return nil, ErrDeadCG } }
func run_diagnostic_loop() { listener, err := net.Listen("tcp", "127.0.0.1:9222") if err != nil { panic(err) } for { nconn, err := listener.Accept() if err != nil { kilog.Warning("Problem while accepting stacktrace diag socket: %s", err.Error()) continue } go func() { defer nconn.Close() for { str := <-kilog.FineChannel _, err := nconn.Write([]byte(fmt.Sprintf("%s\n", str))) if err != nil { return } } }() } }
func handleSocks(clnt io.ReadWriteCloser) { defer clnt.Close() defer kilog.Debug("exited handleSocks") destin, err := socks5.ReadRequest(clnt) if err != nil { kilog.Warning("problem while reading SOCKS5 request: %v", err.Error()) return } kilog.Debug("SOCKS beginning to handle %v", destin) if !sagiriNames.CheckEdgeID(destin) { kilog.Warning("invalid name (%v) sent to SOCKS subsystem, misconfig?", destin) // 0x08, address type not supported socks5.CompleteRequest(0x08, clnt) return } parsed := sagiriNames.ParseEdgeID(destin) if parsed.IPAddress == nil { /*kilog.Warning("SOCKS only supports direct connections currently, refusing!") // 0x08, address type not supported socks5.CompleteRequest(0x08, clnt) return*/ remote, err := dialPubKey(parsed.PubKey) if err != nil { kilog.Debug("SOCKS failed to connect to remote anon host (%v)", err) return } defer remote.Close() err = socks5.CompleteRequest(0x00, clnt) if err != nil { kilog.Debug("SOCKS failed to send back response (%v)", err) return } // forward between local and remote go func() { defer clnt.Close() defer remote.Close() io.Copy(remote, clnt) }() io.Copy(clnt, remote) } else { kiriaddr := fmt.Sprintf("%v:%v", parsed.IPAddress, parsed.PortNum) secret := parsed.PubKey // verifier function verifier := func(other natrium.EdDSAPublic) bool { return subtle.ConstantTimeCompare(other, parsed.PubKey) == 1 } remote, err := kiricom.EasyDial(kiriaddr, verifier, secret) if err != nil { kilog.Debug("SOCKS failed to connect to remote host (%v)", err) // 0x04, host unreachable socks5.CompleteRequest(0x04, clnt) return } kilog.Debug("SOCKS succesfully connected to %v:%v on ICOM", parsed.IPAddress, parsed.PortNum) defer remote.Close() err = socks5.CompleteRequest(0x00, clnt) if err != nil { kilog.Debug("SOCKS failed to send back response (%v)", err) return } kilog.Debug("SOCKS successfully sent back response") // forward between local and remote go func() { defer clnt.Close() defer remote.Close() io.Copy(remote, clnt) }() io.Copy(clnt, remote) } }
func (sc *ServerCtx) thrMain() { defer sc.Close() for { var seg kcSegment select { case seg = <-sc.cmn.dnch: switch seg.Flag { case kcOPEN: // conn open request _, exists := sc.cltab[seg.ConnID] if exists { kilog.Warning("kiricom: severe protocol violation: OPEN for already open connection") return } // isn't a protocol violation, continue normally sok := newKcPayload(sc.limit, sc.cmn.upch) sc.cltab[seg.ConnID] = sok sok.connid = seg.ConnID select { case sc.clch <- sok: kilog.Debug("kiricom: accepted connid %v", seg.ConnID) go func() { // death coupler select { case <-sok.deadch: case <-sc.cmn.deadch: sok.destroy("global death") } }() default: kilog.Warning("kiricom: accept queue overfull, rejecting connection") reset := seg reset.Flag = kcCLOS go func() { // in new thread to avoid blocking up the queue select { case sc.cmn.upch <- reset: case <-sc.cmn.deadch: } }() } case kcDATA: fallthrough case kcCLOS: tgt, ok := sc.cltab[seg.ConnID] if !ok { kilog.Debug("kiricom: %v to invalid connid", seg) continue } select { case tgt.inbox <- seg: default: kilog.Warning("kiricom: severe protocol violation: overfull flow control buffer") return } if seg.Flag == kcCLOS { delete(sc.cltab, seg.ConnID) } case kcMORE: tgt, ok := sc.cltab[seg.ConnID] if !ok { kilog.Debug("kiricom: %v to invalid connid", seg) continue } select { case tgt.morech <- true: kilog.Debug("kiricom: sent MORE to connid %v", tgt.connid) default: kilog.Warning("kiricom: severe protocol violation: duplicate MORE") return } } case <-sc.cmn.deadch: return } } }
func (srv *Server) rqDispatch(sock io.ReadWriteCloser, request clntRequest) { kilog.Debug("directory: incoming client with %v", request.Code) var err error switch request.Code { case "CORE": // We simply queue up a monitor if this is the first time. err = struc.Pack(sock, &srvInitResp{"OKAY"}) if err != nil { kilog.Debug("directory: could not send OKAY to client") return } var ck ChordKey ck.FromBytes(request.PubKey) srv.Lock() defer srv.Unlock() _, ok := srv.key2meta[ck] if !ok { srv.key2meta[ck] = Neighbor{ Address: request.Address, Port: request.Port, Secret: request.Secret, PubKey: request.PubKey, } kilog.Debug("directory: incoming %v", request) go srv.monCore(ck) } // otherwise we have nothing to do case "EDGE": // Now we use a certain terrible hack. // We add the client to the chord, get its neighs, then remove it. srv.Lock() var ck ChordKey var neighs []ChordKey ck.FromBytes(request.PubKey) // actually an edge if !srv.crd.cache[ck] { _, err := srv.crd.Join(ck) if err != nil { kilog.Debug("directory: error while joining chord: %v", err.Error()) srv.Unlock() goto BADF } neighs, err = srv.crd.Neighs(ck) if err != nil { panic(err.Error()) } srv.crd.Leave(ck) } else { // actually already in cord neighs, err = srv.crd.Neighs(ck) if err != nil { panic(err.Error()) } } srv.Unlock() // neighs now has the neighbors err = struc.Pack(sock, &srvInitResp{"OKAY"}) if err != nil { kilog.Debug("directory: could not send OKAY to client") return } realNeighs := make([]Neighbor, len(neighs)) srv.Lock() for i, v := range neighs { lol, ok := srv.key2meta[v] realNeighs[i] = lol if !ok { kilog.Warning("directory: invalid neighbor sent: %x -> %v", ck.ToBytes(), i) } } srv.Unlock() err = struc.Pack(sock, &srvEdgeResp{0, realNeighs}) } /*BADP: err = struc.Pack(sock, &srvInitResp{"BADP"}) if err != nil { kilog.Debug("directory: could not send BADP to client") } return*/ BADF: err = struc.Pack(sock, &srvInitResp{"BADF"}) if err != nil { kilog.Debug("directory: could not send BADF to client") } return /*ACDN: err = struc.Pack(sock, &srvInitResp{"ACDN"}) if err != nil { kilog.Debug("directory: could not send ACDN to client") } return*/ }
func newServGroup(aidee natrium.EdDSAPrivate) (*servGroup, error) { ambass := make([]*kiricom.ServerCtx, 8) toret := new(servGroup) toret.ambass = ambass toret.deadch = make(chan bool) toret.wirech = make(chan io.ReadWriteCloser) toret.once = new(sync.Once) toret.aidee = aidee // contact all the ambassadors for i := 0; i < 8; i++ { haha, err := toret.connAmb(i) if err != nil && err != core2core.ErrRejectedReq { for j := 0; j < i; j++ { if ambass[j] != nil { ambass[j].Close() } } return nil, err } ambass[i] = haha } kilog.Debug("serv: all ambassadors of %v notified", aidee.PublicKey()) // spin off a thread to update ambassadors from time to time go func() { for { time.Sleep(time.Minute * 20) FAST: time.Sleep(time.Second) allbad := true for _, v := range ambass { if v != nil { allbad = false break } } if allbad { kilog.Warning("serv: ambassadors ALL BAD!") for i := 0; i < 8; i++ { toret.revAmbass(i) } continue } // pick a random ambassador, kill, and resurrect // TODO do something more graceful here num := rand.Int() % len(ambass) kilog.Debug("serv: ambassador %v of %v condemned", num, aidee.PublicKey()) condemned := ambass[num] if condemned != nil { kilog.Debug("serv: actually executed condemnation") condemned.Close() } else { goto FAST } } }() // spin up threads to handle incoming connections for i, lol := range ambass { lol := lol i := i if lol != nil { go toret.runAmbass(i, lol) } } // return return toret, nil }
func (ctx *sc_ctx) AttachSC(wire io.ReadWriteCloser, serverside bool) { kilog.Debug("AttachSC(%v)", serverside) ctx.lock.Lock() ctx.refcount++ ctx.lock.Unlock() defer func() { ctx.lock.Lock() ctx.refcount-- ctx.lock.Unlock() }() local_stop := make(chan bool) // Signal once for close, synchronous local_close := make(chan bool) // Close to remove this sc from the premises, cleanly ctx.close_ch_ch <- local_close // Read from the other side go func() { id := rand.Int() for { newpkt, err := read_sc_message(wire) if err != nil { kilog.Warning("AttachSC encountered unexpected error %s on %x while READING, DESTROYING STEW", err.Error(), id) ctx.destroy() wire.Close() return } // Check for the dead seqnum if newpkt.seqnum == 0xFFFFFFFFFFFFFFFF { kilog.Debug("Close message received from remote in AttachSC on %x, signalling...", id) if serverside { local_stop <- true kilog.Debug("Close signal successful, sending bakk and returning from %x.", id) clmsg := sc_message{0xFFFFFFFFFFFFFFFF, []byte("")} write_sc_message(clmsg, wire) time.Sleep(time.Second * 10) wire.Close() } else { wire.Close() } return } // Check for ignorable message if newpkt.seqnum == 0xFFFFFFFFFFFFFFFE { DownloadOverheadIncrement(len(newpkt.payload)) continue } select { case ctx.unordered_ch <- newpkt: DownloadIncrement(len(newpkt.payload)) case <-ctx.killswitch: kilog.Debug("Great, we got a KILLSWITCH instead of being able to put into unordered, fml") wire.Close() return } } }() // Write to the other side for { select { case newthing := <-ctx.write_ch: err := write_sc_message(newthing, wire) if err != nil { kilog.Warning("AttachSC encountered unexpected error %s while WRITING, DESTROYING STEW", err.Error()) ctx.destroy() // Will die on next iteration } UploadIncrement(len(newthing.payload)) case <-local_stop: return case <-local_close: kilog.Debug("AttachSC receiving LOCAL_CLOSE, stopping flow & sending remote") clmsg := sc_message{0xFFFFFFFFFFFFFFFF, []byte("")} write_sc_message(clmsg, wire) return case <-ctx.killswitch: kilog.Debug("AttachSC receiving KILLSWITCH, destroying wire") wire.Close() return } } }
func main() { rand.Seed(time.Now().UnixNano()) go run_monitor_loop() flag.Parse() if *confloc == "" { kilog.Warning("No configuration file given, using defaults") } else { err := gcfg.ReadFileInto(&MasterConfig, *confloc) if err != nil { kilog.Warning("Configuration file broken, using defaults") } } if *singhop { MasterConfig.Network.MinCircuitLen = 1 } kilog.Info("Kirisurf %s started! mkh=%s", version, MasterKeyHash) set_gui_progress(0.1) kilog.Info("Bootstrapping 10%%: finding directory address...") dirclient.DIRADDR, _ = dirclient.FindDirectoryURL() set_gui_progress(0.2) kilog.Info("Bootstrapping 20%%: found directory address, refreshing directory...") err := dirclient.RefreshDirectory() if err != nil { kilog.Critical("Stuck at 20%%: directory connection error %s", err.Error()) for { time.Sleep(time.Second) } } set_gui_progress(0.3) kilog.Info("Bootstrapping 30%%: directory refreshed, beginning to build circuits...") go run_diagnostic_loop() dirclient.RefreshDirectory() if MasterConfig.General.Role == "server" { NewSCServer(MasterConfig.General.ORAddr) addr := RegisterNGSCServer(MasterConfig.General.ORAddr) prt, _ := strconv.Atoi( strings.Split(MasterConfig.General.ORAddr, ":")[1]) go func() { err := UPnPForwardAddr(MasterConfig.General.ORAddr) err = UPnPForwardAddr(addr) if err != nil { kilog.Warning("UPnP failed: %s", err) if MasterConfig.Network.OverrideUPnP { go dirclient.RunRelay(prt, MasterKeyHash, MasterConfig.General.IsExit) } return } kilog.Info("UPnP successfully forwarded port") go dirclient.RunRelay(prt, MasterKeyHash, MasterConfig.General.IsExit) }() kilog.Info("Started server!") if *noclient { for { time.Sleep(time.Second) } } } run_client_loop() kilog.Info("Kirisurf exited") }
func buildCirc(tgt directory.ChordKey) (*core2core.Client, error) { // find the closest neighbor to the destination circPool.Lock() nxt := circPool.neighs[0] for _, v := range circPool.neighs[1:] { var vkee directory.ChordKey var xkee directory.ChordKey vkee.FromBytes(v.PubKey) xkee.FromBytes(nxt.PubKey) if vkee.Distance(tgt).Cmp(xkee.Distance(tgt)) == -1 { nxt = v } } circPool.Unlock() kilog.Debug("circ: closest neighbor to %x is %v", tgt.ToBytes(), nxt.PubKey) // begin to route spider, err := core2core.NewClient(nxt) if err != nil { return nil, err } //defer spider.Destroy() // loop closest := false for !closest { neighs, err := spider.ListNeighs() if err != nil { spider.Destroy() return nil, err } if len(neighs) == 0 { kilog.Warning("circ: topology anomaly! node with no neighbors!") spider.Destroy() return nil, err } better := spider.CurrentPublic() closest = true // can we find a closer one? for _, cand := range neighs { var candkee directory.ChordKey var currkee directory.ChordKey candkee.FromBytes(cand) currkee.FromBytes(better) if candkee.Distance(tgt).Cmp(currkee.Distance(tgt)) == -1 { better = cand closest = false } } // connect to the next hop if !closest { kilog.Debug("circ: circuit to %x extending to %v", tgt.ToBytes(), better) err = spider.ConnectNext(better) if err != nil { spider.Destroy() return nil, err } } } return spider, nil }
func RunManagedStewServer() string { listener, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { panic(err.Error()) } // Keep trakk of shteewz type stid struct { top uint64 bot uint64 } stew_table := make(map[stid]*stew_ctx) var stew_table_lk sync.Mutex kilog.Debug("before gc goroutine") // Garbage collect stew table every 30 seconds go func() { for { time.Sleep(time.Second * 30) stew_table_lk.Lock() for stid, ctx := range stew_table { ctx.llctx.lock.Lock() cnt := ctx.llctx.refcount ctx.llctx.lock.Unlock() if cnt == 0 { ctx.destroy() stid := stid go func() { stew_table_lk.Lock() kilog.Debug("Collecting %d:%d...", stid.top, stid.bot) delete(stew_table, stid) stew_table_lk.Unlock() }() } } stew_table_lk.Unlock() } }() kilog.Debug("before main goroutine") go func() { for { thing, err := listener.Accept() if err != nil { continue } go func() { // Obtain the stew id idbuf := make([]byte, 16) _, err := io.ReadFull(thing, idbuf) if err != nil { thing.Close() kilog.Warning("Client didn't send the entire stew ID before dying") return } kilog.Debug("Obtained new SC on server with id=%x", idbuf) top := binary.BigEndian.Uint64(idbuf[0:8]) bot := binary.BigEndian.Uint64(idbuf[8:16]) id := stid{top, bot} stew_table_lk.Lock() if stew_table[id] == nil { stew_table[id] = make_stew_ctx() go stew_table[id].run_stew(true) } xaxa := stew_table[id] stew_table_lk.Unlock() xaxa.llctx.AttachSC(thing, true) }() } }() kilog.Debug("before return") return listener.Addr().String() }
func findPath(directory []KNode, minlen int, condition func(KNode) bool) []KNode { if minlen > len(directory) { minlen = len(directory) } kilog.Debug("Building a circuit with minimum length %d", minlen) rand256 := func() int { buf := make([]byte, 1) rand.Read(buf) return int(buf[0]) } if len(directory) < minlen { minlen = len(directory) if minlen == 0 { kilog.Warning("No nodes online, cannot build any circuit!!!!") return nil } } toret := make([]KNode, 0) // Find an entry point var entry KNode for { idx := rand256() % len(directory) thing := directory[idx] if thing.Address != "(hidden)" && rand256()%10 < 1 { entry = thing break } } // Push the entry onto the slice toret = append(toret, entry) //history := make(map[int]bool) endptr := 0 for { adj := toret[endptr].Adjacents // If already at the end, return if endptr+1 >= minlen && condition(toret[endptr]) { // We want to almost always prune away paths that are ludicrously long, // but we can use them if no other choice if endptr-minlen < 3 && endptr/minlen <= 2 || rand256() < 3 { return toret } else { return findPath(directory, minlen, condition) } } // Otherwise chug along xaxa: idx := rand256() % len(adj) next := directory[adj[idx]] // We cannot allow loops in the path, unless we have to for _, ele := range toret { if ele.PublicKey == next.PublicKey && rand256() < 250 { goto xaxa } } toret = append(toret, next) endptr++ // Absolutely ridiculous paths if len(toret) > 1000 { kilog.Warning("Didn't find a valid path at all!") return nil } } panic("Shouldn't get here") }
func RunMultiplexServer(transport io.ReadWriteCloser) { ctx := make_icom_ctx(transport, true, false, 128) for { thing, err := ctx.our_srv.Accept() if err != nil { return } go func() { defer thing.Close() init_done := make(chan bool) go func() { select { case <-init_done: kilog.Debug("ICOM: Initialization done") return case <-time.After(time.Second * 10): kilog.Warning("ICOM: ** Client still no request after 10 secs **") } }() lenbts := make([]byte, 2) _, err := io.ReadFull(thing, lenbts) if err != nil { kilog.Debug("** Reading destination length failed! **") return } addr := make([]byte, int(lenbts[0])+int(lenbts[1])*256) _, err = io.ReadFull(thing, addr) if err != nil { kilog.Debug("** Reading destination failed! **") return } init_done <- true if addr[0] == 't' { addr = addr[1:] } else { kilog.Warning("UDP support not implemented yet!") thing.Write([]byte("NOIM")) return } remote, err := net.DialTimeout("tcp", string(addr), time.Second*20) if err != nil { kilog.Debug("Connection to %s failed: %s", addr, err.Error()) e := err.(net.Error) if e.Timeout() { thing.Write([]byte("TMOT")) } else { thing.Write([]byte("FAIL")) } return } defer remote.Close() rlrem := remote go func() { defer rlrem.Close() io.Copy(rlrem, thing) }() kilog.Debug("Opened connection to %s", addr) thing.Write([]byte("OKAY")) io.Copy(thing, rlrem) }() } }
func run_client_loop() { listener, err := net.Listen("tcp", MasterConfig.General.SocksAddr) if err != nil { panic(err) } circ_ch <- produce_circ() set_gui_progress(1.0) kilog.Info("Bootstrapping 100%%: client started!") go func() { var haha sync.WaitGroup haha.Add(5) for i := 0; i < 5; i++ { go func() { circ_ch <- produce_circ() haha.Done() }() } haha.Wait() }() for { nconn, err := listener.Accept() if err != nil { kilog.Warning("Problem while accepting client socket: %s", err.Error()) continue } go func() { defer func() { nconn.Close() }() addr, err := socks5.ReadRequest(nconn) if err != nil { kilog.Warning("Problem while reading SOCKS5 request") return } kilog.Debug("Attempting connection to %s...", addr) retry: newcirc := <-circ_ch remote, err := newcirc.SocksAccept(nconn) if err != nil { dirclient.RefreshDirectory() circ_ch <- produce_circ() goto retry } circ_ch <- newcirc defer remote.Close() lenbts := []byte{byte((len(addr) + 1) % 256), byte((len(addr) + 1) / 256)} _, err = remote.Write(lenbts) _, err = remote.Write([]byte(fmt.Sprintf("t%s", addr))) if err != nil { kilog.Debug("Failed to send tunnelling request to %s!", addr) socks5.CompleteRequest(0x03, nconn) return } kilog.Debug("Sent tunneling request") code := make([]byte, 4) _, err = io.ReadFull(remote, code) if err != nil { kilog.Debug("Failed to read response for %s! (%s)", addr, err) socks5.CompleteRequest(0x03, nconn) return } switch string(code) { case "OKAY": kilog.Debug("Successfully tunneled %s!", addr) socks5.CompleteRequest(0x00, nconn) go func() { defer remote.Close() io.Copy(remote, nconn) }() io.Copy(nconn, remote) case "TMOT": kilog.Debug("Tunnel to %s timed out!", addr) socks5.CompleteRequest(0x06, nconn) case "NOIM": kilog.Debug("Tunnel type for %s isn't implemented by server!", addr) socks5.CompleteRequest(0x07, nconn) case "FAIL": kilog.Debug("Tunnel to %s cannot be established!", addr) socks5.CompleteRequest(0x04, nconn) default: kilog.Debug("Protocol error on tunnel to %s! (%s)", addr, string(code)) socks5.CompleteRequest(0x01, nconn) return } }() } }
func newCircGroup(dest natrium.EdDSAPublic) (*circGroup, error) { // 8 targets in total targets := make([]directory.ChordKey, 8) for i := 0; i < 8; i++ { nonce := make([]byte, 8) binary.BigEndian.PutUint64(nonce, uint64(i)) hash := natrium.SecureHash(dest, nonce) targets[i].FromBytes(hash) } toret := new(circGroup) toret.inchan = make(chan chan io.ReadWriteCloser) toret.dedchan = make(chan bool) okaych := make(chan bool, 10) // spin off goroutines for i, tgt := range targets { tgt := tgt i := i kilog.Debug("circ: building circuit %v -> %x for %v", i, tgt.ToBytes(), dest) go func() { goto SKIP // error DIE_IN_DISGRACE: kilog.Warning("circ: circuit action %v for %v (%x) is aborted!", i, dest, tgt.ToBytes()) // TODO don't die when just one circuit dies //toret.Destroy() return SKIP: spider, err := buildCirc(tgt) if err != nil { toret.Destroy() goto DIE_IN_DISGRACE } kilog.Debug("circ: circuit to the closest node to %x (%v) established", tgt.ToBytes(), spider.CurrentPublic()) kilog.Debug("circ: patching through ambassador %v to %v...", i, dest) thing, err := spider.ConnAmbassador(dest) if err != nil { spider.Destroy() goto DIE_IN_DISGRACE } kilog.Debug("circ: patched through ambassador to %v! circuit length %v", dest, spider.CircLength()) defer thing.Close() /*if spider.CircLength() < 1 { kilog.Debug("circ: aborting %v due to bad length", i) return }*/ okaych <- true for { select { case req := <-toret.inchan: kilog.Debug("circ: request to %v routed through %v", dest, i) wire, err := thing.Dial() if err != nil { kilog.Warning("circ: request to %v through %v encountered unusable dialer!", dest, i) go func() { select { case toret.inchan <- req: case <-time.After(time.Second * 2): close(req) } }() return } go func() { select { case req <- wire: case <-toret.dedchan: kilog.Debug("circ: circuit %v for %v closing down safely", i, dest) } }() case <-toret.dedchan: kilog.Debug("circ: circuit %v for %v closing down safely", i, dest) return } } }() } select { case <-okaych: case <-time.After(time.Second * 20): kilog.Warning("circ: nothing happened in 20 seconds for %v, dying", dest) toret.Destroy() return nil, io.ErrNoProgress } // return return toret, nil }