예제 #1
0
파일: client.go 프로젝트: ghmajx/deblocus
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
}
예제 #2
0
파일: d5.go 프로젝트: ghmajx/deblocus
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)
	}
}
예제 #3
0
// 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
}
예제 #4
0
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)
		}
	}
}
예제 #5
0
파일: d5.go 프로젝트: carvenli/deblocus
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)
	}
}
예제 #6
0
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
}
예제 #7
0
파일: d5.go 프로젝트: carvenli/deblocus
//         |------------- 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)
}
예제 #8
0
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
}
예제 #9
0
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
}
예제 #10
0
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)
	}
}
예제 #11
0
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
		}
	}
}
예제 #12
0
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
			}
		}
	}
}
예제 #13
0
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
		}
	}
}
예제 #14
0
파일: client.go 프로젝트: ghmajx/deblocus
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
			}
		}
	}
}
예제 #15
0
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
		}
	}
}