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 }
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)) } }
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 }
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 }
// 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() } } }