Initial commit
commit
cb6a4838cf
@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
port: 7777
|
||||||
|
ip_list: "ip.txt"
|
@ -0,0 +1,8 @@
|
|||||||
|
module github.com/fangdingjun/proxy_util
|
||||||
|
|
||||||
|
go 1.15
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/fangdingjun/go-log/v5 v5.0.0
|
||||||
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
|
)
|
@ -0,0 +1,8 @@
|
|||||||
|
github.com/fangdingjun/go-log v1.0.20 h1:ZNfkghi6WA1wXg2KkBz8idbqg4M63VezKR63OLX6FEw=
|
||||||
|
github.com/fangdingjun/go-log/v5 v5.0.0 h1:vdh9Bk9C4ZFL6KoO6rII73zQIyaLf7hFdBvucO/ckiE=
|
||||||
|
github.com/fangdingjun/go-log/v5 v5.0.0/go.mod h1:V012Oxo0/pSbccX4OFSp9MJglXwNsZo2ByBBorr7zzM=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
@ -0,0 +1,121 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"math/rand"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
log "github.com/fangdingjun/go-log/v5"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getLocalIP() string {
|
||||||
|
n := rand.Int() % len(iplist)
|
||||||
|
return iplist[n]
|
||||||
|
}
|
||||||
|
|
||||||
|
func proxyHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method == http.MethodConnect {
|
||||||
|
handleConnect(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if r.Method == http.MethodGet || r.Method == http.MethodPost {
|
||||||
|
handleHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
http.Error(w, "unsupported method", http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
func localDialer(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
ip := getLocalIP()
|
||||||
|
laddr := &net.TCPAddr{
|
||||||
|
IP: net.ParseIP(ip),
|
||||||
|
Port: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
dialer := &net.Dialer{
|
||||||
|
LocalAddr: laddr,
|
||||||
|
Timeout: 10 * time.Second,
|
||||||
|
}
|
||||||
|
return dialer.DialContext(ctx, network, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
r.Header.Del("proxy-connection")
|
||||||
|
r.Header.Del("proxy-authorization")
|
||||||
|
tr := &http.Transport{
|
||||||
|
DialContext: localDialer,
|
||||||
|
}
|
||||||
|
resp, err := tr.RoundTrip(r)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorln(err)
|
||||||
|
http.Error(w, err.Error(), http.StatusServiceUnavailable)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
hdr := w.Header()
|
||||||
|
resp.Header.Del("connection")
|
||||||
|
|
||||||
|
for k, v := range resp.Header {
|
||||||
|
for _, v1 := range v {
|
||||||
|
hdr.Add(k, v1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
w.WriteHeader(resp.StatusCode)
|
||||||
|
io.Copy(w, resp.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleConnect(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ip := getLocalIP()
|
||||||
|
|
||||||
|
log.Debugf("connect to %s, use local ip %s", r.RequestURI, ip)
|
||||||
|
|
||||||
|
addr := &net.TCPAddr{
|
||||||
|
IP: net.ParseIP(ip),
|
||||||
|
Port: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
dialer := &net.Dialer{
|
||||||
|
LocalAddr: addr,
|
||||||
|
Timeout: 10 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := dialer.Dial("tcp", r.RequestURI)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorln(err)
|
||||||
|
http.Error(w, "connection failed", http.StatusBadGateway)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
hj := w.(http.Hijacker)
|
||||||
|
conn1, _, _ := hj.Hijack()
|
||||||
|
defer conn1.Close()
|
||||||
|
|
||||||
|
fmt.Fprintf(conn1, "HTTP/1.1 200 connection ok\r\n\r\n")
|
||||||
|
|
||||||
|
ch := make(chan struct{}, 2)
|
||||||
|
go func() {
|
||||||
|
io.Copy(conn, conn1)
|
||||||
|
ch <- struct{}{}
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
io.Copy(conn1, conn)
|
||||||
|
ch <- struct{}{}
|
||||||
|
}()
|
||||||
|
<-ch
|
||||||
|
}
|
||||||
|
|
||||||
|
type handler struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
proxyHandler(w, r)
|
||||||
|
}
|
@ -0,0 +1,94 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"math/rand"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
log "github.com/fangdingjun/go-log/v5"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var iplist = []string{}
|
||||||
|
|
||||||
|
// Conf config file
|
||||||
|
type Conf struct {
|
||||||
|
Port int `yaml:"port"`
|
||||||
|
ListFile string `yaml:"ip_list"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var cfg Conf
|
||||||
|
var cfgfile string
|
||||||
|
var logfile string
|
||||||
|
var loglevel string
|
||||||
|
|
||||||
|
flag.StringVar(&cfgfile, "c", "config.yaml", "config file")
|
||||||
|
flag.StringVar(&logfile, "log_file", "", "log file")
|
||||||
|
flag.StringVar(&loglevel, "log_level", "INFO", "log level")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
lv, err := log.ParseLevel(loglevel)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("wrong level name: %s\nvalid level name: DEBUG, INFO, WARN, ERROR, FATAL\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
log.Default.Level = lv
|
||||||
|
|
||||||
|
if logfile != "" {
|
||||||
|
log.Default.Out = &log.FixedSizeFileWriter{
|
||||||
|
Name: logfile,
|
||||||
|
MaxSize: 10 * 1024 * 1024,
|
||||||
|
MaxCount: 4,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rand.Seed(time.Now().Unix())
|
||||||
|
|
||||||
|
data, err := ioutil.ReadFile(cfgfile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
if err = yaml.Unmarshal(data, &cfg); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
loadIPList(cfg.ListFile)
|
||||||
|
|
||||||
|
log.Printf("Listen at http://0.0.0.0:%d", cfg.Port)
|
||||||
|
|
||||||
|
if err = http.ListenAndServe(fmt.Sprintf(":%d", cfg.Port), &handler{}); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadIPList(f string) {
|
||||||
|
fp, err := os.Open(f)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorln(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer fp.Close()
|
||||||
|
|
||||||
|
r := bufio.NewReader(fp)
|
||||||
|
for {
|
||||||
|
line, err := r.ReadString('\n')
|
||||||
|
if err != nil {
|
||||||
|
if err != io.EOF {
|
||||||
|
log.Errorln(err)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
line = strings.Trim(line, " \r\n\t")
|
||||||
|
if line == "" || line[0] == '#' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
iplist = append(iplist, line)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue