Пример #1
0
func (s *HttpServer) forwardRequest(req *http.Request) {
	last := s.Base.Chain.lastNode
	if last == nil {
		return
	}
	cc, err := s.Base.Chain.GetConn()
	if err != nil {
		glog.V(LWARNING).Infof("[http] %s -> %s : %s", s.conn.RemoteAddr(), last.Addr, err)

		b := []byte("HTTP/1.1 503 Service unavailable\r\n" +
			"Proxy-Agent: gost/" + Version + "\r\n\r\n")
		glog.V(LDEBUG).Infof("[http] %s <- %s\n%s", s.conn.RemoteAddr(), last.Addr, string(b))
		s.conn.Write(b)
		return
	}
	defer cc.Close()

	if last.User != nil {
		req.Header.Set("Proxy-Authorization",
			"Basic "+base64.StdEncoding.EncodeToString([]byte(last.User.String())))
	}

	cc.SetWriteDeadline(time.Now().Add(WriteTimeout))
	if err = req.WriteProxy(cc); err != nil {
		glog.V(LWARNING).Infof("[http] %s -> %s : %s", s.conn.RemoteAddr(), req.Host, err)
		return
	}
	cc.SetWriteDeadline(time.Time{})

	glog.V(LINFO).Infof("[http] %s <-> %s", s.conn.RemoteAddr(), req.Host)
	s.Base.transport(s.conn, cc)
	glog.V(LINFO).Infof("[http] %s >-< %s", s.conn.RemoteAddr(), req.Host)
	return
}
Пример #2
0
func doRequest(req *http.Request) (*http.Response, error) {
	if proxyURL != nil {
		c, err := dial(proxyURL.Host)
		if err != nil {
			log.Println(err)
			return nil, err
		}
		defer c.Close()

		setBasicAuth(req)
		if err := req.WriteProxy(c); err != nil {
			log.Println(err)
			return nil, err
		}
		/*
			b, err := ioutil.ReadAll(c)
			if err != nil {
				log.Println(err)
				return nil, err
			}
		*/
		return http.ReadResponse(bufio.NewReader(c), req)
	}

	return http.DefaultClient.Do(req)
}
Пример #3
0
func (handler *SogouProxyHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
	proxyConn := mustDialSogou(handler)

	timestamp := fmt.Sprintf("%08x", time.Now().Unix())
	request.Header.Add("X-Sogou-Timestamp", timestamp)
	tag := fmt.Sprintf("%08x", sogouTagHash(timestamp+request.Host+"SogouExplorerProxy"))
	request.Header.Add("X-Sogou-Tag", tag)
	request.Header.Add("X-Sogou-Auth", "58C41A7C258CAB58167E110BB5DEF7AF/4.1.3.8107/md5")

	request.WriteProxy(proxyConn)

	hj, ok := writer.(http.Hijacker)
	if !ok {
		log.Println("ERROR: ", "webserver doesn't support hijacking", http.StatusInternalServerError)
		http.Error(writer, "webserver doesn't support hijacking", http.StatusInternalServerError)
		return
	}
	clientConn, _, err := hj.Hijack()
	if err != nil {
		log.Println("ERROR: ", err, http.StatusInternalServerError)
		http.Error(writer, err.Error(), http.StatusInternalServerError)
		return
	}

	proxyBufReader := bufio.NewReader(proxyConn)
	response, err := http.ReadResponse(proxyBufReader, request)
	if err != nil {
		http.Error(writer, err.Error(), http.StatusInternalServerError)
		return
	}
	if request.Method == "CONNECT" {
		response.Body.Close()
	} else {
		defer response.Body.Close()
	}

	log.Printf("%s %s %s\n<- %s\n", request.RemoteAddr, request.Method, request.RequestURI, response.Status)
	response.Write(clientConn)

	if request.Method == "CONNECT" && response.StatusCode == http.StatusOK {
		go copyAndClose(proxyConn, clientConn)
		go copyAndClose(clientConn, proxyBufReader)
	} else {
		clientConn.Close()
		proxyConn.Close()
	}
}
Пример #4
0
func (h *ProxyHTTPHandler) doConnect(w http.ResponseWriter, r *http.Request) {
	var (
		clientConn net.Conn
		serverConn net.Conn
		err        error
	)
	hj, ok := w.(http.Hijacker)
	if !ok {
		http.Error(w, "", http.StatusInternalServerError)
		return
	}
	clientConn, _, err = hj.Hijack()
	if err != nil {
		http.Error(w, "", http.StatusInternalServerError)
		return
	}
	removeProxyHeaders(r)
	pacConn, err := h.pac.PacConn(r.URL)
	if err != nil {
		http.Error(w, "", http.StatusBadGateway)
		return
	}
	if pacConn != nil {
		serverConn, err = pacConn.Dial()
		if err != nil {
			http.Error(w, "", http.StatusBadGateway)
			return
		}
		defer serverConn.Close()
		r.WriteProxy(serverConn)
	} else {
		serverConn, err = net.Dial("tcp", r.URL.Host)
		if err != nil {
			http.Error(w, "", http.StatusBadGateway)
			return
		}
		defer serverConn.Close()
		clientConn.Write([]byte("HTTP/1.0 200 OK\r\n\r\n"))
	}
	defer clientConn.Close()
	defer serverConn.Close()
	go io.Copy(clientConn, serverConn)
	io.Copy(serverConn, clientConn)
}
Пример #5
0
func (conn *ForwardConnection) writeHttpRequest(req *http.Request) error {
	var err error
	index := 0
	for {
		if conn.manager.overProxy {
			err = req.WriteProxy(conn.forward_conn)
		} else {
			err = req.Write(conn.forward_conn)
		}

		if nil != err {
			log.Printf("Resend request since error:%v occured.\n", err)
			conn.Close()
			conn.initForwardConn(req.Host, strings.EqualFold(req.Method, "Connect"))
		} else {
			return nil
		}
		index++
		if index == 2 {
			return err
		}
	}
	return nil
}
Пример #6
0
func (client *Client) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	r.Header.Add("Proxy-Authenticate", client.psw)
	c, err := net.Dial("tcp", client.remote_addr)
	if err != nil {
		//should not print
		log.Println(GetColorError(err))
		return
	}
	defer c.Close()
	if tc, ok := c.(*net.TCPConn); ok {
		if tc.SetReadBuffer(4096*32) != nil {
			log.Println(GetColorError(err))
			return
		}
		if tc.SetKeepAlive(true) != nil {
			log.Println(GetColorError(err))
			return
		}
		if tc.SetKeepAlivePeriod(1*time.Minute) != nil {
			log.Println(GetColorError(err))
			return
		}
	}
	conn := NewRecord(tls.Client(c, &tls.Config{InsecureSkipVerify: true}), client.lock, &client.upload, &client.download)
	//Send the requset to own proxy server
	read := bufio.NewReader(conn)
	if err = r.WriteProxy(conn); err != nil {
		log.Println(GetColorError(err))
		atomic.AddUint64(&client.errCounter, 1)
		return
	}
	if r.Method == "CONNECT" {
		//send the https request
		resp, err := http.ReadResponse(read, r)
		if err != nil {
			log.Println(GetColorError(err))
			return
		}
		defer resp.Body.Close()
		if resp.StatusCode != 200 {
			return
		}
		hij, ok := w.(http.Hijacker)
		if !ok {
			log.Println("httpserver does not support hijacking")
			return
		}
		proxyClient, _, e := hij.Hijack()
		if e != nil {
			log.Println("Cannot hijack connection " + e.Error())
			return
		}
		//write the 200 ok to the client
		proxyClient.Write([]byte("HTTP/1.1 200 OK\r\n\r\n"))
		//connect keep the connect alive
		go copyAndClose(proxyClient, read)
		copyAndClose(conn, proxyClient)
		return
	}
	//read the response
	resp, err := http.ReadResponse(read, r)
	if err != nil {
		log.Println(GetColorError(err))
		atomic.AddUint64(&client.errCounter, 1)
		return
	}
	defer resp.Body.Close()
	copyHeaders(w.Header(), resp.Header)
	w.WriteHeader(resp.StatusCode)
	io.Copy(w, resp.Body)
}
Пример #7
0
func handleHttpRequest(req *http.Request, conn net.Conn, arg Args) {
	if glog.V(LDEBUG) {
		dump, err := httputil.DumpRequest(req, false)
		if err != nil {
			glog.Infoln(err)
		} else {
			glog.Infoln(string(dump))
		}
	}
	glog.V(LINFO).Infoln("[http] CONNECT", req.Host)

	var username, password string
	if arg.User != nil {
		username = arg.User.Username()
		password, _ = arg.User.Password()
	}

	u, p, _ := basicAuth(req.Header.Get("Proxy-Authorization"))
	req.Header.Del("Proxy-Authorization")

	if (username != "" && u != username) || (password != "" && p != password) {
		resp := "HTTP/1.1 407 Proxy Authentication Required\r\n" +
			"Proxy-Authenticate: Basic realm=\"gost\"\r\n" +
			"Proxy-Agent: gost/" + Version + "\r\n\r\n"

		if _, err := conn.Write([]byte(resp)); err != nil {
			glog.V(LWARNING).Infoln(err)
		}
		glog.V(LDEBUG).Infoln(resp)

		glog.V(LWARNING).Infoln("http: proxy authentication required")
		return
	}

	c, err := Connect(req.Host)
	if err != nil {
		glog.V(LWARNING).Infoln("[http] CONNECT", req.Host, err)

		b := []byte("HTTP/1.1 503 Service unavailable\r\n" +
			"Proxy-Agent: gost/" + Version + "\r\n\r\n")
		glog.V(LDEBUG).Infoln(string(b))
		conn.Write(b)
		return
	}
	defer c.Close()

	if req.Method == "CONNECT" {
		b := []byte("HTTP/1.1 200 Connection established\r\n" +
			"Proxy-Agent: gost/" + Version + "\r\n\r\n")
		glog.V(LDEBUG).Infoln(string(b))

		if _, err := conn.Write(b); err != nil {
			glog.V(LWARNING).Infoln(err)
			return
		}
	} else {
		if len(forwardArgs) > 0 {
			err = req.WriteProxy(c)
		} else {
			err = req.Write(c)
		}
		if err != nil {
			glog.V(LWARNING).Infoln(err)
			return
		}
	}

	glog.V(LINFO).Infoln("[http] CONNECT", req.Host, "OK")
	Transport(conn, c)
}
Пример #8
0
func LHttpRequest(L *lua.LState, r *http.Request) *lua.LTable {
	t := L.NewTable()
	t.RawSetString("body", LReadCloser(L, r.Body))
	t.RawSetString("close", lua.LBool(r.Close))
	t.RawSetString("content_length", lua.LNumber(r.ContentLength))
	t.RawSetString("header", LHttpHeader(L, r.Header))
	t.RawSetString("host", lua.LString(r.Host))
	t.RawSetString("method", lua.LString(r.Method))
	t.RawSetString("proto", lua.LString(r.Proto))
	t.RawSetString("proto_major", lua.LNumber(r.ProtoMajor))
	t.RawSetString("proto_minor", lua.LNumber(r.ProtoMinor))
	t.RawSetString("remote_addr", lua.LString(r.RemoteAddr))
	t.RawSetString("request_uri", lua.LString(r.RequestURI))
	t.RawSetString("trailer", LHttpHeader(L, r.Trailer))
	t.RawSetString("tls", lua.LNil)
	// Cancel <-chan struct{} // not applicable to server per net/http docs

	// how to make lazy?  func or...?
	t.RawSetString("transfer_encoding", LStringSlice(L, r.TransferEncoding))

	// this could be much better
	t.RawSetString("url", lua.LString(r.URL.String()))

	L.SetFuncs(t, map[string]lua.LGFunction{
		// AddCookie(c *Cookie)
		// BasicAuth() (username, password string, ok bool)
		// Cookie(name string) (*Cookie, error)
		// Cookies() []*Cookie
		// FormFile(key string) (multipart.File, *multipart.FileHeader, error)
		// FormValue(key string) string
		// MultipartReader() (*multipart.Reader, error)
		// ParseForm() error
		// ParseMultipartForm(maxMemory int64) error
		// PostFormValue(key string) string
		// ProtoAtLeast(major, minor int) bool
		// Referer() string
		// SetBasicAuth(username, password string)
		"user_agent": func(L *lua.LState) int {
			L.Push(lua.LString(r.UserAgent()))
			return 1
		},
		// Write(w io.Writer) error
		"write": func(L *lua.LState) int {
			o := L.CheckAny(1)
			w, ok := o.(io.Writer)
			if !ok {
				L.Push(lua.LString("not a writer"))
				return 1
			}
			err := r.Write(w)
			if err == nil {
				L.Push(lua.LNil)
			} else {
				L.Push(lua.LString(err.Error()))
			}
			return 1
		},
		// WriteProxy(w io.Writer) error
		"write_proxy": func(L *lua.LState) int {
			o := L.CheckAny(1)
			w, ok := o.(io.Writer)
			if !ok {
				L.Push(lua.LString("not a writer"))
				return 1
			}
			err := r.WriteProxy(w)
			if err == nil {
				L.Push(lua.LNil)
			} else {
				L.Push(lua.LString(err.Error()))
			}
			return 1
		},
	})
	return t
}
Пример #9
0
func handle(con net.Conn, out string) {
	defer con.Close()

	laddr := con.LocalAddr().(*net.TCPAddr)

	var outs []string
	for _, o := range strings.Fields(out) {
		outs = append(outs, getHostPort(o))
	}
	if len(outs) == 0 && laddr.Port == 443 {
		for _, name := range []string{"HTTPS_PROXY", "https_proxy"} {
			if value := os.Getenv(name); len(value) > 0 {
				if o := getHostPort(value); len(o) > 0 {
					outs = append(outs, o)
				}
			}
		}
	}
	if len(outs) == 0 {
		for _, name := range []string{"HTTP_PROXY", "http_proxy"} {
			if value := os.Getenv(name); len(value) > 0 {
				if o := getHostPort(value); len(o) > 0 {
					outs = append(outs, o)
				}
			}
		}
	}

	var v4addrs []string
	var v6addrs []string
	for _, out := range outs {
		if host, port, err := net.SplitHostPort(out); err != nil {
			log.Print("proxy config %v error %v", out, err)
		} else if ips, err := net.LookupIP(host); err == nil {
			for _, ip := range ips {
				if ip.To4() != nil {
					v4addrs = append(v4addrs, net.JoinHostPort(ip.String(), port))
				} else {
					v6addrs = append(v6addrs, net.JoinHostPort(ip.String(), port))
				}
			}
		} else {
			log.Print(laddr, err)
		}
	}

	var addrs []string
	if laddr.IP.To4() != nil {
		addrs = append(v4addrs, v6addrs...)
	} else {
		addrs = append(v6addrs, v4addrs...)
	}

	switch laddr.Port {
	case 80:
		rcon := bufio.NewReader(TimedIo{con})

		getRequest := func() *http.Request {
			req, err := http.ReadRequest(rcon)
			if err != nil {
				if err == io.EOF {
					// pass
				} else if e, ok := err.(net.Error); ok && e.Timeout() {
					// pass
				} else {
					log.Print(laddr, fmt.Errorf("http.ReadRequest %v", err))
				}
				return nil
			}

			// using Opaque and RawQuery is stable
			if len(req.URL.Scheme) == 0 {
				req.URL.Scheme = "http"
				if len(req.URL.Host) == 0 {
					req.URL.Host = req.Host
				}
				if len(req.URL.Host) == 0 {
					req.URL.Host = laddr.IP.String()
				}
			}
			return req
		}

		var req *http.Request
		for _, addr := range addrs {
			if err := func() error {
				var conOut net.Conn
				var rconOut *bufio.Reader
				for {
					if req == nil {
						req = getRequest()
					}
					if req == nil {
						return nil
					}
					if conOut == nil {
						var e1 error
						conOut, e1 = net.DialTimeout("tcp", addr, 2*time.Second)
						if e1 != nil {
							return e1
						}
						rconOut = bufio.NewReader(TimedIo{conOut})
						defer conOut.Close()
					}

					if err := req.WriteProxy(conOut); err != nil {
						return err
					} else if res, err := http.ReadResponse(rconOut, req); err != nil {
						return err
					} else {
						sent := make(chan bool)
						go func() {
							io.Copy(TimedIo{conOut}, req.Body)
							close(sent)
						}()
						res.Write(con)
						_ = <-sent

						if "keep-alive" != req.Header.Get("Connection") || "keep-alive" != res.Header.Get("Connection") {
							return nil
						}
						req = nil
					}
				}
				return nil
			}(); err != nil {
				log.Print(laddr, err)
			} else {
				return
			}
		}
	case 443:
		// tried here to use hostname from SSL ClientHello entry,
		// but wild clients did not support it.
		// like github.com/elazarl/goproxy
		// using github.com/inconshreveable/go-vhost
		req := &http.Request{
			Method: "CONNECT",
			Host:   con.LocalAddr().String(),
			URL:    &url.URL{},
		}
		for _, addr := range addrs {
			if err := func() error {
				conOut, err := net.DialTimeout("tcp", addr, 2*time.Second)
				if err != nil {
					return err
				}
				defer conOut.Close()

				if err := req.WriteProxy(conOut); err != nil {
					return err
				} else if res, err := http.ReadResponse(bufio.NewReader(TimedIo{conOut}), req); err != nil {
					return err
				} else if res.StatusCode != 200 {
					return fmt.Errorf("proxy error %v", res)
				} else {
					sent := make(chan bool)
					go func() {
						io.Copy(TimedIo{conOut}, TimedIo{con})
						close(sent)
					}()
					io.Copy(TimedIo{con}, res.Body)
					_ = <-sent
					return nil
				}
			}(); err != nil {
				log.Print(laddr, err)
			} else {
				return
			}
		}
	}
	log.Printf("handle faild for %v %v", laddr, addrs)
}