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 (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 (t *Session) DataTunServe(fconn *Conn, buf []byte) { defer func() { var offline bool if atomic.AddInt32(&t.activeCnt, -1) <= 0 { offline = true t.mgr.clearTokens(t) t.mux.destroy() } var err = recover() if log.V(1) { log.Infof("Tun=%s was disconnected. %v\n", fconn.identifier, nvl(err, NULL)) if offline { log.Infof("Client=%s was offline\n", t.cid) } } if DEBUG { ex.CatchException(err) } }() atomic.AddInt32(&t.activeCnt, 1) if buf != nil { token := buf[:TKSZ] fconn.cipher = t.cipherFactory.NewCipher(token) buf = nil } else { // first negotiation had initialized cipher, the buf will be null log.Infof("Client=%s is online\n", t.cid) } if log.V(1) { log.Infof("Tun=%s is established\n", fconn.identifier) } t.mux.Listen(fconn, t.eventHandler, DT_PING_INTERVAL) }
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 *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) startDataTun(again bool) { var connected bool defer func() { if connected { atomic.AddInt32(&c.dtCnt, -1) } if err := recover(); err != nil { log.Errorf("DTun failed to connect(%s). Retry after %s\n", err, RETRY_INTERVAL) c.eventHandler(evt_dt_closed, true) if DEBUG { ex.CatchException(err) } } }() if again { time.Sleep(RETRY_INTERVAL) } for { if atomic.LoadInt32(&c.State) == 0 { conn := c.createDataTun() connected = true if log.V(1) { log.Infof("DTun(%s) is established\n", conn.sign()) } atomic.AddInt32(&c.dtCnt, 1) c.mux.Listen(conn, c.eventHandler, c.tp.dtInterval) log.Errorf("DTun(%s) was disconnected. Reconnect after %s\n", conn.sign(), RETRY_INTERVAL) break } else { c.pendingSema.acquire(RETRY_INTERVAL) } } }
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) } }
// destroy each listener of all pooled tun, and destroy egress queues func (p *multiplexer) destroy() { defer func() { if !ex.CatchException(recover()) { p.status = MUX_CLOSED } }() // will not send evt_dt_closed while pending_close was indicated p.status = MUX_PENDING_CLOSE p.router.destroy() // destroy queue p.pool.destroy() }
func (r *egressRouter) clean() { defer func() { ex.CatchException(recover()) }() r.lock.Lock() defer r.lock.Unlock() for k, e := range r.registry { // call conn.LocalAddr will give rise to checking fd. if e == nil || e.closed >= TCP_CLOSED || e.conn.LocalAddr() == nil { delete(r.registry, k) } } }
func (t *Session) DataTunServe(fconn *Conn, buf []byte) { var svr = t.svr defer func() { atomic.AddInt32(&svr.dtCnt, -1) SafeClose(fconn) err := recover() log.Infof("Client(%s)-DT was disconnected. %v\n", fconn.identifier, err) if DEBUG { ex.CatchException(err) } }() atomic.AddInt32(&svr.dtCnt, 1) token := buf[:TKSZ] fconn.cipher = t.cipherFactory.NewCipher(token) log.Infof("Client(%s)-DT is established\n", fconn.identifier) svr.mux.Listen(fconn, t.eventHandler, DT_PING_INTERVAL) }
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 (c *Client) StartTun(mustRestart bool) { var ( wait bool tun *Conn rn = atomic.LoadInt32(&c.round) ) for { if wait { time.Sleep(RETRY_INTERVAL) } if rn < atomic.LoadInt32(&c.round) { return } if mustRestart { mustRestart = false if atomic.SwapInt32(&c.State, CLT_PENDING) >= CLT_WORKING { tun, rn = c.restart() if tun == nil { return } } else { return } } if atomic.LoadInt32(&c.State) == CLT_WORKING { // negotiation conn executed here firstly will not be null // otherwise must be null then create new one. if tun == nil { var err error tun, err = c.createDataTun() if err != nil { if DEBUG { ex.CatchException(err) } log.Errorf("Failed to connect %s. Reconnect after %s\n", err, RETRY_INTERVAL) wait = true continue } } if log.V(1) { log.Infof("Tun=%s is established\n", tun.sign()) } atomic.AddInt32(&c.dtCnt, 1) c.mux.Listen(tun, c.eventHandler, c.tp.dtInterval) dtcnt := atomic.AddInt32(&c.dtCnt, -1) log.Errorf("Tun=%s was disconnected, Reconnect after %s\n", tun.sign(), RETRY_INTERVAL) if atomic.LoadInt32(&c.mux.pingCnt) <= 0 { // dirty tokens: used abandoned tokens c.clearTokens() } if dtcnt <= 0 { // restart: all connections were disconnected log.Errorf("Connections %s were lost\n", tun.identifier) go c.StartTun(true) return } else { // reconnect // waiting and don't use old tun wait = true tun = nil } } else { // can't create tun and waiting for release if !c.pendingConn.acquire(RETRY_INTERVAL) { return } } } }