// |------------- tun params ------------| // | len~2 | version~4 | interval~2 | reserved~? | tokens~20N ; hash~20 func (nego *d5SNegotiation) respondTestWithToken(sconn *hashedConn, session *Session) (err error) { var headLen = TUN_PARAMS_LEN + 2 // 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(CTL_PING_INTERVAL)) 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) 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) return INCONSISTENT_HASH } _, err = sconn.Write(rHash) ThrowErr(err) return }
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 (s *S5Step1) HandshakeAck() bool { msg := []byte{5, 0} if s.err != nil { // handshake error feedback log.Errorln(s.err) if ex, y := s.err.(*exception.Exception); y { msg[1] = byte(ex.Code()) } else { msg[1] = 0xff } s.conn.Write(msg) s.conn.Close() return true } // accept _, err := s.conn.Write(msg) if err != nil { log.Errorln(err) s.conn.Close() return true } return false }
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 (nego *d5CNegotiation) validateAndGetTokens(sconn *hashedConn, t *tunParams) (err error) { 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 { return INCOMPATIBLE_VERSION.Apply(oVerStr) } } ofs := 4 t.stInterval = int(binary.BigEndian.Uint16(buf[ofs:])) 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(2) { n := len(buf) - TUN_PARAMS_LEN log.Infof("Got tokens length=%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) return INCONSISTENT_HASH } return }
// 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() } } }