func (c *Client) initialNegotiation() (tun *Conn) { var newParams = new(tunParams) var err error tun, err = c.nego.negotiate(newParams) if err != nil { if log.V(1) == true || DEBUG { log.Errorf("Connection failed %s, Error: %s. Retry after %s", c.nego.RemoteName(), err, RETRY_INTERVAL) } else { log.Errorf("Connection failed %s. Retry after %s", c.nego.RemoteName(), RETRY_INTERVAL) } if strings.Contains(err.Error(), "closed") { log.Warningln(string(bytes.Repeat([]byte{'+'}, 30))) log.Warningln("Maybe your clock is inaccurate, or your client credential is invalid.") log.Warningln(string(bytes.Repeat([]byte{'+'}, 30))) os.Exit(2) } return nil } c.params = newParams c.token = newParams.token tun.identifier = c.nego.RemoteName() log.Infof("Login to the gateway %s successfully", tun.identifier) return }
func verifyHash(hConn *hashedConn, isServ bool) { hashBuf := make([]byte, hConn.hashSize*2) rHash, wHash := hConn.HashSum() var err error if !isServ { // client send hash at first copy(hashBuf[:hConn.hashSize], rHash) copy(hashBuf[hConn.hashSize:], wHash) setWTimeout(hConn) _, err = hConn.Write(hashBuf) ThrowErr(err) } setRTimeout(hConn) _, err = io.ReadFull(hConn, hashBuf) ThrowErr(err) rHashp, wHashp := hashBuf[:hConn.hashSize], hashBuf[hConn.hashSize:] if !bytes.Equal(rHash, wHashp) || !bytes.Equal(wHash, rHashp) { log.Errorln("My hash is inconsistent with peer") if DEBUG { log.Errorf(" My Hash r:[% x] w:[% x]", rHash, wHash) log.Errorf("Peer Hash r:[% x] w:[% x]", rHashp, wHashp) } ThrowErr(INCONSISTENT_HASH) } if isServ { // server reply hash copy(hashBuf[:hConn.hashSize], rHash) copy(hashBuf[hConn.hashSize:], wHash) setWTimeout(hConn) _, err = hConn.Write(hashBuf) ThrowErr(err) } }
// return header=1 + TKSZ*many func (s *SessionMgr) createTokens(session *Session, many int) []byte { s.lock.Lock() defer s.lock.Unlock() var ( tokens = make([]byte, 1+many*TKSZ) i64buf = make([]byte, 8) _tokens = tokens[1:] sha = sha1.New() ) rand.Seed(time.Now().UnixNano()) sha.Write([]byte(session.uid)) for i := 0; i < many; i++ { binary.BigEndian.PutUint64(i64buf, uint64(rand.Int63())) sha.Write(i64buf) binary.BigEndian.PutUint64(i64buf, uint64(time.Now().UnixNano())) sha.Write(i64buf) pos := i * TKSZ sha.Sum(_tokens[pos:pos]) token := _tokens[pos : pos+TKSZ] key := fmt.Sprintf("%x", token) if _, y := s.container[key]; y { i-- continue } s.container[key] = session session.tokens[key] = true } if log.V(4) { log.Errorf("sessionMap created=%d len=%d\n", many, len(s.container)) } return tokens }
func (p *multiplexer) connectToDest(frm *frame, key string, tun *Conn) { defer func() { ex.CatchException(recover()) }() var ( dstConn net.Conn err error target = string(frm.data) ) dstConn, err = net.DialTimeout("tcp", target, GENERAL_SO_TIMEOUT) frm.length = 0 if err != nil { p.router.removePreRegistered(key) log.Errorf("Cannot connect to [%s] for %s error: %s\n", target, key, err) frm.action = FRAME_ACTION_OPEN_N tunWrite2(tun, frm) } else { if log.V(1) { log.Infoln("OPEN", target, "for", key) } dstConn.SetReadDeadline(ZERO_TIME) edge := p.router.register(key, target, tun, dstConn, false) // write edge frm.action = FRAME_ACTION_OPEN_Y if tunWrite2(tun, frm) == nil { p.relay(edge, tun, frm.sid) // read edge } else { // send open_y failed SafeClose(tun) } } }
func (nego *d5CNegotiation) validateAndGetTokens(sconn *hashedConn, t *tunParams) { buf, err := ReadFullByLen(2, sconn) ThrowErr(err) tVer := VERSION oVer := binary.BigEndian.Uint32(buf) if oVer > tVer { oVerStr := fmt.Sprintf("%d.%d.%04d", oVer>>24, (oVer>>16)&0xFF, oVer&0xFFFF) tVer >>= 16 oVer >>= 16 if tVer == oVer { log.Warningf("Caution !!! Please upgrade to new version, remote is v%s\n", oVerStr) } else { err = INCOMPATIBLE_VERSION.Apply(oVerStr) } ThrowErr(err) } ofs := 4 ofs += 2 t.dtInterval = int(binary.BigEndian.Uint16(buf[ofs:])) ofs += 2 t.tunQty = int(buf[ofs]) t.token = buf[TUN_PARAMS_LEN:] if log.V(3) { n := len(buf) - TUN_PARAMS_LEN log.Infof("Received tokens count=%d\n", n/TKSZ) } rHash := sconn.RHashSum() wHash := sconn.WHashSum() _, err = sconn.Write(rHash) ThrowErr(err) oHash := make([]byte, TKSZ) _, err = sconn.Read(oHash) if !bytes.Equal(wHash, oHash) { log.Errorln("Server hash/r is inconsistence with the client/w") log.Errorf("rHash: [% x] wHash: [% x]\n", rHash, wHash) log.Errorf("oHash: [% x]\n", oHash) ThrowErr(INCONSISTENT_HASH) } }
func (c *Client) initialNegotiation() (tun *Conn) { var tp = new(tunParams) var err error tun, err = c.nego.negotiate(tp) if err != nil { log.Errorf("Failed to connect %s, Retry after %s\n", c.nego.RemoteName(), RETRY_INTERVAL) return nil } c.token, c.tp = tp.token, tp tp.token = nil tun.identifier = c.nego.RemoteName() log.Infoln("Login to the gateway", c.nego.RemoteName(), "successfully") return tun }
// |------------- tun params ------------| // | len~2 | version~4 | interval~2 | reserved~? | tokens~20N ; hash~20 func (nego *d5SNegotiation) respondTestWithToken(sconn *hashedConn, session *Session) { var ( headLen = TUN_PARAMS_LEN + 2 err error ) // tun params tpBuf := randArray(headLen, headLen) binary.BigEndian.PutUint16(tpBuf, uint16(TUN_PARAMS_LEN+GENERATE_TOKEN_NUM*TKSZ)) ofs := 2 copy(tpBuf[ofs:], ito4b(VERSION)) ofs += 4 binary.BigEndian.PutUint16(tpBuf[ofs:], uint16(0)) ofs += 2 binary.BigEndian.PutUint16(tpBuf[ofs:], uint16(DT_PING_INTERVAL)) ofs += 2 tpBuf[ofs] = PARALLEL_TUN_QTY _, err = sconn.Write(tpBuf) ThrowErr(err) tokens := nego.sessionMgr.createTokens(session, GENERATE_TOKEN_NUM) _, err = sconn.Write(tokens[1:]) ThrowErr(err) rHash := sconn.RHashSum() wHash := sconn.WHashSum() oHash := make([]byte, TKSZ) _, err = sconn.Read(oHash) ThrowErr(err) if !bytes.Equal(wHash, oHash) { log.Errorln("Remote hash/r not equals self/w") log.Errorf("rHash: [% x] wHash: [% x]\n", rHash, wHash) log.Errorf("oHash: [% x]\n", oHash) panic(INCONSISTENT_HASH) } _, err = sconn.Write(rHash) ThrowErr(err) }
func (m *clientMgr) selectClient() *t.Client { if m.num > 1 { i := rand.Intn(m.num<<4) >> 4 for _, v := range m.indexChain[i : i+m.num-1] { if w := m.clients[v]; w != nil && atomic.LoadInt32(&w.State) >= 0 { return w } } } else { if w := m.clients[0]; w != nil && atomic.LoadInt32(&w.State) >= 0 { return w } } log.Errorf("No available tunnels for servicing new request") time.Sleep(t.REST_INTERVAL) return nil }
func (c *Client) initialNegotiation() (tun *Conn) { var tp = new(tunParams) var err error tun, err = c.nego.negotiate(tp) if err != nil { log.Errorf("Failed to connect %s, Retry after %s\n", c.nego.RemoteName(), RETRY_INTERVAL) if strings.Contains(err.Error(), "closed") { log.Warningln("Maybe your clock is inaccurate, or your client credential is invalid.") os.Exit(2) } return nil } c.token, c.tp = tp.token, tp tp.token = nil tun.identifier = c.nego.RemoteName() log.Infoln("Login to the gateway", c.nego.RemoteName(), "successfully") return tun }
func (context *bootContext) startClient() { defer func() { ex.CatchException(advice(recover())) sigChan <- t.Bye }() conf, err := t.Parse_d5c_file(context.config) if err != nil { log.Fatalln(advice(err)) } context.setLogVerbose(conf.Verbose) log.Infoln(versionString()) log.Infoln("Socks5/Http is working at", conf.ListenAddr) ln, err := net.ListenTCP("tcp", conf.ListenAddr) if err != nil { log.Fatalln(err) } defer ln.Close() dhKey, _ := c.NewDHKey(DH_METHOD) client := t.NewClient(conf, dhKey) context.components = append(context.components, client) context.closeable = append(context.closeable, ln) go client.StartTun(true) for { conn, err := ln.Accept() if err == nil { if client.IsReady() { go client.ClientServe(conn) continue } else { log.Errorf("No available tunnels for servicing new request") time.Sleep(time.Second) } } t.SafeClose(conn) } }
func (p *multiplexer) relay(edge *edgeConn, tun *Conn, sid uint16) { var ( buf = bytePool.Get(FRAME_MAX_LEN) code byte src = edge.conn ) defer func() { // positively close then notify peer if edge.bitwiseCompareAndSet(TCP_CLOSE_R) && code != FRAME_ACTION_OPEN_DENIED { pack(buf, FRAME_ACTION_CLOSE_W, sid, nil) go func() { // tell peer to closeW frameWriteBuffer(tun, buf[:FRAME_HEADER_LEN]) bytePool.Put(buf) }() } else { bytePool.Put(buf) } if code == FRAME_ACTION_OPEN_Y { closeR(src) } else { // remote open failed SafeClose(src) if log.V(1) { switch code { case FRAME_ACTION_OPEN_N: log.Infof("Remote open %s failed", edge.dest) case FRAME_ACTION_OPEN_DENIED: log.Infof("Request %s was denied by remote", edge.dest) } } } }() if edge.positive { // for client _len := pack(buf, FRAME_ACTION_OPEN, sid, []byte(edge.dest[2:])) // dest with a leading mark if frameWriteBuffer(tun, buf[:_len]) != nil { SafeClose(tun) return } } var ( tn int // total nr int er error _fast_open = p.isClient ) for { if _fast_open { // In fastOpening, the timeout will give rise to recheck fastopen state src.SetReadDeadline(time.Now().Add(READ_TMO_IN_FASTOPEN)) received := false select { case code = <-edge.ready: received = true default: } if received { if code == FRAME_ACTION_OPEN_Y { _fast_open = false // fastopen finished } else { return } } else { // ready-chan was not ready if tn >= FAST_OPEN_BUF_MAX_SIZE { // must waiting for signal select { case code = <-edge.ready: case <-time.After(WAITING_OPEN_TIMEOUT): log.Errorf("waiting open-signal sid=%d timeout for %s\n", sid, edge.dest) } // timeout or open-signal received if code == FRAME_ACTION_OPEN_Y { _fast_open = false // fastopen finished } else { return } } } // Received signal-y then finish fastopen if !_fast_open { // read forever src.SetReadDeadline(ZERO_TIME) } } nr, er = src.Read(buf[FRAME_HEADER_LEN:]) if nr > 0 { tn += nr pack(buf, FRAME_ACTION_DATA, sid, uint16(nr)) if frameWriteBuffer(tun, buf[:nr+FRAME_HEADER_LEN]) != nil { SafeClose(tun) return } } // timeout to recheck open signal if er != nil && !(_fast_open && IsTimeout(er)) { if er != io.EOF && DEBUG { log.Infof("read to the end of edge total=%d err=(%v)", tn, er) } return } } }
func (c *Client) StartTun(mustRestart bool) { var ( wait bool tun *Conn rn = atomic.LoadInt32(&c.round) ) for { if wait { time.Sleep(RETRY_INTERVAL) } if rn < atomic.LoadInt32(&c.round) { return } if mustRestart { mustRestart = false if atomic.SwapInt32(&c.State, CLT_PENDING) >= CLT_WORKING { tun, rn = c.restart() if tun == nil { return } } else { return } } if atomic.LoadInt32(&c.State) == CLT_WORKING { // negotiation conn executed here firstly will not be null // otherwise must be null then create new one. if tun == nil { var err error tun, err = c.createDataTun() if err != nil { if DEBUG { ex.CatchException(err) } log.Errorf("Failed to connect %s. Reconnect after %s\n", err, RETRY_INTERVAL) wait = true continue } } if log.V(1) { log.Infof("Tun=%s is established\n", tun.sign()) } atomic.AddInt32(&c.dtCnt, 1) c.mux.Listen(tun, c.eventHandler, c.tp.pingInterval) dtcnt := atomic.AddInt32(&c.dtCnt, -1) log.Errorf("Tun=%s was disconnected, Reconnect after %s\n", tun.sign(), RETRY_INTERVAL) if atomic.LoadInt32(&c.mux.pingCnt) <= 0 { // dirty tokens: used abandoned tokens c.clearTokens() } if dtcnt <= 0 { // restart: all connections were disconnected log.Errorf("Connections %s were lost\n", tun.identifier) go c.StartTun(true) return } else { // reconnect // waiting and don't use old tun wait = true tun = nil } } else { // can't create tun and waiting for release if !c.pendingConn.acquire(RETRY_INTERVAL) { return } } } }
func (p *multiplexer) relay(edge *edgeConn, tun *Conn, sid uint16) { var ( buf = make([]byte, FRAME_MAX_LEN) code byte src = edge.conn ) defer func() { // positively close then notify peer if edge.bitwiseCompareAndSet(TCP_CLOSE_R) && code != FRAME_ACTION_OPEN_DENIED { _frame(buf, FRAME_ACTION_CLOSE_W, sid, nil) go tunWrite1(tun, buf[:FRAME_HEADER_LEN]) // tell peer to closeW } if code == FRAME_ACTION_OPEN_Y { closeR(src) } else { // remote open failed SafeClose(src) if log.V(1) { switch code { case FRAME_ACTION_OPEN_N: log.Infof("Remote open %s failed", edge.dest) case FRAME_ACTION_OPEN_DENIED: log.Infof("Request %s was denied by remote", edge.dest) } } } }() if edge.positive { // for client _len := _frame(buf, FRAME_ACTION_OPEN, sid, []byte(edge.dest)) if tunWrite1(tun, buf[:_len]) != nil { SafeClose(tun) return } } var ( tn int // total nr int er error _fast_open = /* FAST_OPEN && */ p.isClient ) for { if _fast_open { src.SetReadDeadline(time.Now().Add(READ_TMO_IN_FASTOPEN)) v, y := reflect.ValueOf(edge.ready).TryRecv() if y { code = v.Interface().(byte) if code == FRAME_ACTION_OPEN_Y { _fast_open = false // fastopen finished } else { return } } else { // ready-chan was not ready if tn >= FAST_OPEN_BUF_MAX_SIZE { // must waiting for signal select { case code = <-edge.ready: case <-time.After(WAITING_OPEN_TIMEOUT): log.Errorf("waiting open-signal sid=%d timeout for %s\n", sid, edge.dest) } // timeout or open-signal received if code == FRAME_ACTION_OPEN_Y { _fast_open = false // fastopen finished } else { return } } } if !_fast_open { // fastopen finished // read forever src.SetReadDeadline(ZERO_TIME) } } nr, er = src.Read(buf[FRAME_HEADER_LEN:]) if nr > 0 { tn += nr _frame(buf, FRAME_ACTION_DATA, sid, uint16(nr)) if tunWrite1(tun, buf[:nr+FRAME_HEADER_LEN]) != nil { SafeClose(tun) return } } // timeout to recheck open signal if er != nil && !(_fast_open && IsTimeout(er)) { return } } }
func (c *Client) StartTun(mustRestart bool) { var ( wait bool tun *Conn rn = atomic.LoadInt32(&c.round) ) for { if wait { time.Sleep(RETRY_INTERVAL) } if rn < atomic.LoadInt32(&c.round) { return } if mustRestart { // clear mustRestart mustRestart = false // prevent concurrently if atomic.CompareAndSwapInt32(&c.state, CLT_WORKING, CLT_PENDING) { tun, rn = c.restart() } else { return } } if atomic.LoadInt32(&c.state) == CLT_WORKING { // negotiation conn executed here firstly will not be null // otherwise must be null then create new one. if tun == nil { var err error tun, err = c.createDataTun() if err != nil { if log.V(1) == true || DEBUG { log.Errorf("Connection failed %s, Error: %s. Reconnect after %s", c.nego.RemoteName(), err, RETRY_INTERVAL) } else { log.Errorf("Connection failed %s. Reconnect after %s", c.nego.RemoteName(), RETRY_INTERVAL) } wait = true continue } } if log.V(1) { log.Infof("Tun %s is established\n", tun.sign()) } cnt := atomic.AddInt32(&c.dtCnt, 1) c.mux.Listen(tun, c.eventHandler, c.params.pingInterval+int(cnt)) dtcnt := atomic.AddInt32(&c.dtCnt, -1) log.Errorf("Tun %s was disconnected, Reconnect after %s\n", tun.sign(), RETRY_INTERVAL) tun.cipher.Cleanup() if atomic.LoadInt32(&c.mux.pingCnt) <= 0 { // dirty tokens: used abandoned tokens c.clearTokens() } if dtcnt <= 0 { // restart: all connections were disconnected log.Errorf("Connections %s were lost\n", tun.identifier) go c.StartTun(true) return } else { // reconnect // don't use old tun wait, tun = true, nil } } else { // can't create tun and waiting for release if !c.pendingConn.acquire(RETRY_INTERVAL) { return } } } }
func (p *multiplexer) relay(edge *edgeConn, tun *Conn, sid uint16) { var ( buf = make([]byte, FRAME_MAX_LEN) code byte src = edge.conn ) defer func() { if edge.bitwiseCompareAndSet(TCP_CLOSE_R) { // only positively _frame(buf, FRAME_ACTION_CLOSE_W, sid, nil) tunWrite1(tun, buf[:FRAME_HEADER_LEN]) // tell peer to closeW } if code == FRAME_ACTION_OPEN_Y { closeR(src) } else { // remote open failed SafeClose(src) } }() if edge.positive { // for client _len := _frame(buf, FRAME_ACTION_OPEN, sid, []byte(edge.dest)) if tunWrite1(tun, buf[:_len]) != nil { SafeClose(tun) return } } var ( tn int // total nr int er error _fast_open = /* FAST_OPEN && */ p.isClient ) for { if _fast_open { v, y := reflect.ValueOf(edge.ready).TryRecv() if y { code = v.Interface().(byte) switch code { case FRAME_ACTION_OPEN_Y: _fast_open = false // read forever case FRAME_ACTION_OPEN_N: return } } else { if tn >= FAST_OPEN_BUF_MAX_SIZE { // must waiting for signal select { case code = <-edge.ready: case <-time.After(WAITING_OPEN_TIMEOUT): log.Errorf("waiting open-signal sid=%d timeout for %s\n", sid, edge.dest) } // timeout or open-signal received if code == FRAME_ACTION_OPEN_Y { _fast_open = false // read forever } else { return } } // else could read again } } nr, er = src.Read(buf[FRAME_HEADER_LEN:]) if nr > 0 { tn += nr _frame(buf, FRAME_ACTION_DATA, sid, uint16(nr)) if tunWrite1(tun, buf[:nr+FRAME_HEADER_LEN]) != nil { SafeClose(tun) return } } if er != nil { return } } }