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) } } }
func (nego *d5SNegotiation) verifyThenDHExchange(conn net.Conn, credBuf []byte) (key []byte, err error) { userIdentity, err := RSADecrypt(credBuf, nego.RSAKeys.priv) ThrowErr(err) clientIdentity := string(userIdentity) if log.V(2) { log.Infoln("Auth clientIdentity:", clientIdentity) } allow, ex := nego.AuthSys.Authenticate(userIdentity) cDHPub, err := ReadFullByLen(2, conn) if !allow { log.Warningf("Auth %s failed: %v\n", clientIdentity, ex) conn.Write([]byte{0, 1, 0xff}) return nil, ex } nego.clientIdentity = clientIdentity key = takeSharedKey(nego.dhKeys, cDHPub) // if log.V(5) { // dumpHex("Sharedkey", key) // } buf := new(bytes.Buffer) buf.Write(nego.dhKeys.pubLen) buf.Write(nego.dhKeys.pub) _, err = buf.WriteTo(conn) return }
func (context *bootContext) startServer() { defer func() { ex.CatchException(recover()) sigChan <- t.Bye }() var conf = t.Parse_d5sFile(context.config) context.setLogVerbose(conf.Verbose) log.Info(versionString()) log.Infoln("Server is listening on", conf.ListenAddr) ln, err := net.ListenTCP("tcp", conf.ListenAddr) if err != nil { log.Fatalln(err) } defer ln.Close() dhKeys := t.GenerateDHKeyPairs() server := t.NewServer(conf, dhKeys) context.statser = server for { conn, err := ln.AcceptTCP() if err == nil { go server.TunnelServe(conn) } else { t.SafeClose(conn) } } }
func (t *signalTunnel) acknowledged() { if log.V(4) { log.Infoln("Ping/acknowledged by", t.remoteAddr) } t.tun.SetReadDeadline(ZERO_TIME) t.active(-2) // so slow down the tempo }
func (context *bootContext) startClient() { defer func() { ex.CatchException(recover()) sigChan <- t.Bye }() var conf = t.Parse_d5cFile(context.config) context.setLogVerbose(conf.Verbose) log.Info(versionString()) log.Infoln("Socks5/Http is working at", conf.ListenAddr) mgr := NewClientMgr(conf) context.statser = mgr ln, err := net.ListenTCP("tcp", conf.ListenAddr) if err != nil { log.Fatalln(err) } defer ln.Close() for { conn, err := ln.Accept() if err == nil { go mgr.selectClientServ(conn) } else { t.SafeClose(conn) } } }
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) } }
// close for ending of queued task func (q *equeue) _close(force bool, close_code uint) { q.lock.Lock() defer q.lock.Unlock() e := q.edge if log.V(4) { switch close_code { case CLOSED_BY_ERR: log.Infoln("terminate", e.dest) case CLOSED_FORCE: log.Infoln("close", e.dest) case CLOSED_WRITE: log.Infof("closeW %s by peer\n", e.dest) } } q.buffer.Init() q.buffer = nil if force { e.closed = TCP_CLOSE_R | TCP_CLOSE_W SafeClose(e.conn) } else { closeW(e.conn) } }
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 = tp.token tp.token = nil c.tp = tp log.Infoln("Login to the gateway", c.nego.RemoteName(), "successfully") return tun }
func sendFrame(frm *frame) (werr bool) { dst := frm.conn.conn if log.V(5) { log.Infoln("SEND queue", frm) } dst.SetWriteDeadline(time.Now().Add(GENERAL_SO_TIMEOUT)) nw, ew := dst.Write(frm.data) if nw == int(frm.length) && ew == nil { return } werr = true // an error occured log.Warningf("Write edge(%s) error(%v). %s\n", frm.conn.dest, ew, frm) return }
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 waitSignal() { USR2 := syscall.Signal(12) // fake signal-USR2 for windows signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM, USR2) for sig := range sigChan { switch sig { case t.Bye: log.Exitln("Exiting.") return case syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM: log.Exitln("Terminated by", sig) return case USR2: context.doStats() default: log.Infoln("Ingore signal", sig) } } }
func (t *signalTunnel) active(times int64) { t.lock.Lock() defer t.lock.Unlock() if times > 0 { // active link in transferring var d = (times - t.lastResetTime) << 1 // allow reset at least half interval if d > int64(t.interval/time.Second) { if log.V(4) { log.Infoln("suppress the next ping task") } t.lastResetTime = times t.lived.Reset(t.interval) } } else if times < 0 { // scheduled ping t.interval = t.baseInterval * time.Duration(-times) t.lastResetTime = time.Now().Unix() t.lived.Reset(t.interval) } }
func (s *S5Step1) respondSocks5() bool { var ack = []byte{5, 0, 0, 1, 0, 0, 0, 0, 0, 0} if s.err != nil { // handshake error feedback if ex, y := s.err.(*exception.Exception); y { ack[1] = byte(ex.Code()) } else { ack[1] = 0x1 } s.conn.Write(ack) s.conn.Close() return true } // accept _, err := s.conn.Write(ack) if err != nil { log.Infoln(err) return true } return false }
func (c *Client) eventHandler(e event, msg ...interface{}) { var mlen = len(msg) switch e { case evt_st_closed: atomic.StoreInt32(&c.State, -1) c.clearTokens() log.Errorf("Lost connection of gateway %s. Reconnect after %s\n", c.nego.RemoteName(), RETRY_INTERVAL) go c.StartSigTun(mlen > 0) case evt_st_ready: atomic.StoreInt32(&c.State, 0) log.Infoln("Tunnel negotiated with gateway", msg[0], "successfully") go c.startMultiplexer() case evt_dt_closed: go c.startDataTun(mlen > 0) case evt_st_msg: if mlen == 1 { go c.commandHandler(msg[0].(byte), nil) } else { go c.commandHandler(msg[0].(byte), msg[1].([]byte)) } case evt_st_active: c.sigTun.active(msg[0].(int64)) } }
// 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() } } }