예제 #1
0
func (p *multiplexer) bestSend(data []byte, action_desc string) bool {
	var buf = make([]byte, FRAME_HEADER_LEN+len(data))
	_frame(buf, FRAME_ACTION_TOKENS, 0, data)
	var tun *Conn
	for i := 1; i <= 3; i++ {
		if p.status < 0 /* MUX_CLOSED */ || p.pool == nil {
			if log.V(4) {
				log.Warningln("abandon sending data of", action_desc)
			}
			break
		}
		tun = p.pool.Select()
		if tun != nil {
			if tunWrite1(tun, buf) == nil {
				return true
			}
		} else {
			time.Sleep(time.Millisecond * 200 * time.Duration(i))
		}
	}
	if log.V(3) {
		log.Warningln("failed to send data of", action_desc)
	}
	return false
}
func (c *Client) getToken() []byte {
	c.lock.Lock()
	defer func() {
		c.lock.Unlock()
		tlen := len(c.token) / TKSZ
		if tlen <= TOKENS_FLOOR && atomic.LoadInt32(&c.State) == 0 {
			atomic.AddInt32(&c.State, 1)
			if log.V(4) {
				log.Infof("Request new tokens, pool=%d\n", tlen)
			}
			c.sigTun.postCommand(TOKEN_REQUEST, nil)
		}
	}()
	for len(c.token) < TKSZ {
		log.Warningln("waiting for token. May be the requests are coming too fast.")
		c.waitTK.Wait()
		if atomic.LoadInt32(&c.State) < 0 {
			panic("Abandon the request beacause the tunSession was lost.")
		}
	}
	token := c.token[:TKSZ]
	c.token = c.token[TKSZ:]

	return token
}
func (t *Server) TunnelServe(conn *net.TCPConn) {
	fconn := NewConnWithHash(conn)
	defer func() {
		fconn.FreeHash()
		ex.CatchException(recover())
	}()
	nego := &d5SNegotiation{Server: t}
	session, err := nego.negotiate(fconn)
	if session != nil {
		// unique
		fconn.identifier = fmt.Sprintf("%s@%s", session.uid, fconn.RemoteAddr())
	}
	if err != nil {
		if err == DATATUN_SESSION { // dataTunnel
			go session.DataTunServe(fconn.Conn, nego.tokenBuf)
		} else {
			log.Warningln("Close abnormal connection from", conn.RemoteAddr(), err)
			SafeClose(conn)
			if session != nil {
				t.sessionMgr.clearTokens(session)
			}
		}
	} else if session != nil { // signalTunnel
		atomic.AddInt32(&t.stCnt, 1)
		log.Infof("Client(%s)-ST is established\n", fconn.identifier)
		var st = NewSignalTunnel(session.tun, 0)
		session.svr = t
		session.sigTun = st
		go st.start(session.eventHandler)
	}
}
func (c *Client) ClientServe(conn net.Conn) {
	var done bool
	defer func() {
		ex.CatchException(recover())
		if !done {
			SafeClose(conn)
		}
	}()

	pbConn := NewPushbackInputStream(conn)
	switch detectProtocol(pbConn) {
	case REQ_PROT_SOCKS5:
		s5 := S5Step1{conn: pbConn}
		s5.Handshake()
		if !s5.HandshakeAck() {
			literalTarget := s5.parseSocks5Request()
			if !s5.respondSocks5() {
				c.mux.HandleRequest("SOCKS5", conn, literalTarget)
				done = true
			}
		}
	case REQ_PROT_HTTP:
		prot, literalTarget := httpProxyHandshake(pbConn)
		if prot == REQ_PROT_HTTP { // plain http
			c.mux.HandleRequest("HTTP", pbConn, literalTarget)
		} else { // http tunnel
			c.mux.HandleRequest("HTTP/T", conn, literalTarget)
		}
		done = true
	default:
		log.Warningln("unrecognized request from", conn.RemoteAddr())
		time.Sleep(REST_INTERVAL)
	}

}
func (nego *d5SNegotiation) transSession(conn *hashedConn, buf []byte) (session *Session, err error) {
	token := buf[:TKSZ]
	if ss := nego.sessionMgr.take(token); ss != nil {
		nego.tokenBuf = buf
		return ss, DATATUN_SESSION
	}
	log.Warningln("Incorrect token from", conn.RemoteAddr())
	return nil, VALIDATION_FAILED
}
예제 #6
0
파일: d5.go 프로젝트: hangim/deblocus
func (nego *d5SNegotiation) dataSession(hConn *hashedConn, buf []byte) (session *Session, err error) {
	token := buf[:TKSZ]
	if session := nego.sessionMgr.take(token); session != nil {
		session.identifyConn(hConn.Conn)
		nego.tokenBuf = buf
		return session, DATATUN_SESSION
	}
	log.Warningln("Incorrect token from", hConn.RemoteAddr())
	return nil, VALIDATION_FAILED
}
func (t *signalTunnel) imAlive() {
	if log.V(4) {
		log.Infoln("Ping/responded to", t.remoteAddr)
	}
	t.active(-1) // up tempo for become a sender
	_, err := t.postCommand(CTL_PONG, nil)
	if err != nil {
		SafeClose(t.tun)
		log.Warningln("Reply ping failed and then closed", t.remoteAddr, err)
	}
}
func (t *signalTunnel) areYouAlive() {
	if log.V(4) {
		log.Infoln("Ping/launched to", t.remoteAddr)
	}
	_, err := t.postCommand(CTL_PING, nil)
	// Either waiting pong timeout or send ping failed
	if err != nil {
		SafeClose(t.tun)
		log.Warningln("Ping remote failed and then closed", t.remoteAddr, err)
	} else {
		t.tun.SetReadDeadline(time.Now().Add(GENERAL_SO_TIMEOUT * 2))
		// impossible call by timer, will reset by acknowledged or read timeout.
		t.active(-1)
	}
}
func (s *S5Step1) Handshake() {
	var buf = make([]byte, 2)
	_, err := io.ReadFull(s.conn, buf)
	if err != nil {
		s.err = INVALID_SOCKS5_HEADER.Apply(err)
		return
	}
	ver, nmethods := buf[0], int(buf[1])
	if ver != SOCKS5_VER || nmethods < 1 {
		s.err = INVALID_SOCKS5_HEADER.Apply(fmt.Sprintf("[% x]", buf[:2]))
		return
	}
	buf = make([]byte, nmethods+1) // consider method non-00
	n, err := io.ReadAtLeast(s.conn, buf, nmethods)
	if err != nil || n != nmethods {
		s.err = INVALID_SOCKS5_HEADER
		log.Warningln("invalid socks5 header:", hex.EncodeToString(buf))
	}
}
예제 #10
0
파일: server.go 프로젝트: hangim/deblocus
func (t *Server) TunnelServe(conn *net.TCPConn) {
	fconn := NewConnWithHash(conn)
	defer func() {
		fconn.FreeHash()
		ex.CatchException(recover())
	}()
	nego := &d5SNegotiation{Server: t}
	session, err := nego.negotiate(fconn)

	if err == nil || err == DATATUN_SESSION { // dataTunnel
		go session.DataTunServe(fconn.Conn, nego.tokenBuf)
	} else {
		log.Warningln("Close abnormal connection from", conn.RemoteAddr(), err)
		SafeClose(conn)
		if session != nil {
			t.sessionMgr.clearTokens(session)
		}
	}
}
func (t *signalTunnel) start(handler event_handler) {
	defer func() {
		ex.CatchException(recover())
		if t.lived != nil {
			// must clear timer
			t.lived.Stop()
		}
		if handler != nil {
			handler(evt_st_closed, true)
		}
	}()
	buf := make([]byte, CMD_HEADER_LEN)
	for {
		n, err := t.tun.Read(buf)
		if err != nil {
			log.Warningln("Exiting signalTunnel caused by", err)
			break
		}
		if n == CMD_HEADER_LEN {
			cmd := buf[0]
			argslen := binary.BigEndian.Uint16(buf[2:])
			if argslen > 0 {
				argsbuf := make([]byte, argslen)
				n, err = t.tun.Read(argsbuf)
				handler(evt_st_msg, cmd, argsbuf)
			} else {
				switch cmd {
				case CTL_PING: // reply
					go t.imAlive()
				case CTL_PONG: // aware of living
					go t.acknowledged()
				default:
					handler(evt_st_msg, cmd)
				}
			}
		} else {
			log.Errorln("Abnormal command", buf, err)
			continue
		}
	}
}
func CatchException(e interface{}) bool {
	if ex, y := e.(*Exception); y && ex.warning {
		log.Errorln(ex.msg)
		return true
	} else if e != nil {
		if DEBUG {
			buf := make([]byte, 1600)
			runtime.Stack(buf, false)
			fmt.Println(e)
			fmt.Println(string(buf))
		} else {
			if s, y := e.(string); y {
				log.Warningln(s)
			} else {
				log.Errorln(e)
			}
		}
		return true
	}
	return false
}
예제 #13
0
파일: client.go 프로젝트: hangim/deblocus
func (c *Client) getToken() []byte {
	c.lock.Lock()
	defer c.lock.Unlock()

	var tlen = len(c.token) / TKSZ
	if tlen <= TOKENS_FLOOR {
		c.requireTokens()
	}
	for len(c.token) < TKSZ {
		log.Warningln("waiting for token. May be the requests are coming too fast.")
		if !c.pendingTK.acquire(RETRY_INTERVAL * 2) { // discarded request
			panic("Aborted")
		}
		if atomic.LoadInt32(&c.State) < CLT_WORKING {
			panic("Abandon the request by shutdown.")
		}
	}
	var token = c.token[:TKSZ]
	c.token = c.token[TKSZ:]
	return token
}
예제 #14
0
// TODO notify peer to slow down when queue increased too fast
func (p *multiplexer) Listen(tun *Conn, handler event_handler, interval int) {
	tun.priority = &TSPriority{0, 1e9}
	p.pool.Push(tun)
	defer p.onTunDisconnected(tun, handler)
	tun.SetSockOpt(1, 0, 1)
	var (
		header = make([]byte, FRAME_HEADER_LEN)
		router = p.router
		idle   = NewIdler(interval, p.isClient)
		nr     int
		er     error
		frm    *frame
		key    string
	)
	if !p.isClient {
		// first ping frame will let client to be aware of using a valid token.
		idle.ping(tun)
	}
	for {
		idle.newRound(tun)
		nr, er = io.ReadFull(tun, header)
		if nr == FRAME_HEADER_LEN {
			frm = _parseFrameHeader(header)
			if frm.length > 0 {
				nr, er = io.ReadFull(tun, frm.data)
			}
		}
		if er != nil {
			switch idle.consumeError(er) {
			case ERR_NEW_PING:
				if idle.ping(tun) == nil {
					continue
				}
			case ERR_PING_TIMEOUT:
				if log.V(2) {
					log.Warningln("Peer was unresponsive then close", tun.identifier)
				}
			default:
				if log.V(2) {
					log.Warningln("Read tunnel", tun.identifier, er)
				}
			}
			return // error, abandon tunnel
		}
		key = sessionKey(tun, frm.sid)

		switch frm.action {
		case FRAME_ACTION_CLOSE_W:
			if edge, _ := router.getRegistered(key); edge != nil {
				edge.closed |= TCP_CLOSE_W
				edge.deliver(frm)
			}
		case FRAME_ACTION_CLOSE_R:
			if edge, _ := router.getRegistered(key); edge != nil {
				edge.closed |= TCP_CLOSE_R
				closeR(edge.conn)
			}
		case FRAME_ACTION_DATA:
			edge, pre := router.getRegistered(key)
			if edge != nil {
				edge.deliver(frm)
			} else if pre {
				router.preDeliver(key, frm)
			} else {
				if log.V(2) {
					log.Warningln("peer send data to an unexisted socket.", key, frm)
				}
				// trigger sending close to notice peer.
				_frame(header, FRAME_ACTION_CLOSE_R, frm.sid, nil)
				if tunWrite1(tun, header) != nil {
					return
				}
			}
		case FRAME_ACTION_OPEN:
			router.preRegister(key)
			go p.connectToDest(frm, key, tun)
		case FRAME_ACTION_OPEN_N, FRAME_ACTION_OPEN_Y:
			edge, _ := router.getRegistered(key)
			if edge != nil {
				if log.V(4) {
					if frm.action == FRAME_ACTION_OPEN_Y {
						log.Infoln(p.role, "recv OPEN_Y", frm)
					} else {
						log.Infoln(p.role, "recv OPEN_N", frm)
					}
				}
				edge.ready <- frm.action
				close(edge.ready)
			} else {
				if log.V(2) {
					log.Warningln("peer send OPENx to an unexisted socket.", key, frm)
				}
			}
		case FRAME_ACTION_PING:
			if idle.pong(tun) == nil {
				atomic.AddInt32(&p.pingCnt, 1)
			} else { // reply pong failed
				return
			}
		case FRAME_ACTION_PONG:
			if !idle.verify() {
				log.Warningln("Incorrect action_pong received")
			}
		case FRAME_ACTION_TOKENS:
			handler(evt_tokens, frm.data)
		default:
			log.Errorln(p.role, "Unrecognized", frm)
		}
		tun.Update()
	}
}
// TODO notify peer to slow down when queue increased too fast
func (p *multiplexer) Listen(tun *Conn, handler event_handler, interval int) {
	if p.isClient {
		tun.priority = &TSPriority{0, 1e9}
		p.pool.Push(tun)
	}
	defer p.onTunDisconnected(tun, handler)
	tun.SetSockOpt(1, 1, 0)
	var (
		header     = make([]byte, FRAME_HEADER_LEN)
		router     = p.router
		idle       = NewIdler(interval, p.isClient)
		lastActive = time.Now().Unix()
		nr         int
		er         error
		now        int64
		frm        *frame
		key        string
	)
	for {
		idle.newRound(tun)
		nr, er = io.ReadFull(tun, header)
		if nr == FRAME_HEADER_LEN {
			frm = _parseFrameHeader(header)
			if frm.length > 0 {
				nr, er = io.ReadFull(tun, frm.data)
			}
		}
		if er != nil {
			switch idle.consumeError(er) {
			case ERR_NEW_PING:
				if idle.ping(tun) == nil {
					continue
				}
			case ERR_PING_TIMEOUT:
				log.Errorln("Peer was unresponsive then close", tun.identifier)
			default:
				log.Errorln("Read tunnel", tun.identifier, er)
			}
			return // error, abandon tunnel
		}
		key = sessionKey(tun, frm.sid)

		switch frm.action {
		case FRAME_ACTION_CLOSE_W:
			if edge := router.getRegistered(key); edge != nil {
				edge.closed |= TCP_CLOSE_W
				edge.deliver(frm)
			}
		case FRAME_ACTION_CLOSE_R:
			if edge := router.getRegistered(key); edge != nil {
				edge.closed |= TCP_CLOSE_R
				closeR(edge.conn)
			}
		case FRAME_ACTION_DATA:
			edge := router.getRegistered(key)
			if edge == nil {
				if log.V(2) {
					log.Warningln("peer send data to an unexisted socket.", key, frm)
				}
				// trigger sending close to notice peer.
				_frame(header, FRAME_ACTION_CLOSE_R, frm.sid, nil)
				if tunWrite1(tun, header) != nil {
					return
				}
			} else {
				edge.deliver(frm)
			}
		case FRAME_ACTION_OPEN:
			go p.connectToDest(frm, key, tun)
		case FRAME_ACTION_OPEN_N, FRAME_ACTION_OPEN_Y:
			edge := router.getRegistered(key)
			if edge == nil {
				if log.V(2) {
					log.Warningln("peer send OPENx to an unexisted socket.", key, frm)
				}
			} else {
				if log.V(4) {
					if frm.action == FRAME_ACTION_OPEN_Y {
						log.Infoln(p.mode, "recv OPEN_Y", frm)
					} else {
						log.Infoln(p.mode, "recv OPEN_N", frm)
					}
				}
				edge.ready <- frm.action
				close(edge.ready)
			}
		case FRAME_ACTION_PING:
			if idle.pong(tun) != nil {
				return
			}
		case FRAME_ACTION_PONG:
			if !idle.verify() {
				log.Warningln("Incorrect action_pong received")
			}
		default:
			log.Errorln(p.mode, "Unrecognized", frm)
		}

		// prevent frequently calling, especially in high-speed transmitting.
		if now = time.Now().Unix(); (now-lastActive) > 2 && handler != nil {
			lastActive = now
			handler(evt_st_active, now)
		}
		if p.isClient {
			tun.Update()
		}
	}
}