Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

功能增强 #6

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

白嫖云函数,构建自己的代理服务

基于https://github.com/Sakurasan/scf-proxy修改

## 更新
1. 增加http/2协议转发\
需关闭ALPN,例如:Firefox about:config security.ssl.enable_alpn=false
2. 支持浏览器代理
3. 原有的命令行方式改为yaml配置文件
## 快速食用🍰
```
sh build.sh
Expand Down
3 changes: 1 addition & 2 deletions build.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@

#!/bin/bash
work_path=$(cd `dirname $0`/../; pwd)
echo $work_path

GOOS=linux GOARCH=amd64 go build -o main cmd/main.go
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -v -a -ldflags '-s -w' -gcflags="all=-trimpath=${PWD}" -asmflags="all=-trimpath=${PWD}" -o main cmd/main.go
zip main.zip main
56 changes: 38 additions & 18 deletions cmd/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,20 @@ package main

import (
"crypto/tls"
"flag"
"fmt"
"log"
"github.com/chroblert/jlog"
"golang.org/x/net/http2"
"net"
"net/http"
"net/http/httputil"
"scf-proxy/pkg/mitm"
"scf-proxy/pkg/scf"
"scf-proxy/pkg/viper"
"sync"
"time"
)

const (
HTTP_ADDR = "127.0.0.1:8080"
//HTTP_ADDR = "127.0.0.1:8080"
SESSIONS_TO_CACHE = 10000
)

Expand All @@ -24,23 +25,25 @@ var (
)

func init() {
flag.StringVar(&clientPort, "p", "8080", "scf-proxy 客户端端口")
flag.StringVar(&scf.ScfApiProxyUrl, "scfurl", "", "scf-proxy 服务端地址")
flag.Parse()
if scf.ScfApiProxyUrl == "" {
panic("scf-proxy 服务端地址为空")
}
fmt.Println(scf.ScfApiProxyUrl)

_ = jlog.SetLogFullPath("logs/client.log", 0755, 0755)
jlog.SetStoreToFile(true)
jlog.SetMaxSizePerLogFile("10MB")
jlog.SetMaxStoreDays(30)
jlog.SetLogCount(30)
jlog.IsIniCreateNewLog(true)
jlog.SetVerbose(true)
scf.ScfApiProxyUrl, clientPort = viper.YamlConfig()
}

func main() {
exampleWg.Add(1)
runHTTPServer()
// Uncomment the below line to keep the server running
exampleWg.Wait()
//defer jlog.Flush()

// Output:

}

func runHTTPServer() {
Expand All @@ -66,20 +69,36 @@ func runHTTPServer() {

rp := &httputil.ReverseProxy{
Director: func(req *http.Request) {
log.Printf("Processing request to: %s", req.URL)
jlog.Infof("Processing request to: %s", req.URL)
},
Transport: &http.Transport{
//Transport: &http.Transport{
// //AllowHTTP: true,
// TLSClientConfig: &tls.Config{
// // Use a TLS session cache to minimize TLS connection establishment
// // Requires Go 1.3+
// ClientSessionCache: tls.NewLRUClientSessionCache(SESSIONS_TO_CACHE),
// },
// //DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {
// // return net.Dial(network, addr)
// //},
//},
Transport: &http2.Transport{
AllowHTTP: true,
TLSClientConfig: &tls.Config{
// Use a TLS session cache to minimize TLS connection establishment
// Requires Go 1.3+
ClientSessionCache: tls.NewLRUClientSessionCache(SESSIONS_TO_CACHE),
},
DialTLS: func(netw, addr string, cfg *tls.Config) (net.Conn, error) {
return net.Dial(netw, addr)
},
},
FlushInterval: -1,
}

handler, err := mitm.Wrap(rp, cryptoConfig)
if err != nil {
log.Fatalf("Unable to wrap reverse proxy: %s", err)
jlog.Fatalf("Unable to wrap reverse proxy: %s", err)
}

server := &http.Server{
Expand All @@ -88,14 +107,15 @@ func runHTTPServer() {
ReadTimeout: 1 * time.Minute,
WriteTimeout: 1 * time.Minute,
}

_ = http2.ConfigureServer(server, nil)
go func() {
log.Printf("About to start HTTP proxy at :%s", clientPort)
jlog.Infof("About to start HTTP proxy at :%s\n", clientPort)
if err := server.ListenAndServe(); err != nil {
log.Fatalf("Unable to start HTTP proxy: %s", err)
jlog.Fatalf("Unable to start HTTP proxy: %s", err)
}
exampleWg.Done()
}()

return
//}
}
4 changes: 1 addition & 3 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@ import (
"context"
"encoding/json"
"fmt"

"scf-proxy/pkg/scf"

"github.com/sirupsen/logrus"
log "github.com/sirupsen/logrus"
"github.com/tencentyun/scf-go-lib/cloudfunction"
"github.com/tencentyun/scf-go-lib/events"
"scf-proxy/pkg/scf"
)

func main() {
Expand Down
9 changes: 9 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@ module scf-proxy
go 1.15

require (
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6 // indirect
github.com/chroblert/jlog v0.0.8
github.com/coreos/etcd v3.3.10+incompatible // indirect
github.com/coreos/go-etcd v2.0.0+incompatible // indirect
github.com/sirupsen/logrus v1.8.1
github.com/spf13/viper v1.12.0
github.com/tencentyun/scf-go-lib v0.0.0-20200624065115-ba679e2ec9c9
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8 // indirect
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77 // indirect
golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2
golang.org/x/sys v0.0.0-20220624220833-87e55d714810 // indirect
)
27 changes: 19 additions & 8 deletions pkg/mitm/mitm.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@ package mitm
import (
"crypto/tls"
"fmt"
"github.com/chroblert/jlog"
"golang.org/x/net/http2"
"golang.org/x/net/http2/h2c"
"io"
"log"
"net/http"
"net/http/httputil"
"scf-proxy/pkg/scf"
"strings"
"sync"
"time"
)

const (
Expand All @@ -30,9 +32,14 @@ type HandlerWrapper struct {
}

func Wrap(handler http.Handler, cryptoConf *CryptoConfig) (*HandlerWrapper, error) {
h2s := &http2.Server{
IdleTimeout: time.Second * 60,
}
wrapper := &HandlerWrapper{
cryptoConf: cryptoConf,
wrapped: handler,
cryptoConf: cryptoConf,
//wrapped: handler,
//http/2 支持
wrapped: h2c.NewHandler(handler, h2s),
dynamicCerts: NewCache(),
}
err := wrapper.initCrypto()
Expand All @@ -48,8 +55,9 @@ func (wrapper *HandlerWrapper) ServeHTTP(resp http.ResponseWriter, req *http.Req
wrapper.intercept(resp, req)
} else {
// wrapper.wrapped.ServeHTTP(resp, req)
reqdump, _ := httputil.DumpRequest(req, true)
fmt.Println("dump req:", string(reqdump))
//reqdump, _ := httputil.DumpRequest(req, true)
//fmt.Println("dump req:", string(reqdump))
//jlog.Info(string(reqdump))
scf.HandlerHttp(resp, req)
}
}
Expand All @@ -73,13 +81,16 @@ func (wrapper *HandlerWrapper) intercept(resp http.ResponseWriter, req *http.Req
return
}
tlsConfig := makeConfig(wrapper.cryptoConf.ServerTLSConfig)
//HTTP/2 支持
tlsConfig.NextProtos = []string{"h2"}

tlsConfig.Certificates = []tls.Certificate{*cert}
tlsConnIn := tls.Server(connIn, tlsConfig)

listener := &mitmListener{tlsConnIn}

handler := http.HandlerFunc(func(resp2 http.ResponseWriter, req2 *http.Request) {
//req2.ProtoMajor
req2.URL.Scheme = "https"
req2.URL.Host = req2.Host
req2.RequestURI = req2.URL.String()
Expand All @@ -91,7 +102,7 @@ func (wrapper *HandlerWrapper) intercept(resp http.ResponseWriter, req *http.Req
go func() {
err = http.Serve(listener, handler)
if err != nil && err != io.EOF {
log.Printf("Error serving mitm'ed connection: %s", err)
jlog.Printf("Error serving mitm'ed connection: %s", err)
}
}()

Expand All @@ -116,7 +127,7 @@ func hostIncludingPort(req *http.Request) (host string) {
}

func respBadGateway(resp http.ResponseWriter, msg string) {
log.Println(msg)
jlog.Error(msg)
resp.WriteHeader(502)
resp.Write([]byte(msg))
}
63 changes: 48 additions & 15 deletions pkg/scf/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import (
"bytes"
"encoding/base64"
"encoding/json"
"github.com/chroblert/jlog"
"io/ioutil"
"log"
"net/http"
"net/http/httputil"
"strings"
)

var (
Expand All @@ -17,55 +18,87 @@ var (
func HandlerHttp(w http.ResponseWriter, r *http.Request) {
dumpReq, err := httputil.DumpRequest(r, true)
if err != nil {
log.Println(err)
jlog.Error(err)
w.WriteHeader(http.StatusServiceUnavailable)
return
}

// 解决当url为/的问题
event := &DefineEvent{
URL: r.URL.String(),
Content: base64.StdEncoding.EncodeToString(dumpReq),
}
//jlog.Println(event.URL, event.Content)
bytejson, err := json.Marshal(event)
if err != nil {
log.Println(err)
jlog.Error(err)
w.WriteHeader(http.StatusServiceUnavailable)
return
}

req, err := http.NewRequest("POST", ScfApiProxyUrl, bytes.NewReader(bytejson))
if err != nil {
log.Println(err)
jlog.Error(err)
w.WriteHeader(http.StatusServiceUnavailable)
return
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Println("client.Do()", err)
jlog.Error(err)
w.WriteHeader(http.StatusServiceUnavailable)
return
}
bytersp, _ := ioutil.ReadAll(resp.Body)

var respevent RespEvent
if err := json.Unmarshal(bytersp, &respevent); err != nil {
log.Println(err)
w.WriteHeader(http.StatusServiceUnavailable)
jlog.Error(err)
jlog.Error(string(bytersp))
w.WriteHeader(resp.StatusCode)
w.Write(bytersp)
//w.WriteHeader(http.StatusServiceUnavailable)
return
}
if resp.StatusCode > 0 && resp.StatusCode != 200 {
log.Println(err)
w.WriteHeader(http.StatusServiceUnavailable)
jlog.Error(err)
w.WriteHeader(resp.StatusCode)
w.Write(bytersp)
//w.WriteHeader(http.StatusServiceUnavailable)
return
}
retByte, err := base64.StdEncoding.DecodeString(respevent.Data)
//处理头+内容
resp1 := strings.Split(respevent.Data, "^")
respHeaders, err := base64.StdEncoding.DecodeString(resp1[0])
respBody, err := base64.StdEncoding.DecodeString(resp1[1])
//retByte, err := base64.StdEncoding.DecodeString(respevent.Data)
if err != nil {
log.Println(err)
w.WriteHeader(http.StatusServiceUnavailable)
jlog.Error(err)
w.WriteHeader(resp.StatusCode)
return
}
err1 := resp.Body.Close()
if err1 != nil {
jlog.Error(err1)
w.WriteHeader(resp.StatusCode)
return
}
respHeadersMap := make(map[string][]string)
err = json.Unmarshal(respHeaders, &respHeadersMap)
for k, v := range respHeadersMap {
var s []string
for _, val := range v {
s = append(s, val)
}
w.Header().Set(k, s[0])
}
_, err2 := w.Write(respBody)
if err2 != nil {
jlog.Error(err2)
w.WriteHeader(resp.StatusCode)
return
}
resp.Body.Close()

w.Write(retByte)
//w.Write(retByte)
return
}

//}
Loading