func (d *directChannel) read() { defer d.Close() for { c := d.conn if nil == c { return } c.SetReadDeadline(time.Now().Add(d.ReadTimeout())) b := make([]byte, 1500) n, err := c.Read(b) if n > 0 { var ev event.Event if !d.udpProxyConn { ev = &event.TCPChunkEvent{Content: b[0:n]} } else { ev = &event.UDPEvent{Content: b[0:n]} } //log.Printf("######recv %T", ev) ev.SetId(d.sid) proxy.HandleEvent(ev) } if nil != err { if !d.udpProxyConn { closeEv := &event.ConnCloseEvent{} closeEv.SetId(d.sid) proxy.HandleEvent(closeEv) } return } } }
func getProxySessionByEvent(ctx *ConnContext, ev event.Event) *ProxySession { cid := ctx.ConnId sid := SessionId{cid, ev.GetId()} sessionMutex.Lock() defer sessionMutex.Unlock() if p, exist := proxySessionMap[sid]; exist { return p } createIfMissing := false switch ev.(type) { case *event.TCPOpenEvent: createIfMissing = true case *event.HTTPRequestEvent: createIfMissing = true case *event.UDPEvent: createIfMissing = true } if !createIfMissing { return nil } p := new(ProxySession) p.Id = sid p.CreateTime = time.Now() p.ch = make(chan event.Event, 100) go p.processEvents() proxySessionMap[sid] = p atomic.AddInt32(&sessionSize, 1) return p }
func (p *DirectProxy) Serve(session *proxy.ProxySession, ev event.Event) error { if nil == session.Remote || session.Remote.C.Closed() { switch ev.(type) { case *event.TCPOpenEvent: case *event.HTTPRequestEvent: case *event.UDPEvent: default: session.Close() return fmt.Errorf("Can NOT create direct channel by event:%T", ev) } c, err := newDirectChannel(ev, &p.conf) if nil != err { session.Close() return err } session.Remote = &proxy.RemoteChannel{ Addr: c.addr, DirectIO: true, } session.Remote.C = c if c.httpsProxyConn { session.Hijacked = true return nil } } if nil == session.Remote { return fmt.Errorf("No remote connected.") } switch ev.(type) { case *event.UDPEvent: session.Remote.WriteRaw(ev.(*event.UDPEvent).Content) case *event.ConnCloseEvent: session.Remote.Close() case *event.TCPOpenEvent: case *event.ConnTestEvent: //do nothing case *event.TCPChunkEvent: session.Remote.WriteRaw(ev.(*event.TCPChunkEvent).Content) case *event.HTTPRequestEvent: req := ev.(*event.HTTPRequestEvent) content := req.HTTPEncode() _, err := session.Remote.WriteRaw(content) if nil != err { closeEv := &event.ConnCloseEvent{} closeEv.SetId(ev.GetId()) proxy.HandleEvent(closeEv) return err } return nil default: log.Printf("Invalid event type:%T to process", ev) } return nil }
func (p *RejectProxy) Serve(session *proxy.ProxySession, ev event.Event) error { if _, ok := ev.(*event.HTTPRequestEvent); ok { forbidden := &event.HTTPResponseEvent{} forbidden.SetId(ev.GetId()) forbidden.StatusCode = 404 proxy.HandleEvent(forbidden) } else { session.Close() } return nil }
func HandleEvent(ev event.Event) error { session := getProxySession(ev.GetId()) if nil == session { switch ev.(type) { case *event.ConnCloseEvent: case *event.NotifyEvent: case *event.HeartBeatEvent: default: log.Printf("No session:%d found for %T", ev.GetId(), ev) } return sessionNotExist } return session.handle(ev) }
func (p *ProxySession) publish(ev event.Event) { ev.SetId(p.Id.Id) start := time.Now() timeout := start.Add(60 * time.Second) for !p.closeByClient && time.Now().Before(timeout) { queue := getEventQueue(p.Id.ConnId, false) if nil != queue { err := queue.Publish(ev, 10*time.Second) if nil != err { continue } return } time.Sleep(5 * time.Millisecond) } if !p.closeByClient { log.Printf("Session[%s:%d] publish event timeout after %v", p.Id.User, p.Id.Id, time.Now().Sub(start)) p.forceClose() } }
func handleEvent(ev event.Event, ctx *ConnContext) (event.Event, error) { switch ev.(type) { case *event.AuthEvent: auth := ev.(*event.AuthEvent) err := authConnection(auth, ctx) var authres event.NotifyEvent authres.SetId(ev.GetId()) if nil == err { authres.Code = event.SuccessAuthed } else { authres.Code = event.ErrAuthFailed } return &authres, nil case *event.HeartBeatEvent: //do nothing case *event.ChannelCloseReqEvent: ctx.Closing = true queue := getEventQueue(ctx.ConnId, false) if nil != queue { queue.Publish(nil, 1*time.Minute) } case *event.ConnTestEvent: session := getProxySessionByEvent(ctx, ev) if nil == session { log.Printf("Session:%d is NOT exist now.", ev.GetId()) queue := getEventQueue(ctx.ConnId, false) if nil != queue { closeEv := &event.ConnCloseEvent{} closeEv.SetId(ev.GetId()) queue.Publish(closeEv, 10*time.Millisecond) } } default: session := getProxySessionByEvent(ctx, ev) if nil != session { session.offer(ev) } if _, ok := ev.(*event.ConnCloseEvent); !ok { if nil == session { log.Printf("No session:%d found for event %T", ev.GetId(), ev) } } else { if nil != session { session.closeByClient = true } } } return nil, nil }
func (p *PaasProxy) Serve(session *proxy.ProxySession, ev event.Event) error { if nil == session.Remote { session.SetRemoteChannel(p.cs.Select()) //session.Remote = p.cs.Select() if session.Remote == nil { session.Close() return fmt.Errorf("No proxy channel in PaasProxy") } } switch ev.(type) { case *event.TCPChunkEvent: session.Remote.Write(ev) case *event.ConnTestEvent: session.Remote.Write(ev) case *event.UDPEvent: session.Remote.Write(ev) case *event.TCPOpenEvent: session.Remote.Write(ev) case *event.ConnCloseEvent: session.Remote.Write(ev) case *event.HTTPRequestEvent: if strings.EqualFold(ev.(*event.HTTPRequestEvent).Method, "Connect") { session.Hijacked = true host := ev.(*event.HTTPRequestEvent).Headers.Get("Host") tcpOpen := &event.TCPOpenEvent{Addr: host} tcpOpen.SetId(ev.GetId()) session.Remote.Write(tcpOpen) } else { session.Remote.Write(ev) } default: session.Close() log.Printf("Invalid event type:%T to process", ev) } return nil }
func newDirectChannel(ev event.Event, conf *proxy.ProxyChannelConfig) (*directChannel, error) { host := "" port := "" network := "tcp" needHttpsConnect := false switch ev.(type) { case *event.UDPEvent: network = "udp" host = ev.(*event.UDPEvent).Addr case *event.TCPOpenEvent: host = ev.(*event.TCPOpenEvent).Addr needHttpsConnect = true case *event.HTTPRequestEvent: req := ev.(*event.HTTPRequestEvent) host = req.Headers.Get("Host") needHttpsConnect = strings.EqualFold(req.Method, "Connect") default: return nil, fmt.Errorf("Can NOT create direct channel by event:%T", ev) } //log.Printf("Session:%d enter direct with host %s & event:%T", ev.GetId(), host, ev) if len(host) == 0 { return nil, fmt.Errorf("Empty remote addr in event") } if strings.Contains(host, ":") { host, port, _ = net.SplitHostPort(host) } else { if needHttpsConnect { port = "443" } else { port = "80" } } if len(conf.SNIProxy) > 0 && port == "443" && network == "tcp" && hosts.InHosts(conf.SNIProxy) { host = conf.SNIProxy } isIP := net.ParseIP(host) != nil useTLS := false if conf.ForceTLS && port == "80" && hosts.InHosts(host) { useTLS = true } else { useTLS = false } if !isIP { host = hosts.GetHost(host) } //log.Printf("Session:%d get host:%s", ev.GetId(), host) addr := "" if nil == conf.ProxyURL() { if useTLS { addr = host + ":443" } else { if len(port) > 0 { addr = host + ":" + port } else { if needHttpsConnect { addr = host + ":443" } else { addr = host + ":80" } } } } else { addr = conf.ProxyURL().Host } connectHost, connectPort, _ := net.SplitHostPort(addr) if net.ParseIP(connectHost) == nil { iphost, err := proxy.DnsGetDoaminIP(connectHost) if nil != err { return nil, err } addr = net.JoinHostPort(iphost, connectPort) } dailTimeout := conf.DialTimeout if 0 == dailTimeout { dailTimeout = 5 } //log.Printf("Session:%d connect %s:%s for %s %T %v %v %s", ev.GetId(), network, addr, host, ev, needHttpsConnect, conf.ProxyURL(), net.JoinHostPort(host, port)) c, err := netx.DialTimeout(network, addr, time.Duration(dailTimeout)*time.Second) if nil != conf.ProxyURL() && nil == err { if strings.HasPrefix(conf.ProxyURL().Scheme, "socks") { err = helper.Socks5ProxyConnect(conf.ProxyURL(), c, net.JoinHostPort(host, port)) } else { if needHttpsConnect { err = helper.HTTPProxyConnect(conf.ProxyURL(), c, "https://"+net.JoinHostPort(host, port)) } } } if nil != err { log.Printf("Failed to connect %s for %s with error:%v", addr, host, err) return nil, err } d := &directChannel{ev.GetId(), c, needHttpsConnect, network == "udp", conf, addr} //d := &directChannel{ev.GetId(), c, fromHttpsConnect, network == "udp", toReplaceSNI, false, nil} if useTLS { tlcfg := &tls.Config{} tlcfg.InsecureSkipVerify = true sniLen := len(conf.SNI) if sniLen > 0 { tlcfg.ServerName = conf.SNI[rand.Intn(sniLen)] } tlsconn := tls.Client(c, tlcfg) err = tlsconn.Handshake() if nil != err { log.Printf("Failed to handshake with %s", addr) } d.conn = tlsconn } go d.read() return d, nil }