// 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(log.LV_ACT_FRM) { 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("CloseWrite %s by peer\n", e.dest) } } for i, e := q.buffer.Len(), q.buffer.Front(); i > 0; i, e = i-1, e.Next() { f := e.Value.(*frame) if f != nil { f.free() } } q.buffer = nil if force { atomic.StoreUint32(&e.closed, TCP_CLOSED) SafeClose(e.conn) } else { closeW(e.conn) } }
func (ctx *bootContext) startServer() { defer func() { sigChan <- Bye }() var ( conn *net.TCPConn ln *net.TCPListener err error ) server := NewServer(ctx.cman) addr := ctx.cman.ListenAddr(SR_SERVER) ln, err = net.ListenTCP("tcp", addr) fatalError(err) defer ln.Close() ctx.register(server, ln) log.Infoln(versionString()) log.Infoln("Server is listening on", addr) for { conn, err = ln.AcceptTCP() if err == nil { go server.TunnelServe(conn) } else { SafeClose(conn) } } }
func (ctx *bootContext) startClient() { defer func() { sigChan <- Bye }() var ( conn *net.TCPConn ln *net.TCPListener err error ) client := NewClient(ctx.cman) addr := ctx.cman.ListenAddr(SR_CLIENT) ln, err = net.ListenTCP("tcp", addr) fatalError(err) defer ln.Close() ctx.register(client, ln) log.Infoln(versionString()) log.Infoln("Proxy(SOCKS5/HTTP) is listening on", addr) // connect to server go client.StartTun(true) for { conn, err = ln.AcceptTCP() if err == nil { go client.ClientServe(conn) } else { SafeClose(conn) } } }
func (n *d5sman) authenticate(conn *Conn, session *Session) error { var err error setRTimeout(conn) hashSRand, err := ReadFullByLen(1, conn) if err != nil { // client aborted if IsClosedError(err) { return ABORTED_ERROR.Apply(err) } else { return exception.Spawn(&err, "srand: read connection") } } myHashSRand := hash256(n.sRand) if !bytes.Equal(hashSRand, myHashSRand) { // MITM ? return INCONSISTENT_HASH } // client identity setRTimeout(conn) idBuf, err := ReadFullByLen(1, conn) if err != nil { return exception.Spawn(&err, "auth: read connection") } user, passwd, err := n.deserializeIdentity(idBuf) if err != nil { return err } if log.V(log.LV_LOGIN) { log.Infoln("Login request:", user) } pass, err := n.AuthSys.Authenticate(user, passwd) if !pass { // authSys denied log.Warningf("Auth %s:%s failed: %v\n", user, passwd, err) // reply failed msg conn.Write([]byte{1, 0}) return VALIDATION_FAILED } session.indentifySession(user, conn) w := newMsgWriter() w.WriteL1Msg([]byte{AUTH_PASS}) w.WriteL2Msg(n.tunParams.serialize()) // send tokens num := maxInt(GENERATE_TOKEN_NUM, n.Parallels+2) tokens := n.sessionMgr.createTokens(session, num) w.WriteL2Msg(tokens[1:]) // skip index=0 setWTimeout(conn) err = w.WriteTo(conn) return exception.Spawn(&err, "setting: write connection") }
func NewGeoIPFilter(keyword string) (f *GeoIPFilter, e error) { if len(keyword) != 2 { return nil, fmt.Errorf("filter keyword must be 2-byte country_iso_code") } f = new(GeoIPFilter) f.keyword = StoU16(strings.ToUpper(keyword)) f.tab = deserialize(buildGeoDB()) log.Infoln("Init DestIPFilter with target keyword", keyword) return }
func (h *ConnPool) Select() *Conn { h.lock.Lock() defer h.lock.Unlock() if h.pool.Len() < 1 { return nil } sort.Sort(h.pool) if log.V(log.LV_TUN_SELECT) { log.Infoln("Selected tun", h.pool[0].LocalAddr()) } selected := h.pool[0] atomic.AddInt64(&selected.priority.rank, SELECT_DECREASE) return selected }
func sendFrame(frm *frame) bool { dst := frm.conn.conn if log.V(log.LV_DAT_FRM) { 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 false } // an error occured if log.V(log.LV_WARN_EDGE) { log.Warningf("Write edge (%s) error (%v) %s\n", frm.conn.dest, ew, frm) } return true }
func waitSignal() { USR2 := syscall.Signal(12) // fake signal-USR2 for windows signal.Notify(sigChan, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM, USR2) for sig := range sigChan { switch sig { case Bye: log.Exitln("Exiting.") context.doClose() return case syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM: log.Exitln("Terminated by", sig) context.doClose() return case USR2: context.doStats() default: log.Infoln("Ingore signal", sig) } } }
func (p *multiplexer) connectToDest(frm *frame, key string, tun *Conn) { defer func() { p.wg.Done() ex.Catch(recover(), nil) }() var ( dstConn net.Conn err error target = string(frm.data) denied = false ) if p.filter != nil { denied = p.filter.Filter(target) } if !denied { dstConn, err = dialer.Dial("tcp", target) } if err != nil || denied { p.router.removePreRegistered(key) if denied { frm.action = FRAME_ACTION_OPEN_DENIED log.Warningf("Denied request [%s] for %s\n", target, key) } else { frm.action = FRAME_ACTION_OPEN_N log.Warningf("Cannot connect to [%s] for %s error: %s\n", target, key, err) } frameWriteHead(tun, frm) } else { edge := p.router.register(key, target, tun, dstConn, false) // write edge if log.V(log.LV_SVR_OPEN) { log.Infoln("OPEN", target, "for", key) } dstConn.SetReadDeadline(ZERO_TIME) frm.action = FRAME_ACTION_OPEN_Y if frameWriteHead(tun, frm) == nil { p.relay(edge, tun, frm.sid) // read edge } else { // send open_y failed SafeClose(tun) } } }
// TODO notify peer to slow down when queue increased too fast func (p *multiplexer) Listen(tun *Conn, handler event_handler, interval int) error { 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 nil } switch idle.consumeError(er) { case ERR_NEW_PING: if er = idle.ping(tun); er == nil { continue } case ERR_PING_TIMEOUT: er = ex.New("Peer was unresponsive then close") } // abandon this connection return er } // prefix tun.identifier 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(log.LV_WARN) { log.Warningln("Peer sent data to an unexisted socket.", key, frm) } // trigger sending close to notice peer. pack(header, FRAME_ACTION_CLOSE_R, frm.sid, nil) if er = frameWriteBuffer(tun, header); er != nil { return er } } case FRAME_ACTION_OPEN: router.preRegister(key) p.wg.Add(1) 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(log.LV_ACT_FRM) { log.Infoln(p.role, "received OPEN_x", frm) } edge.ready <- frm.action close(edge.ready) } else { if log.V(log.LV_WARN) { log.Warningln("Peer sent OPEN_x to an unexisted socket.", key, frm) } } case FRAME_ACTION_PING: if er = idle.pong(tun); er == nil { atomic.AddInt32(&p.pingCnt, 1) } else { // reply pong failed return er } case FRAME_ACTION_PONG: if idle.verify() { if p.isClient && idle.lastPing > 0 { sRtt, devRtt := idle.updateRtt() atomic.StoreInt32(&p.sRtt, sRtt) if DEBUG { log.Infof("sRtt=%d devRtt=%d", sRtt, devRtt) if devRtt+(sRtt>>2) > sRtt { // restart ??? log.Warningf("Network jitter sRtt=%d devRtt=%d", sRtt, devRtt) } } } } else { log.Warningln("Incorrect action_pong received") } case FRAME_ACTION_TOKENS: handler(evt_tokens, frm.data) default: // impossible return fmt.Errorf("Unrecognized %s", frm) } tun.Update() } }