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) } }
func CatchException(e interface{}) bool { if e != nil { if s, y := e.(string); y { log.Warningln(s) } else if ex, y := e.(*Exception); y && ex.warning { log.Errorln(ex.msg) return true } else { log.Errorln(e) } if DEBUG || bool(log.V(3)) { buf := make([]byte, 1600) n := runtime.Stack(buf, false) log.DirectPrintln(string(buf[:n])) } return true } return false }
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 (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) } }
// |------------- 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) }
// 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) idle = NewIdler(interval, p.isClient) router = p.router nr int er error frm *frame key string ) if !p.isClient { // server first ping client // make client 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, er = parse_frame(header) if er == nil && len(frm.data) > 0 { // read All and discard tail random nr, er = io.ReadFull(tun, frm.data) frm.data = frm.data[:frm.length] } } if er != nil { // shutdown if atomic.LoadInt32(&p.status) < 0 { time.Sleep(time.Second) return } switch idle.consumeError(er) { case ERR_NEW_PING: if idle.ping(tun) == nil { continue } case ERR_PING_TIMEOUT: if log.V(1) { log.Errorln("Peer was unresponsive then close", tun.identifier) } default: if log.V(1) { log.Errorln("Error", tun.identifier, er) } } // abandon this connection return } key = sessionKey(tun, frm.sid) switch frm.action { case FRAME_ACTION_CLOSE_W: if edge, _ := router.getRegistered(key); edge != nil { edge.bitwiseCompareAndSet(TCP_CLOSE_W) edge.deliver(frm) } case FRAME_ACTION_CLOSE_R: if edge, _ := router.getRegistered(key); edge != nil { edge.bitwiseCompareAndSet(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. pack(header, FRAME_ACTION_CLOSE_R, frm.sid, nil) if frameWriteBuffer(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, FRAME_ACTION_OPEN_DENIED: edge, _ := router.getRegistered(key) if edge != nil { if log.V(4) { log.Infoln(p.role, "recv OPEN_x", frm) } edge.ready <- frm.action close(edge.ready) } else { if log.V(2) { log.Warningln("peer send OPEN_x 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() { if p.isClient && idle.lastPing > 0 { sRtt, devRtt := idle.updateRtt() if DEBUG { log.Infof("sRtt=%d devRtt=%d", sRtt, devRtt) } if devRtt+(sRtt>>2) > sRtt { // restart ??? log.Warningf("Unstable network sRtt=%d devRtt=%d", sRtt, devRtt) } } } else { 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) { tun.priority = &TSPriority{0, 1e9} p.pool.Push(tun) defer p.onTunDisconnected(tun, handler) tun.SetSockOpt(1, 2, 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.bitwiseCompareAndSet(TCP_CLOSE_W) edge.deliver(frm) } case FRAME_ACTION_CLOSE_R: if edge, _ := router.getRegistered(key); edge != nil { edge.bitwiseCompareAndSet(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() } }