func wrapC4RequestEvent(ev event.Event) event.Event { var encrypt event.EncryptEventV2 encrypt.SetHash(ev.GetHash()) encrypt.EncryptType = c4_cfg.Encrypter encrypt.Ev = ev return &encrypt }
func (c4 *C4RemoteSession) handleTunnelResponse(conn *SessionConnection, ev event.Event) error { switch ev.GetType() { case event.EVENT_TCP_CONNECTION_TYPE: cev := ev.(*event.SocketConnectionEvent) if cev.Status == event.TCP_CONN_CLOSED { log.Printf("Session[%d]Remote %s connection closed, current proxy addr:%s\n", conn.SessionID, cev.Addr, c4.remote_proxy_addr) if c4.remote_proxy_addr == cev.Addr { c4.closed = true conn.Close() c4.Close() return io.EOF } } case event.EVENT_TCP_CHUNK_TYPE: chunk := ev.(*event.TCPChunkEvent) log.Printf("Session[%d]Handle TCP chunk[%d-%d]\n", conn.SessionID, chunk.Sequence, len(chunk.Content)) n, err := conn.LocalRawConn.Write(chunk.Content) if nil != err { log.Printf("[%d]Failed to write chunk[%d-%d] to local client:%v.\n", ev.GetHash(), chunk.Sequence, len(chunk.Content), err) conn.Close() c4.Close() return err } if n < len(chunk.Content) { log.Printf("[%d]Less data written[%d-%d] to local client.\n", ev.GetHash(), n, len(chunk.Content)) } chunk.Content = nil case event.HTTP_RESPONSE_EVENT_TYPE: log.Printf("Session[%d]Handle HTTP Response event with range task:%p\n", conn.SessionID, c4.rangeWorker) res := ev.(*event.HTTPResponseEvent) httpres := res.ToResponse() //log.Printf("Session[%d]Recv res %d %v\n", ev.GetHash(), httpres.StatusCode, httpres.Header) if nil != c4.rangeWorker { httpWriter := func(preq *http.Request) error { return c4.writeHttpRequest(preq) } pres, err := c4.rangeWorker.ProcessAyncResponse(httpres, httpWriter) if nil == err { if nil != pres { //log.Printf("Session[%d] %d %v\n", ev.GetHash(), pres.StatusCode, pres.Header) go pres.Write(conn.LocalRawConn) } else { //log.Printf("Session[%d]NULLL\n", ev.GetHash()) } } else { log.Printf("####%v\n", err) c4.Close() conn.Close() } } else { httpres.Write(conn.LocalRawConn) } default: log.Printf("Unexpected event type:%d\n", ev.GetType()) } return nil }
func processRecvEvent(ev event.Event, user string) { serv := getProxySession(user, ev.GetHash()) ev = event.ExtractEvent(ev) switch ev.GetType() { case event.EVENT_USER_LOGIN_TYPE: req := ev.(*event.UserLoginEvent) closeProxyUser(req.User) case event.EVENT_TCP_CONNECTION_TYPE: req := ev.(*event.SocketConnectionEvent) if req.Status == event.TCP_CONN_CLOSED { deleteProxySession(user, ev.GetHash()) } case event.HTTP_REQUEST_EVENT_TYPE: req := ev.(*event.HTTPRequestEvent) err := serv.initConn(req.Method, req.GetHeader("Host")) if nil != err { log.Printf("Failed to init conn for reason:%v\n", err) } if strings.EqualFold(req.Method, "Connect") { res := &event.TCPChunkEvent{} res.SetHash(ev.GetHash()) if nil == serv.conn { res.Content = []byte("HTTP/1.1 503 ServiceUnavailable\r\n\r\n") } else { res.Content = []byte("HTTP/1.1 200 OK\r\n\r\n") //log.Printf("Return established.\n") } offerSendEvent(res, user) } else { if nil != serv.conn { err := req.Write(serv.conn) if nil != err { log.Printf("Failed to write http request %v\n", err) deleteProxySession(user, serv.id) return } } else { res := &event.TCPChunkEvent{} res.SetHash(ev.GetHash()) res.Content = []byte("HTTP/1.1 503 ServiceUnavailable\r\n\r\n") offerSendEvent(res, serv.user) } } case event.EVENT_TCP_CHUNK_TYPE: if nil == serv.conn { //log.Printf("[%d]No session conn %d", ev.GetHash()) deleteProxySession(serv.user, serv.id) return } chunk := ev.(*event.TCPChunkEvent) //.Printf("[%d]Chunk has %d", ev.GetHash(), len(chunk.Content)) _, err := serv.conn.Write(chunk.Content) if nil != err { log.Printf("Failed to write chunk %v\n", err) serv.closeSession() return } } }
func HandleEvent(tags *event.EventHeaderTags, ev event.Event, ctx appengine.Context, sender EventSendService) error { res, err := handleRecvEvent(tags, ev, ctx) if nil != err { ctx.Errorf("Failed to handle event[%d:%d] for reason:%v", ev.GetType(), ev.GetVersion(), err) return err } if nil == res { var empty bytes.Buffer sender.Send(&empty) return nil } res.SetHash(ev.GetHash()) compressType := Cfg.CompressType if httpres, ok := res.(*event.HTTPResponseEvent); ok { v := httpres.GetHeader("Content-Type") if len(v) > 0 && Cfg.CompressType != event.COMPRESSOR_NONE { if isContentTypeInCompressFilter(v) { compressType = event.COMPRESSOR_NONE } } } x := new(event.CompressEvent) x.SetHash(ev.GetHash()) x.CompressType = compressType x.Ev = res y := new(event.EncryptEvent) y.SetHash(ev.GetHash()) y.EncryptType = Cfg.EncryptType y.Ev = x var buf bytes.Buffer tags.Encode(&buf) event.EncodeEvent(&buf, y) sender.Send(&buf) return nil }
func (gae *GAEHttpConnection) requestOverTunnel(conn *SessionConnection, ev event.Event) (err error, res event.Event) { if nil == gae.tunnelChannel { gae.tunnelChannel = make(chan event.Event) go gae.tunnel_write(conn) //go gae.tunnel_read(conn) } switch ev.GetType() { case event.HTTP_REQUEST_EVENT_TYPE: req := ev.(*event.HTTPRequestEvent) default_port := "80" if strings.EqualFold(req.RawReq.Method, "CONNECT") { conn.State = STATE_RECV_HTTP_CHUNK default_port = "443" } else { conn.State = STATE_RECV_HTTP } log.Printf("Session[%d]Request %s\n", req.GetHash(), util.GetURLString(req.RawReq, true)) scd := &event.SocketConnectWithDataEvent{} scd.Content, err = httputil.DumpRequest(req.RawReq, true) if nil != err { log.Printf("Session[%d]Failed to encode request to bytes", req.GetHash()) return } scd.SetHash(ev.GetHash()) scd.Net = "tcp" scd.Addr = req.RawReq.Host if !strings.Contains(scd.Addr, ":") { scd.Addr = net.JoinHostPort(req.RawReq.Host, default_port) } gae.tunnel_remote_addr = scd.Addr gae.tunnelChannel <- scd case event.HTTP_CHUNK_EVENT_TYPE: chunk := ev.(*event.HTTPChunkEvent) tcp_chunk := &event.TCPChunkEvent{Content: chunk.Content} tcp_chunk.SetHash(ev.GetHash()) gae.tunnelChannel <- tcp_chunk conn.State = STATE_RECV_HTTP_CHUNK } return nil, nil }
func (gae *GAEHttpConnection) handleTunnelResponse(conn *SessionConnection, ev event.Event) error { switch ev.GetType() { case event.EVENT_TCP_CONNECTION_TYPE: cev := ev.(*event.SocketConnectionEvent) log.Printf("[%d]Recv conn event:%v.\n", ev.GetHash(), cev.Status) if cev.Status == event.TCP_CONN_CLOSED { if gae.tunnel_remote_addr == cev.Addr { conn.Close() } } case event.EVENT_TCP_CHUNK_TYPE: chunk := ev.(*event.TCPChunkEvent) _, err := conn.LocalRawConn.Write(chunk.Content) if nil != err { log.Printf("[%d]Failed to write data to local client:%v.\n", ev.GetHash(), err) conn.Close() } default: log.Printf("Unexpected event type:%d\n", ev.GetType()) } return nil }
func offerSendEvent(ev event.Event, user string) { switch ev.GetType() { case event.EVENT_TCP_CHUNK_TYPE: var compress event.CompressEventV2 compress.SetHash(ev.GetHash()) compress.Ev = ev compress.CompressType = event.COMPRESSOR_SNAPPY ev = &compress } var encrypt event.EncryptEventV2 encrypt.SetHash(ev.GetHash()) encrypt.EncryptType = event.ENCRYPTER_SE1 encrypt.Ev = ev ev = &encrypt idx := int(ev.GetHash()) % len(send_evs[user]) send_evs[user][idx] <- ev }
func (auto *ForwardConnection) Request(conn *SessionConnection, ev event.Event) (err error, res event.Event) { f := func(local, remote net.Conn) { n, err := io.Copy(remote, local) if nil != err { local.Close() remote.Close() } auto.forwardChan <- int(n) } //L: auto.closed = false switch ev.GetType() { case event.HTTP_REQUEST_EVENT_TYPE: req := ev.(*event.HTTPRequestEvent) addr := req.RawReq.Host if !strings.Contains(addr, ":") { if conn.Type == HTTPS_TUNNEL { addr = net.JoinHostPort(addr, "443") } else { addr = net.JoinHostPort(addr, "80") } } err = auto.initForwardConn(addr, conn.Type == HTTPS_TUNNEL) if nil != err { log.Printf("Failed to connect forward address for %s.\n", addr) return err, nil } if conn.Type == HTTPS_TUNNEL { log.Printf("Session[%d]Request %s\n", req.GetHash(), util.GetURLString(req.RawReq, true)) if !auto.manager.overProxy || strings.HasPrefix(auto.conn_url.Scheme, "socks") { conn.LocalRawConn.Write([]byte("HTTP/1.1 200 Connection established\r\n\r\n")) } else { auto.writeHttpRequest(req.RawReq) } go f(conn.LocalRawConn, auto.forward_conn) go f(auto.forward_conn, conn.LocalRawConn) atomic.AddInt32(&total_forwared_routine_num, 2) <-auto.forwardChan <-auto.forwardChan atomic.AddInt32(&total_forwared_routine_num, -2) auto.Close() conn.State = STATE_SESSION_CLOSE } else { log.Printf("Session[%d]Request %s\n", req.GetHash(), util.GetURLString(req.RawReq, true)) if auto.manager.inject_crlf { log.Printf("Session[%d]Inject CRLF for %s", ev.GetHash(), req.RawReq.Host) auto.forward_conn.Write(CRLFs) } err := auto.writeHttpRequest(req.RawReq) if nil != err { return err, nil } if common.DebugEnable { var tmp bytes.Buffer req.RawReq.Write(&tmp) log.Printf("Session[%d]Send request \n%s\n", ev.GetHash(), tmp.String()) } resp, err := http.ReadResponse(auto.buf_forward_conn, req.RawReq) if err != nil { log.Printf("Session[%d]Recv response with error %v\n", ev.GetHash(), err) return err, nil } //log.Printf("Session[%d]Recv response %v\n", ev.GetHash(), resp) err = resp.Write(conn.LocalRawConn) resp.Body.Close() if common.DebugEnable { var tmp bytes.Buffer resp.Write(&tmp) log.Printf("Session[%d]Recv response \n%s\n", ev.GetHash(), tmp.String()) } if nil != err || !util.IsResponseKeepAlive(resp) || !util.IsRequestKeepAlive(req.RawReq) { conn.LocalRawConn.Close() auto.Close() conn.State = STATE_SESSION_CLOSE } else { conn.State = STATE_RECV_HTTP } } default: } return nil, nil }
func (gae *GAEHttpConnection) requestEvent(client *http.Client, conn *SessionConnection, ev event.Event) (err error, res event.Event) { auth := gae.gaeAuth if nil == auth { auth = gae.manager.auths.Select().(*GAEAuth) } domain := auth.appid + ".appspot.com" if strings.Contains(auth.appid, ".") { domain = auth.appid } addr, _ := getLocalHostMapping(domain) scheme := MODE_HTTP if strings.EqualFold(MODE_HTTPS, gae_cfg.ConnectionMode) { scheme = MODE_HTTPS } var buf bytes.Buffer var tags event.EventHeaderTags tags.Token = auth.token tags.Encode(&buf) if ev.GetType() == event.HTTP_REQUEST_EVENT_TYPE { var compress event.CompressEvent compress.SetHash(ev.GetHash()) compress.Ev = ev compress.CompressType = gae_cfg.Compressor var encrypt event.EncryptEvent encrypt.SetHash(ev.GetHash()) encrypt.EncryptType = gae_cfg.Encrypter encrypt.Ev = &compress event.EncodeEvent(&buf, &encrypt) } else { var encrypt event.EncryptEvent encrypt.SetHash(ev.GetHash()) encrypt.EncryptType = gae_cfg.Encrypter encrypt.Ev = ev event.EncodeEvent(&buf, &encrypt) } req := &http.Request{ Method: "POST", URL: &url.URL{Scheme: scheme, Host: addr, Path: "/invoke"}, ProtoMajor: 1, ProtoMinor: 1, Host: addr, Header: make(http.Header), Body: ioutil.NopCloser(&buf), ContentLength: int64(buf.Len()), } if len(gae_cfg.UA) > 0 { req.Header.Set("User-Agent", gae_cfg.UA) } req.Close = false req.Header.Set("Connection", "keep-alive") req.Header.Set("Content-Type", "image/jpeg") var response *http.Response response, err = gaeHttpClient.Do(req) if nil != err { log.Printf("Failed to request data from GAE:%s for:%s\n", domain, err.Error()) return err, nil } else { if response.StatusCode != 200 { log.Printf("Session[%d]Invalid response:%d\n", ev.GetHash(), response.StatusCode) return fmt.Errorf("Invalid response:%d", response.StatusCode), nil } else { var buf bytes.Buffer n, err := io.Copy(&buf, response.Body) if int64(n) < response.ContentLength { return fmt.Errorf("No sufficient space in body."), nil } if nil != err { return err, nil } response.Body.Close() if !tags.Decode(&buf) { return fmt.Errorf("Failed to decode event tag"), nil } err, res = event.DecodeEvent(&buf) if nil == err { res = event.ExtractEvent(res) } return err, res } } return nil, nil }
func wsOfferEvent(server string, ev event.Event) { chs := c4WsChannelTable[server] index := int(ev.GetHash()) % len(chs) chs[index] <- wrapC4RequestEvent(ev) }
func (c4 *C4RemoteSession) Request(conn *SessionConnection, ev event.Event) (err error, res event.Event) { c4.sess = conn if len(c4.server) == 0 { c4.server = c4.manager.servers.Select().(string) } c4.sess = conn c4.closed = false setC4SessionTable(c4) switch ev.GetType() { case event.HTTP_REQUEST_EVENT_TYPE: req := ev.(*event.HTTPRequestEvent) default_port := "80" if strings.EqualFold(req.RawReq.Method, "CONNECT") { conn.State = STATE_RECV_HTTP_CHUNK default_port = "443" } else { conn.State = STATE_RECV_HTTP } log.Printf("Session[%d] Request %s\n", req.GetHash(), util.GetURLString(req.RawReq, true)) if nil != err { log.Printf("Session[%d]Failed to encode request to bytes", req.GetHash()) return } remote_addr := req.RawReq.Host if !strings.Contains(remote_addr, ":") { remote_addr = net.JoinHostPort(req.RawReq.Host, default_port) } if strings.Contains(req.Url, "http://") { req.Url = req.Url[7+len(req.RawReq.Host):] } c4.rangeWorker = nil c4.remote_proxy_addr = remote_addr if strings.EqualFold(req.Method, "GET") && c4_cfg.MultiRangeFetchEnable { if c4.injectRange || hostPatternMatched(c4_cfg.InjectRange, req.RawReq.Host) { if nil == c4.doRangeFetch(req.RawReq) { return nil, nil } } } c4.offerRequestEvent(req) rest := req.RawReq.ContentLength tmpbuf := make([]byte, 8192) for rest > 0 { n, err := req.RawReq.Body.Read(tmpbuf) if nil == err { rest = rest - int64(n) chunk := &event.TCPChunkEvent{Content: tmpbuf[0:n]} chunk.SetHash(req.GetHash()) c4.offerRequestEvent(chunk) } else { break } } req.RawReq.Body.Close() case event.HTTP_CHUNK_EVENT_TYPE: //log.Printf("Session[%d]Offer chunk\n", conn.SessionID) chunk := ev.(*event.HTTPChunkEvent) tcp_chunk := &event.TCPChunkEvent{Content: chunk.Content} tcp_chunk.SetHash(ev.GetHash()) c4.offerRequestEvent(tcp_chunk) conn.State = STATE_RECV_HTTP_CHUNK } return nil, nil }