├── .gitignore ├── Makefile ├── README.md ├── main.go ├── media └── whatsmyip-results.png ├── proxy-ng.pem ├── socks5-proxies.json ├── useragents.json ├── vendor └── github.com │ ├── eahydra │ └── socks │ │ ├── LICENSE │ │ ├── README.md │ │ ├── cmd │ │ └── socksd │ │ │ ├── README.md │ │ │ ├── cipher.go │ │ │ ├── cipher_conn.go │ │ │ ├── config.go │ │ │ ├── decorate_client.go │ │ │ ├── decorate_conn.go │ │ │ ├── decorate_direct.go │ │ │ ├── decorate_listener.go │ │ │ ├── dns_cache.go │ │ │ ├── log.go │ │ │ ├── main.go │ │ │ ├── pac_generator.go │ │ │ ├── pac_updater.go │ │ │ └── upstream_client.go │ │ ├── direct.go │ │ ├── example_test.go │ │ ├── http_proxy.go │ │ ├── shadowsocks_client.go │ │ ├── socks4.go │ │ ├── socks4_test.go │ │ ├── socks5_client.go │ │ ├── socks5_client_test.go │ │ └── socks5_server.go │ └── elazarl │ └── goproxy │ ├── LICENSE │ ├── README.md │ ├── actions.go │ ├── all.bash │ ├── ca.pem │ ├── certs.go │ ├── chunked.go │ ├── counterecryptor.go │ ├── counterecryptor_test.go │ ├── ctx.go │ ├── dispatcher.go │ ├── doc.go │ ├── examples │ ├── goproxy-basic │ │ ├── README.md │ │ └── main.go │ ├── goproxy-eavesdropper │ │ └── main.go │ ├── goproxy-httpdump │ │ ├── README.md │ │ └── httpdump.go │ ├── goproxy-jquery-version │ │ ├── README.md │ │ ├── jquery1.html │ │ ├── jquery2.html │ │ ├── jquery_homepage.html │ │ ├── jquery_test.go │ │ ├── main.go │ │ ├── php_man.html │ │ └── w3schools.html │ ├── goproxy-no-reddit-at-worktime │ │ ├── README.md │ │ └── noreddit.go │ ├── goproxy-sokeepalive │ │ └── sokeepalive.go │ ├── goproxy-sslstrip │ │ └── sslstrip.go │ ├── goproxy-stats │ │ ├── README.md │ │ └── main.go │ ├── goproxy-transparent │ │ ├── README.md │ │ ├── proxy.sh │ │ └── transparent.go │ ├── goproxy-upside-down-ternet │ │ └── main.go │ └── goproxy-yui-minify │ │ └── yui.go │ ├── ext │ ├── auth │ │ ├── basic.go │ │ └── basic_test.go │ ├── html │ │ ├── cp1255.html │ │ ├── cp1255.txt │ │ ├── html.go │ │ └── html_test.go │ └── image │ │ └── image.go │ ├── https.go │ ├── key.pem │ ├── proxy.go │ ├── proxy_test.go │ ├── regretable │ ├── regretreader.go │ └── regretreader_test.go │ ├── responses.go │ ├── signer.go │ ├── signer_test.go │ ├── test_data │ ├── baby.jpg │ ├── football.png │ └── panda.png │ └── transport │ ├── roundtripper.go │ ├── transport.go │ └── util.go └── version.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | proxy-ng 3 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GIT_VERSION=`git log --pretty=format:"%h" -1` 2 | BIN_VERSION=`cat version.txt` 3 | 4 | osx: 5 | GOOS=darwin GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-X main.gitCommit=${GIT_VERSION} -X main.appVersion=${BIN_VERSION}" -o proxy-ng-darwin main.go 6 | 7 | linux: 8 | GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-X main.gitCommit=${GIT_VERSION} -X main.appVersion=${BIN_VERSION}" -o proxy-ng-linux main.go 9 | 10 | windows: 11 | GOOS=windows GOARCH=amd64 CGO_ENABLED=0 go build -ldflags "-X main.gitCommit=${GIT_VERSION} -X main.appVersion=${BIN_VERSION}" -o proxy-ng-windows main.go 12 | 13 | build: osx linux windows -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Proxy-ng 2 | 3 | ## Purpose 4 | 5 | Wanted to make use of multiple socks proxies in a random order. Along with using socks proxies in a random order, I wanted each request to have a random useragent. 6 | 7 | ## Setup 8 | 9 | ### Build 10 | 11 | * `git clone https://github.com/jamesbcook/proxy-ng.git` 12 | * `make` 13 | * `./proxy-ng -help` 14 | 15 | ### Pre-Built binary 16 | 17 | * Download from [here](https://github.com/jamesbcook/proxy-ng/releases) 18 | * `./proxy-ng -help` 19 | 20 | ## Running 21 | 22 | Proxy-ng opens the following ports: 23 | 24 | * 9292 for the local socks proxy 25 | * 9293 for the local http proxy 26 | 27 | Unless specified by a flag, Proxy-ng will use look for the following files in its running directory: 28 | 29 | * useragents.json 30 | * socks5-proxies.json 31 | 32 | ## Example 33 | 34 | I use [cloud-proxy](https://github.com/tomsteele/cloud-proxy) to setup multiple socks proxies 35 | 36 | ```bash 37 | ./cloud-proxy -token xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -key 'xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx' -count 5 38 | 2018/07/01 18:12:22 Creating 1 droplets to region nyc1 39 | 2018/07/01 18:12:23 Creating 1 droplets to region sgp1 40 | 2018/07/01 18:12:24 Creating 1 droplets to region lon1 41 | 2018/07/01 18:12:25 Creating 1 droplets to region nyc3 42 | 2018/07/01 18:12:26 Creating 1 droplets to region ams3 43 | 2018/07/01 18:12:27 Droplets deployed. Waiting 100 seconds... 44 | 2018/07/01 18:14:08 SSH proxy started on port 55555 on droplet name: cloud-proxy-OucHZHiV IP: 159.65.236.62 45 | 2018/07/01 18:14:09 SSH proxy started on port 55556 on droplet name: cloud-proxy-q4AZAYVN IP: 178.128.95.250 46 | 2018/07/01 18:14:10 SSH proxy started on port 55557 on droplet name: cloud-proxy-RQLq0UQm IP: 139.59.173.24 47 | 2018/07/01 18:14:11 SSH proxy started on port 55558 on droplet name: cloud-proxy-eVd59B6d IP: 209.97.153.98 48 | 2018/07/01 18:14:11 SSH proxy started on port 55559 on droplet name: cloud-proxy-oSRSfFO1 IP: 188.166.6.62 49 | 2018/07/01 18:14:11 proxychains config 50 | socks5 127.0.0.1 55555 51 | socks5 127.0.0.1 55556 52 | socks5 127.0.0.1 55557 53 | socks5 127.0.0.1 55558 54 | socks5 127.0.0.1 55559 55 | 2018/07/01 18:14:11 socksd config 56 | "upstreams": [ 57 | {"type": "socks5", "address": "127.0.0.1:55555"}, 58 | {"type": "socks5", "address": "127.0.0.1:55556"}, 59 | {"type": "socks5", "address": "127.0.0.1:55557"}, 60 | {"type": "socks5", "address": "127.0.0.1:55558"}, 61 | {"type": "socks5", "address": "127.0.0.1:55559"} 62 | ] 63 | 2018/07/01 18:14:11 Please CTRL-C to destroy droplets 64 | ``` 65 | 66 | After pointing the browser to the local http listener setup by Proxy-ng and heading to whatsmyip.org it showed my hostname and IP to be different. 67 | 68 | ![whatsmyip](https://github.com/jamesbcook/proxy-ng/raw/master/media/whatsmyip-results.png) 69 | 70 | ## Help Output 71 | 72 | ```text 73 | Usage of ./proxy-ng: 74 | -http string 75 | HTTP listener to accept connections, this changes the useragent on each request (default "localhost:9293") 76 | -socks string 77 | Local socks listener to accept connections (default "localhost:9292") 78 | -socksFile string 79 | Socks file that contains socks proxies to use (default "socks5-proxies.json") 80 | -uaFile string 81 | Json file that contains useragents to use (default "useragents.json") 82 | -verbose 83 | Verbose output from proxy 84 | -version 85 | Current Version 86 | ``` -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "flag" 7 | "fmt" 8 | "log" 9 | "math/rand" 10 | "net" 11 | "net/http" 12 | "os" 13 | "time" 14 | 15 | "github.com/eahydra/socks" 16 | "github.com/elazarl/goproxy" 17 | "github.com/jamesbcook/print" 18 | ) 19 | 20 | var ( 21 | appVersion string 22 | gitCommit string 23 | ) 24 | 25 | //UserAgent contains a slice of useragents to be used 26 | type UserAgent struct { 27 | Names []string `json:"UserAgents"` 28 | } 29 | 30 | //SocksProxy contains a slice of proxies to be used 31 | type SocksProxy struct { 32 | Names []string `json:"Proxies"` 33 | } 34 | 35 | //UpstreamDialer contains a slice of socks dialers to be used 36 | type UpstreamDialer struct { 37 | forwardDialers []socks.Dialer 38 | } 39 | 40 | func init() { 41 | rand.Seed(time.Now().UTC().UnixNano()) 42 | } 43 | 44 | type flags struct { 45 | userAgentFile string 46 | socks5File string 47 | socksListener string 48 | httpListener string 49 | verbose bool 50 | } 51 | 52 | func flagSetup() *flags { 53 | uaFile := flag.String("uaFile", "useragents.json", "Json file that contains useragents to use") 54 | socksFile := flag.String("socksFile", "socks5-proxies.json", "Socks file that contains socks proxies to use") 55 | socksListen := flag.String("socks", "localhost:9292", "Local socks listener to accept connections") 56 | httpListen := flag.String("http", "localhost:9293", "HTTP listener to accept connections, this changes the useragent on each request") 57 | verbose := flag.Bool("verbose", false, "Verbose output from proxy") 58 | version := flag.Bool("version", false, "Current Version") 59 | flag.Parse() 60 | if *version { 61 | fmt.Printf("proxy-ng v%s %s\n", appVersion, gitCommit) 62 | os.Exit(0) 63 | } 64 | return &flags{userAgentFile: *uaFile, socks5File: *socksFile, 65 | socksListener: *socksListen, httpListener: *httpListen, 66 | verbose: *verbose} 67 | } 68 | 69 | func main() { 70 | myFlags := flagSetup() 71 | f, err := os.Open(myFlags.userAgentFile) 72 | if err != nil { 73 | print.Badln(err) 74 | } 75 | f2, err := os.Open(myFlags.socks5File) 76 | if err != nil { 77 | print.Badln(err) 78 | } 79 | var buf bytes.Buffer 80 | buf.ReadFrom(f) 81 | ua := &UserAgent{} 82 | if err := json.Unmarshal(buf.Bytes(), ua); err != nil { 83 | print.Badln(err) 84 | } 85 | buf.Reset() 86 | proxies := &SocksProxy{} 87 | buf.ReadFrom(f2) 88 | if err := json.Unmarshal(buf.Bytes(), proxies); err != nil { 89 | print.Badln(err) 90 | } 91 | var router socks.Dialer 92 | proxy := goproxy.NewProxyHttpServer() 93 | if myFlags.verbose { 94 | router = logBuildUpStream(BuildUpstreamRouter)(proxies.Names) 95 | proxy.ConnectDial = func(network, address string) (net.Conn, error) { 96 | return logDialer(router.Dial)(network, address) 97 | } 98 | proxy.Tr.Dial = func(network, address string) (net.Conn, error) { 99 | return logDialer(router.Dial)(network, address) 100 | } 101 | } else { 102 | router = BuildUpstreamRouter(proxies.Names) 103 | proxy.ConnectDial = func(network, address string) (net.Conn, error) { 104 | return router.Dial(network, address) 105 | } 106 | proxy.Tr.Dial = func(network, address string) (net.Conn, error) { 107 | return router.Dial(network, address) 108 | } 109 | } 110 | socksListen, err := net.Listen("tcp", myFlags.socksListener) 111 | if err != nil { 112 | print.Badln(err) 113 | } 114 | if myFlags.verbose { 115 | print.Goodf("Started socks listener on %s\n", myFlags.socksListener) 116 | } 117 | socksvr, err := socks.NewSocks5Server(router) 118 | if err != nil { 119 | print.Badln(err) 120 | } 121 | httpListen, err := net.Listen("tcp", myFlags.httpListener) 122 | if err != nil { 123 | print.Badln(err) 124 | } 125 | if myFlags.verbose { 126 | print.Goodf("Started http listener on %s\n", myFlags.httpListener) 127 | } 128 | proxy.OnRequest().HandleConnect(goproxy.AlwaysMitm) 129 | proxy.OnRequest().DoFunc( 130 | func(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { 131 | r.Header.Set("User-Agent", ua.randomName()) 132 | return r, nil 133 | }) 134 | go func() { 135 | http.Serve(httpListen, proxy) 136 | }() 137 | print.Goodln("Ready") 138 | if err := socksvr.Serve(socksListen); err != nil { 139 | print.Badln(err) 140 | } 141 | } 142 | 143 | func (ua UserAgent) randomName() string { 144 | max := len(ua.Names) 145 | if max == 0 { 146 | return ua.Names[0] 147 | } 148 | randomUA := 0 + rand.Intn(max-0) 149 | return ua.Names[randomUA] 150 | } 151 | 152 | //NewUpstreamDialer to be added to the array of dialers 153 | func NewUpstreamDialer(forwardDialers []socks.Dialer) *UpstreamDialer { 154 | return &UpstreamDialer{ 155 | forwardDialers: forwardDialers, 156 | } 157 | } 158 | 159 | func (u *UpstreamDialer) getRandomDialer() socks.Dialer { 160 | max := len(u.forwardDialers) 161 | if max == 0 { 162 | return u.forwardDialers[0] 163 | } 164 | randomDialer := 0 + rand.Intn(max-0) 165 | return u.forwardDialers[randomDialer] 166 | } 167 | 168 | func logDialer(f func(network, address string) (net.Conn, error)) func(network, address string) (net.Conn, error) { 169 | return func(network, address string) (net.Conn, error) { 170 | conn, err := f(network, address) 171 | print.Statusf("Connecting to %v\n", conn.RemoteAddr()) 172 | return conn, err 173 | } 174 | } 175 | 176 | //Dial is a custom dialer that picks a random dialer before it makes it's connection 177 | func (u *UpstreamDialer) Dial(network, address string) (net.Conn, error) { 178 | router := u.getRandomDialer() 179 | conn, err := router.Dial(network, address) 180 | if err != nil { 181 | return nil, err 182 | } 183 | return conn, nil 184 | } 185 | 186 | func logBuildUpStream(f func(proxies []string) socks.Dialer) func(proxies []string) socks.Dialer { 187 | return func(proxies []string) socks.Dialer { 188 | for x := range proxies { 189 | print.Statusf("Loading %s\n", proxies[x]) 190 | } 191 | defer print.Goodln("Loading complete") 192 | return f(proxies) 193 | } 194 | } 195 | 196 | //BuildUpstreamRouter populates the slice of dialers 197 | func BuildUpstreamRouter(proxies []string) socks.Dialer { 198 | var allForward []socks.Dialer 199 | for _, proxy := range proxies { 200 | forward, err := socks.NewSocks5Client("tcp", proxy, "", "", socks.Direct) 201 | if err != nil { 202 | log.Fatal(err) 203 | } 204 | allForward = append(allForward, forward) 205 | } 206 | return NewUpstreamDialer(allForward) 207 | } 208 | -------------------------------------------------------------------------------- /media/whatsmyip-results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesbcook/proxy-ng/ee3e213ab8d9498a6b7743f0acf5ff30a44ffb38/media/whatsmyip-results.png -------------------------------------------------------------------------------- /proxy-ng.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIF9DCCA9ygAwIBAgIJAODqYUwoVjJkMA0GCSqGSIb3DQEBCwUAMIGOMQswCQYD 3 | VQQGEwJJTDEPMA0GA1UECAwGQ2VudGVyMQwwCgYDVQQHDANMb2QxEDAOBgNVBAoM 4 | B0dvUHJveHkxEDAOBgNVBAsMB0dvUHJveHkxGjAYBgNVBAMMEWdvcHJveHkuZ2l0 5 | aHViLmlvMSAwHgYJKoZIhvcNAQkBFhFlbGF6YXJsQGdtYWlsLmNvbTAeFw0xNzA0 6 | MDUyMDAwMTBaFw0zNzAzMzEyMDAwMTBaMIGOMQswCQYDVQQGEwJJTDEPMA0GA1UE 7 | CAwGQ2VudGVyMQwwCgYDVQQHDANMb2QxEDAOBgNVBAoMB0dvUHJveHkxEDAOBgNV 8 | BAsMB0dvUHJveHkxGjAYBgNVBAMMEWdvcHJveHkuZ2l0aHViLmlvMSAwHgYJKoZI 9 | hvcNAQkBFhFlbGF6YXJsQGdtYWlsLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP 10 | ADCCAgoCggIBAJ4Qy+H6hhoY1s0QRcvIhxrjSHaO/RbaFj3rwqcnpOgFq07gRdI9 11 | 3c0TFKQJHpgv6feLRhEvX/YllFYu4J35lM9ZcYY4qlKFuStcX8Jm8fqpgtmAMBzP 12 | sqtqDi8M9RQGKENzU9IFOnCV7SAeh45scMuI3wz8wrjBcH7zquHkvqUSYZz035t9 13 | V6WTrHyTEvT4w+lFOVN2bA/6DAIxrjBiF6DhoJqnha0SZtDfv77XpwGG3EhA/qoh 14 | hiYrDruYK7zJdESQL44LwzMPupVigqalfv+YHfQjbhT951IVurW2NJgRyBE62dLr 15 | lHYdtT9tCTCrd+KJNMJ+jp9hAjdIu1Br/kifU4F4+4ZLMR9Ueji0GkkPKsYdyMnq 16 | j0p0PogyvP1l4qmboPImMYtaoFuYmMYlebgC9LN10bL91K4+jLt0I1YntEzrqgJo 17 | WsJztYDw543NzSy5W+/cq4XRYgtq1b0RWwuUiswezmMoeyHZ8BQJe2xMjAOllASD 18 | fqa8OK3WABHJpy4zUrnUBiMuPITzD/FuDx4C5IwwlC68gHAZblNqpBZCX0nFCtKj 19 | YOcI2So5HbQ2OC8QF+zGVuduHUSok4hSy2BBfZ1pfvziqBeetWJwFvapGB44nIHh 20 | WKNKvqOxLNIy7e+TGRiWOomrAWM18VSR9LZbBxpJK7PLSzWqYJYTRCZHAgMBAAGj 21 | UzBRMB0GA1UdDgQWBBR4uDD9Y6x7iUoHO+32ioOcw1ICZTAfBgNVHSMEGDAWgBR4 22 | uDD9Y6x7iUoHO+32ioOcw1ICZTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB 23 | CwUAA4ICAQAaCEupzGGqcdh+L7BzhX7zyd7yzAKUoLxFrxaZY34Xyj3lcx1XoK6F 24 | AqsH2JM25GixgadzhNt92JP7vzoWeHZtLfstrPS638Y1zZi6toy4E49viYjFk5J0 25 | C6ZcFC04VYWWx6z0HwJuAS08tZ37JuFXpJGfXJOjZCQyxse0Lg0tuKLMeXDCk2Y3 26 | Ba0noeuNyHRoWXXPyiUoeApkVCU5gIsyiJSWOjhJ5hpJG06rQNfNYexgKrrraEin 27 | o0jmEMtJMx5TtD83hSnLCnFGBBq5lkE7jgXME1KsbIE3lJZzRX1mQwUK8CJDYxye 28 | i6M/dzSvy0SsPvz8fTAlprXRtWWtJQmxgWENp3Dv+0Pmux/l+ilk7KA4sMXGhsfr 29 | bvTOeWl1/uoFTPYiWR/ww7QEPLq23yDFY04Q7Un0qjIk8ExvaY8lCkXMgc8i7sGY 30 | VfvOYb0zm67EfAQl3TW8Ky5fl5CcxpVCD360Bzi6hwjYixa3qEeBggOixFQBFWft 31 | 8wrkKTHpOQXjn4sDPtet8imm9UYEtzWrFX6T9MFYkBR0/yye0FIh9+YPiTA6WB86 32 | NCNwK5Yl6HuvF97CIH5CdgO+5C7KifUtqTOL8pQKbNwy0S3sNYvB+njGvRpR7pKV 33 | BUnFpB/Atptqr4CUlTXrc5IPLAqAfmwk5IKcwy3EXUbruf9Dwz69YA== 34 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /socks5-proxies.json: -------------------------------------------------------------------------------- 1 | { 2 | "Proxies": [ 3 | "127.0.0.1:55555", 4 | "127.0.0.1:55556", 5 | "127.0.0.1:55557", 6 | "127.0.0.1:55558", 7 | "127.0.0.1:55559" 8 | ] 9 | } -------------------------------------------------------------------------------- /useragents.json: -------------------------------------------------------------------------------- 1 | { 2 | "UserAgents": [ 3 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", 4 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0", 5 | "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", 6 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", 7 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1 Safari/605.1.15", 8 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", 9 | "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:59.0) Gecko/20100101 Firefox/59.0", 10 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", 11 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", 12 | "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0", 13 | "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", 14 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299", 15 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:59.0) Gecko/20100101 Firefox/59.0", 16 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/604.5.6 (KHTML, like Gecko) Version/11.0.3 Safari/604.5.6", 17 | "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", 18 | "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko", 19 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", 20 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36", 21 | "Mozilla/5.0 (X11; Linux x86_64; rv:59.0) Gecko/20100101 Firefox/59.0", 22 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", 23 | "Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0", 24 | "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko", 25 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", 26 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1 Safari/605.1.15", 27 | "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", 28 | "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", 29 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:59.0) Gecko/20100101 Firefox/59.0", 30 | "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/65.0.3325.181 Chrome/65.0.3325.181 Safari/537.36", 31 | "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", 32 | "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.106 Safari/537.36", 33 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", 34 | "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:52.0) Gecko/20100101 Firefox/52.0", 35 | "Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:59.0) Gecko/20100101 Firefox/59.0", 36 | "Mozilla/5.0 (Windows NT 6.1; rv:59.0) Gecko/20100101 Firefox/59.0", 37 | "Mozilla/5.0 (iPad; CPU OS 11_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.0 Mobile/15E148 Safari/604.1", 38 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0", 39 | "Mozilla/5.0 (Windows NT 6.1; rv:52.0) Gecko/20100101 Firefox/52.0", 40 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0", 41 | "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", 42 | "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", 43 | "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0; Trident/5.0)", 44 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1 Safari/605.1.15", 45 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.64", 46 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", 47 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/604.4.7 (KHTML, like Gecko) Version/11.0.2 Safari/604.4.7", 48 | "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:59.0) Gecko/20100101 Firefox/59.0", 49 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.40", 50 | "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36", 51 | "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; Trident/5.0)", 52 | "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", 53 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:59.0) Gecko/20100101 Firefox/59.0", 54 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36", 55 | "Mozilla/5.0 (Windows NT 6.1; Trident/7.0; rv:11.0) like Gecko", 56 | "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", 57 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/604.5.6 (KHTML, like Gecko) Version/11.0.3 Safari/604.5.6", 58 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36", 59 | "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", 60 | "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0", 61 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", 62 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36", 63 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/604.3.5 (KHTML, like Gecko) Version/11.0.1 Safari/604.3.5", 64 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:57.0) Gecko/20100101 Firefox/57.0", 65 | "Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:59.0) Gecko/20100101 Firefox/59.0", 66 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36", 67 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36", 68 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36 Edge/14.14393", 69 | "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:56.0) Gecko/20100101 Firefox/56.0", 70 | "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:59.0) Gecko/20100101 Firefox/59.0", 71 | "Mozilla/5.0 (iPad; CPU OS 11_2_6 like Mac OS X) AppleWebKit/604.5.6 (KHTML, like Gecko) Version/11.0 Mobile/15D100 Safari/604.1", 72 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:60.0) Gecko/20100101 Firefox/60.0", 73 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8", 74 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36", 75 | "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36", 76 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", 77 | "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36", 78 | "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:52.0) Gecko/20100101 Firefox/52.0", 79 | "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko", 80 | "Mozilla/5.0 (Windows NT 5.1; rv:52.0) Gecko/20100101 Firefox/52.0", 81 | "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 OPR/52.0.2871.64", 82 | "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0", 83 | "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv11.0) like Gecko", 84 | "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36" 85 | ] 86 | } -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2010-2016 Google, Inc. http://angularjs.org 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/README.md: -------------------------------------------------------------------------------- 1 | # SOCKS 2 | [![Build Status](https://travis-ci.org/eahydra/socks.svg?branch=master)](https://travis-ci.org/eahydra/socks) [![GoDoc](https://godoc.org/github.com/eahydra/socks?status.svg)](https://godoc.org/github.com/eahydra/socks) 3 | 4 | SOCKS implements SOCKS4/5 Proxy Protocol and HTTP Tunnel which can help you get through firewall. 5 | The [cmd/socksd](https://github.com/eahydra/socks/blob/master/cmd/socksd) build with package SOCKS, supports cipher connection which crypto method is rc4, des, aes-128-cfb, aes-192-cfb and aes-256-cfb, upstream which can be shadowsocks or socsk5. 6 | 7 | # Install 8 | Assume you have go installed, you can install from source. 9 | ``` 10 | go get github.com/eahydra/socks 11 | ``` 12 | 13 | If you want to install [cmd/socksd](https://github.com/eahydra/socks/blob/master/cmd/socksd), please read the [README.md](https://github.com/eahydra/socks/blob/master/cmd/socksd/README.md) -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/cmd/socksd/README.md: -------------------------------------------------------------------------------- 1 | # SOCKS 2 | [![Build Status](https://travis-ci.org/eahydra/socks.svg?branch=master)](https://travis-ci.org/eahydra/socks) 3 | 4 | The cmd/socksd build with package SOCKS, supports cipher connection which crypto method is rc4, des, aes-128-cfb, aes-192-cfb and aes-256-cfb, upstream which can be shadowsocks or socsk5. 5 | 6 | # Install 7 | Assume you have go installed, you can install from source. 8 | ``` 9 | go get github.com/eahydra/socks/cmd/socksd 10 | ``` 11 | 12 | # Usage 13 | Configuration file is in json format. The file must name **socks.config** and put it with socksd together. 14 | Configuration parameters as follows: 15 | ```json 16 | { 17 | "pac":{ 18 | "address":"127.0.0.1:50000", 19 | "proxy":"127.0.0.1:40000", 20 | "socks5":"127.0.0.1:8000", 21 | "local_rule_file":"gfw.txt", 22 | "remote_rule_file":"https://raw.githubusercontent.com/Leask/BRICKS/master/gfw.bricks", 23 | "upstream":{ 24 | "type":"shadowsocks", 25 | "crypto": "aes-256-cfb", 26 | "password": "111222333", 27 | "address": "106.182.12.24:10089" 28 | } 29 | }, 30 | "proxies":[ 31 | { 32 | "http":":40000", 33 | "socks4": ":9000", 34 | "socks5": ":8000", 35 | "upstreams": [ 36 | { 37 | "type":"shadowsocks", 38 | "crypto": "aes-256-cfb", 39 | "password": "111222333", 40 | "address": "106.182.12.24:10089" 41 | } 42 | ] 43 | } 44 | ] 45 | } 46 | 47 | ``` 48 | 49 | * **pac** - PAC config 50 | * **address** - Specifies the PAC server (127.0.0.1:50000) 51 | * **proxy** - (OPTIONAL) Enable HTTP Proxy in PAC 52 | * **socks5** - (OPTIONAL) Enable SOCKS5 Proxy in PAC 53 | * **local_rule_file** - (OPTIONAL) Local PAC rule file that per line is domain 54 | * **remote_rule_file** - (OPTIONAL) Remote PAC rule file like as [bricks](https://raw.githubusercontent.com/Leask/BRICKS/master/gfw.bricks) 55 | * **upstream** - (OPTIONAL) Through upstream to get **remote_rule_file** 56 | * **proxies** - The array of proxy config item 57 | * **http** - (OPTIONAL) Enable http proxy tunnel (127.0.0.1:8080 or :8080) 58 | * **socks4** - (OPTIONAL) Enable SOCKS4 proxy (127.0.0.1:9090 or :9090) 59 | * **socks5** - (OPTIONAL) Enable SOCKS5 proxy (127.0.0.1:9999 or :9999) 60 | * **crypto** - (OPTIONAL) SOCKS5's crypto method, now supports rc4, des, aes-128-cfb, aes-192-cfb and aes-256-cfb 61 | * **password** - If you set **crypto**, you must also set passsword 62 | * **dnsCacheTimeout** - (OPTIONAL) Enable dns cache (unit is second) 63 | * **upstreams** - The array of **upstream** 64 | * **upstream** 65 | * **type** - Specifies the type of upstream proxy server. Now supports shadowsocks and socks5 66 | * **crypto** - Specifies the crypto method of upstream proxy server. The crypto method is same as **localCryptoMethod** 67 | * **password** - Specifies the crypto password of upstream proxy server 68 | * **address** - Specifies the address of upstream proxy server (8.8.8.8:1111) 69 | -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/cmd/socksd/cipher.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/aes" 5 | "crypto/cipher" 6 | "crypto/des" 7 | "crypto/md5" 8 | "crypto/rand" 9 | "crypto/rc4" 10 | "io" 11 | 12 | "github.com/codahale/chacha20" 13 | ) 14 | 15 | func md5sum(d []byte) []byte { 16 | h := md5.New() 17 | h.Write(d) 18 | return h.Sum(nil) 19 | } 20 | 21 | func evpBytesToKey(password []byte, keylen int) (key []byte) { 22 | const md5len = 16 23 | cnt := (keylen-1)/md5len + 1 24 | m := make([]byte, cnt*md5len) 25 | copy(m, md5sum(password)) 26 | 27 | d := make([]byte, md5len+len(password)) 28 | start := 0 29 | for i := 1; i < cnt; i++ { 30 | start += md5len 31 | copy(d, m[start-md5len:start]) 32 | copy(d[md5len:], password) 33 | copy(m[start:], md5sum(d)) 34 | } 35 | return m[:keylen] 36 | } 37 | 38 | type RC4Cipher struct { 39 | *cipher.StreamReader 40 | *cipher.StreamWriter 41 | } 42 | 43 | func NewRC4Cipher(rwc io.ReadWriteCloser, password []byte) (*RC4Cipher, error) { 44 | decryptCipher, err := rc4.NewCipher(password) 45 | if err != nil { 46 | return nil, err 47 | } 48 | encryptCipher, err := rc4.NewCipher(password) 49 | if err != nil { 50 | return nil, err 51 | } 52 | return &RC4Cipher{ 53 | StreamReader: &cipher.StreamReader{ 54 | S: decryptCipher, 55 | R: rwc, 56 | }, 57 | StreamWriter: &cipher.StreamWriter{ 58 | S: encryptCipher, 59 | W: rwc, 60 | }, 61 | }, nil 62 | } 63 | 64 | type Chacha20Cipher struct { 65 | password []byte 66 | rwc io.ReadWriteCloser 67 | *cipher.StreamReader 68 | *cipher.StreamWriter 69 | } 70 | 71 | func NewChacha20Cipher(rwc io.ReadWriteCloser, password []byte) (*Chacha20Cipher, error) { 72 | password = evpBytesToKey(password, chacha20.KeySize) 73 | return &Chacha20Cipher{ 74 | rwc: rwc, 75 | password: password, 76 | }, nil 77 | } 78 | 79 | func (c *Chacha20Cipher) Read(p []byte) (n int, err error) { 80 | if c.StreamReader == nil { 81 | iv := make([]byte, chacha20.NonceSize) 82 | n, err = io.ReadFull(c.rwc, iv) 83 | if err != nil { 84 | return n, err 85 | } 86 | stream, err := chacha20.New(c.password, iv) 87 | if err != nil { 88 | return n, err 89 | } 90 | 91 | c.StreamReader = &cipher.StreamReader{ 92 | S: stream, 93 | R: c.rwc, 94 | } 95 | } 96 | return c.StreamReader.Read(p) 97 | } 98 | 99 | func (c *Chacha20Cipher) Write(p []byte) (n int, err error) { 100 | if c.StreamWriter == nil { 101 | iv := make([]byte, chacha20.NonceSize) 102 | _, err = rand.Read(iv) 103 | if err != nil { 104 | return 0, err 105 | } 106 | stream, err := chacha20.New(c.password, iv) 107 | if err != nil { 108 | return n, err 109 | } 110 | c.StreamWriter = &cipher.StreamWriter{ 111 | S: stream, 112 | W: c.rwc, 113 | } 114 | n, err := c.rwc.Write(iv) 115 | if err != nil { 116 | return n, err 117 | } 118 | } 119 | return c.StreamWriter.Write(p) 120 | } 121 | 122 | type DESCFBCipher struct { 123 | block cipher.Block 124 | rwc io.ReadWriteCloser 125 | *cipher.StreamReader 126 | *cipher.StreamWriter 127 | } 128 | 129 | func NewDESCFBCipher(rwc io.ReadWriteCloser, password []byte) (*DESCFBCipher, error) { 130 | block, err := des.NewCipher(password) 131 | if err != nil { 132 | return nil, err 133 | } 134 | 135 | return &DESCFBCipher{ 136 | block: block, 137 | rwc: rwc, 138 | }, nil 139 | } 140 | 141 | func (d *DESCFBCipher) Read(p []byte) (n int, err error) { 142 | if d.StreamReader == nil { 143 | iv := make([]byte, d.block.BlockSize()) 144 | n, err = io.ReadFull(d.rwc, iv) 145 | if err != nil { 146 | return n, err 147 | } 148 | stream := cipher.NewCFBDecrypter(d.block, iv) 149 | d.StreamReader = &cipher.StreamReader{ 150 | S: stream, 151 | R: d.rwc, 152 | } 153 | } 154 | return d.StreamReader.Read(p) 155 | } 156 | 157 | func (d *DESCFBCipher) Write(p []byte) (n int, err error) { 158 | if d.StreamWriter == nil { 159 | iv := make([]byte, d.block.BlockSize()) 160 | _, err = rand.Read(iv) 161 | if err != nil { 162 | return 0, err 163 | } 164 | stream := cipher.NewCFBEncrypter(d.block, iv) 165 | d.StreamWriter = &cipher.StreamWriter{ 166 | S: stream, 167 | W: d.rwc, 168 | } 169 | n, err := d.rwc.Write(iv) 170 | if err != nil { 171 | return n, err 172 | } 173 | } 174 | return d.StreamWriter.Write(p) 175 | } 176 | 177 | func (d *DESCFBCipher) Close() error { 178 | if d.StreamWriter != nil { 179 | d.StreamWriter.Close() 180 | } 181 | if d.rwc != nil { 182 | d.rwc.Close() 183 | } 184 | return nil 185 | } 186 | 187 | type AESCFBCipher struct { 188 | rwc io.ReadWriteCloser 189 | iv []byte 190 | block cipher.Block 191 | *cipher.StreamReader 192 | *cipher.StreamWriter 193 | } 194 | 195 | func NewAESCFGCipher(rwc io.ReadWriteCloser, password []byte, bit int) (*AESCFBCipher, error) { 196 | block, err := aes.NewCipher(evpBytesToKey(password, bit)) 197 | if err != nil { 198 | return nil, err 199 | } 200 | return &AESCFBCipher{ 201 | block: block, 202 | rwc: rwc, 203 | }, nil 204 | } 205 | 206 | func (a *AESCFBCipher) Read(p []byte) (n int, err error) { 207 | if a.StreamReader == nil { 208 | iv := make([]byte, a.block.BlockSize()) 209 | n, err = io.ReadFull(a.rwc, iv) 210 | if err != nil { 211 | return n, err 212 | } 213 | stream := cipher.NewCFBDecrypter(a.block, iv) 214 | a.StreamReader = &cipher.StreamReader{ 215 | S: stream, 216 | R: a.rwc, 217 | } 218 | } 219 | return a.StreamReader.Read(p) 220 | } 221 | 222 | func (a *AESCFBCipher) Write(p []byte) (n int, err error) { 223 | if a.StreamWriter == nil { 224 | iv := make([]byte, a.block.BlockSize()) 225 | _, err = rand.Read(iv) 226 | if err != nil { 227 | return 0, err 228 | } 229 | stream := cipher.NewCFBEncrypter(a.block, iv) 230 | a.StreamWriter = &cipher.StreamWriter{ 231 | S: stream, 232 | W: a.rwc, 233 | } 234 | n, err := a.rwc.Write(iv) 235 | if err != nil { 236 | return n, err 237 | } 238 | } 239 | return a.StreamWriter.Write(p) 240 | } 241 | 242 | func (a *AESCFBCipher) Close() error { 243 | if a.StreamWriter != nil { 244 | a.StreamWriter.Close() 245 | } 246 | if a.rwc != nil { 247 | a.rwc.Close() 248 | } 249 | return nil 250 | } 251 | -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/cmd/socksd/cipher_conn.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io" 5 | "net" 6 | "strings" 7 | ) 8 | 9 | type CipherConn struct { 10 | net.Conn 11 | rwc io.ReadWriteCloser 12 | } 13 | 14 | func (c *CipherConn) Read(data []byte) (int, error) { 15 | return c.rwc.Read(data) 16 | } 17 | 18 | func (c *CipherConn) Write(data []byte) (int, error) { 19 | return c.rwc.Write(data) 20 | } 21 | 22 | func (c *CipherConn) Close() error { 23 | err := c.Conn.Close() 24 | c.rwc.Close() 25 | return err 26 | } 27 | 28 | func NewCipherConn(conn net.Conn, cryptMethod string, password []byte) (*CipherConn, error) { 29 | var rwc io.ReadWriteCloser 30 | var err error 31 | switch strings.ToLower(cryptMethod) { 32 | default: 33 | rwc = conn 34 | case "rc4": 35 | rwc, err = NewRC4Cipher(conn, password) 36 | case "des": 37 | rwc, err = NewDESCFBCipher(conn, password) 38 | case "aes-128-cfb": 39 | rwc, err = NewAESCFGCipher(conn, password, 16) 40 | case "aes-192-cfb": 41 | rwc, err = NewAESCFGCipher(conn, password, 24) 42 | case "aes-256-cfb": 43 | rwc, err = NewAESCFGCipher(conn, password, 32) 44 | case "chacha20": 45 | rwc, err = NewChacha20Cipher(conn, password) 46 | } 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | return &CipherConn{ 52 | Conn: conn, 53 | rwc: rwc, 54 | }, nil 55 | } 56 | 57 | func NewCipherConnDecorator(cryptoMethod, password string) ConnDecorator { 58 | return func(conn net.Conn) (net.Conn, error) { 59 | return NewCipherConn(conn, cryptoMethod, []byte(password)) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/cmd/socksd/config.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "io/ioutil" 6 | ) 7 | 8 | type Upstream struct { 9 | Type string `json:"type"` 10 | Crypto string `json:"crypto"` 11 | Password string `json:"password"` 12 | Address string `json:"address"` 13 | } 14 | 15 | type PAC struct { 16 | Address string `json:"address"` 17 | Proxy string `json:"proxy"` 18 | SOCKS5 string `json:"socks5"` 19 | LocalRules string `json:"local_rule_file"` 20 | RemoteRules string `json:"remote_rule_file"` 21 | Upstream Upstream `json:"upstream"` 22 | } 23 | 24 | type Proxy struct { 25 | HTTP string `json:"http"` 26 | SOCKS4 string `json:"socks4"` 27 | SOCKS5 string `json:"socks5"` 28 | Crypto string `json:"crypto"` 29 | Password string `json:"password"` 30 | DNSCacheTimeout int `json:"dnsCacheTimeout"` 31 | Upstreams []Upstream `json:"upstreams"` 32 | } 33 | 34 | type Config struct { 35 | PAC PAC `json:"pac"` 36 | Proxies []Proxy `json:"proxies"` 37 | } 38 | 39 | func LoadConfig(s string) (*Config, error) { 40 | data, err := ioutil.ReadFile(s) 41 | if err != nil { 42 | return nil, err 43 | } 44 | cfgGroup := &Config{} 45 | if err = json.Unmarshal(data, cfgGroup); err != nil { 46 | return nil, err 47 | } 48 | return cfgGroup, nil 49 | } 50 | -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/cmd/socksd/decorate_client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net" 5 | 6 | "github.com/eahydra/socks" 7 | ) 8 | 9 | type DecorateClient struct { 10 | forward socks.Dialer 11 | decorators []ConnDecorator 12 | } 13 | 14 | func NewDecorateClient(forward socks.Dialer, ds ...ConnDecorator) *DecorateClient { 15 | d := &DecorateClient{ 16 | forward: forward, 17 | } 18 | d.decorators = append(d.decorators, ds...) 19 | return d 20 | } 21 | 22 | func (d *DecorateClient) Dial(network, address string) (net.Conn, error) { 23 | conn, err := d.forward.Dial(network, address) 24 | if err != nil { 25 | ErrLog.Println("DecorateClient forward.Dial failed, err:", err, address) 26 | return nil, err 27 | } 28 | dconn, err := DecorateConn(conn, d.decorators...) 29 | if err != nil { 30 | conn.Close() 31 | return nil, err 32 | } 33 | return dconn, nil 34 | } 35 | -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/cmd/socksd/decorate_conn.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "net" 4 | 5 | type ConnDecorator func(net.Conn) (net.Conn, error) 6 | 7 | func DecorateConn(conn net.Conn, ds ...ConnDecorator) (net.Conn, error) { 8 | decorated := conn 9 | var err error 10 | for _, decorate := range ds { 11 | decorated, err = decorate(decorated) 12 | if err != nil { 13 | return nil, err 14 | } 15 | } 16 | return decorated, nil 17 | } 18 | -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/cmd/socksd/decorate_direct.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net" 5 | 6 | "github.com/eahydra/socks" 7 | ) 8 | 9 | type DecorateDirect struct { 10 | dnsCache *DNSCache 11 | } 12 | 13 | func NewDecorateDirect(dnsCacheTime int) *DecorateDirect { 14 | var dnsCache *DNSCache 15 | if dnsCacheTime != 0 { 16 | dnsCache = NewDNSCache(dnsCacheTime) 17 | } 18 | return &DecorateDirect{ 19 | dnsCache: dnsCache, 20 | } 21 | } 22 | 23 | func parseAddress(address string) (interface{}, string, error) { 24 | host, port, err := net.SplitHostPort(address) 25 | if err != nil { 26 | return nil, "", err 27 | } 28 | ip := net.ParseIP(address) 29 | if ip != nil { 30 | return ip, port, nil 31 | } else { 32 | return host, port, nil 33 | } 34 | } 35 | 36 | func (d *DecorateDirect) Dial(network, address string) (net.Conn, error) { 37 | host, port, err := parseAddress(address) 38 | if err != nil { 39 | return nil, err 40 | } 41 | var dest string 42 | var ipCached bool 43 | switch h := host.(type) { 44 | case net.IP: 45 | { 46 | dest = h.String() 47 | ipCached = true 48 | } 49 | case string: 50 | { 51 | dest = h 52 | if d.dnsCache != nil { 53 | if p, ok := d.dnsCache.Get(h); ok { 54 | dest = p.String() 55 | ipCached = true 56 | } 57 | } 58 | } 59 | } 60 | address = net.JoinHostPort(dest, port) 61 | destConn, err := socks.Direct.Dial(network, address) 62 | if err != nil { 63 | return nil, err 64 | } 65 | 66 | if d.dnsCache != nil && !ipCached { 67 | d.dnsCache.Set(host.(string), destConn.RemoteAddr().(*net.TCPAddr).IP) 68 | } 69 | return destConn, nil 70 | } 71 | -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/cmd/socksd/decorate_listener.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "net" 4 | 5 | type DecorateListener struct { 6 | listener net.Listener 7 | decorators []ConnDecorator 8 | } 9 | 10 | func NewDecorateListener(listener net.Listener, ds ...ConnDecorator) *DecorateListener { 11 | l := &DecorateListener{ 12 | listener: listener, 13 | } 14 | l.decorators = append(l.decorators, ds...) 15 | return l 16 | } 17 | 18 | func (s *DecorateListener) Accept() (net.Conn, error) { 19 | conn, err := s.listener.Accept() 20 | if err != nil { 21 | return nil, err 22 | } 23 | dconn, err := DecorateConn(conn, s.decorators...) 24 | if err != nil { 25 | conn.Close() 26 | return nil, err 27 | } 28 | return dconn, nil 29 | } 30 | 31 | func (s *DecorateListener) Close() error { 32 | return s.listener.Close() 33 | } 34 | 35 | func (s *DecorateListener) Addr() net.Addr { 36 | return s.listener.Addr() 37 | } 38 | -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/cmd/socksd/dns_cache.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net" 5 | "sync" 6 | "time" 7 | ) 8 | 9 | type DNSCache struct { 10 | lock sync.RWMutex 11 | cacheTimeout time.Duration 12 | dns map[string]DNSElement 13 | } 14 | 15 | type DNSElement struct { 16 | ip net.IP 17 | startTime time.Time 18 | } 19 | 20 | func NewDNSCache(cacheTimeout int) *DNSCache { 21 | if cacheTimeout <= 0 { 22 | cacheTimeout = 30 23 | } 24 | return &DNSCache{ 25 | cacheTimeout: time.Duration(cacheTimeout) * time.Minute, 26 | dns: make(map[string]DNSElement), 27 | } 28 | } 29 | 30 | func (c *DNSCache) Get(domain string) (net.IP, bool) { 31 | c.lock.RLock() 32 | e, ok := c.dns[domain] 33 | c.lock.RUnlock() 34 | if ok && time.Since(e.startTime) > c.cacheTimeout { 35 | c.lock.Lock() 36 | delete(c.dns, domain) 37 | c.lock.Unlock() 38 | return nil, false 39 | } 40 | return e.ip, ok 41 | } 42 | 43 | func (c *DNSCache) Set(domain string, ip net.IP) { 44 | c.lock.Lock() 45 | c.dns[domain] = DNSElement{ip: ip, startTime: time.Now()} 46 | c.lock.Unlock() 47 | } 48 | -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/cmd/socksd/log.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "os" 6 | ) 7 | 8 | var ( 9 | InfoLog = log.New(os.Stdout, "INFO ", log.LstdFlags) 10 | ErrLog = log.New(os.Stderr, "ERROR ", log.LstdFlags) 11 | WarnLog = log.New(os.Stdout, "WARN ", log.LstdFlags) 12 | ) 13 | -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/cmd/socksd/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "flag" 7 | "net" 8 | "net/http" 9 | "os" 10 | "os/signal" 11 | "strings" 12 | 13 | "github.com/eahydra/socks" 14 | ) 15 | 16 | func main() { 17 | var configFile string 18 | flag.StringVar(&configFile, "c", "socks.config", "config file path") 19 | flag.Parse() 20 | 21 | conf, err := LoadConfig(configFile) 22 | if err != nil { 23 | ErrLog.Println("initGlobalConfig failed, err:", err) 24 | return 25 | } 26 | InfoLog.Println("load config succeeded") 27 | 28 | for _, c := range conf.Proxies { 29 | router := BuildUpstreamRouter(c) 30 | runHTTPProxyServer(c, router) 31 | runSOCKS4Server(c, router) 32 | runSOCKS5Server(c, router) 33 | } 34 | runPACServer(conf.PAC) 35 | 36 | sigChan := make(chan os.Signal, 1) 37 | signal.Notify(sigChan, os.Kill, os.Interrupt) 38 | <-sigChan 39 | } 40 | 41 | func BuildUpstream(upstream Upstream, forward socks.Dialer) (socks.Dialer, error) { 42 | cipherDecorator := NewCipherConnDecorator(upstream.Crypto, upstream.Password) 43 | forward = NewDecorateClient(forward, cipherDecorator) 44 | 45 | switch strings.ToLower(upstream.Type) { 46 | case "socks5": 47 | { 48 | return socks.NewSocks5Client("tcp", upstream.Address, "", "", forward) 49 | } 50 | case "shadowsocks": 51 | { 52 | return socks.NewShadowSocksClient("tcp", upstream.Address, forward) 53 | } 54 | } 55 | return nil, errors.New("unknown upstream type" + upstream.Type) 56 | } 57 | 58 | func BuildUpstreamRouter(conf Proxy) socks.Dialer { 59 | var allForward []socks.Dialer 60 | for _, upstream := range conf.Upstreams { 61 | var forward socks.Dialer 62 | var err error 63 | forward = NewDecorateDirect(conf.DNSCacheTimeout) 64 | forward, err = BuildUpstream(upstream, forward) 65 | if err != nil { 66 | ErrLog.Println("failed to BuildUpstream, err:", err) 67 | continue 68 | } 69 | allForward = append(allForward, forward) 70 | } 71 | if len(allForward) == 0 { 72 | router := NewDecorateDirect(conf.DNSCacheTimeout) 73 | allForward = append(allForward, router) 74 | } 75 | return NewUpstreamDialer(allForward) 76 | } 77 | 78 | func runHTTPProxyServer(conf Proxy, router socks.Dialer) { 79 | if conf.HTTP != "" { 80 | listener, err := net.Listen("tcp", conf.HTTP) 81 | if err != nil { 82 | ErrLog.Println("net.Listen at ", conf.HTTP, " failed, err:", err) 83 | return 84 | } 85 | go func() { 86 | defer listener.Close() 87 | httpProxy := socks.NewHTTPProxy(router) 88 | http.Serve(listener, httpProxy) 89 | }() 90 | } 91 | } 92 | 93 | func runSOCKS4Server(conf Proxy, forward socks.Dialer) { 94 | if conf.SOCKS4 != "" { 95 | listener, err := net.Listen("tcp", conf.SOCKS4) 96 | if err != nil { 97 | ErrLog.Println("net.Listen failed, err:", err, conf.SOCKS4) 98 | return 99 | } 100 | cipherDecorator := NewCipherConnDecorator(conf.Crypto, conf.Password) 101 | listener = NewDecorateListener(listener, cipherDecorator) 102 | socks4Svr, err := socks.NewSocks4Server(forward) 103 | if err != nil { 104 | listener.Close() 105 | ErrLog.Println("socks.NewSocks4Server failed, err:", err) 106 | } 107 | go func() { 108 | defer listener.Close() 109 | socks4Svr.Serve(listener) 110 | }() 111 | } 112 | } 113 | 114 | func runSOCKS5Server(conf Proxy, forward socks.Dialer) { 115 | if conf.SOCKS5 != "" { 116 | listener, err := net.Listen("tcp", conf.SOCKS5) 117 | if err != nil { 118 | ErrLog.Println("net.Listen failed, err:", err, conf.SOCKS5) 119 | return 120 | } 121 | cipherDecorator := NewCipherConnDecorator(conf.Crypto, conf.Password) 122 | listener = NewDecorateListener(listener, cipherDecorator) 123 | socks5Svr, err := socks.NewSocks5Server(forward) 124 | if err != nil { 125 | listener.Close() 126 | ErrLog.Println("socks.NewSocks5Server failed, err:", err) 127 | return 128 | } 129 | go func() { 130 | defer listener.Close() 131 | socks5Svr.Serve(listener) 132 | }() 133 | } 134 | } 135 | 136 | func runPACServer(pac PAC) { 137 | pu, err := NewPACUpdater(pac) 138 | if err != nil { 139 | ErrLog.Println("failed to NewPACUpdater, err:", err) 140 | return 141 | } 142 | 143 | http.HandleFunc("/proxy.pac", func(w http.ResponseWriter, r *http.Request) { 144 | w.Header().Add("Content-Type", "application/x-ns-proxy-autoconfig") 145 | data, time := pu.get() 146 | reader := bytes.NewReader(data) 147 | http.ServeContent(w, r, "proxy.pac", time, reader) 148 | }) 149 | go http.ListenAndServe(pac.Address, nil) 150 | } 151 | -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/cmd/socksd/pac_generator.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "sort" 7 | "text/template" 8 | ) 9 | 10 | var pacTemplate = ` 11 | var proxy = "{{if .Socks5}}SOCKS5 {{.Socks5}};{{end}}{{if .Proxy}}PROXY {{.Proxy}}{{end}};"; 12 | 13 | var domains = { 14 | {{.Rules}} 15 | }; 16 | 17 | var hasOwnProperty = Object.hasOwnProperty; 18 | 19 | function FindProxyForURL(url, host) { 20 | if (isPlainHostName(host) || host === '127.0.0.1' || host === 'localhost') { 21 | return 'DIRECT'; 22 | } 23 | var suffix; 24 | var pos = host.lastIndexOf('.'); 25 | while(1) { 26 | suffix = host.substring(pos + 1); 27 | if (hasOwnProperty.call(domains, suffix)) { 28 | return proxy; 29 | } 30 | if (pos <= 0) { 31 | break; 32 | } 33 | pos = host.lastIndexOf('.', pos - 1); 34 | } 35 | return 'DIRECT'; 36 | } 37 | ` 38 | 39 | type PACGenerator struct { 40 | filter map[string]bool 41 | rules []string 42 | proxy string 43 | socks5 string 44 | } 45 | 46 | func NewPACGenerator(proxy, socks5 string) *PACGenerator { 47 | return &PACGenerator{ 48 | filter: make(map[string]bool), 49 | proxy: proxy, 50 | socks5: socks5, 51 | } 52 | } 53 | 54 | func (p *PACGenerator) Generate(rules []string) ([]byte, error) { 55 | for _, v := range rules { 56 | if _, ok := p.filter[v]; !ok { 57 | p.filter[v] = true 58 | p.rules = append(p.rules, v) 59 | } 60 | } 61 | sort.Strings(p.rules) 62 | 63 | s := "" 64 | for n, v := range p.rules { 65 | s += fmt.Sprintf("'%s' : 1", v) 66 | if n+1 != len(p.rules) { 67 | s += "," 68 | } 69 | } 70 | 71 | data := struct { 72 | Proxy string 73 | Socks5 string 74 | Rules string 75 | }{ 76 | Proxy: p.proxy, 77 | Socks5: p.socks5, 78 | Rules: s, 79 | } 80 | t, err := template.New("proxy.pac").Parse(pacTemplate) 81 | if err != nil { 82 | ErrLog.Println("failed to parse pacTempalte, err:", err) 83 | } 84 | buff := bytes.NewBuffer(nil) 85 | err = t.Execute(buff, &data) 86 | if err != nil { 87 | return nil, err 88 | } 89 | return buff.Bytes(), nil 90 | } 91 | -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/cmd/socksd/pac_updater.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "io" 6 | "net/http" 7 | "os" 8 | "sync" 9 | "time" 10 | 11 | "github.com/eahydra/socks" 12 | ) 13 | 14 | type PACUpdater struct { 15 | pac PAC 16 | lock sync.RWMutex 17 | data []byte 18 | modtime time.Time 19 | timer *time.Timer 20 | } 21 | 22 | func NewPACUpdater(pac PAC) (*PACUpdater, error) { 23 | p := &PACUpdater{ 24 | pac: pac, 25 | } 26 | go p.backgroundUpdate() 27 | return p, nil 28 | } 29 | 30 | func parseRule(reader io.Reader) ([]string, error) { 31 | var err error 32 | var line []byte 33 | var rules []string 34 | r := bufio.NewReader(reader) 35 | for line, _, err = r.ReadLine(); err == nil; line, _, err = r.ReadLine() { 36 | s := string(line) 37 | if s != "" { 38 | rules = append(rules, s) 39 | } 40 | } 41 | if err == io.EOF { 42 | err = nil 43 | } 44 | return rules, err 45 | } 46 | 47 | func loadLocalRule(filepath string) ([]string, error) { 48 | f, err := os.OpenFile(filepath, os.O_RDONLY, os.ModePerm) 49 | if err != nil { 50 | return nil, err 51 | } 52 | defer f.Close() 53 | return parseRule(f) 54 | } 55 | 56 | func loadRemoteRule(ruleURL string, upstream Upstream) ([]string, error) { 57 | forward, err := BuildUpstream(upstream, socks.Direct) 58 | if err != nil { 59 | return nil, err 60 | } 61 | client := &http.Client{ 62 | Transport: &http.Transport{ 63 | Dial: forward.Dial, 64 | }, 65 | } 66 | resp, err := client.Get(ruleURL) 67 | if err != nil { 68 | return nil, err 69 | } 70 | defer resp.Body.Close() 71 | return parseRule(resp.Body) 72 | } 73 | 74 | func (p *PACUpdater) get() ([]byte, time.Time) { 75 | p.lock.RLock() 76 | defer p.lock.RUnlock() 77 | d := make([]byte, len(p.data)) 78 | copy(d, p.data) 79 | return d, p.modtime 80 | } 81 | 82 | func (p *PACUpdater) set(data []byte) { 83 | p.lock.Lock() 84 | defer p.lock.Unlock() 85 | p.data = make([]byte, len(data)) 86 | copy(p.data, data) 87 | p.modtime = time.Now() 88 | } 89 | 90 | func (p *PACUpdater) backgroundUpdate() { 91 | pg := NewPACGenerator(p.pac.Proxy, p.pac.SOCKS5) 92 | for { 93 | duration := 1 * time.Minute 94 | if rules, err := loadLocalRule(p.pac.LocalRules); err == nil { 95 | if data, err := pg.Generate(rules); err == nil { 96 | p.set(data) 97 | InfoLog.Println("update rules from", p.pac.LocalRules, "succeeded") 98 | } 99 | } 100 | 101 | if rules, err := loadRemoteRule(p.pac.RemoteRules, p.pac.Upstream); err == nil { 102 | if data, err := pg.Generate(rules); err == nil { 103 | p.set(data) 104 | duration = 1 * time.Hour 105 | InfoLog.Println("update rules from", p.pac.RemoteRules, "succeeded") 106 | } 107 | } 108 | time.Sleep(duration) 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/cmd/socksd/upstream_client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "net" 5 | "sync/atomic" 6 | 7 | "github.com/eahydra/socks" 8 | ) 9 | 10 | type UpstreamDialer struct { 11 | nextRouter uint64 12 | forwardDialers []socks.Dialer 13 | } 14 | 15 | func NewUpstreamDialer(forwardDialers []socks.Dialer) *UpstreamDialer { 16 | return &UpstreamDialer{ 17 | forwardDialers: forwardDialers, 18 | } 19 | } 20 | 21 | func (u *UpstreamDialer) getNextDialer() socks.Dialer { 22 | old := atomic.AddUint64(&u.nextRouter, 1) 23 | return u.forwardDialers[old%uint64(len(u.forwardDialers))] 24 | } 25 | 26 | func (u *UpstreamDialer) Dial(network, address string) (net.Conn, error) { 27 | router := u.getNextDialer() 28 | conn, err := router.Dial(network, address) 29 | if err != nil { 30 | ErrLog.Println("UpstreamDialer router.Dial failed, err:", err, network, address) 31 | return nil, err 32 | } 33 | return conn, nil 34 | } 35 | -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/direct.go: -------------------------------------------------------------------------------- 1 | package socks 2 | 3 | import "net" 4 | 5 | // A Dialer is a means to establish a connection. 6 | type Dialer interface { 7 | // Dial connects to the given address via the proxy. 8 | Dial(network, address string) (net.Conn, error) 9 | } 10 | 11 | type direct struct{} 12 | 13 | // Direct is a direct proxy which implements Dialer interface: one that makes connections directly. 14 | var Direct = direct{} 15 | 16 | func (direct) Dial(network, address string) (net.Conn, error) { 17 | return net.Dial(network, address) 18 | } 19 | -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/example_test.go: -------------------------------------------------------------------------------- 1 | package socks 2 | 3 | import ( 4 | "net" 5 | "net/http" 6 | "net/http/httputil" 7 | ) 8 | 9 | func ExampleSocks5Client() { 10 | user := "" 11 | password := "" 12 | client, err := NewSocks5Client("tcp", "127.0.0.1:1080", user, password, Direct) 13 | if err != nil { 14 | return 15 | } 16 | conn, err := client.Dial("tcp", "www.google.com:80") 17 | if err != nil { 18 | return 19 | } 20 | httpClient := httputil.NewClientConn(conn, nil) 21 | defer httpClient.Close() 22 | 23 | request, err := http.NewRequest("GET", "/", nil) 24 | if err != nil { 25 | return 26 | } 27 | resp, err := httpClient.Do(request) 28 | if err != nil { 29 | return 30 | } 31 | dump, err := httputil.DumpResponse(resp, true) 32 | if err != nil { 33 | return 34 | } 35 | println(string(dump)) 36 | return 37 | } 38 | 39 | func ExampleSocks5Server() { 40 | listener, err := net.Listen("tcp", ":1080") 41 | if err != nil { 42 | return 43 | } 44 | defer listener.Close() 45 | 46 | if server, err := NewSocks5Server(Direct); err == nil { 47 | server.Serve(listener) 48 | } 49 | } 50 | 51 | func ExampleSocks4Client() { 52 | user := "" 53 | client, err := NewSocks4Client("tcp", "127.0.0.1:1080", user, Direct) 54 | if err != nil { 55 | return 56 | } 57 | addrs, err := net.LookupHost("www.google.com") 58 | if err != nil { 59 | return 60 | } 61 | if len(addrs) == 0 { 62 | return 63 | } 64 | conn, err := client.Dial("tcp", addrs[0]+":80") 65 | if err != nil { 66 | return 67 | } 68 | httpClient := httputil.NewClientConn(conn, nil) 69 | defer httpClient.Close() 70 | 71 | request, err := http.NewRequest("GET", "/", nil) 72 | if err != nil { 73 | return 74 | } 75 | resp, err := httpClient.Do(request) 76 | if err != nil { 77 | return 78 | } 79 | dump, err := httputil.DumpResponse(resp, true) 80 | if err != nil { 81 | return 82 | } 83 | println(string(dump)) 84 | return 85 | } 86 | 87 | func ExampleSocks4Server() { 88 | listener, err := net.Listen("tcp", ":1080") 89 | if err != nil { 90 | return 91 | } 92 | defer listener.Close() 93 | 94 | if server, err := NewSocks4Server(Direct); err == nil { 95 | server.Serve(listener) 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/http_proxy.go: -------------------------------------------------------------------------------- 1 | package socks 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "net" 7 | "net/http" 8 | "net/http/httputil" 9 | "net/url" 10 | ) 11 | 12 | // HTTPProxy is an HTTP Handler that serve CONNECT method and 13 | // route request to proxy server by Router. 14 | type HTTPProxy struct { 15 | *httputil.ReverseProxy 16 | forward Dialer 17 | } 18 | 19 | // NewHTTPProxy constructs one HTTPProxy 20 | func NewHTTPProxy(forward Dialer) *HTTPProxy { 21 | return &HTTPProxy{ 22 | ReverseProxy: &httputil.ReverseProxy{ 23 | Director: director, 24 | Transport: &http.Transport{ 25 | Dial: func(network, addr string) (net.Conn, error) { 26 | return forward.Dial(network, addr) 27 | }, 28 | }, 29 | }, 30 | forward: forward, 31 | } 32 | } 33 | 34 | func director(request *http.Request) { 35 | u, err := url.Parse(request.RequestURI) 36 | if err != nil { 37 | return 38 | } 39 | request.RequestURI = u.RequestURI() 40 | v := request.Header.Get("Proxy-Connection") 41 | if v != "" { 42 | request.Header.Del("Proxy-Connection") 43 | request.Header.Del("Connection") 44 | request.Header.Add("Connection", v) 45 | } 46 | } 47 | 48 | // ServeHTTPTunnel serve incoming request with CONNECT method, then route data to proxy server 49 | func (h *HTTPProxy) ServeHTTPTunnel(response http.ResponseWriter, request *http.Request) { 50 | var conn net.Conn 51 | if hj, ok := response.(http.Hijacker); ok { 52 | var err error 53 | if conn, _, err = hj.Hijack(); err != nil { 54 | http.Error(response, err.Error(), http.StatusInternalServerError) 55 | return 56 | } 57 | } else { 58 | http.Error(response, "Hijacker failed", http.StatusInternalServerError) 59 | return 60 | } 61 | defer conn.Close() 62 | 63 | dest, err := h.forward.Dial("tcp", request.Host) 64 | if err != nil { 65 | fmt.Fprintf(conn, "HTTP/1.0 500 NewRemoteSocks failed, err:%s\r\n\r\n", err) 66 | return 67 | } 68 | defer dest.Close() 69 | 70 | if request.Body != nil { 71 | if _, err = io.Copy(dest, request.Body); err != nil { 72 | fmt.Fprintf(conn, "%d %s", http.StatusBadGateway, err.Error()) 73 | return 74 | } 75 | } 76 | fmt.Fprintf(conn, "HTTP/1.0 200 Connection established\r\n\r\n") 77 | 78 | go func() { 79 | defer conn.Close() 80 | defer dest.Close() 81 | io.Copy(dest, conn) 82 | }() 83 | io.Copy(conn, dest) 84 | } 85 | 86 | // ServeHTTP implements HTTP Handler 87 | func (h *HTTPProxy) ServeHTTP(response http.ResponseWriter, request *http.Request) { 88 | if request.Method == "CONNECT" { 89 | h.ServeHTTPTunnel(response, request) 90 | } else { 91 | h.ReverseProxy.ServeHTTP(response, request) 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/shadowsocks_client.go: -------------------------------------------------------------------------------- 1 | package socks 2 | 3 | import ( 4 | "errors" 5 | "net" 6 | "strconv" 7 | ) 8 | 9 | // ShadowSocksClient implements ShadowSocks Proxy Protocol 10 | type ShadowSocksClient struct { 11 | network string 12 | address string 13 | forward Dialer 14 | } 15 | 16 | // NewShadowSocksClient return a new ShadowSocksClient that implements Dialer interface. 17 | func NewShadowSocksClient(network, address string, forward Dialer) (*ShadowSocksClient, error) { 18 | return &ShadowSocksClient{ 19 | network: network, 20 | address: address, 21 | forward: forward, 22 | }, nil 23 | } 24 | 25 | // Dial return a new net.Conn that through proxy server establish with address 26 | func (s *ShadowSocksClient) Dial(network, address string) (net.Conn, error) { 27 | switch network { 28 | case "tcp", "tcp4", "tcp6": 29 | default: 30 | return nil, errors.New("socks: no support ShadowSocks proxy connections of type: " + network) 31 | } 32 | 33 | host, portStr, err := net.SplitHostPort(address) 34 | if err != nil { 35 | return nil, err 36 | } 37 | port, err := strconv.Atoi(portStr) 38 | if err != nil { 39 | return nil, errors.New("socks: failed to parse port number:" + portStr) 40 | } 41 | if port < 1 || port > 0xffff { 42 | return nil, errors.New("socks5: port number out of range:" + portStr) 43 | } 44 | 45 | conn, err := s.forward.Dial(s.network, s.address) 46 | if err != nil { 47 | return nil, err 48 | } 49 | closeConn := &conn 50 | defer func() { 51 | if closeConn != nil { 52 | (*closeConn).Close() 53 | } 54 | }() 55 | 56 | buff := make([]byte, 0, 266) 57 | if ip := net.ParseIP(host); ip != nil { 58 | if ip4 := ip.To4(); ip4 != nil { 59 | buff = append(buff, 1) 60 | ip = ip4 61 | } else { 62 | buff = append(buff, 4) 63 | } 64 | buff = append(buff, ip...) 65 | } else { 66 | if len(host) > 255 { 67 | return nil, errors.New("socks: destination hostname too long: " + host) 68 | } 69 | buff = append(buff, 3) 70 | buff = append(buff, uint8(len(host))) 71 | buff = append(buff, host...) 72 | } 73 | buff = append(buff, uint8(port>>8), uint8(port)) 74 | 75 | _, err = conn.Write(buff) 76 | if err != nil { 77 | return nil, err 78 | } 79 | 80 | closeConn = nil 81 | return conn, nil 82 | } 83 | -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/socks4.go: -------------------------------------------------------------------------------- 1 | package socks 2 | 3 | import ( 4 | "bufio" 5 | "errors" 6 | "fmt" 7 | "io" 8 | "net" 9 | "strconv" 10 | ) 11 | 12 | const ( 13 | socks4Version = 4 14 | socks4Connect = 1 15 | socks4Granted = 90 16 | socks4Rejected = 91 17 | socks4ConnectFailed = 92 18 | socks4UserIDInvalid = 93 19 | ) 20 | 21 | var socks4Errors = []string{ 22 | "", 23 | "request rejected or failed", 24 | "request rejected because SOCKS server cannot connect to identd on the client", 25 | "request rejected because the client program and identd report different user-ids", 26 | } 27 | 28 | // Socks4Server implements Socks4 Proxy Protocol(http://www.openssh.com/txt/socks4.protocol). 29 | // Just support CONNECT command. 30 | type Socks4Server struct { 31 | forward Dialer 32 | } 33 | 34 | // NewSocks4Server returns a new Socks4Server that can serve from new clients. 35 | func NewSocks4Server(forward Dialer) (*Socks4Server, error) { 36 | return &Socks4Server{ 37 | forward: forward, 38 | }, nil 39 | } 40 | 41 | // Serve with net.Listener for clients. 42 | func (s *Socks4Server) Serve(listener net.Listener) error { 43 | for { 44 | conn, err := listener.Accept() 45 | if err != nil { 46 | if netErr, ok := err.(net.Error); ok && netErr.Temporary() { 47 | continue 48 | } else { 49 | return err 50 | } 51 | } 52 | 53 | go serveSOCKS4Client(conn, s.forward) 54 | } 55 | } 56 | 57 | // Socks4Client implements Socks4 Proxy Protocol(http://www.openssh.com/txt/socks4.protocol). 58 | type Socks4Client struct { 59 | network string 60 | address string 61 | userID string 62 | forward Dialer 63 | } 64 | 65 | // NewSocks4Client return a new Socks4Client that implements Dialer interface. 66 | // network must be supported by forward, address is proxy server's address, userID can empty. 67 | func NewSocks4Client(network, address, userID string, forward Dialer) (*Socks4Client, error) { 68 | return &Socks4Client{ 69 | network: network, 70 | address: address, 71 | userID: userID, 72 | forward: forward, 73 | }, nil 74 | } 75 | 76 | // Dial return a new net.Conn if succeeded. network must be tcp, tcp4 or tcp6, address only is IPV4. 77 | func (s *Socks4Client) Dial(network, address string) (net.Conn, error) { 78 | switch network { 79 | case "tcp", "tcp4", "tcp6": 80 | default: 81 | return nil, errors.New("socks: no support for SOCKS4 proxy connections of type:" + network) 82 | } 83 | 84 | host, portStr, err := net.SplitHostPort(address) 85 | if err != nil { 86 | return nil, err 87 | } 88 | port, err := strconv.Atoi(portStr) 89 | if err != nil { 90 | return nil, errors.New("socks: failed to parse port:" + portStr) 91 | } 92 | if port < 1 || port > 0xffff { 93 | return nil, errors.New("socks: port number out of range:" + portStr) 94 | } 95 | ip := net.ParseIP(host) 96 | if ip == nil { 97 | return nil, errors.New("socks: destination host invalid:" + host) 98 | } 99 | ip4 := ip.To4() 100 | if ip4 == nil { 101 | return nil, errors.New("socks:destination ip must be ipv4:" + host) 102 | } 103 | 104 | conn, err := s.forward.Dial(s.network, s.address) 105 | if err != nil { 106 | return nil, err 107 | } 108 | closeConn := &conn 109 | defer func() { 110 | if closeConn != nil { 111 | (*closeConn).Close() 112 | } 113 | }() 114 | 115 | buff := make([]byte, 0, 8+len(s.userID)+1) 116 | buff = append(buff, socks4Version, socks4Connect) 117 | buff = append(buff, byte(port>>8), byte(port)) 118 | buff = append(buff, ip4...) 119 | if len(s.userID) != 0 { 120 | buff = append(buff, []byte(s.userID)...) 121 | } 122 | buff = append(buff, 0) 123 | 124 | if _, err := conn.Write(buff); err != nil { 125 | return nil, errors.New("socks: failed to write connect request to SOCKS4 server at: " + s.address + ": " + err.Error()) 126 | } 127 | buff = buff[:8] 128 | if _, err := io.ReadFull(conn, buff); err != nil { 129 | return nil, errors.New("socks: failed to read connect reply from SOCKS4 server at: " + s.address + ": " + err.Error()) 130 | } 131 | if buff[1] != socks4Granted { 132 | cd := int(buff[1]) - socks4Granted 133 | failure := "unknown error" 134 | if cd < len(socks4Errors) && cd >= 0 { 135 | failure = socks4Errors[cd] 136 | } 137 | return nil, errors.New("socks: SOCKS4 server at " + s.address + " failed to connect: " + failure) 138 | } 139 | 140 | closeConn = nil 141 | return conn, nil 142 | } 143 | 144 | func serveSOCKS4Client(conn net.Conn, forward Dialer) { 145 | defer conn.Close() 146 | 147 | reader := bufio.NewReader(conn) 148 | buff, err := reader.Peek(9) 149 | if err != nil { 150 | return 151 | } 152 | if buff[8] != 0 { 153 | if _, err = reader.ReadSlice(0); err != nil { 154 | return 155 | } 156 | } 157 | 158 | reply := make([]byte, 8) 159 | if buff[0] != socks4Version { 160 | reply[1] = socks4Rejected 161 | conn.Write(reply) 162 | return 163 | } 164 | if buff[1] != socks4Connect { 165 | reply[1] = socks4Rejected 166 | conn.Write(reply) 167 | return 168 | } 169 | 170 | port := uint16(buff[2])<<8 | uint16(buff[3]) 171 | ip := buff[4:8] 172 | 173 | host := fmt.Sprintf("%d.%d.%d.%d:%d", ip[0], ip[1], ip[2], ip[3], port) 174 | dest, err := forward.Dial("tcp4", host) 175 | if err != nil { 176 | reply[1] = socks4ConnectFailed 177 | conn.Write(reply) 178 | return 179 | } 180 | defer dest.Close() 181 | 182 | reply[1] = socks4Granted 183 | if _, err = conn.Write(reply); err != nil { 184 | return 185 | } 186 | 187 | go func() { 188 | defer conn.Close() 189 | defer dest.Close() 190 | io.Copy(dest, conn) 191 | }() 192 | io.Copy(conn, dest) 193 | } 194 | -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/socks4_test.go: -------------------------------------------------------------------------------- 1 | package socks 2 | 3 | import ( 4 | "net" 5 | "net/http" 6 | "net/http/httputil" 7 | "testing" 8 | ) 9 | 10 | const ( 11 | TestSocks4ServerAddr = "127.0.0.1:8000" 12 | TestSocks4TargetDomain = "www.baidu.com" 13 | ) 14 | 15 | func TestSocks4Client(t *testing.T) { 16 | listener, err := net.Listen("tcp", TestSocks4ServerAddr) 17 | if err != nil { 18 | t.Fatal(err) 19 | } 20 | defer listener.Close() 21 | go func() { 22 | server, err := NewSocks4Server(Direct) 23 | if err != nil { 24 | t.Fatal(err) 25 | } 26 | server.Serve(listener) 27 | }() 28 | 29 | client, err := NewSocks4Client("tcp", TestSocks4ServerAddr, "", Direct) 30 | if err != nil { 31 | t.Fatal(err) 32 | } 33 | 34 | addrs, err := net.LookupHost(TestSocks4TargetDomain) 35 | if err != nil { 36 | t.Fatal(err) 37 | } 38 | if len(addrs) == 0 { 39 | t.Fatal("net.LookupHost with " + TestSocks4TargetDomain + " result invalid") 40 | } 41 | 42 | conn, err := client.Dial("tcp", addrs[0]+":80") 43 | if err != nil { 44 | t.Fatal("socks4 client.Dial failed, err: " + err.Error()) 45 | } 46 | t.Log("client.Dial succeeded") 47 | httpClient := httputil.NewClientConn(conn, nil) 48 | if err != nil { 49 | conn.Close() 50 | t.Fatal(err) 51 | } 52 | defer httpClient.Close() 53 | 54 | request, err := http.NewRequest("GET", "/", nil) 55 | if err != nil { 56 | t.Fatal(err) 57 | } 58 | resp, err := httpClient.Do(request) 59 | if err != nil { 60 | t.Fatal(err) 61 | } 62 | data, err := httputil.DumpResponse(resp, true) 63 | if err != nil { 64 | t.Fatal(err) 65 | } 66 | t.Log("socks4 HTTP Get:", string(data)) 67 | } 68 | -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/socks5_client.go: -------------------------------------------------------------------------------- 1 | package socks 2 | 3 | import ( 4 | "errors" 5 | "io" 6 | "net" 7 | "strconv" 8 | ) 9 | 10 | const ( 11 | socks5Version = 5 12 | 13 | socks5AuthNone = 0 14 | socks5AuthPassword = 2 15 | socks5AuthNoAccept = 0xff 16 | 17 | socks5AuthPasswordVer = 1 18 | 19 | socks5Connect = 1 20 | 21 | socks5IP4 = 1 22 | socks5Domain = 3 23 | socks5IP6 = 4 24 | ) 25 | 26 | const ( 27 | socks5Success = 0 28 | socks5GeneralFailure = 1 29 | socks5ConnectNotAllowed = 2 30 | socks5NetworkUnreachable = 3 31 | socks5HostUnreachable = 4 32 | socks5ConnectionRefused = 5 33 | socks5TTLExpired = 6 34 | socks5CommandNotSupported = 7 35 | socks5AddressTypeNotSupported = 8 36 | ) 37 | 38 | var socks5Errors = []string{ 39 | "", 40 | "general SOCKS server failure", 41 | "connection not allowed by ruleset", 42 | "network unreachable", 43 | "Host unreachable", 44 | "Connection refused", 45 | "TTL expired", 46 | "Command not supported", 47 | "Address type not supported", 48 | } 49 | 50 | // Socks5Client implements Socks5 Proxy Protocol(RFC 1928) Client Protocol. 51 | // Just support CONNECT command, and support USERNAME/PASSWORD authentication methods(RFC 1929) 52 | type Socks5Client struct { 53 | network string 54 | address string 55 | user string 56 | password string 57 | forward Dialer 58 | } 59 | 60 | // NewSocks5Client return a new Socks5Client that implements Dialer interface. 61 | func NewSocks5Client(network, address, user, password string, forward Dialer) (*Socks5Client, error) { 62 | return &Socks5Client{ 63 | network: network, 64 | address: address, 65 | user: user, 66 | password: password, 67 | forward: forward, 68 | }, nil 69 | } 70 | 71 | // Dial return a new net.Conn that through the CONNECT command to establish connections with proxy server. 72 | // address as RFC's requirements that can be IPV4, IPV6 and domain host, such as 8.8.8.8:999 or google.com:80 73 | func (s *Socks5Client) Dial(network, address string) (net.Conn, error) { 74 | switch network { 75 | case "tcp", "tcp4", "tcp6": 76 | default: 77 | return nil, errors.New("socks: no support for SOCKS5 proxy connections of type:" + network) 78 | } 79 | 80 | conn, err := s.forward.Dial(s.network, s.address) 81 | if err != nil { 82 | return nil, err 83 | } 84 | closeConn := &conn 85 | defer func() { 86 | if closeConn != nil { 87 | (*closeConn).Close() 88 | } 89 | }() 90 | 91 | host, portStr, err := net.SplitHostPort(address) 92 | if err != nil { 93 | return nil, err 94 | } 95 | 96 | // check port 97 | port, err := strconv.Atoi(portStr) 98 | if err != nil { 99 | return nil, errors.New("socks: failed to parse port number: " + portStr) 100 | } 101 | if port < 1 || port > 0xffff { 102 | return nil, errors.New("socks: port number out of range: " + portStr) 103 | } 104 | 105 | buff := make([]byte, 0, 6+len(host)) 106 | 107 | buff = append(buff, socks5Version) 108 | 109 | // set authentication methods 110 | if len(s.user) > 0 && len(s.user) < 256 && len(s.password) < 256 { 111 | buff = append(buff, 2, socks5AuthNone, socks5AuthPassword) 112 | } else { 113 | buff = append(buff, 1, socks5AuthNone) 114 | } 115 | 116 | // send authentication methods 117 | if _, err := conn.Write(buff); err != nil { 118 | return nil, errors.New("socks: failed to write handshake request at: " + s.address + ": " + err.Error()) 119 | } 120 | if _, err := io.ReadFull(conn, buff[:2]); err != nil { 121 | return nil, errors.New("socks: failed to read handshake reply at: " + s.address + ": " + err.Error()) 122 | } 123 | 124 | // handle authentication methods reply 125 | if buff[0] != socks5Version { 126 | return nil, errors.New("socks: SOCKS5 server at: " + s.address + " invalid version" + strconv.Itoa(int(buff[0]))) 127 | } 128 | if buff[1] == socks5AuthNoAccept { 129 | return nil, errors.New("socks: SOCKS server at: " + s.address + " no acceptable methods") 130 | } 131 | 132 | if buff[1] == socks5AuthPassword { 133 | // build username/password authentication request 134 | buff = buff[:0] 135 | buff = append(buff, socks5AuthPasswordVer) 136 | buff = append(buff, uint8(len(s.user))) 137 | buff = append(buff, []byte(s.user)...) 138 | buff = append(buff, uint8(len(s.password))) 139 | buff = append(buff, []byte(s.password)...) 140 | 141 | if _, err := conn.Write(buff); err != nil { 142 | return nil, errors.New("socks: failed to write password authentication request to SOCKS5 server at: " + s.address + ": " + err.Error()) 143 | } 144 | if _, err := io.ReadFull(conn, buff[:2]); err != nil { 145 | return nil, errors.New("socks: failed to read password authentication reply from SOCKS5 server at: " + s.address + ": " + err.Error()) 146 | } 147 | // 0 indicates success 148 | if buff[1] != 0 { 149 | return nil, errors.New("socks: SOCKS5 server at: " + s.address + " reject username/password") 150 | } 151 | } 152 | 153 | // build connect request 154 | buff = buff[:0] 155 | buff = append(buff, socks5Version, socks5Connect, 0) 156 | 157 | if ip := net.ParseIP(host); ip != nil { 158 | if ip4 := ip.To4(); ip4 != nil { 159 | buff = append(buff, socks5IP4) 160 | ip = ip4 161 | } else { 162 | buff = append(buff, socks5IP6) 163 | } 164 | buff = append(buff, ip...) 165 | } else { 166 | if len(host) > 255 { 167 | return nil, errors.New("socks: destination hostname too long: " + host) 168 | } 169 | buff = append(buff, socks5Domain) 170 | buff = append(buff, uint8(len(host))) 171 | buff = append(buff, host...) 172 | } 173 | buff = append(buff, byte(port>>8), byte(port)) 174 | 175 | if _, err := conn.Write(buff); err != nil { 176 | return nil, errors.New("socks: failed to write connect request to SOCKS5 server at: " + s.address + ": " + err.Error()) 177 | } 178 | if _, err := io.ReadFull(conn, buff[:4]); err != nil { 179 | return nil, errors.New("socks: failed to read connect reply from SOCKS5 server at: " + s.address + ": " + err.Error()) 180 | } 181 | 182 | failure := "unknown error" 183 | if int(buff[1]) < len(socks5Errors) { 184 | failure = socks5Errors[buff[1]] 185 | } 186 | if len(failure) > 0 { 187 | return nil, errors.New("socks: SOCKS5 server failed to connect: " + failure) 188 | } 189 | 190 | // read remain data include BIND.ADDRESS and BIND.PORT 191 | discardBytes := 0 192 | switch buff[3] { 193 | case socks5IP4: 194 | discardBytes = net.IPv4len 195 | case socks5IP6: 196 | discardBytes = net.IPv6len 197 | case socks5Domain: 198 | if _, err := io.ReadFull(conn, buff[:1]); err != nil { 199 | return nil, errors.New("socks: failed to read domain length from SOCKS5 server at: " + s.address + ": " + err.Error()) 200 | } 201 | discardBytes = int(buff[0]) 202 | default: 203 | return nil, errors.New("socks: got unknown address type " + strconv.Itoa(int(buff[3])) + " from SOCKS5 server at: " + s.address) 204 | } 205 | discardBytes += 2 206 | if cap(buff) < discardBytes { 207 | buff = make([]byte, discardBytes) 208 | } else { 209 | buff = buff[:discardBytes] 210 | } 211 | if _, err := io.ReadFull(conn, buff); err != nil { 212 | return nil, errors.New("socks: failed to read address and port from SOCKS5 server at: " + s.address + ": " + err.Error()) 213 | } 214 | 215 | closeConn = nil 216 | return conn, nil 217 | } 218 | 219 | func serveSocks5Client(conn net.Conn, forward Dialer) { 220 | defer conn.Close() 221 | 222 | buff := make([]byte, 262) 223 | reply := []byte{0x05, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22} 224 | 225 | if _, err := io.ReadFull(conn, buff[:2]); err != nil { 226 | return 227 | } 228 | if buff[0] != socks5Version { 229 | reply[1] = socks5AuthNoAccept 230 | conn.Write(reply[:2]) 231 | return 232 | } 233 | numMethod := buff[1] 234 | if _, err := io.ReadFull(conn, buff[:numMethod]); err != nil { 235 | return 236 | } 237 | reply[1] = socks5AuthNone 238 | if _, err := conn.Write(reply[:2]); err != nil { 239 | return 240 | } 241 | 242 | if _, err := io.ReadFull(conn, buff[:4]); err != nil { 243 | return 244 | } 245 | if buff[1] != socks5Connect { 246 | reply[1] = socks5CommandNotSupported 247 | conn.Write(reply) 248 | return 249 | } 250 | 251 | addressType := buff[3] 252 | addressLen := 0 253 | switch addressType { 254 | case socks5IP4: 255 | addressLen = net.IPv4len 256 | case socks5IP6: 257 | addressLen = net.IPv6len 258 | case socks5Domain: 259 | if _, err := io.ReadFull(conn, buff[:1]); err != nil { 260 | return 261 | } 262 | addressLen = int(buff[0]) 263 | default: 264 | reply[1] = socks5AddressTypeNotSupported 265 | conn.Write(reply) 266 | return 267 | } 268 | host := make([]byte, addressLen) 269 | if _, err := io.ReadFull(conn, host); err != nil { 270 | return 271 | } 272 | if _, err := io.ReadFull(conn, buff[:2]); err != nil { 273 | return 274 | } 275 | hostStr := "" 276 | switch addressType { 277 | case socks5IP4, socks5IP6: 278 | ip := net.IP(host) 279 | hostStr = ip.String() 280 | case socks5Domain: 281 | hostStr = string(host) 282 | } 283 | port := uint16(buff[0])<<8 | uint16(buff[1]) 284 | if port < 1 || port > 0xffff { 285 | reply[1] = socks5HostUnreachable 286 | conn.Write(reply) 287 | return 288 | } 289 | portStr := strconv.Itoa(int(port)) 290 | 291 | hostStr = net.JoinHostPort(hostStr, portStr) 292 | dest, err := forward.Dial("tcp", hostStr) 293 | if err != nil { 294 | reply[1] = socks5ConnectionRefused 295 | conn.Write(reply) 296 | return 297 | } 298 | defer dest.Close() 299 | reply[1] = socks5Success 300 | if _, err := conn.Write(reply); err != nil { 301 | return 302 | } 303 | 304 | go func() { 305 | defer conn.Close() 306 | defer dest.Close() 307 | io.Copy(conn, dest) 308 | }() 309 | 310 | io.Copy(dest, conn) 311 | } 312 | -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/socks5_client_test.go: -------------------------------------------------------------------------------- 1 | package socks 2 | 3 | import ( 4 | "net" 5 | "net/http" 6 | "net/http/httputil" 7 | "testing" 8 | ) 9 | 10 | const ( 11 | TestSocks5ServerAddress = "127.0.0.1:8001" 12 | TestSocks5TargetDomain = "www.baidu.com" 13 | ) 14 | 15 | func TestSocks5Client(t *testing.T) { 16 | listener, err := net.Listen("tcp", TestSocks5ServerAddress) 17 | if err != nil { 18 | t.Fatal(err) 19 | } 20 | defer listener.Close() 21 | 22 | go func() { 23 | server, err := NewSocks5Server(Direct) 24 | if err != nil { 25 | t.Fatal(err) 26 | } 27 | server.Serve(listener) 28 | }() 29 | 30 | client, err := NewSocks5Client("tcp", TestSocks5ServerAddress, "", "", Direct) 31 | if err != nil { 32 | t.Fatal(err) 33 | } 34 | conn, err := client.Dial("tcp", TestSocks5TargetDomain+":80") 35 | if err != nil { 36 | t.Fatal(err) 37 | } 38 | 39 | t.Log("client.Dial succeeded") 40 | httpClient := httputil.NewClientConn(conn, nil) 41 | if err != nil { 42 | conn.Close() 43 | t.Fatal(err) 44 | } 45 | defer httpClient.Close() 46 | 47 | request, err := http.NewRequest("GET", "/", nil) 48 | if err != nil { 49 | t.Fatal(err) 50 | } 51 | resp, err := httpClient.Do(request) 52 | if err != nil { 53 | t.Fatal(err) 54 | } 55 | data, err := httputil.DumpResponse(resp, true) 56 | if err != nil { 57 | t.Fatal(err) 58 | } 59 | t.Log("socks5 HTTP Get:", string(data)) 60 | 61 | } 62 | -------------------------------------------------------------------------------- /vendor/github.com/eahydra/socks/socks5_server.go: -------------------------------------------------------------------------------- 1 | package socks 2 | 3 | import "net" 4 | 5 | // Socks5Server implements Socks5 Proxy Protocol(RFC 1928), just support CONNECT command. 6 | type Socks5Server struct { 7 | forward Dialer 8 | } 9 | 10 | // NewSocks5Server return a new Socks5Server 11 | func NewSocks5Server(forward Dialer) (*Socks5Server, error) { 12 | return &Socks5Server{ 13 | forward: forward, 14 | }, nil 15 | } 16 | 17 | // Serve with net.Listener for new incoming clients. 18 | func (s *Socks5Server) Serve(listener net.Listener) error { 19 | for { 20 | conn, err := listener.Accept() 21 | if err != nil { 22 | if netErr, ok := err.(net.Error); ok && netErr.Temporary() { 23 | continue 24 | } else { 25 | return err 26 | } 27 | } 28 | 29 | go serveSocks5Client(conn, s.forward) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Elazar Leibovich. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Elazar Leibovich. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | [![GoDoc](https://godoc.org/github.com/elazarl/goproxy?status.svg)](https://godoc.org/github.com/elazarl/goproxy) 4 | [![Join the chat at https://gitter.im/elazarl/goproxy](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/elazarl/goproxy?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 5 | 6 | Package goproxy provides a customizable HTTP proxy library for Go (golang), 7 | 8 | It supports regular HTTP proxy, HTTPS through CONNECT, and "hijacking" HTTPS 9 | connection using "Man in the Middle" style attack. 10 | 11 | The intent of the proxy, is to be usable with reasonable amount of traffic 12 | yet, customizable and programable. 13 | 14 | The proxy itself is simply a `net/http` handler. 15 | 16 | In order to use goproxy, one should set their browser to use goproxy as an HTTP 17 | proxy. Here is how you do that [in Chrome](https://support.google.com/chrome/answer/96815?hl=en) 18 | and [in Firefox](http://www.wikihow.com/Enter-Proxy-Settings-in-Firefox). 19 | 20 | For example, the URL you should use as proxy when running `./bin/basic` is 21 | `localhost:8080`, as this is the default binding for the basic proxy. 22 | 23 | ## Mailing List 24 | 25 | New features would be discussed on the [mailing list](https://groups.google.com/forum/#!forum/goproxy-dev) 26 | before their development. 27 | 28 | ## Latest Stable Release 29 | 30 | Get the latest goproxy from `gopkg.in/elazarl/goproxy.v1`. 31 | 32 | # Why not Fiddler2? 33 | 34 | Fiddler is an excellent software with similar intent. However, Fiddler is not 35 | as customable as goproxy intend to be. The main difference is, Fiddler is not 36 | intended to be used as a real proxy. 37 | 38 | A possible use case that suits goproxy but 39 | not Fiddler, is, gathering statistics on page load times for a certain website over a week. 40 | With goproxy you could ask all your users to set their proxy to a dedicated machine running a 41 | goproxy server. Fiddler is a GUI app not designed to be ran like a server for multiple users. 42 | 43 | # A taste of goproxy 44 | 45 | To get a taste of `goproxy`, a basic HTTP/HTTPS transparent proxy 46 | 47 | 48 | package main 49 | 50 | import ( 51 | "github.com/elazarl/goproxy" 52 | "log" 53 | "net/http" 54 | ) 55 | 56 | func main() { 57 | proxy := goproxy.NewProxyHttpServer() 58 | proxy.Verbose = true 59 | log.Fatal(http.ListenAndServe(":8080", proxy)) 60 | } 61 | 62 | 63 | This line will add `X-GoProxy: yxorPoG-X` header to all requests sent through the proxy 64 | 65 | proxy.OnRequest().DoFunc( 66 | func(r *http.Request,ctx *goproxy.ProxyCtx)(*http.Request,*http.Response) { 67 | r.Header.Set("X-GoProxy","yxorPoG-X") 68 | return r,nil 69 | }) 70 | 71 | `DoFunc` will process all incoming requests to the proxy. It will add a header to the request 72 | and return it. The proxy will send the modified request. 73 | 74 | Note that we returned nil value as the response. Have we returned a response, goproxy would 75 | have discarded the request and sent the new response to the client. 76 | 77 | In order to refuse connections to reddit at work time 78 | 79 | proxy.OnRequest(goproxy.DstHostIs("www.reddit.com")).DoFunc( 80 | func(r *http.Request,ctx *goproxy.ProxyCtx)(*http.Request,*http.Response) { 81 | if h,_,_ := time.Now().Clock(); h >= 8 && h <= 17 { 82 | return r,goproxy.NewResponse(r, 83 | goproxy.ContentTypeText,http.StatusForbidden, 84 | "Don't waste your time!") 85 | } 86 | return r,nil 87 | }) 88 | 89 | `DstHostIs` returns a `ReqCondition`, that is a function receiving a `Request` and returning a boolean 90 | we will only process requests that matches the condition. `DstHostIs("www.reddit.com")` will return 91 | a `ReqCondition` accepting only requests directed to "www.reddit.com". 92 | 93 | `DoFunc` will recieve a function that will preprocess the request. We can change the request, or 94 | return a response. If the time is between 8:00am and 17:00pm, we will neglect the request, and 95 | return a precanned text response saying "do not waste your time". 96 | 97 | See additional examples in the examples directory. 98 | 99 | # What's New 100 | 101 | 1. Ability to `Hijack` CONNECT requests. See 102 | [the eavesdropper example](https://github.com/elazarl/goproxy/blob/master/examples/goproxy-eavesdropper/main.go#L27) 103 | 2. Transparent proxy support for http/https including MITM certificate generation for TLS. See the [transparent example.](https://github.com/elazarl/goproxy/tree/master/examples/goproxy-transparent) 104 | 105 | # License 106 | 107 | I put the software temporarily under the Go-compatible BSD license, 108 | if this prevents someone from using the software, do let mee know and I'll consider changing it. 109 | 110 | At any rate, user feedback is very important for me, so I'll be delighted to know if you're using this package. 111 | 112 | # Beta Software 113 | 114 | I've received a positive feedback from a few people who use goproxy in production settings. 115 | I believe it is good enough for usage. 116 | 117 | I'll try to keep reasonable backwards compatability. In case of a major API change, 118 | I'll change the import path. 119 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/actions.go: -------------------------------------------------------------------------------- 1 | package goproxy 2 | 3 | import "net/http" 4 | 5 | // ReqHandler will "tamper" with the request coming to the proxy server 6 | // If Handle returns req,nil the proxy will send the returned request 7 | // to the destination server. If it returns nil,resp the proxy will 8 | // skip sending any requests, and will simply return the response `resp` 9 | // to the client. 10 | type ReqHandler interface { 11 | Handle(req *http.Request, ctx *ProxyCtx) (*http.Request, *http.Response) 12 | } 13 | 14 | // A wrapper that would convert a function to a ReqHandler interface type 15 | type FuncReqHandler func(req *http.Request, ctx *ProxyCtx) (*http.Request, *http.Response) 16 | 17 | // FuncReqHandler.Handle(req,ctx) <=> FuncReqHandler(req,ctx) 18 | func (f FuncReqHandler) Handle(req *http.Request, ctx *ProxyCtx) (*http.Request, *http.Response) { 19 | return f(req, ctx) 20 | } 21 | 22 | // after the proxy have sent the request to the destination server, it will 23 | // "filter" the response through the RespHandlers it has. 24 | // The proxy server will send to the client the response returned by the RespHandler. 25 | // In case of error, resp will be nil, and ctx.RoundTrip.Error will contain the error 26 | type RespHandler interface { 27 | Handle(resp *http.Response, ctx *ProxyCtx) *http.Response 28 | } 29 | 30 | // A wrapper that would convert a function to a RespHandler interface type 31 | type FuncRespHandler func(resp *http.Response, ctx *ProxyCtx) *http.Response 32 | 33 | // FuncRespHandler.Handle(req,ctx) <=> FuncRespHandler(req,ctx) 34 | func (f FuncRespHandler) Handle(resp *http.Response, ctx *ProxyCtx) *http.Response { 35 | return f(resp, ctx) 36 | } 37 | 38 | // When a client send a CONNECT request to a host, the request is filtered through 39 | // all the HttpsHandlers the proxy has, and if one returns true, the connection is 40 | // sniffed using Man in the Middle attack. 41 | // That is, the proxy will create a TLS connection with the client, another TLS 42 | // connection with the destination the client wished to connect to, and would 43 | // send back and forth all messages from the server to the client and vice versa. 44 | // The request and responses sent in this Man In the Middle channel are filtered 45 | // through the usual flow (request and response filtered through the ReqHandlers 46 | // and RespHandlers) 47 | type HttpsHandler interface { 48 | HandleConnect(req string, ctx *ProxyCtx) (*ConnectAction, string) 49 | } 50 | 51 | // A wrapper that would convert a function to a HttpsHandler interface type 52 | type FuncHttpsHandler func(host string, ctx *ProxyCtx) (*ConnectAction, string) 53 | 54 | // FuncHttpsHandler should implement the RespHandler interface 55 | func (f FuncHttpsHandler) HandleConnect(host string, ctx *ProxyCtx) (*ConnectAction, string) { 56 | return f(host, ctx) 57 | } 58 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/all.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | go test || exit 4 | for action in $@; do go $action; done 5 | 6 | mkdir -p bin 7 | find regretable examples/* ext/* -maxdepth 0 -type d | while read d; do 8 | (cd $d 9 | go build -o ../../bin/$(basename $d) 10 | find *_test.go -maxdepth 0 2>/dev/null|while read f;do 11 | for action in $@; do go $action; done 12 | go test 13 | break 14 | done) 15 | done 16 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICSjCCAbWgAwIBAgIBADALBgkqhkiG9w0BAQUwSjEjMCEGA1UEChMaZ2l0aHVi 3 | LmNvbS9lbGF6YXJsL2dvcHJveHkxIzAhBgNVBAMTGmdpdGh1Yi5jb20vZWxhemFy 4 | bC9nb3Byb3h5MB4XDTAwMDEwMTAwMDAwMFoXDTQ5MTIzMTIzNTk1OVowSjEjMCEG 5 | A1UEChMaZ2l0aHViLmNvbS9lbGF6YXJsL2dvcHJveHkxIzAhBgNVBAMTGmdpdGh1 6 | Yi5jb20vZWxhemFybC9nb3Byb3h5MIGdMAsGCSqGSIb3DQEBAQOBjQAwgYkCgYEA 7 | vz9BbCaJjxs73Tvcq3leP32hAGerQ1RgvlZ68Z4nZmoVHfl+2Nr/m0dmW+GdOfpT 8 | cs/KzfJjYGr/84x524fiuR8GdZ0HOtXJzyF5seoWnbBIuyr1PbEpgRhGQMqqOUuj 9 | YExeLbfNHPIoJ8XZ1Vzyv3YxjbmjWA+S/uOe9HWtDbMCAwEAAaNGMEQwDgYDVR0P 10 | AQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1UdEwEB/wQFMAMBAf8w 11 | DAYDVR0RBAUwA4IBKjALBgkqhkiG9w0BAQUDgYEAIcL8huSmGMompNujsvePTUnM 12 | oEUKtX4Eh/+s+DSfV/TyI0I+3GiPpLplEgFWuoBIJGios0r1dKh5N0TGjxX/RmGm 13 | qo7E4jjJuo8Gs5U8/fgThZmshax2lwLtbRNwhvUVr65GdahLsZz8I+hySLuatVvR 14 | qHHq/FQORIiNyNpq/Hg= 15 | -----END CERTIFICATE----- 16 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/certs.go: -------------------------------------------------------------------------------- 1 | package goproxy 2 | 3 | import ( 4 | "crypto/tls" 5 | "crypto/x509" 6 | ) 7 | 8 | func init() { 9 | if goproxyCaErr != nil { 10 | panic("Error parsing builtin CA " + goproxyCaErr.Error()) 11 | } 12 | var err error 13 | if GoproxyCa.Leaf, err = x509.ParseCertificate(GoproxyCa.Certificate[0]); err != nil { 14 | panic("Error parsing builtin CA " + err.Error()) 15 | } 16 | } 17 | 18 | var tlsClientSkipVerify = &tls.Config{InsecureSkipVerify: true} 19 | 20 | var defaultTLSConfig = &tls.Config{ 21 | InsecureSkipVerify: true, 22 | } 23 | 24 | var CA_CERT = []byte(`-----BEGIN CERTIFICATE----- 25 | MIIF9DCCA9ygAwIBAgIJAODqYUwoVjJkMA0GCSqGSIb3DQEBCwUAMIGOMQswCQYD 26 | VQQGEwJJTDEPMA0GA1UECAwGQ2VudGVyMQwwCgYDVQQHDANMb2QxEDAOBgNVBAoM 27 | B0dvUHJveHkxEDAOBgNVBAsMB0dvUHJveHkxGjAYBgNVBAMMEWdvcHJveHkuZ2l0 28 | aHViLmlvMSAwHgYJKoZIhvcNAQkBFhFlbGF6YXJsQGdtYWlsLmNvbTAeFw0xNzA0 29 | MDUyMDAwMTBaFw0zNzAzMzEyMDAwMTBaMIGOMQswCQYDVQQGEwJJTDEPMA0GA1UE 30 | CAwGQ2VudGVyMQwwCgYDVQQHDANMb2QxEDAOBgNVBAoMB0dvUHJveHkxEDAOBgNV 31 | BAsMB0dvUHJveHkxGjAYBgNVBAMMEWdvcHJveHkuZ2l0aHViLmlvMSAwHgYJKoZI 32 | hvcNAQkBFhFlbGF6YXJsQGdtYWlsLmNvbTCCAiIwDQYJKoZIhvcNAQEBBQADggIP 33 | ADCCAgoCggIBAJ4Qy+H6hhoY1s0QRcvIhxrjSHaO/RbaFj3rwqcnpOgFq07gRdI9 34 | 3c0TFKQJHpgv6feLRhEvX/YllFYu4J35lM9ZcYY4qlKFuStcX8Jm8fqpgtmAMBzP 35 | sqtqDi8M9RQGKENzU9IFOnCV7SAeh45scMuI3wz8wrjBcH7zquHkvqUSYZz035t9 36 | V6WTrHyTEvT4w+lFOVN2bA/6DAIxrjBiF6DhoJqnha0SZtDfv77XpwGG3EhA/qoh 37 | hiYrDruYK7zJdESQL44LwzMPupVigqalfv+YHfQjbhT951IVurW2NJgRyBE62dLr 38 | lHYdtT9tCTCrd+KJNMJ+jp9hAjdIu1Br/kifU4F4+4ZLMR9Ueji0GkkPKsYdyMnq 39 | j0p0PogyvP1l4qmboPImMYtaoFuYmMYlebgC9LN10bL91K4+jLt0I1YntEzrqgJo 40 | WsJztYDw543NzSy5W+/cq4XRYgtq1b0RWwuUiswezmMoeyHZ8BQJe2xMjAOllASD 41 | fqa8OK3WABHJpy4zUrnUBiMuPITzD/FuDx4C5IwwlC68gHAZblNqpBZCX0nFCtKj 42 | YOcI2So5HbQ2OC8QF+zGVuduHUSok4hSy2BBfZ1pfvziqBeetWJwFvapGB44nIHh 43 | WKNKvqOxLNIy7e+TGRiWOomrAWM18VSR9LZbBxpJK7PLSzWqYJYTRCZHAgMBAAGj 44 | UzBRMB0GA1UdDgQWBBR4uDD9Y6x7iUoHO+32ioOcw1ICZTAfBgNVHSMEGDAWgBR4 45 | uDD9Y6x7iUoHO+32ioOcw1ICZTAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEB 46 | CwUAA4ICAQAaCEupzGGqcdh+L7BzhX7zyd7yzAKUoLxFrxaZY34Xyj3lcx1XoK6F 47 | AqsH2JM25GixgadzhNt92JP7vzoWeHZtLfstrPS638Y1zZi6toy4E49viYjFk5J0 48 | C6ZcFC04VYWWx6z0HwJuAS08tZ37JuFXpJGfXJOjZCQyxse0Lg0tuKLMeXDCk2Y3 49 | Ba0noeuNyHRoWXXPyiUoeApkVCU5gIsyiJSWOjhJ5hpJG06rQNfNYexgKrrraEin 50 | o0jmEMtJMx5TtD83hSnLCnFGBBq5lkE7jgXME1KsbIE3lJZzRX1mQwUK8CJDYxye 51 | i6M/dzSvy0SsPvz8fTAlprXRtWWtJQmxgWENp3Dv+0Pmux/l+ilk7KA4sMXGhsfr 52 | bvTOeWl1/uoFTPYiWR/ww7QEPLq23yDFY04Q7Un0qjIk8ExvaY8lCkXMgc8i7sGY 53 | VfvOYb0zm67EfAQl3TW8Ky5fl5CcxpVCD360Bzi6hwjYixa3qEeBggOixFQBFWft 54 | 8wrkKTHpOQXjn4sDPtet8imm9UYEtzWrFX6T9MFYkBR0/yye0FIh9+YPiTA6WB86 55 | NCNwK5Yl6HuvF97CIH5CdgO+5C7KifUtqTOL8pQKbNwy0S3sNYvB+njGvRpR7pKV 56 | BUnFpB/Atptqr4CUlTXrc5IPLAqAfmwk5IKcwy3EXUbruf9Dwz69YA== 57 | -----END CERTIFICATE-----`) 58 | 59 | var CA_KEY = []byte(`-----BEGIN RSA PRIVATE KEY----- 60 | MIIJKAIBAAKCAgEAnhDL4fqGGhjWzRBFy8iHGuNIdo79FtoWPevCpyek6AWrTuBF 61 | 0j3dzRMUpAkemC/p94tGES9f9iWUVi7gnfmUz1lxhjiqUoW5K1xfwmbx+qmC2YAw 62 | HM+yq2oOLwz1FAYoQ3NT0gU6cJXtIB6Hjmxwy4jfDPzCuMFwfvOq4eS+pRJhnPTf 63 | m31XpZOsfJMS9PjD6UU5U3ZsD/oMAjGuMGIXoOGgmqeFrRJm0N+/vtenAYbcSED+ 64 | qiGGJisOu5grvMl0RJAvjgvDMw+6lWKCpqV+/5gd9CNuFP3nUhW6tbY0mBHIETrZ 65 | 0uuUdh21P20JMKt34ok0wn6On2ECN0i7UGv+SJ9TgXj7hksxH1R6OLQaSQ8qxh3I 66 | yeqPSnQ+iDK8/WXiqZug8iYxi1qgW5iYxiV5uAL0s3XRsv3Urj6Mu3QjVie0TOuq 67 | AmhawnO1gPDnjc3NLLlb79yrhdFiC2rVvRFbC5SKzB7OYyh7IdnwFAl7bEyMA6WU 68 | BIN+prw4rdYAEcmnLjNSudQGIy48hPMP8W4PHgLkjDCULryAcBluU2qkFkJfScUK 69 | 0qNg5wjZKjkdtDY4LxAX7MZW524dRKiTiFLLYEF9nWl+/OKoF561YnAW9qkYHjic 70 | geFYo0q+o7Es0jLt75MZGJY6iasBYzXxVJH0tlsHGkkrs8tLNapglhNEJkcCAwEA 71 | AQKCAgAwSuNvxHHqUUJ3XoxkiXy1u1EtX9x1eeYnvvs2xMb+WJURQTYz2NEGUdkR 72 | kPO2/ZSXHAcpQvcnpi2e8y2PNmy/uQ0VPATVt6NuWweqxncR5W5j82U/uDlXY8y3 73 | lVbfak4s5XRri0tikHvlP06dNgZ0OPok5qi7d+Zd8yZ3Y8LXfjkykiIrSG1Z2jdt 74 | zCWTkNmSUKMGG/1CGFxI41Lb12xuq+C8v4f469Fb6bCUpyCQN9rffHQSGLH6wVb7 75 | +68JO+d49zCATpmx5RFViMZwEcouXxRvvc9pPHXLP3ZPBD8nYu9kTD220mEGgWcZ 76 | 3L9dDlZPcSocbjw295WMvHz2QjhrDrb8gXwdpoRyuyofqgCyNxSnEC5M13SjOxtf 77 | pjGzjTqh0kDlKXg2/eTkd9xIHjVhFYiHIEeITM/lHCfWwBCYxViuuF7pSRPzTe8U 78 | C440b62qZSPMjVoquaMg+qx0n9fKSo6n1FIKHypv3Kue2G0WhDeK6u0U288vQ1t4 79 | Ood3Qa13gZ+9hwDLbM/AoBfVBDlP/tpAwa7AIIU1ZRDNbZr7emFdctx9B6kLINv3 80 | 4PDOGM2xrjOuACSGMq8Zcu7LBz35PpIZtviJOeKNwUd8/xHjWC6W0itgfJb5I1Nm 81 | V6Vj368pGlJx6Se26lvXwyyrc9pSw6jSAwARBeU4YkNWpi4i6QKCAQEA0T7u3P/9 82 | jZJSnDN1o2PXymDrJulE61yguhc/QSmLccEPZe7or06/DmEhhKuCbv+1MswKDeag 83 | /1JdFPGhL2+4G/f/9BK3BJPdcOZSz7K6Ty8AMMBf8AehKTcSBqwkJWcbEvpHpKJ6 84 | eDqn1B6brXTNKMT6fEEXCuZJGPBpNidyLv/xXDcN7kCOo3nGYKfB5OhFpNiL63tw 85 | +LntU56WESZwEqr8Pf80uFvsyXQK3a5q5HhIQtxl6tqQuPlNjsDBvCqj0x72mmaJ 86 | ZVsVWlv7khUrCwAXz7Y8K7mKKBd2ekF5hSbryfJsxFyvEaWUPhnJpTKV85lAS+tt 87 | FQuIp9TvKYlRQwKCAQEAwWJN8jysapdhi67jO0HtYOEl9wwnF4w6XtiOYtllkMmC 88 | 06/e9h7RsRyWPMdu3qRDPUYFaVDy6+dpUDSQ0+E2Ot6AHtVyvjeUTIL651mFIo/7 89 | OSUCEc+HRo3SfPXdPhSQ2thNTxl6y9XcFacuvbthgr70KXbvC4k6IEmdpf/0Kgs9 90 | 7QTZCG26HDrEZ2q9yMRlRaL2SRD+7Y2xra7gB+cQGFj6yn0Wd/07er49RqMXidQf 91 | KR2oYfev2BDtHXoSZFfhFGHlOdLvWRh90D4qZf4vQ+g/EIMgcNSoxjvph1EShmKt 92 | sjhTHtoHuu+XmEQvIewk2oCI+JvofBkcnpFrVvUUrQKCAQAaTIufETmgCo0BfuJB 93 | N/JOSGIl0NnNryWwXe2gVgVltbsmt6FdL0uKFiEtWJUbOF5g1Q5Kcvs3O/XhBQGa 94 | QbNlKIVt+tAv7hm97+Tmn/MUsraWagdk1sCluns0hXxBizT27KgGhDlaVRz05yfv 95 | 5CdJAYDuDwxDXXBAhy7iFJEgYSDH00+X61tCJrMNQOh4ycy/DEyBu1EWod+3S85W 96 | t3sMjZsIe8P3i+4137Th6eMbdha2+JaCrxfTd9oMoCN5b+6JQXIDM/H+4DTN15PF 97 | 540yY7+aZrAnWrmHknNcqFAKsTqfdi2/fFqwoBwCtiEG91WreU6AfEWIiJuTZIru 98 | sIibAoIBAAqIwlo5t+KukF+9jR9DPh0S5rCIdvCvcNaN0WPNF91FPN0vLWQW1bFi 99 | L0TsUDvMkuUZlV3hTPpQxsnZszH3iK64RB5p3jBCcs+gKu7DT59MXJEGVRCHT4Um 100 | YJryAbVKBYIGWl++sZO8+JotWzx2op8uq7o+glMMjKAJoo7SXIiVyC/LHc95urOi 101 | 9+PySphPKn0anXPpexmRqGYfqpCDo7rPzgmNutWac80B4/CfHb8iUPg6Z1u+1FNe 102 | yKvcZHgW2Wn00znNJcCitufLGyAnMofudND/c5rx2qfBx7zZS7sKUQ/uRYjes6EZ 103 | QBbJUA/2/yLv8YYpaAaqj4aLwV8hRpkCggEBAIh3e25tr3avCdGgtCxS7Y1blQ2c 104 | ue4erZKmFP1u8wTNHQ03T6sECZbnIfEywRD/esHpclfF3kYAKDRqIP4K905Rb0iH 105 | 759ZWt2iCbqZznf50XTvptdmjm5KxvouJzScnQ52gIV6L+QrCKIPelLBEIqCJREh 106 | pmcjjocD/UCCSuHgbAYNNnO/JdhnSylz1tIg26I+2iLNyeTKIepSNlsBxnkLmqM1 107 | cj/azKBaT04IOMLaN8xfSqitJYSraWMVNgGJM5vfcVaivZnNh0lZBv+qu6YkdM88 108 | 4/avCJ8IutT+FcMM+GbGazOm5ALWqUyhrnbLGc4CQMPfe7Il6NxwcrOxT8w= 109 | -----END RSA PRIVATE KEY-----`) 110 | 111 | var GoproxyCa, goproxyCaErr = tls.X509KeyPair(CA_CERT, CA_KEY) 112 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/chunked.go: -------------------------------------------------------------------------------- 1 | // Taken from $GOROOT/src/pkg/net/http/chunked 2 | // needed to write https responses to client. 3 | package goproxy 4 | 5 | import ( 6 | "io" 7 | "strconv" 8 | ) 9 | 10 | // newChunkedWriter returns a new chunkedWriter that translates writes into HTTP 11 | // "chunked" format before writing them to w. Closing the returned chunkedWriter 12 | // sends the final 0-length chunk that marks the end of the stream. 13 | // 14 | // newChunkedWriter is not needed by normal applications. The http 15 | // package adds chunking automatically if handlers don't set a 16 | // Content-Length header. Using newChunkedWriter inside a handler 17 | // would result in double chunking or chunking with a Content-Length 18 | // length, both of which are wrong. 19 | func newChunkedWriter(w io.Writer) io.WriteCloser { 20 | return &chunkedWriter{w} 21 | } 22 | 23 | // Writing to chunkedWriter translates to writing in HTTP chunked Transfer 24 | // Encoding wire format to the underlying Wire chunkedWriter. 25 | type chunkedWriter struct { 26 | Wire io.Writer 27 | } 28 | 29 | // Write the contents of data as one chunk to Wire. 30 | // NOTE: Note that the corresponding chunk-writing procedure in Conn.Write has 31 | // a bug since it does not check for success of io.WriteString 32 | func (cw *chunkedWriter) Write(data []byte) (n int, err error) { 33 | 34 | // Don't send 0-length data. It looks like EOF for chunked encoding. 35 | if len(data) == 0 { 36 | return 0, nil 37 | } 38 | 39 | head := strconv.FormatInt(int64(len(data)), 16) + "\r\n" 40 | 41 | if _, err = io.WriteString(cw.Wire, head); err != nil { 42 | return 0, err 43 | } 44 | if n, err = cw.Wire.Write(data); err != nil { 45 | return 46 | } 47 | if n != len(data) { 48 | err = io.ErrShortWrite 49 | return 50 | } 51 | _, err = io.WriteString(cw.Wire, "\r\n") 52 | 53 | return 54 | } 55 | 56 | func (cw *chunkedWriter) Close() error { 57 | _, err := io.WriteString(cw.Wire, "0\r\n") 58 | return err 59 | } 60 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/counterecryptor.go: -------------------------------------------------------------------------------- 1 | package goproxy 2 | 3 | import ( 4 | "crypto/aes" 5 | "crypto/cipher" 6 | "crypto/rsa" 7 | "crypto/sha256" 8 | "crypto/x509" 9 | "errors" 10 | ) 11 | 12 | type CounterEncryptorRand struct { 13 | cipher cipher.Block 14 | counter []byte 15 | rand []byte 16 | ix int 17 | } 18 | 19 | func NewCounterEncryptorRandFromKey(key interface{}, seed []byte) (r CounterEncryptorRand, err error) { 20 | var keyBytes []byte 21 | switch key := key.(type) { 22 | case *rsa.PrivateKey: 23 | keyBytes = x509.MarshalPKCS1PrivateKey(key) 24 | default: 25 | err = errors.New("only RSA keys supported") 26 | return 27 | } 28 | h := sha256.New() 29 | if r.cipher, err = aes.NewCipher(h.Sum(keyBytes)[:aes.BlockSize]); err != nil { 30 | return 31 | } 32 | r.counter = make([]byte, r.cipher.BlockSize()) 33 | if seed != nil { 34 | copy(r.counter, h.Sum(seed)[:r.cipher.BlockSize()]) 35 | } 36 | r.rand = make([]byte, r.cipher.BlockSize()) 37 | r.ix = len(r.rand) 38 | return 39 | } 40 | 41 | func (c *CounterEncryptorRand) Seed(b []byte) { 42 | if len(b) != len(c.counter) { 43 | panic("SetCounter: wrong counter size") 44 | } 45 | copy(c.counter, b) 46 | } 47 | 48 | func (c *CounterEncryptorRand) refill() { 49 | c.cipher.Encrypt(c.rand, c.counter) 50 | for i := 0; i < len(c.counter); i++ { 51 | if c.counter[i]++; c.counter[i] != 0 { 52 | break 53 | } 54 | } 55 | c.ix = 0 56 | } 57 | 58 | func (c *CounterEncryptorRand) Read(b []byte) (n int, err error) { 59 | if c.ix == len(c.rand) { 60 | c.refill() 61 | } 62 | if n = len(c.rand) - c.ix; n > len(b) { 63 | n = len(b) 64 | } 65 | copy(b, c.rand[c.ix:c.ix+n]) 66 | c.ix += n 67 | return 68 | } 69 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/counterecryptor_test.go: -------------------------------------------------------------------------------- 1 | package goproxy_test 2 | 3 | import ( 4 | "bytes" 5 | "crypto/rsa" 6 | "encoding/binary" 7 | "github.com/elazarl/goproxy" 8 | "io" 9 | "math" 10 | "math/rand" 11 | "testing" 12 | ) 13 | 14 | type RandSeedReader struct { 15 | r rand.Rand 16 | } 17 | 18 | func (r *RandSeedReader) Read(b []byte) (n int, err error) { 19 | for i := range b { 20 | b[i] = byte(r.r.Int() & 0xFF) 21 | } 22 | return len(b), nil 23 | } 24 | 25 | func TestCounterEncDifferentConsecutive(t *testing.T) { 26 | k, err := rsa.GenerateKey(&RandSeedReader{*rand.New(rand.NewSource(0xFF43109))}, 128) 27 | fatalOnErr(err, "rsa.GenerateKey", t) 28 | c, err := goproxy.NewCounterEncryptorRandFromKey(k, []byte("the quick brown fox run over the lazy dog")) 29 | fatalOnErr(err, "NewCounterEncryptorRandFromKey", t) 30 | for i := 0; i < 100*1000; i++ { 31 | var a, b int64 32 | binary.Read(&c, binary.BigEndian, &a) 33 | binary.Read(&c, binary.BigEndian, &b) 34 | if a == b { 35 | t.Fatal("two consecutive equal int64", a, b) 36 | } 37 | } 38 | } 39 | 40 | func TestCounterEncIdenticalStreams(t *testing.T) { 41 | k, err := rsa.GenerateKey(&RandSeedReader{*rand.New(rand.NewSource(0xFF43109))}, 128) 42 | fatalOnErr(err, "rsa.GenerateKey", t) 43 | c1, err := goproxy.NewCounterEncryptorRandFromKey(k, []byte("the quick brown fox run over the lazy dog")) 44 | fatalOnErr(err, "NewCounterEncryptorRandFromKey", t) 45 | c2, err := goproxy.NewCounterEncryptorRandFromKey(k, []byte("the quick brown fox run over the lazy dog")) 46 | fatalOnErr(err, "NewCounterEncryptorRandFromKey", t) 47 | nout := 1000 48 | out1, out2 := make([]byte, nout), make([]byte, nout) 49 | io.ReadFull(&c1, out1) 50 | tmp := out2[:] 51 | rand.Seed(0xFF43109) 52 | for len(tmp) > 0 { 53 | n := 1 + rand.Intn(256) 54 | if n > len(tmp) { 55 | n = len(tmp) 56 | } 57 | n, err := c2.Read(tmp[:n]) 58 | fatalOnErr(err, "CounterEncryptorRand.Read", t) 59 | tmp = tmp[n:] 60 | } 61 | if !bytes.Equal(out1, out2) { 62 | t.Error("identical CSPRNG does not produce the same output") 63 | } 64 | } 65 | 66 | func stddev(data []int) float64 { 67 | var sum, sum_sqr float64 = 0, 0 68 | for _, h := range data { 69 | sum += float64(h) 70 | sum_sqr += float64(h) * float64(h) 71 | } 72 | n := float64(len(data)) 73 | variance := (sum_sqr - ((sum * sum) / n)) / (n - 1) 74 | return math.Sqrt(variance) 75 | } 76 | 77 | func TestCounterEncStreamHistogram(t *testing.T) { 78 | k, err := rsa.GenerateKey(&RandSeedReader{*rand.New(rand.NewSource(0xFF43109))}, 128) 79 | fatalOnErr(err, "rsa.GenerateKey", t) 80 | c, err := goproxy.NewCounterEncryptorRandFromKey(k, []byte("the quick brown fox run over the lazy dog")) 81 | fatalOnErr(err, "NewCounterEncryptorRandFromKey", t) 82 | nout := 100 * 1000 83 | out := make([]byte, nout) 84 | io.ReadFull(&c, out) 85 | refhist := make([]int, 256) 86 | for i := 0; i < nout; i++ { 87 | refhist[rand.Intn(256)]++ 88 | } 89 | hist := make([]int, 256) 90 | for _, b := range out { 91 | hist[int(b)]++ 92 | } 93 | refstddev, stddev := stddev(refhist), stddev(hist) 94 | // due to lack of time, I guestimate 95 | t.Logf("ref:%v - act:%v = %v", refstddev, stddev, math.Abs(refstddev-stddev)) 96 | if math.Abs(refstddev-stddev) >= 1 { 97 | t.Errorf("stddev of ref histogram different than regular PRNG: %v %v", refstddev, stddev) 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/ctx.go: -------------------------------------------------------------------------------- 1 | package goproxy 2 | 3 | import ( 4 | "net/http" 5 | "regexp" 6 | ) 7 | 8 | // ProxyCtx is the Proxy context, contains useful information about every request. It is passed to 9 | // every user function. Also used as a logger. 10 | type ProxyCtx struct { 11 | // Will contain the client request from the proxy 12 | Req *http.Request 13 | // Will contain the remote server's response (if available. nil if the request wasn't send yet) 14 | Resp *http.Response 15 | RoundTripper RoundTripper 16 | // will contain the recent error that occured while trying to send receive or parse traffic 17 | Error error 18 | // A handle for the user to keep data in the context, from the call of ReqHandler to the 19 | // call of RespHandler 20 | UserData interface{} 21 | // Will connect a request to a response 22 | Session int64 23 | proxy *ProxyHttpServer 24 | } 25 | 26 | type RoundTripper interface { 27 | RoundTrip(req *http.Request, ctx *ProxyCtx) (*http.Response, error) 28 | } 29 | 30 | type RoundTripperFunc func(req *http.Request, ctx *ProxyCtx) (*http.Response, error) 31 | 32 | func (f RoundTripperFunc) RoundTrip(req *http.Request, ctx *ProxyCtx) (*http.Response, error) { 33 | return f(req, ctx) 34 | } 35 | 36 | func (ctx *ProxyCtx) RoundTrip(req *http.Request) (*http.Response, error) { 37 | if ctx.RoundTripper != nil { 38 | return ctx.RoundTripper.RoundTrip(req, ctx) 39 | } 40 | return ctx.proxy.Tr.RoundTrip(req) 41 | } 42 | 43 | func (ctx *ProxyCtx) printf(msg string, argv ...interface{}) { 44 | ctx.proxy.Logger.Printf("[%03d] "+msg+"\n", append([]interface{}{ctx.Session & 0xFF}, argv...)...) 45 | } 46 | 47 | // Logf prints a message to the proxy's log. Should be used in a ProxyHttpServer's filter 48 | // This message will be printed only if the Verbose field of the ProxyHttpServer is set to true 49 | // 50 | // proxy.OnRequest().DoFunc(func(r *http.Request,ctx *goproxy.ProxyCtx) (*http.Request, *http.Response){ 51 | // nr := atomic.AddInt32(&counter,1) 52 | // ctx.Printf("So far %d requests",nr) 53 | // return r, nil 54 | // }) 55 | func (ctx *ProxyCtx) Logf(msg string, argv ...interface{}) { 56 | if ctx.proxy.Verbose { 57 | ctx.printf("INFO: "+msg, argv...) 58 | } 59 | } 60 | 61 | // Warnf prints a message to the proxy's log. Should be used in a ProxyHttpServer's filter 62 | // This message will always be printed. 63 | // 64 | // proxy.OnRequest().DoFunc(func(r *http.Request,ctx *goproxy.ProxyCtx) (*http.Request, *http.Response){ 65 | // f,err := os.OpenFile(cachedContent) 66 | // if err != nil { 67 | // ctx.Warnf("error open file %v: %v",cachedContent,err) 68 | // return r, nil 69 | // } 70 | // return r, nil 71 | // }) 72 | func (ctx *ProxyCtx) Warnf(msg string, argv ...interface{}) { 73 | ctx.printf("WARN: "+msg, argv...) 74 | } 75 | 76 | var charsetFinder = regexp.MustCompile("charset=([^ ;]*)") 77 | 78 | // Will try to infer the character set of the request from the headers. 79 | // Returns the empty string if we don't know which character set it used. 80 | // Currently it will look for charset= in the Content-Type header of the request. 81 | func (ctx *ProxyCtx) Charset() string { 82 | charsets := charsetFinder.FindStringSubmatch(ctx.Resp.Header.Get("Content-Type")) 83 | if charsets == nil { 84 | return "" 85 | } 86 | return charsets[1] 87 | } 88 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/dispatcher.go: -------------------------------------------------------------------------------- 1 | package goproxy 2 | 3 | import ( 4 | "bytes" 5 | "io/ioutil" 6 | "net" 7 | "net/http" 8 | "regexp" 9 | "strings" 10 | ) 11 | 12 | // ReqCondition.HandleReq will decide whether or not to use the ReqHandler on an HTTP request 13 | // before sending it to the remote server 14 | type ReqCondition interface { 15 | RespCondition 16 | HandleReq(req *http.Request, ctx *ProxyCtx) bool 17 | } 18 | 19 | // RespCondition.HandleReq will decide whether or not to use the RespHandler on an HTTP response 20 | // before sending it to the proxy client. Note that resp might be nil, in case there was an 21 | // error sending the request. 22 | type RespCondition interface { 23 | HandleResp(resp *http.Response, ctx *ProxyCtx) bool 24 | } 25 | 26 | // ReqConditionFunc.HandleReq(req,ctx) <=> ReqConditionFunc(req,ctx) 27 | type ReqConditionFunc func(req *http.Request, ctx *ProxyCtx) bool 28 | 29 | // RespConditionFunc.HandleResp(resp,ctx) <=> RespConditionFunc(resp,ctx) 30 | type RespConditionFunc func(resp *http.Response, ctx *ProxyCtx) bool 31 | 32 | func (c ReqConditionFunc) HandleReq(req *http.Request, ctx *ProxyCtx) bool { 33 | return c(req, ctx) 34 | } 35 | 36 | // ReqConditionFunc cannot test responses. It only satisfies RespCondition interface so that 37 | // to be usable as RespCondition. 38 | func (c ReqConditionFunc) HandleResp(resp *http.Response, ctx *ProxyCtx) bool { 39 | return c(ctx.Req, ctx) 40 | } 41 | 42 | func (c RespConditionFunc) HandleResp(resp *http.Response, ctx *ProxyCtx) bool { 43 | return c(resp, ctx) 44 | } 45 | 46 | // UrlHasPrefix returns a ReqCondition checking wether the destination URL the proxy client has requested 47 | // has the given prefix, with or without the host. 48 | // For example UrlHasPrefix("host/x") will match requests of the form 'GET host/x', and will match 49 | // requests to url 'http://host/x' 50 | func UrlHasPrefix(prefix string) ReqConditionFunc { 51 | return func(req *http.Request, ctx *ProxyCtx) bool { 52 | return strings.HasPrefix(req.URL.Path, prefix) || 53 | strings.HasPrefix(req.URL.Host+req.URL.Path, prefix) || 54 | strings.HasPrefix(req.URL.Scheme+req.URL.Host+req.URL.Path, prefix) 55 | } 56 | } 57 | 58 | // UrlIs returns a ReqCondition, testing whether or not the request URL is one of the given strings 59 | // with or without the host prefix. 60 | // UrlIs("google.com/","foo") will match requests 'GET /' to 'google.com', requests `'GET google.com/' to 61 | // any host, and requests of the form 'GET foo'. 62 | func UrlIs(urls ...string) ReqConditionFunc { 63 | urlSet := make(map[string]bool) 64 | for _, u := range urls { 65 | urlSet[u] = true 66 | } 67 | return func(req *http.Request, ctx *ProxyCtx) bool { 68 | _, pathOk := urlSet[req.URL.Path] 69 | _, hostAndOk := urlSet[req.URL.Host+req.URL.Path] 70 | return pathOk || hostAndOk 71 | } 72 | } 73 | 74 | // ReqHostMatches returns a ReqCondition, testing whether the host to which the request was directed to matches 75 | // any of the given regular expressions. 76 | func ReqHostMatches(regexps ...*regexp.Regexp) ReqConditionFunc { 77 | return func(req *http.Request, ctx *ProxyCtx) bool { 78 | for _, re := range regexps { 79 | if re.MatchString(req.Host) { 80 | return true 81 | } 82 | } 83 | return false 84 | } 85 | } 86 | 87 | // ReqHostIs returns a ReqCondition, testing whether the host to which the request is directed to equal 88 | // to one of the given strings 89 | func ReqHostIs(hosts ...string) ReqConditionFunc { 90 | hostSet := make(map[string]bool) 91 | for _, h := range hosts { 92 | hostSet[h] = true 93 | } 94 | return func(req *http.Request, ctx *ProxyCtx) bool { 95 | _, ok := hostSet[req.URL.Host] 96 | return ok 97 | } 98 | } 99 | 100 | var localHostIpv4 = regexp.MustCompile(`127\.0\.0\.\d+`) 101 | 102 | // IsLocalHost checks whether the destination host is explicitly local host 103 | // (buggy, there can be IPv6 addresses it doesn't catch) 104 | var IsLocalHost ReqConditionFunc = func(req *http.Request, ctx *ProxyCtx) bool { 105 | return req.URL.Host == "::1" || 106 | req.URL.Host == "0:0:0:0:0:0:0:1" || 107 | localHostIpv4.MatchString(req.URL.Host) || 108 | req.URL.Host == "localhost" 109 | } 110 | 111 | // UrlMatches returns a ReqCondition testing whether the destination URL 112 | // of the request matches the given regexp, with or without prefix 113 | func UrlMatches(re *regexp.Regexp) ReqConditionFunc { 114 | return func(req *http.Request, ctx *ProxyCtx) bool { 115 | return re.MatchString(req.URL.Path) || 116 | re.MatchString(req.URL.Host+req.URL.Path) 117 | } 118 | } 119 | 120 | // DstHostIs returns a ReqCondition testing wether the host in the request url is the given string 121 | func DstHostIs(host string) ReqConditionFunc { 122 | return func(req *http.Request, ctx *ProxyCtx) bool { 123 | return req.URL.Host == host 124 | } 125 | } 126 | 127 | // SrcIpIs returns a ReqCondition testing whether the source IP of the request is one of the given strings 128 | func SrcIpIs(ips ...string) ReqCondition { 129 | return ReqConditionFunc(func(req *http.Request, ctx *ProxyCtx) bool { 130 | for _, ip := range ips { 131 | if strings.HasPrefix(req.RemoteAddr, ip+":") { 132 | return true 133 | } 134 | } 135 | return false 136 | }) 137 | } 138 | 139 | // Not returns a ReqCondition negating the given ReqCondition 140 | func Not(r ReqCondition) ReqConditionFunc { 141 | return func(req *http.Request, ctx *ProxyCtx) bool { 142 | return !r.HandleReq(req, ctx) 143 | } 144 | } 145 | 146 | // ContentTypeIs returns a RespCondition testing whether the HTTP response has Content-Type header equal 147 | // to one of the given strings. 148 | func ContentTypeIs(typ string, types ...string) RespCondition { 149 | types = append(types, typ) 150 | return RespConditionFunc(func(resp *http.Response, ctx *ProxyCtx) bool { 151 | if resp == nil { 152 | return false 153 | } 154 | contentType := resp.Header.Get("Content-Type") 155 | for _, typ := range types { 156 | if contentType == typ || strings.HasPrefix(contentType, typ+";") { 157 | return true 158 | } 159 | } 160 | return false 161 | }) 162 | } 163 | 164 | // ProxyHttpServer.OnRequest Will return a temporary ReqProxyConds struct, aggregating the given condtions. 165 | // You will use the ReqProxyConds struct to register a ReqHandler, that would filter 166 | // the request, only if all the given ReqCondition matched. 167 | // Typical usage: 168 | // proxy.OnRequest(UrlIs("example.com/foo"),UrlMatches(regexp.MustParse(`.*\.exampl.\com\./.*`)).Do(...) 169 | func (proxy *ProxyHttpServer) OnRequest(conds ...ReqCondition) *ReqProxyConds { 170 | return &ReqProxyConds{proxy, conds} 171 | } 172 | 173 | // ReqProxyConds aggregate ReqConditions for a ProxyHttpServer. Upon calling Do, it will register a ReqHandler that would 174 | // handle the request if all conditions on the HTTP request are met. 175 | type ReqProxyConds struct { 176 | proxy *ProxyHttpServer 177 | reqConds []ReqCondition 178 | } 179 | 180 | // DoFunc is equivalent to proxy.OnRequest().Do(FuncReqHandler(f)) 181 | func (pcond *ReqProxyConds) DoFunc(f func(req *http.Request, ctx *ProxyCtx) (*http.Request, *http.Response)) { 182 | pcond.Do(FuncReqHandler(f)) 183 | } 184 | 185 | // ReqProxyConds.Do will register the ReqHandler on the proxy, 186 | // the ReqHandler will handle the HTTP request if all the conditions 187 | // aggregated in the ReqProxyConds are met. Typical usage: 188 | // proxy.OnRequest().Do(handler) // will call handler.Handle(req,ctx) on every request to the proxy 189 | // proxy.OnRequest(cond1,cond2).Do(handler) 190 | // // given request to the proxy, will test if cond1.HandleReq(req,ctx) && cond2.HandleReq(req,ctx) are true 191 | // // if they are, will call handler.Handle(req,ctx) 192 | func (pcond *ReqProxyConds) Do(h ReqHandler) { 193 | pcond.proxy.reqHandlers = append(pcond.proxy.reqHandlers, 194 | FuncReqHandler(func(r *http.Request, ctx *ProxyCtx) (*http.Request, *http.Response) { 195 | for _, cond := range pcond.reqConds { 196 | if !cond.HandleReq(r, ctx) { 197 | return r, nil 198 | } 199 | } 200 | return h.Handle(r, ctx) 201 | })) 202 | } 203 | 204 | // HandleConnect is used when proxy receives an HTTP CONNECT request, 205 | // it'll then use the HttpsHandler to determine what should it 206 | // do with this request. The handler returns a ConnectAction struct, the Action field in the ConnectAction 207 | // struct returned will determine what to do with this request. ConnectAccept will simply accept the request 208 | // forwarding all bytes from the client to the remote host, ConnectReject will close the connection with the 209 | // client, and ConnectMitm, will assume the underlying connection is an HTTPS connection, and will use Man 210 | // in the Middle attack to eavesdrop the connection. All regular handler will be active on this eavesdropped 211 | // connection. 212 | // The ConnectAction struct contains possible tlsConfig that will be used for eavesdropping. If nil, the proxy 213 | // will use the default tls configuration. 214 | // proxy.OnRequest().HandleConnect(goproxy.AlwaysReject) // rejects all CONNECT requests 215 | func (pcond *ReqProxyConds) HandleConnect(h HttpsHandler) { 216 | pcond.proxy.httpsHandlers = append(pcond.proxy.httpsHandlers, 217 | FuncHttpsHandler(func(host string, ctx *ProxyCtx) (*ConnectAction, string) { 218 | for _, cond := range pcond.reqConds { 219 | if !cond.HandleReq(ctx.Req, ctx) { 220 | return nil, "" 221 | } 222 | } 223 | return h.HandleConnect(host, ctx) 224 | })) 225 | } 226 | 227 | // HandleConnectFunc is equivalent to HandleConnect, 228 | // for example, accepting CONNECT request if they contain a password in header 229 | // io.WriteString(h,password) 230 | // passHash := h.Sum(nil) 231 | // proxy.OnRequest().HandleConnectFunc(func(host string, ctx *ProxyCtx) (*ConnectAction, string) { 232 | // c := sha1.New() 233 | // io.WriteString(c,ctx.Req.Header.Get("X-GoProxy-Auth")) 234 | // if c.Sum(nil) == passHash { 235 | // return OkConnect, host 236 | // } 237 | // return RejectConnect, host 238 | // }) 239 | func (pcond *ReqProxyConds) HandleConnectFunc(f func(host string, ctx *ProxyCtx) (*ConnectAction, string)) { 240 | pcond.HandleConnect(FuncHttpsHandler(f)) 241 | } 242 | 243 | func (pcond *ReqProxyConds) HijackConnect(f func(req *http.Request, client net.Conn, ctx *ProxyCtx)) { 244 | pcond.proxy.httpsHandlers = append(pcond.proxy.httpsHandlers, 245 | FuncHttpsHandler(func(host string, ctx *ProxyCtx) (*ConnectAction, string) { 246 | for _, cond := range pcond.reqConds { 247 | if !cond.HandleReq(ctx.Req, ctx) { 248 | return nil, "" 249 | } 250 | } 251 | return &ConnectAction{Action: ConnectHijack, Hijack: f}, host 252 | })) 253 | } 254 | 255 | // ProxyConds is used to aggregate RespConditions for a ProxyHttpServer. 256 | // Upon calling ProxyConds.Do, it will register a RespHandler that would 257 | // handle the HTTP response from remote server if all conditions on the HTTP response are met. 258 | type ProxyConds struct { 259 | proxy *ProxyHttpServer 260 | reqConds []ReqCondition 261 | respCond []RespCondition 262 | } 263 | 264 | // ProxyConds.DoFunc is equivalent to proxy.OnResponse().Do(FuncRespHandler(f)) 265 | func (pcond *ProxyConds) DoFunc(f func(resp *http.Response, ctx *ProxyCtx) *http.Response) { 266 | pcond.Do(FuncRespHandler(f)) 267 | } 268 | 269 | // ProxyConds.Do will register the RespHandler on the proxy, h.Handle(resp,ctx) will be called on every 270 | // request that matches the conditions aggregated in pcond. 271 | func (pcond *ProxyConds) Do(h RespHandler) { 272 | pcond.proxy.respHandlers = append(pcond.proxy.respHandlers, 273 | FuncRespHandler(func(resp *http.Response, ctx *ProxyCtx) *http.Response { 274 | for _, cond := range pcond.reqConds { 275 | if !cond.HandleReq(ctx.Req, ctx) { 276 | return resp 277 | } 278 | } 279 | for _, cond := range pcond.respCond { 280 | if !cond.HandleResp(resp, ctx) { 281 | return resp 282 | } 283 | } 284 | return h.Handle(resp, ctx) 285 | })) 286 | } 287 | 288 | // OnResponse is used when adding a response-filter to the HTTP proxy, usual pattern is 289 | // proxy.OnResponse(cond1,cond2).Do(handler) // handler.Handle(resp,ctx) will be used 290 | // // if cond1.HandleResp(resp) && cond2.HandleResp(resp) 291 | func (proxy *ProxyHttpServer) OnResponse(conds ...RespCondition) *ProxyConds { 292 | return &ProxyConds{proxy, make([]ReqCondition, 0), conds} 293 | } 294 | 295 | // AlwaysMitm is a HttpsHandler that always eavesdrop https connections, for example to 296 | // eavesdrop all https connections to www.google.com, we can use 297 | // proxy.OnRequest(goproxy.ReqHostIs("www.google.com")).HandleConnect(goproxy.AlwaysMitm) 298 | var AlwaysMitm FuncHttpsHandler = func(host string, ctx *ProxyCtx) (*ConnectAction, string) { 299 | return MitmConnect, host 300 | } 301 | 302 | // AlwaysReject is a HttpsHandler that drops any CONNECT request, for example, this code will disallow 303 | // connections to hosts on any other port than 443 304 | // proxy.OnRequest(goproxy.Not(goproxy.ReqHostMatches(regexp.MustCompile(":443$"))). 305 | // HandleConnect(goproxy.AlwaysReject) 306 | var AlwaysReject FuncHttpsHandler = func(host string, ctx *ProxyCtx) (*ConnectAction, string) { 307 | return RejectConnect, host 308 | } 309 | 310 | // HandleBytes will return a RespHandler that read the entire body of the request 311 | // to a byte array in memory, would run the user supplied f function on the byte arra, 312 | // and will replace the body of the original response with the resulting byte array. 313 | func HandleBytes(f func(b []byte, ctx *ProxyCtx) []byte) RespHandler { 314 | return FuncRespHandler(func(resp *http.Response, ctx *ProxyCtx) *http.Response { 315 | b, err := ioutil.ReadAll(resp.Body) 316 | if err != nil { 317 | ctx.Warnf("Cannot read response %s", err) 318 | return resp 319 | } 320 | resp.Body.Close() 321 | 322 | resp.Body = ioutil.NopCloser(bytes.NewBuffer(f(b, ctx))) 323 | return resp 324 | }) 325 | } 326 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package goproxy provides a customizable HTTP proxy, 3 | supporting hijacking HTTPS connection. 4 | 5 | The intent of the proxy, is to be usable with reasonable amount of traffic 6 | yet, customizable and programable. 7 | 8 | The proxy itself is simply an `net/http` handler. 9 | 10 | Typical usage is 11 | 12 | proxy := goproxy.NewProxyHttpServer() 13 | proxy.OnRequest(..conditions..).Do(..requesthandler..) 14 | proxy.OnRequest(..conditions..).DoFunc(..requesthandlerFunction..) 15 | proxy.OnResponse(..conditions..).Do(..responesHandler..) 16 | proxy.OnResponse(..conditions..).DoFunc(..responesHandlerFunction..) 17 | http.ListenAndServe(":8080", proxy) 18 | 19 | Adding a header to each request 20 | 21 | proxy.OnRequest().DoFunc(func(r *http.Request,ctx *goproxy.ProxyCtx) (*http.Request, *http.Response){ 22 | r.Header.Set("X-GoProxy","1") 23 | return r, nil 24 | }) 25 | 26 | Note that the function is called before the proxy sends the request to the server 27 | 28 | For printing the content type of all incoming responses 29 | 30 | proxy.OnResponse().DoFunc(func(r *http.Response, ctx *goproxy.ProxyCtx)*http.Response{ 31 | println(ctx.Req.Host,"->",r.Header.Get("Content-Type")) 32 | return r 33 | }) 34 | 35 | note that we used the ProxyCtx context variable here. It contains the request 36 | and the response (Req and Resp, Resp is nil if unavailable) of this specific client 37 | interaction with the proxy. 38 | 39 | To print the content type of all responses from a certain url, we'll add a 40 | ReqCondition to the OnResponse function: 41 | 42 | proxy.OnResponse(goproxy.UrlIs("golang.org/pkg")).DoFunc(func(r *http.Response, ctx *goproxy.ProxyCtx)*http.Response{ 43 | println(ctx.Req.Host,"->",r.Header.Get("Content-Type")) 44 | return r 45 | }) 46 | 47 | We can write the condition ourselves, conditions can be set on request and on response 48 | 49 | var random = ReqConditionFunc(func(r *http.Request) bool { 50 | return rand.Intn(1) == 0 51 | }) 52 | var hasGoProxyHeader = RespConditionFunc(func(resp *http.Response,req *http.Request)bool { 53 | return resp.Header.Get("X-GoProxy") != "" 54 | }) 55 | 56 | Caution! If you give a RespCondition to the OnRequest function, you'll get a run time panic! It doesn't 57 | make sense to read the response, if you still haven't got it! 58 | 59 | Finally, we have convenience function to throw a quick response 60 | 61 | proxy.OnResponse(hasGoProxyHeader).DoFunc(func(r*http.Response,ctx *goproxy.ProxyCtx)*http.Response { 62 | r.Body.Close() 63 | return goproxy.ForbiddenTextResponse(ctx.Req,"Can't see response with X-GoProxy header!") 64 | }) 65 | 66 | we close the body of the original repsonse, and return a new 403 response with a short message. 67 | 68 | Example use cases: 69 | 70 | 1. https://github.com/elazarl/goproxy/tree/master/examples/goproxy-avgsize 71 | 72 | To measure the average size of an Html served in your site. One can ask 73 | all the QA team to access the website by a proxy, and the proxy will 74 | measure the average size of all text/html responses from your host. 75 | 76 | 2. [not yet implemented] 77 | 78 | All requests to your web servers should be directed through the proxy, 79 | when the proxy will detect html pieces sent as a response to AJAX 80 | request, it'll send a warning email. 81 | 82 | 3. https://github.com/elazarl/goproxy/blob/master/examples/goproxy-httpdump/ 83 | 84 | Generate a real traffic to your website by real users using through 85 | proxy. Record the traffic, and try it again for more real load testing. 86 | 87 | 4. https://github.com/elazarl/goproxy/tree/master/examples/goproxy-no-reddit-at-worktime 88 | 89 | Will allow browsing to reddit.com between 8:00am and 17:00pm 90 | 91 | 5. https://github.com/elazarl/goproxy/tree/master/examples/goproxy-jquery-version 92 | 93 | Will warn if multiple versions of jquery are used in the same domain. 94 | 95 | 6. https://github.com/elazarl/goproxy/blob/master/examples/goproxy-upside-down-ternet/ 96 | 97 | Modifies image files in an HTTP response via goproxy's image extension found in ext/. 98 | 99 | */ 100 | package goproxy 101 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/examples/goproxy-basic/README.md: -------------------------------------------------------------------------------- 1 | # Simple HTTP Proxy 2 | 3 | `goproxy-basic` starts an HTTP proxy on :8080. It only handles explicit CONNECT 4 | requests. 5 | 6 | Start it in one shell: 7 | 8 | ```sh 9 | goproxy-basic -v 10 | ``` 11 | 12 | Fetch goproxy homepage in another: 13 | 14 | ```sh 15 | http_proxy=http://127.0.0.1:8080 wget -O - \ 16 | http://ripper234.com/p/introducing-goproxy-light-http-proxy/ 17 | ``` 18 | 19 | The homepage HTML content should be displayed in the console. The proxy should 20 | have logged the request being processed: 21 | 22 | ```sh 23 | 2015/04/09 18:19:17 [001] INFO: Got request /p/introducing-goproxy-light-http-proxy/ ripper234.com GET http://ripper234.com/p/introducing-goproxy-light-http-proxy/ 24 | 2015/04/09 18:19:17 [001] INFO: Sending request GET http://ripper234.com/p/introducing-goproxy-light-http-proxy/ 25 | 2015/04/09 18:19:18 [001] INFO: Received response 200 OK 26 | 2015/04/09 18:19:18 [001] INFO: Copying response to client 200 OK [200] 27 | 2015/04/09 18:19:18 [001] INFO: Copied 44333 bytes to client error= 28 | ``` 29 | 30 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/examples/goproxy-basic/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/elazarl/goproxy" 5 | "log" 6 | "flag" 7 | "net/http" 8 | ) 9 | 10 | func main() { 11 | verbose := flag.Bool("v", false, "should every proxy request be logged to stdout") 12 | addr := flag.String("addr", ":8080", "proxy listen address") 13 | flag.Parse() 14 | proxy := goproxy.NewProxyHttpServer() 15 | proxy.Verbose = *verbose 16 | log.Fatal(http.ListenAndServe(*addr, proxy)) 17 | } 18 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/examples/goproxy-eavesdropper/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "log" 6 | "net/http" 7 | "regexp" 8 | 9 | "github.com/elazarl/goproxy" 10 | ) 11 | 12 | func orPanic(err error) { 13 | if err != nil { 14 | panic(err) 15 | } 16 | } 17 | 18 | func main() { 19 | proxy := goproxy.NewProxyHttpServer() 20 | proxy.OnRequest(goproxy.ReqHostMatches(regexp.MustCompile("^.*$"))).HandleConnect(goproxy.AlwaysMitm) 21 | proxy.OnRequest().DoFunc( 22 | func(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { 23 | r.Header.Set("User-Agent", "SpinderMonkey") 24 | return r, nil 25 | }) 26 | verbose := flag.Bool("v", false, "should every proxy request be logged to stdout") 27 | addr := flag.String("addr", ":8080", "proxy listen address") 28 | flag.Parse() 29 | proxy.Verbose = *verbose 30 | log.Fatal(http.ListenAndServe(*addr, proxy)) 31 | } 32 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/examples/goproxy-httpdump/README.md: -------------------------------------------------------------------------------- 1 | # Trace HTTP Requests and Responses 2 | 3 | `goproxy-httpdump` starts an HTTP proxy on :8080. It handles explicit CONNECT 4 | requests and traces them in a "db" directory created in the proxy working 5 | directory. Each request type and headers are logged in a "log" file, while 6 | their bodies are dumped in files prefixed with the request session identifier. 7 | 8 | Additionally, the example demonstrates how to: 9 | - Log information asynchronously (see HttpLogger) 10 | - Allow the proxy to be stopped manually while ensuring all pending requests 11 | have been processed (in this case, logged). 12 | 13 | Start it in one shell: 14 | 15 | ```sh 16 | goproxy-httpdump 17 | ``` 18 | 19 | Fetch goproxy homepage in another: 20 | 21 | ```sh 22 | http_proxy=http://127.0.0.1:8080 wget -O - \ 23 | http://ripper234.com/p/introducing-goproxy-light-http-proxy/ 24 | ``` 25 | 26 | A "db" directory should have appeared where you started the proxy, containing 27 | two files: 28 | - log: the request/response traces 29 | - 1\_resp: the first response body 30 | 31 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/examples/goproxy-httpdump/httpdump.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "flag" 6 | "fmt" 7 | "io" 8 | "log" 9 | "net" 10 | "net/http" 11 | "net/http/httputil" 12 | "os" 13 | "os/signal" 14 | "path" 15 | "sync" 16 | "time" 17 | 18 | "github.com/elazarl/goproxy" 19 | "github.com/elazarl/goproxy/transport" 20 | ) 21 | 22 | type FileStream struct { 23 | path string 24 | f *os.File 25 | } 26 | 27 | func NewFileStream(path string) *FileStream { 28 | return &FileStream{path, nil} 29 | } 30 | 31 | func (fs *FileStream) Write(b []byte) (nr int, err error) { 32 | if fs.f == nil { 33 | fs.f, err = os.Create(fs.path) 34 | if err != nil { 35 | return 0, err 36 | } 37 | } 38 | return fs.f.Write(b) 39 | } 40 | 41 | func (fs *FileStream) Close() error { 42 | fmt.Println("Close", fs.path) 43 | if fs.f == nil { 44 | return errors.New("FileStream was never written into") 45 | } 46 | return fs.f.Close() 47 | } 48 | 49 | type Meta struct { 50 | req *http.Request 51 | resp *http.Response 52 | err error 53 | t time.Time 54 | sess int64 55 | bodyPath string 56 | from string 57 | } 58 | 59 | func fprintf(nr *int64, err *error, w io.Writer, pat string, a ...interface{}) { 60 | if *err != nil { 61 | return 62 | } 63 | var n int 64 | n, *err = fmt.Fprintf(w, pat, a...) 65 | *nr += int64(n) 66 | } 67 | 68 | func write(nr *int64, err *error, w io.Writer, b []byte) { 69 | if *err != nil { 70 | return 71 | } 72 | var n int 73 | n, *err = w.Write(b) 74 | *nr += int64(n) 75 | } 76 | 77 | func (m *Meta) WriteTo(w io.Writer) (nr int64, err error) { 78 | if m.req != nil { 79 | fprintf(&nr, &err, w, "Type: request\r\n") 80 | } else if m.resp != nil { 81 | fprintf(&nr, &err, w, "Type: response\r\n") 82 | } 83 | fprintf(&nr, &err, w, "ReceivedAt: %v\r\n", m.t) 84 | fprintf(&nr, &err, w, "Session: %d\r\n", m.sess) 85 | fprintf(&nr, &err, w, "From: %v\r\n", m.from) 86 | if m.err != nil { 87 | // note the empty response 88 | fprintf(&nr, &err, w, "Error: %v\r\n\r\n\r\n\r\n", m.err) 89 | } else if m.req != nil { 90 | fprintf(&nr, &err, w, "\r\n") 91 | buf, err2 := httputil.DumpRequest(m.req, false) 92 | if err2 != nil { 93 | return nr, err2 94 | } 95 | write(&nr, &err, w, buf) 96 | } else if m.resp != nil { 97 | fprintf(&nr, &err, w, "\r\n") 98 | buf, err2 := httputil.DumpResponse(m.resp, false) 99 | if err2 != nil { 100 | return nr, err2 101 | } 102 | write(&nr, &err, w, buf) 103 | } 104 | return 105 | } 106 | 107 | // HttpLogger is an asynchronous HTTP request/response logger. It traces 108 | // requests and responses headers in a "log" file in logger directory and dumps 109 | // their bodies in files prefixed with the session identifiers. 110 | // Close it to ensure pending items are correctly logged. 111 | type HttpLogger struct { 112 | path string 113 | c chan *Meta 114 | errch chan error 115 | } 116 | 117 | func NewLogger(basepath string) (*HttpLogger, error) { 118 | f, err := os.Create(path.Join(basepath, "log")) 119 | if err != nil { 120 | return nil, err 121 | } 122 | logger := &HttpLogger{basepath, make(chan *Meta), make(chan error)} 123 | go func() { 124 | for m := range logger.c { 125 | if _, err := m.WriteTo(f); err != nil { 126 | log.Println("Can't write meta", err) 127 | } 128 | } 129 | logger.errch <- f.Close() 130 | }() 131 | return logger, nil 132 | } 133 | 134 | func (logger *HttpLogger) LogResp(resp *http.Response, ctx *goproxy.ProxyCtx) { 135 | body := path.Join(logger.path, fmt.Sprintf("%d_resp", ctx.Session)) 136 | from := "" 137 | if ctx.UserData != nil { 138 | from = ctx.UserData.(*transport.RoundTripDetails).TCPAddr.String() 139 | } 140 | if resp == nil { 141 | resp = emptyResp 142 | } else { 143 | resp.Body = NewTeeReadCloser(resp.Body, NewFileStream(body)) 144 | } 145 | logger.LogMeta(&Meta{ 146 | resp: resp, 147 | err: ctx.Error, 148 | t: time.Now(), 149 | sess: ctx.Session, 150 | from: from}) 151 | } 152 | 153 | var emptyResp = &http.Response{} 154 | var emptyReq = &http.Request{} 155 | 156 | func (logger *HttpLogger) LogReq(req *http.Request, ctx *goproxy.ProxyCtx) { 157 | body := path.Join(logger.path, fmt.Sprintf("%d_req", ctx.Session)) 158 | if req == nil { 159 | req = emptyReq 160 | } else { 161 | req.Body = NewTeeReadCloser(req.Body, NewFileStream(body)) 162 | } 163 | logger.LogMeta(&Meta{ 164 | req: req, 165 | err: ctx.Error, 166 | t: time.Now(), 167 | sess: ctx.Session, 168 | from: req.RemoteAddr}) 169 | } 170 | 171 | func (logger *HttpLogger) LogMeta(m *Meta) { 172 | logger.c <- m 173 | } 174 | 175 | func (logger *HttpLogger) Close() error { 176 | close(logger.c) 177 | return <-logger.errch 178 | } 179 | 180 | // TeeReadCloser extends io.TeeReader by allowing reader and writer to be 181 | // closed. 182 | type TeeReadCloser struct { 183 | r io.Reader 184 | w io.WriteCloser 185 | c io.Closer 186 | } 187 | 188 | func NewTeeReadCloser(r io.ReadCloser, w io.WriteCloser) io.ReadCloser { 189 | return &TeeReadCloser{io.TeeReader(r, w), w, r} 190 | } 191 | 192 | func (t *TeeReadCloser) Read(b []byte) (int, error) { 193 | return t.r.Read(b) 194 | } 195 | 196 | // Close attempts to close the reader and write. It returns an error if both 197 | // failed to Close. 198 | func (t *TeeReadCloser) Close() error { 199 | err1 := t.c.Close() 200 | err2 := t.w.Close() 201 | if err1 != nil { 202 | return err1 203 | } 204 | return err2 205 | } 206 | 207 | // stoppableListener serves stoppableConn and tracks their lifetime to notify 208 | // when it is safe to terminate the application. 209 | type stoppableListener struct { 210 | net.Listener 211 | sync.WaitGroup 212 | } 213 | 214 | type stoppableConn struct { 215 | net.Conn 216 | wg *sync.WaitGroup 217 | } 218 | 219 | func newStoppableListener(l net.Listener) *stoppableListener { 220 | return &stoppableListener{l, sync.WaitGroup{}} 221 | } 222 | 223 | func (sl *stoppableListener) Accept() (net.Conn, error) { 224 | c, err := sl.Listener.Accept() 225 | if err != nil { 226 | return c, err 227 | } 228 | sl.Add(1) 229 | return &stoppableConn{c, &sl.WaitGroup}, nil 230 | } 231 | 232 | func (sc *stoppableConn) Close() error { 233 | sc.wg.Done() 234 | return sc.Conn.Close() 235 | } 236 | 237 | func main() { 238 | verbose := flag.Bool("v", false, "should every proxy request be logged to stdout") 239 | addr := flag.String("l", ":8080", "on which address should the proxy listen") 240 | flag.Parse() 241 | proxy := goproxy.NewProxyHttpServer() 242 | proxy.Verbose = *verbose 243 | if err := os.MkdirAll("db", 0755); err != nil { 244 | log.Fatal("Can't create dir", err) 245 | } 246 | logger, err := NewLogger("db") 247 | if err != nil { 248 | log.Fatal("can't open log file", err) 249 | } 250 | tr := transport.Transport{Proxy: transport.ProxyFromEnvironment} 251 | // For every incoming request, override the RoundTripper to extract 252 | // connection information. Store it is session context log it after 253 | // handling the response. 254 | proxy.OnRequest().DoFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { 255 | ctx.RoundTripper = goproxy.RoundTripperFunc(func(req *http.Request, ctx *goproxy.ProxyCtx) (resp *http.Response, err error) { 256 | ctx.UserData, resp, err = tr.DetailedRoundTrip(req) 257 | return 258 | }) 259 | logger.LogReq(req, ctx) 260 | return req, nil 261 | }) 262 | proxy.OnResponse().DoFunc(func(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response { 263 | logger.LogResp(resp, ctx) 264 | return resp 265 | }) 266 | l, err := net.Listen("tcp", *addr) 267 | if err != nil { 268 | log.Fatal("listen:", err) 269 | } 270 | sl := newStoppableListener(l) 271 | ch := make(chan os.Signal) 272 | signal.Notify(ch, os.Interrupt) 273 | go func() { 274 | <-ch 275 | log.Println("Got SIGINT exiting") 276 | sl.Add(1) 277 | sl.Close() 278 | logger.Close() 279 | sl.Done() 280 | }() 281 | log.Println("Starting Proxy") 282 | http.Serve(sl, proxy) 283 | sl.Wait() 284 | log.Println("All connections closed - exit") 285 | } 286 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/examples/goproxy-jquery-version/README.md: -------------------------------------------------------------------------------- 1 | # Content Analysis 2 | 3 | `goproxy-jquery-version` starts an HTTP proxy on :8080. It checks HTML 4 | responses, looks for scripts referencing jQuery library and emits warnings if 5 | different versions of the library are being used for a given host. 6 | 7 | Start it in one shell: 8 | 9 | ```sh 10 | goproxy-jquery-version 11 | ``` 12 | 13 | Fetch goproxy homepage in another: 14 | 15 | ```sh 16 | http_proxy=http://127.0.0.1:8080 wget -O - \ 17 | http://ripper234.com/p/introducing-goproxy-light-http-proxy/ 18 | ``` 19 | 20 | Goproxy homepage uses jQuery and a mix of plugins. First the proxy reports the 21 | first use of jQuery it detects for the domain. Then, because the regular 22 | expression matching the jQuery sources is imprecise, it reports a mismatch with 23 | a plugin reference: 24 | 25 | ```sh 26 | 2015/04/11 11:23:02 [001] WARN: ripper234.com uses //ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js 27 | 2015/04/11 11:23:02 [001] WARN: In http://ripper234.com/p/introducing-goproxy-light-http-proxy/, \ 28 | Contradicting jqueries //ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js \ 29 | http://ripper234.wpengine.netdna-cdn.com/wp-content/plugins/wp-ajax-edit-comments/js/jquery.colorbox.min.js?ver=5.0.36 30 | ``` 31 | 32 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/examples/goproxy-jquery-version/jquery1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/examples/goproxy-jquery-version/jquery2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/examples/goproxy-jquery-version/jquery_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "io/ioutil" 6 | "log" 7 | "net/http" 8 | "net/http/httptest" 9 | "net/url" 10 | "strings" 11 | "testing" 12 | ) 13 | 14 | func equal(u, v []string) bool { 15 | if len(u) != len(v) { 16 | return false 17 | } 18 | for i, _ := range u { 19 | if u[i] != v[i] { 20 | return false 21 | } 22 | } 23 | return true 24 | } 25 | 26 | func readFile(fname string, t *testing.T) string { 27 | b, err := ioutil.ReadFile(fname) 28 | if err != nil { 29 | t.Fatal("readFile", err) 30 | } 31 | return string(b) 32 | } 33 | 34 | func TestDefectiveScriptParser(t *testing.T) { 35 | if l := len(findScriptSrc(` 36 | 37 | 38 | 39 | 45 | 46 | 47 | `)); l != 0 { 48 | t.Fail() 49 | } 50 | urls := findScriptSrc(readFile("w3schools.html", t)) 51 | if !equal(urls, []string{"http://partner.googleadservices.com/gampad/google_service.js", 52 | "//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"}) { 53 | t.Error("w3schools.html", "src scripts are not recognized", urls) 54 | } 55 | urls = findScriptSrc(readFile("jquery_homepage.html", t)) 56 | if !equal(urls, []string{"http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js", 57 | "http://code.jquery.com/jquery-1.4.2.min.js", 58 | "http://static.jquery.com/files/rocker/scripts/custom.js", 59 | "http://static.jquery.com/donate/donate.js"}) { 60 | t.Error("jquery_homepage.html", "src scripts are not recognized", urls) 61 | } 62 | } 63 | 64 | func proxyWithLog() (*http.Client, *bytes.Buffer) { 65 | proxy := NewJqueryVersionProxy() 66 | proxyServer := httptest.NewServer(proxy) 67 | buf := new(bytes.Buffer) 68 | proxy.Logger = log.New(buf, "", 0) 69 | proxyUrl, _ := url.Parse(proxyServer.URL) 70 | tr := &http.Transport{Proxy: http.ProxyURL(proxyUrl)} 71 | client := &http.Client{Transport: tr} 72 | return client, buf 73 | } 74 | 75 | func get(t *testing.T, server *httptest.Server, client *http.Client, url string) { 76 | resp, err := client.Get(server.URL + url) 77 | if err != nil { 78 | t.Fatal("cannot get proxy", err) 79 | } 80 | ioutil.ReadAll(resp.Body) 81 | resp.Body.Close() 82 | } 83 | 84 | func TestProxyServiceTwoVersions(t *testing.T) { 85 | var fs = httptest.NewServer(http.FileServer(http.Dir("."))) 86 | defer fs.Close() 87 | 88 | client, buf := proxyWithLog() 89 | 90 | get(t, fs, client, "/w3schools.html") 91 | get(t, fs, client, "/php_man.html") 92 | if buf.String() != "" && 93 | !strings.Contains(buf.String(), " uses jquery ") { 94 | t.Error("shouldn't warn on a single URL", buf.String()) 95 | } 96 | get(t, fs, client, "/jquery1.html") 97 | warnings := buf.String() 98 | if !strings.Contains(warnings, "http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js") || 99 | !strings.Contains(warnings, "jquery.1.4.js") || 100 | !strings.Contains(warnings, "Contradicting") { 101 | t.Error("contradicting jquery versions (php_man.html, w3schools.html) does not issue warning", warnings) 102 | } 103 | } 104 | 105 | func TestProxyService(t *testing.T) { 106 | var fs = httptest.NewServer(http.FileServer(http.Dir("."))) 107 | defer fs.Close() 108 | 109 | client, buf := proxyWithLog() 110 | 111 | get(t, fs, client, "/jquery_homepage.html") 112 | warnings := buf.String() 113 | if !strings.Contains(warnings, "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js") || 114 | !strings.Contains(warnings, "http://code.jquery.com/jquery-1.4.2.min.js") || 115 | !strings.Contains(warnings, "Contradicting") { 116 | t.Error("contradicting jquery versions does not issue warning") 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/examples/goproxy-jquery-version/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/elazarl/goproxy" 5 | "github.com/elazarl/goproxy/ext/html" 6 | "log" 7 | "net/http" 8 | "regexp" 9 | ) 10 | 11 | var ( 12 | // who said we can't parse HTML with regexp? 13 | scriptMatcher = regexp.MustCompile(`(?i:]*\ssrc=["']([^"']*)["'])`) 15 | ) 16 | 17 | // findScripts returns all sources of HTML script tags found in input text. 18 | func findScriptSrc(html string) []string { 19 | srcs := make([]string, 0) 20 | matches := scriptMatcher.FindAllStringIndex(html, -1) 21 | for _, match := range matches { 22 | // -1 to capture the whitespace at the end of the script tag 23 | srcMatch := srcAttrMatcher.FindStringSubmatch(html[match[1]-1:]) 24 | if srcMatch != nil { 25 | srcs = append(srcs, srcMatch[1]) 26 | } 27 | } 28 | return srcs 29 | } 30 | 31 | // NewJQueryVersionProxy creates a proxy checking responses HTML content, looks 32 | // for scripts referencing jQuery library and emits warnings if different 33 | // versions of the library are being used for a given host. 34 | func NewJqueryVersionProxy() *goproxy.ProxyHttpServer { 35 | proxy := goproxy.NewProxyHttpServer() 36 | m := make(map[string]string) 37 | jqueryMatcher := regexp.MustCompile(`(?i:jquery\.)`) 38 | proxy.OnResponse(goproxy_html.IsHtml).Do(goproxy_html.HandleString( 39 | func(s string, ctx *goproxy.ProxyCtx) string { 40 | for _, src := range findScriptSrc(s) { 41 | if !jqueryMatcher.MatchString(src) { 42 | continue 43 | } 44 | prev, ok := m[ctx.Req.Host] 45 | if ok { 46 | if prev != src { 47 | ctx.Warnf("In %v, Contradicting jqueries %v %v", 48 | ctx.Req.URL, prev, src) 49 | break 50 | } 51 | } else { 52 | ctx.Warnf("%s uses jquery %s", ctx.Req.Host, src) 53 | m[ctx.Req.Host] = src 54 | } 55 | } 56 | return s 57 | })) 58 | return proxy 59 | } 60 | 61 | func main() { 62 | proxy := NewJqueryVersionProxy() 63 | log.Fatal(http.ListenAndServe(":8080", proxy)) 64 | } 65 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/examples/goproxy-no-reddit-at-worktime/README.md: -------------------------------------------------------------------------------- 1 | # Request Filtering 2 | 3 | `goproxy-no-reddit-at-work` starts an HTTP proxy on :8080. It denies requests 4 | to "www.reddit.com" made between 8am to 5pm inclusive, local time. 5 | 6 | Start it in one shell: 7 | 8 | ```sh 9 | $ goproxy-no-reddit-at-work 10 | ``` 11 | 12 | Fetch reddit in another: 13 | 14 | ```sh 15 | $ http_proxy=http://127.0.0.1:8080 wget -O - http://www.reddit.com 16 | --2015-04-11 16:59:01-- http://www.reddit.com/ 17 | Connecting to 127.0.0.1:8080... connected. 18 | Proxy request sent, awaiting response... 403 Forbidden 19 | 2015-04-11 16:59:01 ERROR 403: Forbidden. 20 | ``` 21 | 22 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/examples/goproxy-no-reddit-at-worktime/noreddit.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/elazarl/goproxy" 5 | "log" 6 | "net/http" 7 | "time" 8 | ) 9 | 10 | func main() { 11 | proxy := goproxy.NewProxyHttpServer() 12 | proxy.OnRequest(goproxy.DstHostIs("www.reddit.com")).DoFunc( 13 | func(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { 14 | h, _, _ := time.Now().Clock() 15 | if h >= 8 && h <= 17 { 16 | return r, goproxy.NewResponse(r, 17 | goproxy.ContentTypeText, http.StatusForbidden, 18 | "Don't waste your time!") 19 | } else { 20 | ctx.Warnf("clock: %d, you can waste your time...", h) 21 | } 22 | return r, nil 23 | }) 24 | log.Fatalln(http.ListenAndServe(":8080", proxy)) 25 | } 26 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/examples/goproxy-sokeepalive/sokeepalive.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "github.com/elazarl/goproxy" 6 | "log" 7 | "net" 8 | "net/http" 9 | ) 10 | 11 | func main() { 12 | verbose := flag.Bool("v", false, "should every proxy request be logged to stdout") 13 | addr := flag.String("addr", ":8080", "proxy listen address") 14 | flag.Parse() 15 | proxy := goproxy.NewProxyHttpServer() 16 | proxy.Tr.Dial = func(network, addr string) (c net.Conn, err error) { 17 | c, err = net.Dial(network, addr) 18 | if c, ok := c.(*net.TCPConn); err == nil && ok { 19 | c.SetKeepAlive(true) 20 | } 21 | return 22 | } 23 | proxy.Verbose = *verbose 24 | log.Fatal(http.ListenAndServe(*addr, proxy)) 25 | } 26 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/examples/goproxy-sslstrip/sslstrip.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/elazarl/goproxy" 5 | "log" 6 | "flag" 7 | "net/http" 8 | ) 9 | 10 | func main() { 11 | verbose := flag.Bool("v", false, "should every proxy request be logged to stdout") 12 | addr := flag.String("addr", ":8080", "proxy listen address") 13 | flag.Parse() 14 | proxy := goproxy.NewProxyHttpServer() 15 | proxy.OnRequest().HandleConnect(goproxy.AlwaysMitm) 16 | proxy.OnRequest().DoFunc(func (req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { 17 | if req.URL.Scheme == "https" { 18 | req.URL.Scheme = "http" 19 | } 20 | return req, nil 21 | }) 22 | proxy.Verbose = *verbose 23 | log.Fatal(http.ListenAndServe(*addr, proxy)) 24 | } 25 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/examples/goproxy-stats/README.md: -------------------------------------------------------------------------------- 1 | # Gather Browsing Statistics 2 | 3 | `goproxy-stats` starts an HTTP proxy on :8080, counts the bytes received for 4 | web resources and prints the cumulative sum per URL every 20 seconds. 5 | 6 | Start it in one shell: 7 | 8 | ```sh 9 | goproxy-stats 10 | ``` 11 | 12 | Fetch goproxy homepage in another: 13 | 14 | ```sh 15 | mkdir tmp 16 | cd tmp 17 | http_proxy=http://127.0.0.1:8080 wget -r -l 1 -H \ 18 | http://ripper234.com/p/introducing-goproxy-light-http-proxy/ 19 | ``` 20 | 21 | Stop it after a moment. `goproxy-stats` should eventually print: 22 | ```sh 23 | listening on :8080 24 | statistics 25 | http://www.telerik.com/fiddler -> 84335 26 | http://msmvps.com/robots.txt -> 157 27 | http://eli.thegreenplace.net/robots.txt -> 294 28 | http://www.phdcomics.com/robots.txt -> 211 29 | http://resharper.blogspot.com/robots.txt -> 221 30 | http://idanz.blogli.co.il/robots.txt -> 271 31 | http://ripper234.com/p/introducing-goproxy-light-http-proxy/ -> 44407 32 | http://live.gnome.org/robots.txt -> 298 33 | http://ponetium.wordpress.com/robots.txt -> 178 34 | http://pilaheleg.blogli.co.il/robots.txt -> 321 35 | http://pilaheleg.wordpress.com/robots.txt -> 178 36 | http://blogli.co.il/ -> 9165 37 | http://nimrod-code.org/robots.txt -> 289 38 | http://www.joelonsoftware.com/robots.txt -> 1245 39 | http://top-performance.blogspot.com/robots.txt -> 227 40 | http://ooc-lang.org/robots.txt -> 345 41 | http://blogs.jetbrains.com/robots.txt -> 293 42 | ``` 43 | 44 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/examples/goproxy-stats/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/elazarl/goproxy" 6 | "github.com/elazarl/goproxy/ext/html" 7 | "io" 8 | "log" 9 | . "net/http" 10 | "time" 11 | ) 12 | 13 | type Count struct { 14 | Id string 15 | Count int64 16 | } 17 | type CountReadCloser struct { 18 | Id string 19 | R io.ReadCloser 20 | ch chan<- Count 21 | nr int64 22 | } 23 | 24 | func (c *CountReadCloser) Read(b []byte) (n int, err error) { 25 | n, err = c.R.Read(b) 26 | c.nr += int64(n) 27 | return 28 | } 29 | func (c CountReadCloser) Close() error { 30 | c.ch <- Count{c.Id, c.nr} 31 | return c.R.Close() 32 | } 33 | 34 | func main() { 35 | proxy := goproxy.NewProxyHttpServer() 36 | timer := make(chan bool) 37 | ch := make(chan Count, 10) 38 | go func() { 39 | for { 40 | time.Sleep(20 * time.Second) 41 | timer <- true 42 | } 43 | }() 44 | go func() { 45 | m := make(map[string]int64) 46 | for { 47 | select { 48 | case c := <-ch: 49 | m[c.Id] = m[c.Id] + c.Count 50 | case <-timer: 51 | fmt.Printf("statistics\n") 52 | for k, v := range m { 53 | fmt.Printf("%s -> %d\n", k, v) 54 | } 55 | } 56 | } 57 | }() 58 | 59 | // IsWebRelatedText filters on html/javascript/css resources 60 | proxy.OnResponse(goproxy_html.IsWebRelatedText).DoFunc(func(resp *Response, ctx *goproxy.ProxyCtx) *Response { 61 | resp.Body = &CountReadCloser{ctx.Req.URL.String(), resp.Body, ch, 0} 62 | return resp 63 | }) 64 | fmt.Printf("listening on :8080\n") 65 | log.Fatal(ListenAndServe(":8080", proxy)) 66 | } 67 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/examples/goproxy-transparent/README.md: -------------------------------------------------------------------------------- 1 | # Transparent Proxy 2 | 3 | This transparent example in goproxy is meant to show how to transparenty proxy and hijack all http and https connections while doing a man-in-the-middle to the TLS session. It requires that goproxy sees all the packets traversing out to the internet. Linux iptables rules deal with changing the source/destination IPs to act transparently, but you do need to setup your network configuration so that goproxy is a mandatory stop on the outgoing route. Primarily you can do this by placing the proxy inline. goproxy does not have any WCCP support itself; patches welcome. 4 | 5 | ## Why not explicit? 6 | 7 | Transparent proxies are more difficult to maintain and setup from a server side, but they require no configuration on the client(s) which could be in unmanaged systems or systems that don't support a proxy configuration. See the [eavesdropper example](https://github.com/elazarl/goproxy/blob/master/examples/goproxy-eavesdropper/main.go) if you want to see an explicit proxy example. 8 | 9 | ## Potential Issues 10 | 11 | Support for very old clients using HTTPS will fail. Clients need to send the SNI value in the TLS ClientHello which most modern clients do these days, but old clients will break. 12 | 13 | If you're routing table allows for it, an explicit http request to goproxy will cause it to fail in an endless loop since it will try to request resources from itself repeatedly. This could be solved in the goproxy code by looking up the hostnames, but it adds a delay that is much easier/faster to handle on the routing side. 14 | 15 | ## Routing Rules 16 | 17 | Example routing rules are included in [proxy.sh](https://github.com/elazarl/goproxy/blob/master/examples/goproxy-transparent/proxy.sh) but are best when setup using your distribution's configuration. 18 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/examples/goproxy-transparent/proxy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # goproxy IP 3 | GOPROXY_SERVER="10.10.10.1" 4 | # goproxy port 5 | GOPROXY_PORT="3129" 6 | GOPROXY_PORT_TLS="3128" 7 | # DO NOT MODIFY BELOW 8 | # Load IPTABLES modules for NAT and IP conntrack support 9 | modprobe ip_conntrack 10 | modprobe ip_conntrack_ftp 11 | echo 1 > /proc/sys/net/ipv4/ip_forward 12 | echo 2 > /proc/sys/net/ipv4/conf/all/rp_filter 13 | 14 | # Clean old firewall 15 | iptables -t nat -F 16 | iptables -t nat -X 17 | iptables -t mangle -F 18 | iptables -t mangle -X 19 | 20 | # Write new rules 21 | iptables -t nat -A PREROUTING -s $GOPROXY_SERVER -p tcp --dport $GOPROXY_PORT -j ACCEPT 22 | iptables -t nat -A PREROUTING -s $GOPROXY_SERVER -p tcp --dport $GOPROXY_PORT_TLS -j ACCEPT 23 | iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination $GOPROXY_SERVER:$GOPROXY_PORT 24 | iptables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT --to-destination $GOPROXY_SERVER:$GOPROXY_PORT_TLS 25 | # The following line supports using goproxy as an explicit proxy in addition 26 | iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination $GOPROXY_SERVER:$GOPROXY_PORT 27 | iptables -t nat -A POSTROUTING -j MASQUERADE 28 | iptables -t mangle -A PREROUTING -p tcp --dport $GOPROXY_PORT -j DROP 29 | iptables -t mangle -A PREROUTING -p tcp --dport $GOPROXY_PORT_TLS -j DROP 30 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/examples/goproxy-transparent/transparent.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "flag" 7 | "fmt" 8 | "log" 9 | "net" 10 | "net/http" 11 | "net/url" 12 | "regexp" 13 | 14 | "github.com/elazarl/goproxy" 15 | "github.com/inconshreveable/go-vhost" 16 | ) 17 | 18 | func orPanic(err error) { 19 | if err != nil { 20 | panic(err) 21 | } 22 | } 23 | 24 | func main() { 25 | verbose := flag.Bool("v", true, "should every proxy request be logged to stdout") 26 | http_addr := flag.String("httpaddr", ":3129", "proxy http listen address") 27 | https_addr := flag.String("httpsaddr", ":3128", "proxy https listen address") 28 | flag.Parse() 29 | 30 | proxy := goproxy.NewProxyHttpServer() 31 | proxy.Verbose = *verbose 32 | if proxy.Verbose { 33 | log.Printf("Server starting up! - configured to listen on http interface %s and https interface %s", *http_addr, *https_addr) 34 | } 35 | 36 | proxy.NonproxyHandler = http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { 37 | if req.Host == "" { 38 | fmt.Fprintln(w, "Cannot handle requests without Host header, e.g., HTTP 1.0") 39 | return 40 | } 41 | req.URL.Scheme = "http" 42 | req.URL.Host = req.Host 43 | proxy.ServeHTTP(w, req) 44 | }) 45 | proxy.OnRequest(goproxy.ReqHostMatches(regexp.MustCompile("^.*$"))). 46 | HandleConnect(goproxy.AlwaysMitm) 47 | proxy.OnRequest(goproxy.ReqHostMatches(regexp.MustCompile("^.*:80$"))). 48 | HijackConnect(func(req *http.Request, client net.Conn, ctx *goproxy.ProxyCtx) { 49 | defer func() { 50 | if e := recover(); e != nil { 51 | ctx.Logf("error connecting to remote: %v", e) 52 | client.Write([]byte("HTTP/1.1 500 Cannot reach destination\r\n\r\n")) 53 | } 54 | client.Close() 55 | }() 56 | clientBuf := bufio.NewReadWriter(bufio.NewReader(client), bufio.NewWriter(client)) 57 | remote, err := connectDial(proxy, "tcp", req.URL.Host) 58 | orPanic(err) 59 | remoteBuf := bufio.NewReadWriter(bufio.NewReader(remote), bufio.NewWriter(remote)) 60 | for { 61 | req, err := http.ReadRequest(clientBuf.Reader) 62 | orPanic(err) 63 | orPanic(req.Write(remoteBuf)) 64 | orPanic(remoteBuf.Flush()) 65 | resp, err := http.ReadResponse(remoteBuf.Reader, req) 66 | orPanic(err) 67 | orPanic(resp.Write(clientBuf.Writer)) 68 | orPanic(clientBuf.Flush()) 69 | } 70 | }) 71 | 72 | go func() { 73 | log.Fatalln(http.ListenAndServe(*http_addr, proxy)) 74 | }() 75 | 76 | // listen to the TLS ClientHello but make it a CONNECT request instead 77 | ln, err := net.Listen("tcp", *https_addr) 78 | if err != nil { 79 | log.Fatalf("Error listening for https connections - %v", err) 80 | } 81 | for { 82 | c, err := ln.Accept() 83 | if err != nil { 84 | log.Printf("Error accepting new connection - %v", err) 85 | continue 86 | } 87 | go func(c net.Conn) { 88 | tlsConn, err := vhost.TLS(c) 89 | if err != nil { 90 | log.Printf("Error accepting new connection - %v", err) 91 | } 92 | if tlsConn.Host() == "" { 93 | log.Printf("Cannot support non-SNI enabled clients") 94 | return 95 | } 96 | connectReq := &http.Request{ 97 | Method: "CONNECT", 98 | URL: &url.URL{ 99 | Opaque: tlsConn.Host(), 100 | Host: net.JoinHostPort(tlsConn.Host(), "443"), 101 | }, 102 | Host: tlsConn.Host(), 103 | Header: make(http.Header), 104 | } 105 | resp := dumbResponseWriter{tlsConn} 106 | proxy.ServeHTTP(resp, connectReq) 107 | }(c) 108 | } 109 | } 110 | 111 | // copied/converted from https.go 112 | func dial(proxy *goproxy.ProxyHttpServer, network, addr string) (c net.Conn, err error) { 113 | if proxy.Tr.Dial != nil { 114 | return proxy.Tr.Dial(network, addr) 115 | } 116 | return net.Dial(network, addr) 117 | } 118 | 119 | // copied/converted from https.go 120 | func connectDial(proxy *goproxy.ProxyHttpServer, network, addr string) (c net.Conn, err error) { 121 | if proxy.ConnectDial == nil { 122 | return dial(proxy, network, addr) 123 | } 124 | return proxy.ConnectDial(network, addr) 125 | } 126 | 127 | type dumbResponseWriter struct { 128 | net.Conn 129 | } 130 | 131 | func (dumb dumbResponseWriter) Header() http.Header { 132 | panic("Header() should not be called on this ResponseWriter") 133 | } 134 | 135 | func (dumb dumbResponseWriter) Write(buf []byte) (int, error) { 136 | if bytes.Equal(buf, []byte("HTTP/1.0 200 OK\r\n\r\n")) { 137 | return len(buf), nil // throw away the HTTP OK response from the faux CONNECT request 138 | } 139 | return dumb.Conn.Write(buf) 140 | } 141 | 142 | func (dumb dumbResponseWriter) WriteHeader(code int) { 143 | panic("WriteHeader() should not be called on this ResponseWriter") 144 | } 145 | 146 | func (dumb dumbResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { 147 | return dumb, bufio.NewReadWriter(bufio.NewReader(dumb), bufio.NewWriter(dumb)), nil 148 | } 149 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/examples/goproxy-upside-down-ternet/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/elazarl/goproxy" 5 | "github.com/elazarl/goproxy/ext/image" 6 | "image" 7 | "log" 8 | "net/http" 9 | ) 10 | 11 | func main() { 12 | proxy := goproxy.NewProxyHttpServer() 13 | proxy.OnResponse().Do(goproxy_image.HandleImage(func(img image.Image, ctx *goproxy.ProxyCtx) image.Image { 14 | dx, dy := img.Bounds().Dx(), img.Bounds().Dy() 15 | 16 | nimg := image.NewRGBA(img.Bounds()) 17 | for i := 0; i < dx; i++ { 18 | for j := 0; j <= dy; j++ { 19 | nimg.Set(i, j, img.At(i, dy-j-1)) 20 | } 21 | } 22 | return nimg 23 | })) 24 | proxy.Verbose = true 25 | log.Fatal(http.ListenAndServe(":8080", proxy)) 26 | } 27 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/examples/goproxy-yui-minify/yui.go: -------------------------------------------------------------------------------- 1 | // This example would minify standalone Javascript files (identified by their content type) 2 | // using the command line utility YUI compressor http://yui.github.io/yuicompressor/ 3 | // Example usage: 4 | // 5 | // ./yui -java /usr/local/bin/java -yuicompressor ~/Downloads/yuicompressor-2.4.8.jar 6 | // $ curl -vx localhost:8080 http://golang.org/lib/godoc/godocs.js 7 | // (function(){function g(){var u=$("#search");if(u.length===0){return}function t(){if(.... 8 | // $ curl http://golang.org/lib/godoc/godocs.js | head -n 3 9 | // // Copyright 2012 The Go Authors. All rights reserved. 10 | // // Use of this source code is governed by a BSD-style 11 | // // license that can be found in the LICENSE file. 12 | package main 13 | 14 | import ( 15 | "flag" 16 | "io" 17 | "io/ioutil" 18 | "log" 19 | "net/http" 20 | "os" 21 | "os/exec" 22 | "path" 23 | "strings" 24 | 25 | "github.com/elazarl/goproxy" 26 | ) 27 | 28 | func main() { 29 | verbose := flag.Bool("v", false, "should every proxy request be logged to stdout") 30 | addr := flag.String("addr", ":8080", "proxy listen address") 31 | java := flag.String("javapath", "java", "where the Java executable is located") 32 | yuicompressor := flag.String("yuicompressor", "", "where the yuicompressor is located, assumed to be in CWD") 33 | yuicompressordir := flag.String("yuicompressordir", ".", "a folder to search yuicompressor in, will be ignored if yuicompressor is set") 34 | flag.Parse() 35 | if *yuicompressor == "" { 36 | files, err := ioutil.ReadDir(*yuicompressordir) 37 | if err != nil { 38 | log.Fatal("Cannot find yuicompressor jar") 39 | } 40 | for _, file := range files { 41 | if strings.HasPrefix(file.Name(), "yuicompressor") && strings.HasSuffix(file.Name(), ".jar") { 42 | c := path.Join(*yuicompressordir, file.Name()) 43 | yuicompressor = &c 44 | break 45 | } 46 | } 47 | } 48 | if *yuicompressor == "" { 49 | log.Fatal("Can't find yuicompressor jar, searched yuicompressor*.jar in dir ", *yuicompressordir) 50 | } 51 | if _, err := os.Stat(*yuicompressor); os.IsNotExist(err) { 52 | log.Fatal("Can't find yuicompressor jar specified ", *yuicompressor) 53 | } 54 | proxy := goproxy.NewProxyHttpServer() 55 | proxy.Verbose = *verbose 56 | proxy.OnResponse().DoFunc(func(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response { 57 | contentType := resp.Header.Get("Content-Type") 58 | if contentType == "application/javascript" || contentType == "application/x-javascript" { 59 | // in real code, response should be streamed as well 60 | var err error 61 | cmd := exec.Command(*java, "-jar", *yuicompressor, "--type", "js") 62 | cmd.Stdin = resp.Body 63 | resp.Body, err = cmd.StdoutPipe() 64 | if err != nil { 65 | ctx.Warnf("Cannot minify content in %v: %v", ctx.Req.URL, err) 66 | return goproxy.TextResponse(ctx.Req, "Error getting stdout pipe") 67 | } 68 | stderr, err := cmd.StderrPipe() 69 | if err != nil { 70 | ctx.Logf("Error obtaining stderr from yuicompress: %s", err) 71 | return goproxy.TextResponse(ctx.Req, "Error getting stderr pipe") 72 | } 73 | if err := cmd.Start(); err != nil { 74 | ctx.Warnf("Cannot minify content in %v: %v", ctx.Req.URL, err) 75 | } 76 | go func() { 77 | defer stderr.Close() 78 | const kb = 1024 79 | msg, err := ioutil.ReadAll(&io.LimitedReader{stderr, 50 * kb}) 80 | if len(msg) != 0 { 81 | ctx.Logf("Error executing yuicompress: %s", string(msg)) 82 | } 83 | if err != nil { 84 | ctx.Logf("Error reading stderr from yuicompress: %s", string(msg)) 85 | } 86 | }() 87 | } 88 | return resp 89 | }) 90 | log.Fatal(http.ListenAndServe(*addr, proxy)) 91 | } 92 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/ext/auth/basic.go: -------------------------------------------------------------------------------- 1 | package auth 2 | 3 | import ( 4 | "bytes" 5 | "encoding/base64" 6 | "io/ioutil" 7 | "net/http" 8 | "strings" 9 | 10 | "github.com/elazarl/goproxy" 11 | ) 12 | 13 | var unauthorizedMsg = []byte("407 Proxy Authentication Required") 14 | 15 | func BasicUnauthorized(req *http.Request, realm string) *http.Response { 16 | // TODO(elazar): verify realm is well formed 17 | return &http.Response{ 18 | StatusCode: 407, 19 | ProtoMajor: 1, 20 | ProtoMinor: 1, 21 | Request: req, 22 | Header: http.Header{"Proxy-Authenticate": []string{"Basic realm=" + realm}}, 23 | Body: ioutil.NopCloser(bytes.NewBuffer(unauthorizedMsg)), 24 | ContentLength: int64(len(unauthorizedMsg)), 25 | } 26 | } 27 | 28 | var proxyAuthorizationHeader = "Proxy-Authorization" 29 | 30 | func auth(req *http.Request, f func(user, passwd string) bool) bool { 31 | authheader := strings.SplitN(req.Header.Get(proxyAuthorizationHeader), " ", 2) 32 | req.Header.Del(proxyAuthorizationHeader) 33 | if len(authheader) != 2 || authheader[0] != "Basic" { 34 | return false 35 | } 36 | userpassraw, err := base64.StdEncoding.DecodeString(authheader[1]) 37 | if err != nil { 38 | return false 39 | } 40 | userpass := strings.SplitN(string(userpassraw), ":", 2) 41 | if len(userpass) != 2 { 42 | return false 43 | } 44 | return f(userpass[0], userpass[1]) 45 | } 46 | 47 | // Basic returns a basic HTTP authentication handler for requests 48 | // 49 | // You probably want to use auth.ProxyBasic(proxy) to enable authentication for all proxy activities 50 | func Basic(realm string, f func(user, passwd string) bool) goproxy.ReqHandler { 51 | return goproxy.FuncReqHandler(func(req *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) { 52 | if !auth(req, f) { 53 | return nil, BasicUnauthorized(req, realm) 54 | } 55 | return req, nil 56 | }) 57 | } 58 | 59 | // BasicConnect returns a basic HTTP authentication handler for CONNECT requests 60 | // 61 | // You probably want to use auth.ProxyBasic(proxy) to enable authentication for all proxy activities 62 | func BasicConnect(realm string, f func(user, passwd string) bool) goproxy.HttpsHandler { 63 | return goproxy.FuncHttpsHandler(func(host string, ctx *goproxy.ProxyCtx) (*goproxy.ConnectAction, string) { 64 | if !auth(ctx.Req, f) { 65 | ctx.Resp = BasicUnauthorized(ctx.Req, realm) 66 | return goproxy.RejectConnect, host 67 | } 68 | return goproxy.OkConnect, host 69 | }) 70 | } 71 | 72 | // ProxyBasic will force HTTP authentication before any request to the proxy is processed 73 | func ProxyBasic(proxy *goproxy.ProxyHttpServer, realm string, f func(user, passwd string) bool) { 74 | proxy.OnRequest().Do(Basic(realm, f)) 75 | proxy.OnRequest().HandleConnect(BasicConnect(realm, f)) 76 | } 77 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/ext/auth/basic_test.go: -------------------------------------------------------------------------------- 1 | package auth_test 2 | 3 | import ( 4 | "encoding/base64" 5 | "io" 6 | "io/ioutil" 7 | "net" 8 | "net/http" 9 | "net/http/httptest" 10 | "net/url" 11 | "os" 12 | "os/exec" 13 | "os/signal" 14 | "sync/atomic" 15 | "testing" 16 | 17 | "github.com/elazarl/goproxy" 18 | "github.com/elazarl/goproxy/ext/auth" 19 | ) 20 | 21 | type ConstantHanlder string 22 | 23 | func (h ConstantHanlder) ServeHTTP(w http.ResponseWriter, r *http.Request) { 24 | io.WriteString(w, string(h)) 25 | } 26 | 27 | func oneShotProxy(proxy *goproxy.ProxyHttpServer) (client *http.Client, s *httptest.Server) { 28 | s = httptest.NewServer(proxy) 29 | 30 | proxyUrl, _ := url.Parse(s.URL) 31 | tr := &http.Transport{Proxy: http.ProxyURL(proxyUrl)} 32 | client = &http.Client{Transport: tr} 33 | return 34 | } 35 | 36 | func times(n int, s string) string { 37 | r := make([]byte, 0, n*len(s)) 38 | for i := 0; i < n; i++ { 39 | r = append(r, s...) 40 | } 41 | return string(r) 42 | } 43 | 44 | func TestBasicConnectAuthWithCurl(t *testing.T) { 45 | expected := ":c>" 46 | background := httptest.NewTLSServer(ConstantHanlder(expected)) 47 | defer background.Close() 48 | proxy := goproxy.NewProxyHttpServer() 49 | proxy.OnRequest().HandleConnect(auth.BasicConnect("my_realm", func(user, passwd string) bool { 50 | return user == "user" && passwd == "open sesame" 51 | })) 52 | _, proxyserver := oneShotProxy(proxy) 53 | defer proxyserver.Close() 54 | 55 | cmd := exec.Command("curl", 56 | "--silent", "--show-error", "--insecure", 57 | "-x", proxyserver.URL, 58 | "-U", "user:open sesame", 59 | "-p", 60 | "--url", background.URL+"/[1-3]", 61 | ) 62 | out, err := cmd.CombinedOutput() // if curl got error, it'll show up in stderr 63 | if err != nil { 64 | t.Fatal(err, string(out)) 65 | } 66 | finalexpected := times(3, expected) 67 | if string(out) != finalexpected { 68 | t.Error("Expected", finalexpected, "got", string(out)) 69 | } 70 | } 71 | 72 | func TestBasicAuthWithCurl(t *testing.T) { 73 | expected := ":c>" 74 | background := httptest.NewServer(ConstantHanlder(expected)) 75 | defer background.Close() 76 | proxy := goproxy.NewProxyHttpServer() 77 | proxy.OnRequest().Do(auth.Basic("my_realm", func(user, passwd string) bool { 78 | return user == "user" && passwd == "open sesame" 79 | })) 80 | _, proxyserver := oneShotProxy(proxy) 81 | defer proxyserver.Close() 82 | 83 | cmd := exec.Command("curl", 84 | "--silent", "--show-error", 85 | "-x", proxyserver.URL, 86 | "-U", "user:open sesame", 87 | "--url", background.URL+"/[1-3]", 88 | ) 89 | out, err := cmd.CombinedOutput() // if curl got error, it'll show up in stderr 90 | if err != nil { 91 | t.Fatal(err, string(out)) 92 | } 93 | finalexpected := times(3, expected) 94 | if string(out) != finalexpected { 95 | t.Error("Expected", finalexpected, "got", string(out)) 96 | } 97 | } 98 | 99 | func TestBasicAuth(t *testing.T) { 100 | expected := "hello" 101 | background := httptest.NewServer(ConstantHanlder(expected)) 102 | defer background.Close() 103 | proxy := goproxy.NewProxyHttpServer() 104 | proxy.OnRequest().Do(auth.Basic("my_realm", func(user, passwd string) bool { 105 | return user == "user" && passwd == "open sesame" 106 | })) 107 | client, proxyserver := oneShotProxy(proxy) 108 | defer proxyserver.Close() 109 | 110 | // without auth 111 | resp, err := client.Get(background.URL) 112 | if err != nil { 113 | t.Fatal(err) 114 | } 115 | if resp.Header.Get("Proxy-Authenticate") != "Basic realm=my_realm" { 116 | t.Error("Expected Proxy-Authenticate header got", resp.Header.Get("Proxy-Authenticate")) 117 | } 118 | if resp.StatusCode != 407 { 119 | t.Error("Expected status 407 Proxy Authentication Required, got", resp.Status) 120 | } 121 | 122 | // with auth 123 | req, err := http.NewRequest("GET", background.URL, nil) 124 | if err != nil { 125 | t.Fatal(err) 126 | } 127 | req.Header.Set("Proxy-Authorization", 128 | "Basic "+base64.StdEncoding.EncodeToString([]byte("user:open sesame"))) 129 | resp, err = client.Do(req) 130 | if err != nil { 131 | t.Fatal(err) 132 | } 133 | if resp.StatusCode != 200 { 134 | t.Error("Expected status 200 OK, got", resp.Status) 135 | } 136 | msg, err := ioutil.ReadAll(resp.Body) 137 | if err != nil { 138 | t.Fatal(err) 139 | } 140 | if string(msg) != "hello" { 141 | t.Errorf("Expected '%s', actual '%s'", expected, string(msg)) 142 | } 143 | } 144 | 145 | func TestWithBrowser(t *testing.T) { 146 | // an easy way to check if auth works with webserver 147 | // to test, run with 148 | // $ go test -run TestWithBrowser -- server 149 | // configure a browser to use the printed proxy address, use the proxy 150 | // and exit with Ctrl-C. It will throw error if your haven't acutally used the proxy 151 | if os.Args[len(os.Args)-1] != "server" { 152 | return 153 | } 154 | proxy := goproxy.NewProxyHttpServer() 155 | println("proxy localhost port 8082") 156 | access := int32(0) 157 | proxy.OnRequest().Do(auth.Basic("my_realm", func(user, passwd string) bool { 158 | atomic.AddInt32(&access, 1) 159 | return user == "user" && passwd == "1234" 160 | })) 161 | l, err := net.Listen("tcp", "localhost:8082") 162 | if err != nil { 163 | t.Fatal(err) 164 | } 165 | ch := make(chan os.Signal) 166 | signal.Notify(ch, os.Interrupt) 167 | go func() { 168 | <-ch 169 | l.Close() 170 | }() 171 | http.Serve(l, proxy) 172 | if access <= 0 { 173 | t.Error("No one accessed the proxy") 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/ext/html/cp1255.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesbcook/proxy-ng/ee3e213ab8d9498a6b7743f0acf5ff30a44ffb38/vendor/github.com/elazarl/goproxy/ext/html/cp1255.html -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/ext/html/cp1255.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesbcook/proxy-ng/ee3e213ab8d9498a6b7743f0acf5ff30a44ffb38/vendor/github.com/elazarl/goproxy/ext/html/cp1255.txt -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/ext/html/html.go: -------------------------------------------------------------------------------- 1 | // extension to goproxy that will allow you to easily filter web browser related content. 2 | package goproxy_html 3 | 4 | import ( 5 | "bytes" 6 | "errors" 7 | "io" 8 | "io/ioutil" 9 | "net/http" 10 | "strings" 11 | 12 | "github.com/rogpeppe/go-charset/charset" 13 | _ "github.com/rogpeppe/go-charset/data" 14 | "github.com/elazarl/goproxy" 15 | ) 16 | 17 | var IsHtml goproxy.RespCondition = goproxy.ContentTypeIs("text/html") 18 | 19 | var IsCss goproxy.RespCondition = goproxy.ContentTypeIs("text/css") 20 | 21 | var IsJavaScript goproxy.RespCondition = goproxy.ContentTypeIs("text/javascript", 22 | "application/javascript") 23 | 24 | var IsJson goproxy.RespCondition = goproxy.ContentTypeIs("text/json") 25 | 26 | var IsXml goproxy.RespCondition = goproxy.ContentTypeIs("text/xml") 27 | 28 | var IsWebRelatedText goproxy.RespCondition = goproxy.ContentTypeIs("text/html", 29 | "text/css", 30 | "text/javascript", "application/javascript", 31 | "text/xml", 32 | "text/json") 33 | 34 | // HandleString will receive a function that filters a string, and will convert the 35 | // request body to a utf8 string, according to the charset specified in the Content-Type 36 | // header. 37 | // guessing Html charset encoding from the tags is not yet implemented. 38 | func HandleString(f func(s string, ctx *goproxy.ProxyCtx) string) goproxy.RespHandler { 39 | return HandleStringReader(func(r io.Reader, ctx *goproxy.ProxyCtx) io.Reader { 40 | b, err := ioutil.ReadAll(r) 41 | if err != nil { 42 | ctx.Warnf("Cannot read string from resp body: %v", err) 43 | return r 44 | } 45 | return bytes.NewBufferString(f(string(b), ctx)) 46 | }) 47 | } 48 | 49 | // Will receive an input stream which would convert the response to utf-8 50 | // The given function must close the reader r, in order to close the response body. 51 | func HandleStringReader(f func(r io.Reader, ctx *goproxy.ProxyCtx) io.Reader) goproxy.RespHandler { 52 | return goproxy.FuncRespHandler(func(resp *http.Response, ctx *goproxy.ProxyCtx) *http.Response { 53 | if ctx.Error != nil { 54 | return nil 55 | } 56 | charsetName := ctx.Charset() 57 | if charsetName == "" { 58 | charsetName = "utf-8" 59 | } 60 | 61 | if strings.ToLower(charsetName) != "utf-8" { 62 | r, err := charset.NewReader(charsetName, resp.Body) 63 | if err != nil { 64 | ctx.Warnf("Cannot convert from %v to utf-8: %v", charsetName, err) 65 | return resp 66 | } 67 | tr, err := charset.TranslatorTo(charsetName) 68 | if err != nil { 69 | ctx.Warnf("Can't translate to %v from utf-8: %v", charsetName, err) 70 | return resp 71 | } 72 | if err != nil { 73 | ctx.Warnf("Cannot translate to %v: %v", charsetName, err) 74 | return resp 75 | } 76 | newr := charset.NewTranslatingReader(f(r, ctx), tr) 77 | resp.Body = &readFirstCloseBoth{ioutil.NopCloser(newr), resp.Body} 78 | } else { 79 | //no translation is needed, already at utf-8 80 | resp.Body = &readFirstCloseBoth{ioutil.NopCloser(f(resp.Body, ctx)), resp.Body} 81 | } 82 | return resp 83 | }) 84 | } 85 | 86 | type readFirstCloseBoth struct { 87 | r io.ReadCloser 88 | c io.Closer 89 | } 90 | 91 | func (rfcb *readFirstCloseBoth) Read(b []byte) (nr int, err error) { 92 | return rfcb.r.Read(b) 93 | } 94 | func (rfcb *readFirstCloseBoth) Close() error { 95 | err1 := rfcb.r.Close() 96 | err2 := rfcb.c.Close() 97 | if err1 != nil && err2 != nil { 98 | return errors.New(err1.Error() + ", " + err2.Error()) 99 | } 100 | if err1 != nil { 101 | return err1 102 | } 103 | return err2 104 | } 105 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/ext/html/html_test.go: -------------------------------------------------------------------------------- 1 | package goproxy_html_test 2 | 3 | import ( 4 | "github.com/elazarl/goproxy" 5 | "github.com/elazarl/goproxy/ext/html" 6 | "io/ioutil" 7 | "net/http" 8 | "net/http/httptest" 9 | "net/url" 10 | "testing" 11 | ) 12 | 13 | type ConstantServer int 14 | 15 | func (s ConstantServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { 16 | w.Header().Set("Content-Type", "text/plain; charset=iso-8859-8") 17 | //w.Header().Set("Content-Type","text/plain; charset=cp-1255") 18 | w.Write([]byte{0xe3, 0xf3}) 19 | } 20 | 21 | func TestCharset(t *testing.T) { 22 | s := httptest.NewServer(ConstantServer(1)) 23 | defer s.Close() 24 | 25 | ch := make(chan string, 2) 26 | proxy := goproxy.NewProxyHttpServer() 27 | proxy.OnResponse().Do(goproxy_html.HandleString( 28 | func(s string, ctx *goproxy.ProxyCtx) string { 29 | ch <- s 30 | return s 31 | })) 32 | proxyServer := httptest.NewServer(proxy) 33 | defer proxyServer.Close() 34 | 35 | proxyUrl, _ := url.Parse(proxyServer.URL) 36 | client := &http.Client{Transport: &http.Transport{Proxy: http.ProxyURL(proxyUrl)}} 37 | 38 | resp, err := client.Get(s.URL + "/cp1255.txt") 39 | if err != nil { 40 | t.Fatal("GET:", err) 41 | } 42 | b, err := ioutil.ReadAll(resp.Body) 43 | if err != nil { 44 | t.Fatal("readAll:", err) 45 | } 46 | resp.Body.Close() 47 | 48 | inHandleString := "" 49 | select { 50 | case inHandleString = <-ch: 51 | default: 52 | } 53 | 54 | if len(b) != 2 || b[0] != 0xe3 || b[1] != 0xf3 { 55 | t.Error("Did not translate back to 0xe3,0xf3, instead", b) 56 | } 57 | if inHandleString != "דף" { 58 | t.Error("HandleString did not convert DALET & PEH SOFIT (דף) from ISO-8859-8 to utf-8, got", []byte(inHandleString)) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/ext/image/image.go: -------------------------------------------------------------------------------- 1 | package goproxy_image 2 | 3 | import ( 4 | "bytes" 5 | "image" 6 | _ "image/gif" 7 | "image/jpeg" 8 | "image/png" 9 | "io/ioutil" 10 | "net/http" 11 | . "github.com/elazarl/goproxy" 12 | "github.com/elazarl/goproxy/regretable" 13 | ) 14 | 15 | var RespIsImage = ContentTypeIs("image/gif", 16 | "image/jpeg", 17 | "image/pjpeg", 18 | "application/octet-stream", 19 | "image/png") 20 | 21 | // "image/tiff" tiff support is in external package, and rarely used, so we omitted it 22 | 23 | func HandleImage(f func(img image.Image, ctx *ProxyCtx) image.Image) RespHandler { 24 | return FuncRespHandler(func(resp *http.Response, ctx *ProxyCtx) *http.Response { 25 | if !RespIsImage.HandleResp(resp, ctx) { 26 | return resp 27 | } 28 | if resp.StatusCode != 200 { 29 | // we might get 304 - not modified response without data 30 | return resp 31 | } 32 | contentType := resp.Header.Get("Content-Type") 33 | 34 | const kb = 1024 35 | regret := regretable.NewRegretableReaderCloserSize(resp.Body, 16*kb) 36 | resp.Body = regret 37 | img, imgType, err := image.Decode(resp.Body) 38 | if err != nil { 39 | regret.Regret() 40 | ctx.Warnf("%s: %s", ctx.Req.Method+" "+ctx.Req.URL.String()+" Image from "+ctx.Req.RequestURI+"content type"+ 41 | contentType+"cannot be decoded returning original image", err) 42 | return resp 43 | } 44 | result := f(img, ctx) 45 | buf := bytes.NewBuffer([]byte{}) 46 | switch contentType { 47 | // No gif image encoder in go - convert to png 48 | case "image/gif", "image/png": 49 | if err := png.Encode(buf, result); err != nil { 50 | ctx.Warnf("Cannot encode image, returning orig %v %v", ctx.Req.URL.String(), err) 51 | return resp 52 | } 53 | resp.Header.Set("Content-Type", "image/png") 54 | case "image/jpeg", "image/pjpeg": 55 | if err := jpeg.Encode(buf, result, nil); err != nil { 56 | ctx.Warnf("Cannot encode image, returning orig %v %v", ctx.Req.URL.String(), err) 57 | return resp 58 | } 59 | case "application/octet-stream": 60 | switch imgType { 61 | case "jpeg": 62 | if err := jpeg.Encode(buf, result, nil); err != nil { 63 | ctx.Warnf("Cannot encode image as jpeg, returning orig %v %v", ctx.Req.URL.String(), err) 64 | return resp 65 | } 66 | case "png", "gif": 67 | if err := png.Encode(buf, result); err != nil { 68 | ctx.Warnf("Cannot encode image as png, returning orig %v %v", ctx.Req.URL.String(), err) 69 | return resp 70 | } 71 | } 72 | default: 73 | panic("unhandlable type" + contentType) 74 | } 75 | resp.Body = ioutil.NopCloser(buf) 76 | return resp 77 | }) 78 | } 79 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/https.go: -------------------------------------------------------------------------------- 1 | package goproxy 2 | 3 | import ( 4 | "bufio" 5 | "crypto/tls" 6 | "errors" 7 | "io" 8 | "io/ioutil" 9 | "net" 10 | "net/http" 11 | "net/url" 12 | "os" 13 | "regexp" 14 | "strconv" 15 | "strings" 16 | "sync" 17 | "sync/atomic" 18 | ) 19 | 20 | type ConnectActionLiteral int 21 | 22 | const ( 23 | ConnectAccept = iota 24 | ConnectReject 25 | ConnectMitm 26 | ConnectHijack 27 | ConnectHTTPMitm 28 | ConnectProxyAuthHijack 29 | ) 30 | 31 | var ( 32 | OkConnect = &ConnectAction{Action: ConnectAccept, TLSConfig: TLSConfigFromCA(&GoproxyCa)} 33 | MitmConnect = &ConnectAction{Action: ConnectMitm, TLSConfig: TLSConfigFromCA(&GoproxyCa)} 34 | HTTPMitmConnect = &ConnectAction{Action: ConnectHTTPMitm, TLSConfig: TLSConfigFromCA(&GoproxyCa)} 35 | RejectConnect = &ConnectAction{Action: ConnectReject, TLSConfig: TLSConfigFromCA(&GoproxyCa)} 36 | httpsRegexp = regexp.MustCompile(`^https:\/\/`) 37 | ) 38 | 39 | type ConnectAction struct { 40 | Action ConnectActionLiteral 41 | Hijack func(req *http.Request, client net.Conn, ctx *ProxyCtx) 42 | TLSConfig func(host string, ctx *ProxyCtx) (*tls.Config, error) 43 | } 44 | 45 | func stripPort(s string) string { 46 | ix := strings.IndexRune(s, ':') 47 | if ix == -1 { 48 | return s 49 | } 50 | return s[:ix] 51 | } 52 | 53 | func (proxy *ProxyHttpServer) dial(network, addr string) (c net.Conn, err error) { 54 | if proxy.Tr.Dial != nil { 55 | return proxy.Tr.Dial(network, addr) 56 | } 57 | return net.Dial(network, addr) 58 | } 59 | 60 | func (proxy *ProxyHttpServer) connectDial(network, addr string) (c net.Conn, err error) { 61 | if proxy.ConnectDial == nil { 62 | return proxy.dial(network, addr) 63 | } 64 | return proxy.ConnectDial(network, addr) 65 | } 66 | 67 | func (proxy *ProxyHttpServer) handleHttps(w http.ResponseWriter, r *http.Request) { 68 | ctx := &ProxyCtx{Req: r, Session: atomic.AddInt64(&proxy.sess, 1), proxy: proxy} 69 | 70 | hij, ok := w.(http.Hijacker) 71 | if !ok { 72 | panic("httpserver does not support hijacking") 73 | } 74 | 75 | proxyClient, _, e := hij.Hijack() 76 | if e != nil { 77 | panic("Cannot hijack connection " + e.Error()) 78 | } 79 | 80 | ctx.Logf("Running %d CONNECT handlers", len(proxy.httpsHandlers)) 81 | todo, host := OkConnect, r.URL.Host 82 | for i, h := range proxy.httpsHandlers { 83 | newtodo, newhost := h.HandleConnect(host, ctx) 84 | 85 | // If found a result, break the loop immediately 86 | if newtodo != nil { 87 | todo, host = newtodo, newhost 88 | ctx.Logf("on %dth handler: %v %s", i, todo, host) 89 | break 90 | } 91 | } 92 | switch todo.Action { 93 | case ConnectAccept: 94 | if !hasPort.MatchString(host) { 95 | host += ":80" 96 | } 97 | targetSiteCon, err := proxy.connectDial("tcp", host) 98 | if err != nil { 99 | httpError(proxyClient, ctx, err) 100 | return 101 | } 102 | ctx.Logf("Accepting CONNECT to %s", host) 103 | proxyClient.Write([]byte("HTTP/1.0 200 OK\r\n\r\n")) 104 | 105 | targetTCP, targetOK := targetSiteCon.(*net.TCPConn) 106 | proxyClientTCP, clientOK := proxyClient.(*net.TCPConn) 107 | if targetOK && clientOK { 108 | go copyAndClose(ctx, targetTCP, proxyClientTCP) 109 | go copyAndClose(ctx, proxyClientTCP, targetTCP) 110 | } else { 111 | go func() { 112 | var wg sync.WaitGroup 113 | wg.Add(2) 114 | go copyOrWarn(ctx, targetSiteCon, proxyClient, &wg) 115 | go copyOrWarn(ctx, proxyClient, targetSiteCon, &wg) 116 | wg.Wait() 117 | proxyClient.Close() 118 | targetSiteCon.Close() 119 | 120 | }() 121 | } 122 | 123 | case ConnectHijack: 124 | ctx.Logf("Hijacking CONNECT to %s", host) 125 | proxyClient.Write([]byte("HTTP/1.0 200 OK\r\n\r\n")) 126 | todo.Hijack(r, proxyClient, ctx) 127 | case ConnectHTTPMitm: 128 | proxyClient.Write([]byte("HTTP/1.0 200 OK\r\n\r\n")) 129 | ctx.Logf("Assuming CONNECT is plain HTTP tunneling, mitm proxying it") 130 | targetSiteCon, err := proxy.connectDial("tcp", host) 131 | if err != nil { 132 | ctx.Warnf("Error dialing to %s: %s", host, err.Error()) 133 | return 134 | } 135 | for { 136 | client := bufio.NewReader(proxyClient) 137 | remote := bufio.NewReader(targetSiteCon) 138 | req, err := http.ReadRequest(client) 139 | if err != nil && err != io.EOF { 140 | ctx.Warnf("cannot read request of MITM HTTP client: %+#v", err) 141 | } 142 | if err != nil { 143 | return 144 | } 145 | req, resp := proxy.filterRequest(req, ctx) 146 | if resp == nil { 147 | if err := req.Write(targetSiteCon); err != nil { 148 | httpError(proxyClient, ctx, err) 149 | return 150 | } 151 | resp, err = http.ReadResponse(remote, req) 152 | if err != nil { 153 | httpError(proxyClient, ctx, err) 154 | return 155 | } 156 | defer resp.Body.Close() 157 | } 158 | resp = proxy.filterResponse(resp, ctx) 159 | if err := resp.Write(proxyClient); err != nil { 160 | httpError(proxyClient, ctx, err) 161 | return 162 | } 163 | } 164 | case ConnectMitm: 165 | proxyClient.Write([]byte("HTTP/1.0 200 OK\r\n\r\n")) 166 | ctx.Logf("Assuming CONNECT is TLS, mitm proxying it") 167 | // this goes in a separate goroutine, so that the net/http server won't think we're 168 | // still handling the request even after hijacking the connection. Those HTTP CONNECT 169 | // request can take forever, and the server will be stuck when "closed". 170 | // TODO: Allow Server.Close() mechanism to shut down this connection as nicely as possible 171 | tlsConfig := defaultTLSConfig 172 | if todo.TLSConfig != nil { 173 | var err error 174 | tlsConfig, err = todo.TLSConfig(host, ctx) 175 | if err != nil { 176 | httpError(proxyClient, ctx, err) 177 | return 178 | } 179 | } 180 | go func() { 181 | //TODO: cache connections to the remote website 182 | rawClientTls := tls.Server(proxyClient, tlsConfig) 183 | if err := rawClientTls.Handshake(); err != nil { 184 | ctx.Warnf("Cannot handshake client %v %v", r.Host, err) 185 | return 186 | } 187 | defer rawClientTls.Close() 188 | clientTlsReader := bufio.NewReader(rawClientTls) 189 | for !isEof(clientTlsReader) { 190 | req, err := http.ReadRequest(clientTlsReader) 191 | var ctx = &ProxyCtx{Req: req, Session: atomic.AddInt64(&proxy.sess, 1), proxy: proxy} 192 | if err != nil && err != io.EOF { 193 | return 194 | } 195 | if err != nil { 196 | ctx.Warnf("Cannot read TLS request from mitm'd client %v %v", r.Host, err) 197 | return 198 | } 199 | req.RemoteAddr = r.RemoteAddr // since we're converting the request, need to carry over the original connecting IP as well 200 | ctx.Logf("req %v", r.Host) 201 | 202 | if !httpsRegexp.MatchString(req.URL.String()) { 203 | req.URL, err = url.Parse("https://" + r.Host + req.URL.String()) 204 | } 205 | 206 | // Bug fix which goproxy fails to provide request 207 | // information URL in the context when does HTTPS MITM 208 | ctx.Req = req 209 | 210 | req, resp := proxy.filterRequest(req, ctx) 211 | if resp == nil { 212 | if err != nil { 213 | ctx.Warnf("Illegal URL %s", "https://"+r.Host+req.URL.Path) 214 | return 215 | } 216 | removeProxyHeaders(ctx, req) 217 | resp, err = ctx.RoundTrip(req) 218 | if err != nil { 219 | ctx.Warnf("Cannot read TLS response from mitm'd server %v", err) 220 | return 221 | } 222 | ctx.Logf("resp %v", resp.Status) 223 | } 224 | resp = proxy.filterResponse(resp, ctx) 225 | defer resp.Body.Close() 226 | 227 | text := resp.Status 228 | statusCode := strconv.Itoa(resp.StatusCode) + " " 229 | if strings.HasPrefix(text, statusCode) { 230 | text = text[len(statusCode):] 231 | } 232 | // always use 1.1 to support chunked encoding 233 | if _, err := io.WriteString(rawClientTls, "HTTP/1.1"+" "+statusCode+text+"\r\n"); err != nil { 234 | ctx.Warnf("Cannot write TLS response HTTP status from mitm'd client: %v", err) 235 | return 236 | } 237 | // Since we don't know the length of resp, return chunked encoded response 238 | // TODO: use a more reasonable scheme 239 | resp.Header.Del("Content-Length") 240 | resp.Header.Set("Transfer-Encoding", "chunked") 241 | if err := resp.Header.Write(rawClientTls); err != nil { 242 | ctx.Warnf("Cannot write TLS response header from mitm'd client: %v", err) 243 | return 244 | } 245 | if _, err = io.WriteString(rawClientTls, "\r\n"); err != nil { 246 | ctx.Warnf("Cannot write TLS response header end from mitm'd client: %v", err) 247 | return 248 | } 249 | chunked := newChunkedWriter(rawClientTls) 250 | if _, err := io.Copy(chunked, resp.Body); err != nil { 251 | ctx.Warnf("Cannot write TLS response body from mitm'd client: %v", err) 252 | return 253 | } 254 | if err := chunked.Close(); err != nil { 255 | ctx.Warnf("Cannot write TLS chunked EOF from mitm'd client: %v", err) 256 | return 257 | } 258 | if _, err = io.WriteString(rawClientTls, "\r\n"); err != nil { 259 | ctx.Warnf("Cannot write TLS response chunked trailer from mitm'd client: %v", err) 260 | return 261 | } 262 | } 263 | ctx.Logf("Exiting on EOF") 264 | }() 265 | case ConnectProxyAuthHijack: 266 | proxyClient.Write([]byte("HTTP/1.1 407 Proxy Authentication Required\r\n")) 267 | todo.Hijack(r, proxyClient, ctx) 268 | case ConnectReject: 269 | if ctx.Resp != nil { 270 | if err := ctx.Resp.Write(proxyClient); err != nil { 271 | ctx.Warnf("Cannot write response that reject http CONNECT: %v", err) 272 | } 273 | } 274 | proxyClient.Close() 275 | } 276 | } 277 | 278 | func httpError(w io.WriteCloser, ctx *ProxyCtx, err error) { 279 | if _, err := io.WriteString(w, "HTTP/1.1 502 Bad Gateway\r\n\r\n"); err != nil { 280 | ctx.Warnf("Error responding to client: %s", err) 281 | } 282 | if err := w.Close(); err != nil { 283 | ctx.Warnf("Error closing client connection: %s", err) 284 | } 285 | } 286 | 287 | func copyOrWarn(ctx *ProxyCtx, dst io.Writer, src io.Reader, wg *sync.WaitGroup) { 288 | if _, err := io.Copy(dst, src); err != nil { 289 | ctx.Warnf("Error copying to client: %s", err) 290 | } 291 | wg.Done() 292 | } 293 | 294 | func copyAndClose(ctx *ProxyCtx, dst, src *net.TCPConn) { 295 | if _, err := io.Copy(dst, src); err != nil { 296 | ctx.Warnf("Error copying to client: %s", err) 297 | } 298 | 299 | dst.CloseWrite() 300 | src.CloseRead() 301 | } 302 | 303 | func dialerFromEnv(proxy *ProxyHttpServer) func(network, addr string) (net.Conn, error) { 304 | https_proxy := os.Getenv("HTTPS_PROXY") 305 | if https_proxy == "" { 306 | https_proxy = os.Getenv("https_proxy") 307 | } 308 | if https_proxy == "" { 309 | return nil 310 | } 311 | return proxy.NewConnectDialToProxy(https_proxy) 312 | } 313 | 314 | func (proxy *ProxyHttpServer) NewConnectDialToProxy(https_proxy string) func(network, addr string) (net.Conn, error) { 315 | u, err := url.Parse(https_proxy) 316 | if err != nil { 317 | return nil 318 | } 319 | if u.Scheme == "" || u.Scheme == "http" { 320 | if strings.IndexRune(u.Host, ':') == -1 { 321 | u.Host += ":80" 322 | } 323 | return func(network, addr string) (net.Conn, error) { 324 | connectReq := &http.Request{ 325 | Method: "CONNECT", 326 | URL: &url.URL{Opaque: addr}, 327 | Host: addr, 328 | Header: make(http.Header), 329 | } 330 | c, err := proxy.dial(network, u.Host) 331 | if err != nil { 332 | return nil, err 333 | } 334 | connectReq.Write(c) 335 | // Read response. 336 | // Okay to use and discard buffered reader here, because 337 | // TLS server will not speak until spoken to. 338 | br := bufio.NewReader(c) 339 | resp, err := http.ReadResponse(br, connectReq) 340 | if err != nil { 341 | c.Close() 342 | return nil, err 343 | } 344 | defer resp.Body.Close() 345 | if resp.StatusCode != 200 { 346 | resp, err := ioutil.ReadAll(resp.Body) 347 | if err != nil { 348 | return nil, err 349 | } 350 | c.Close() 351 | return nil, errors.New("proxy refused connection" + string(resp)) 352 | } 353 | return c, nil 354 | } 355 | } 356 | if u.Scheme == "https" { 357 | if strings.IndexRune(u.Host, ':') == -1 { 358 | u.Host += ":443" 359 | } 360 | return func(network, addr string) (net.Conn, error) { 361 | c, err := proxy.dial(network, u.Host) 362 | if err != nil { 363 | return nil, err 364 | } 365 | c = tls.Client(c, proxy.Tr.TLSClientConfig) 366 | connectReq := &http.Request{ 367 | Method: "CONNECT", 368 | URL: &url.URL{Opaque: addr}, 369 | Host: addr, 370 | Header: make(http.Header), 371 | } 372 | connectReq.Write(c) 373 | // Read response. 374 | // Okay to use and discard buffered reader here, because 375 | // TLS server will not speak until spoken to. 376 | br := bufio.NewReader(c) 377 | resp, err := http.ReadResponse(br, connectReq) 378 | if err != nil { 379 | c.Close() 380 | return nil, err 381 | } 382 | defer resp.Body.Close() 383 | if resp.StatusCode != 200 { 384 | body, err := ioutil.ReadAll(io.LimitReader(resp.Body, 500)) 385 | if err != nil { 386 | return nil, err 387 | } 388 | c.Close() 389 | return nil, errors.New("proxy refused connection" + string(body)) 390 | } 391 | return c, nil 392 | } 393 | } 394 | return nil 395 | } 396 | 397 | func TLSConfigFromCA(ca *tls.Certificate) func(host string, ctx *ProxyCtx) (*tls.Config, error) { 398 | return func(host string, ctx *ProxyCtx) (*tls.Config, error) { 399 | config := *defaultTLSConfig 400 | ctx.Logf("signing for %s", stripPort(host)) 401 | cert, err := signHost(*ca, []string{stripPort(host)}) 402 | if err != nil { 403 | ctx.Warnf("Cannot sign host certificate with provided CA: %s", err) 404 | return nil, err 405 | } 406 | config.Certificates = append(config.Certificates, cert) 407 | return &config, nil 408 | } 409 | } 410 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXQIBAAKBgQC/P0FsJomPGzvdO9yreV4/faEAZ6tDVGC+VnrxnidmahUd+X7Y 3 | 2v+bR2Zb4Z05+lNyz8rN8mNgav/zjHnbh+K5HwZ1nQc61cnPIXmx6hadsEi7KvU9 4 | sSmBGEZAyqo5S6NgTF4tt80c8ignxdnVXPK/djGNuaNYD5L+4570da0NswIDAQAB 5 | AoGBALzIv1b4D7ARTR3NOr6V9wArjiOtMjUrdLhO+9vIp9IEA8ZsA9gjDlCEwbkP 6 | VDnoLjnWfraff5Os6+3JjHy1fYpUiCdnk2XA6iJSL1XWKQZPt3wOunxP4lalDgED 7 | QTRReFbA/y/Z4kSfTXpVj68ytcvSRW/N7q5/qRtbN9804jpBAkEA0s6lvH2btSLA 8 | mcEdwhs7zAslLbdld7rvfUeP82gPPk0S6yUqTNyikqshM9AwAktHY7WvYdKl+ghZ 9 | HTxKVC4DoQJBAOg/IAW5RbXknP+Lf7AVtBgw3E+Yfa3mcdLySe8hjxxyZq825Zmu 10 | Rt5Qj4Lw6ifSFNy4kiiSpE/ZCukYvUXGENMCQFkPxSWlS6tzSzuqQxBGwTSrYMG3 11 | wb6b06JyIXcMd6Qym9OMmBpw/J5KfnSNeDr/4uFVWQtTG5xO+pdHaX+3EQECQQDl 12 | qcbY4iX1gWVfr2tNjajSYz751yoxVbkpiT9joiQLVXYFvpu+JYEfRzsjmWl0h2Lq 13 | AftG8/xYmaEYcMZ6wSrRAkBUwiom98/8wZVlB6qbwhU1EKDFANvICGSWMIhPx3v7 14 | MJqTIj4uJhte2/uyVvZ6DC6noWYgy+kLgqG0S97tUEG8 15 | -----END RSA PRIVATE KEY----- 16 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/proxy.go: -------------------------------------------------------------------------------- 1 | package goproxy 2 | 3 | import ( 4 | "bufio" 5 | "io" 6 | "log" 7 | "net" 8 | "net/http" 9 | "os" 10 | "regexp" 11 | "sync/atomic" 12 | ) 13 | 14 | // The basic proxy type. Implements http.Handler. 15 | type ProxyHttpServer struct { 16 | // session variable must be aligned in i386 17 | // see http://golang.org/src/pkg/sync/atomic/doc.go#L41 18 | sess int64 19 | // setting Verbose to true will log information on each request sent to the proxy 20 | Verbose bool 21 | Logger *log.Logger 22 | NonproxyHandler http.Handler 23 | reqHandlers []ReqHandler 24 | respHandlers []RespHandler 25 | httpsHandlers []HttpsHandler 26 | Tr *http.Transport 27 | // ConnectDial will be used to create TCP connections for CONNECT requests 28 | // if nil Tr.Dial will be used 29 | ConnectDial func(network string, addr string) (net.Conn, error) 30 | } 31 | 32 | var hasPort = regexp.MustCompile(`:\d+$`) 33 | 34 | func copyHeaders(dst, src http.Header) { 35 | for k, _ := range dst { 36 | dst.Del(k) 37 | } 38 | for k, vs := range src { 39 | for _, v := range vs { 40 | dst.Add(k, v) 41 | } 42 | } 43 | } 44 | 45 | func isEof(r *bufio.Reader) bool { 46 | _, err := r.Peek(1) 47 | if err == io.EOF { 48 | return true 49 | } 50 | return false 51 | } 52 | 53 | func (proxy *ProxyHttpServer) filterRequest(r *http.Request, ctx *ProxyCtx) (req *http.Request, resp *http.Response) { 54 | req = r 55 | for _, h := range proxy.reqHandlers { 56 | req, resp = h.Handle(r, ctx) 57 | // non-nil resp means the handler decided to skip sending the request 58 | // and return canned response instead. 59 | if resp != nil { 60 | break 61 | } 62 | } 63 | return 64 | } 65 | func (proxy *ProxyHttpServer) filterResponse(respOrig *http.Response, ctx *ProxyCtx) (resp *http.Response) { 66 | resp = respOrig 67 | for _, h := range proxy.respHandlers { 68 | ctx.Resp = resp 69 | resp = h.Handle(resp, ctx) 70 | } 71 | return 72 | } 73 | 74 | func removeProxyHeaders(ctx *ProxyCtx, r *http.Request) { 75 | r.RequestURI = "" // this must be reset when serving a request with the client 76 | ctx.Logf("Sending request %v %v", r.Method, r.URL.String()) 77 | // If no Accept-Encoding header exists, Transport will add the headers it can accept 78 | // and would wrap the response body with the relevant reader. 79 | r.Header.Del("Accept-Encoding") 80 | // curl can add that, see 81 | // https://jdebp.eu./FGA/web-proxy-connection-header.html 82 | r.Header.Del("Proxy-Connection") 83 | r.Header.Del("Proxy-Authenticate") 84 | r.Header.Del("Proxy-Authorization") 85 | // Connection, Authenticate and Authorization are single hop Header: 86 | // http://www.w3.org/Protocols/rfc2616/rfc2616.txt 87 | // 14.10 Connection 88 | // The Connection general-header field allows the sender to specify 89 | // options that are desired for that particular connection and MUST NOT 90 | // be communicated by proxies over further connections. 91 | r.Header.Del("Connection") 92 | } 93 | 94 | // Standard net/http function. Shouldn't be used directly, http.Serve will use it. 95 | func (proxy *ProxyHttpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { 96 | //r.Header["X-Forwarded-For"] = w.RemoteAddr() 97 | if r.Method == "CONNECT" { 98 | proxy.handleHttps(w, r) 99 | } else { 100 | ctx := &ProxyCtx{Req: r, Session: atomic.AddInt64(&proxy.sess, 1), proxy: proxy} 101 | 102 | var err error 103 | ctx.Logf("Got request %v %v %v %v", r.URL.Path, r.Host, r.Method, r.URL.String()) 104 | if !r.URL.IsAbs() { 105 | proxy.NonproxyHandler.ServeHTTP(w, r) 106 | return 107 | } 108 | r, resp := proxy.filterRequest(r, ctx) 109 | 110 | if resp == nil { 111 | removeProxyHeaders(ctx, r) 112 | resp, err = ctx.RoundTrip(r) 113 | if err != nil { 114 | ctx.Error = err 115 | resp = proxy.filterResponse(nil, ctx) 116 | if resp == nil { 117 | ctx.Logf("error read response %v %v:", r.URL.Host, err.Error()) 118 | http.Error(w, err.Error(), 500) 119 | return 120 | } 121 | } 122 | ctx.Logf("Received response %v", resp.Status) 123 | } 124 | origBody := resp.Body 125 | resp = proxy.filterResponse(resp, ctx) 126 | defer origBody.Close() 127 | ctx.Logf("Copying response to client %v [%d]", resp.Status, resp.StatusCode) 128 | // http.ResponseWriter will take care of filling the correct response length 129 | // Setting it now, might impose wrong value, contradicting the actual new 130 | // body the user returned. 131 | // We keep the original body to remove the header only if things changed. 132 | // This will prevent problems with HEAD requests where there's no body, yet, 133 | // the Content-Length header should be set. 134 | if origBody != resp.Body { 135 | resp.Header.Del("Content-Length") 136 | } 137 | copyHeaders(w.Header(), resp.Header) 138 | w.WriteHeader(resp.StatusCode) 139 | nr, err := io.Copy(w, resp.Body) 140 | if err := resp.Body.Close(); err != nil { 141 | ctx.Warnf("Can't close response body %v", err) 142 | } 143 | ctx.Logf("Copied %v bytes to client error=%v", nr, err) 144 | } 145 | } 146 | 147 | // New proxy server, logs to StdErr by default 148 | func NewProxyHttpServer() *ProxyHttpServer { 149 | proxy := ProxyHttpServer{ 150 | Logger: log.New(os.Stderr, "", log.LstdFlags), 151 | reqHandlers: []ReqHandler{}, 152 | respHandlers: []RespHandler{}, 153 | httpsHandlers: []HttpsHandler{}, 154 | NonproxyHandler: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { 155 | http.Error(w, "This is a proxy server. Does not respond to non-proxy requests.", 500) 156 | }), 157 | Tr: &http.Transport{TLSClientConfig: tlsClientSkipVerify, 158 | Proxy: http.ProxyFromEnvironment}, 159 | } 160 | proxy.ConnectDial = dialerFromEnv(&proxy) 161 | return &proxy 162 | } 163 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/regretable/regretreader.go: -------------------------------------------------------------------------------- 1 | package regretable 2 | 3 | import ( 4 | "io" 5 | ) 6 | 7 | // A RegretableReader will allow you to read from a reader, and then 8 | // to "regret" reading it, and push back everything you've read. 9 | // For example, 10 | // rb := NewRegretableReader(bytes.NewBuffer([]byte{1,2,3})) 11 | // var b = make([]byte,1) 12 | // rb.Read(b) // b[0] = 1 13 | // rb.Regret() 14 | // ioutil.ReadAll(rb.Read) // returns []byte{1,2,3},nil 15 | type RegretableReader struct { 16 | reader io.Reader 17 | overflow bool 18 | r, w int 19 | buf []byte 20 | } 21 | 22 | var defaultBufferSize = 500 23 | 24 | // Same as RegretableReader, but allows closing the underlying reader 25 | type RegretableReaderCloser struct { 26 | RegretableReader 27 | c io.Closer 28 | } 29 | 30 | // Closes the underlying readCloser, you cannot regret after closing the stream 31 | func (rbc *RegretableReaderCloser) Close() error { 32 | return rbc.c.Close() 33 | } 34 | 35 | // initialize a RegretableReaderCloser with underlying readCloser rc 36 | func NewRegretableReaderCloser(rc io.ReadCloser) *RegretableReaderCloser { 37 | return &RegretableReaderCloser{*NewRegretableReader(rc), rc} 38 | } 39 | 40 | // initialize a RegretableReaderCloser with underlying readCloser rc 41 | func NewRegretableReaderCloserSize(rc io.ReadCloser, size int) *RegretableReaderCloser { 42 | return &RegretableReaderCloser{*NewRegretableReaderSize(rc, size), rc} 43 | } 44 | 45 | // The next read from the RegretableReader will be as if the underlying reader 46 | // was never read (or from the last point forget is called). 47 | func (rb *RegretableReader) Regret() { 48 | if rb.overflow { 49 | panic("regretting after overflow makes no sense") 50 | } 51 | rb.r = 0 52 | } 53 | 54 | // Will "forget" everything read so far. 55 | // rb := NewRegretableReader(bytes.NewBuffer([]byte{1,2,3})) 56 | // var b = make([]byte,1) 57 | // rb.Read(b) // b[0] = 1 58 | // rb.Forget() 59 | // rb.Read(b) // b[0] = 2 60 | // rb.Regret() 61 | // ioutil.ReadAll(rb.Read) // returns []byte{2,3},nil 62 | func (rb *RegretableReader) Forget() { 63 | if rb.overflow { 64 | panic("forgetting after overflow makes no sense") 65 | } 66 | rb.r = 0 67 | rb.w = 0 68 | } 69 | 70 | // initialize a RegretableReader with underlying reader r, whose buffer is size bytes long 71 | func NewRegretableReaderSize(r io.Reader, size int) *RegretableReader { 72 | return &RegretableReader{reader: r, buf: make([]byte, size) } 73 | } 74 | 75 | // initialize a RegretableReader with underlying reader r 76 | func NewRegretableReader(r io.Reader) *RegretableReader { 77 | return NewRegretableReaderSize(r, defaultBufferSize) 78 | } 79 | 80 | // reads from the underlying reader. Will buffer all input until Regret is called. 81 | func (rb *RegretableReader) Read(p []byte) (n int, err error) { 82 | if rb.overflow { 83 | return rb.reader.Read(p) 84 | } 85 | if rb.r < rb.w { 86 | n = copy(p, rb.buf[rb.r:rb.w]) 87 | rb.r += n 88 | return 89 | } 90 | n, err = rb.reader.Read(p) 91 | bn := copy(rb.buf[rb.w:], p[:n]) 92 | rb.w, rb.r = rb.w + bn, rb.w + n 93 | if bn < n { 94 | rb.overflow = true 95 | } 96 | return 97 | } 98 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/regretable/regretreader_test.go: -------------------------------------------------------------------------------- 1 | package regretable_test 2 | 3 | import ( 4 | . "github.com/elazarl/goproxy/regretable" 5 | "bytes" 6 | "io" 7 | "io/ioutil" 8 | "strings" 9 | "testing" 10 | ) 11 | 12 | func TestRegretableReader(t *testing.T) { 13 | buf := new(bytes.Buffer) 14 | mb := NewRegretableReader(buf) 15 | word := "12345678" 16 | buf.WriteString(word) 17 | 18 | fivebytes := make([]byte, 5) 19 | mb.Read(fivebytes) 20 | mb.Regret() 21 | 22 | s, _ := ioutil.ReadAll(mb) 23 | if string(s) != word { 24 | t.Errorf("Uncommited read is gone, [%d,%d] actual '%v' expected '%v'\n", len(s), len(word), string(s), word) 25 | } 26 | } 27 | 28 | func TestRegretableEmptyRead(t *testing.T) { 29 | buf := new(bytes.Buffer) 30 | mb := NewRegretableReader(buf) 31 | word := "12345678" 32 | buf.WriteString(word) 33 | 34 | zero := make([]byte, 0) 35 | mb.Read(zero) 36 | mb.Regret() 37 | 38 | s, err := ioutil.ReadAll(mb) 39 | if string(s) != word { 40 | t.Error("Uncommited read is gone, actual:", string(s), "expected:", word, "err:", err) 41 | } 42 | } 43 | 44 | func TestRegretableAlsoEmptyRead(t *testing.T) { 45 | buf := new(bytes.Buffer) 46 | mb := NewRegretableReader(buf) 47 | word := "12345678" 48 | buf.WriteString(word) 49 | 50 | one := make([]byte, 1) 51 | zero := make([]byte, 0) 52 | five := make([]byte, 5) 53 | mb.Read(one) 54 | mb.Read(zero) 55 | mb.Read(five) 56 | mb.Regret() 57 | 58 | s, _ := ioutil.ReadAll(mb) 59 | if string(s) != word { 60 | t.Error("Uncommited read is gone", string(s), "expected", word) 61 | } 62 | } 63 | 64 | func TestRegretableRegretBeforeRead(t *testing.T) { 65 | buf := new(bytes.Buffer) 66 | mb := NewRegretableReader(buf) 67 | word := "12345678" 68 | buf.WriteString(word) 69 | 70 | five := make([]byte, 5) 71 | mb.Regret() 72 | mb.Read(five) 73 | 74 | s, err := ioutil.ReadAll(mb) 75 | if string(s) != "678" { 76 | t.Error("Uncommited read is gone", string(s), len(string(s)), "expected", "678", len("678"), "err:", err) 77 | } 78 | } 79 | 80 | func TestRegretableFullRead(t *testing.T) { 81 | buf := new(bytes.Buffer) 82 | mb := NewRegretableReader(buf) 83 | word := "12345678" 84 | buf.WriteString(word) 85 | 86 | twenty := make([]byte, 20) 87 | mb.Read(twenty) 88 | mb.Regret() 89 | 90 | s, _ := ioutil.ReadAll(mb) 91 | if string(s) != word { 92 | t.Error("Uncommited read is gone", string(s), len(string(s)), "expected", word, len(word)) 93 | } 94 | } 95 | 96 | func assertEqual(t *testing.T, expected, actual string) { 97 | if expected!=actual { 98 | t.Fatal("Expected", expected, "actual", actual) 99 | } 100 | } 101 | 102 | func assertReadAll(t *testing.T, r io.Reader) string { 103 | s, err := ioutil.ReadAll(r) 104 | if err!=nil { 105 | t.Fatal("error when reading", err) 106 | } 107 | return string(s) 108 | } 109 | 110 | func TestRegretableRegretTwice(t *testing.T) { 111 | buf := new(bytes.Buffer) 112 | mb := NewRegretableReader(buf) 113 | word := "12345678" 114 | buf.WriteString(word) 115 | 116 | assertEqual(t, word, assertReadAll(t, mb)) 117 | mb.Regret() 118 | assertEqual(t, word, assertReadAll(t, mb)) 119 | mb.Regret() 120 | assertEqual(t, word, assertReadAll(t, mb)) 121 | } 122 | 123 | type CloseCounter struct { 124 | r io.Reader 125 | closed int 126 | } 127 | 128 | func (cc *CloseCounter) Read(b []byte) (int, error) { 129 | return cc.r.Read(b) 130 | } 131 | 132 | func (cc *CloseCounter) Close() error { 133 | cc.closed++ 134 | return nil 135 | } 136 | 137 | func assert(t *testing.T, b bool, msg string) { 138 | if !b { 139 | t.Errorf("Assertion Error: %s", msg) 140 | } 141 | } 142 | 143 | func TestRegretableCloserSizeRegrets(t *testing.T) { 144 | defer func() { 145 | if r := recover(); r == nil || !strings.Contains(r.(string), "regret") { 146 | t.Error("Did not panic when regretting overread buffer:", r) 147 | } 148 | }() 149 | buf := new(bytes.Buffer) 150 | buf.WriteString("123456") 151 | mb := NewRegretableReaderCloserSize(ioutil.NopCloser(buf), 3) 152 | mb.Read(make([]byte, 4)) 153 | mb.Regret() 154 | } 155 | 156 | func TestRegretableCloserRegretsClose(t *testing.T) { 157 | buf := new(bytes.Buffer) 158 | cc := &CloseCounter{buf, 0} 159 | mb := NewRegretableReaderCloser(cc) 160 | word := "12345678" 161 | buf.WriteString(word) 162 | 163 | mb.Read([]byte{0}) 164 | mb.Close() 165 | if cc.closed != 1 { 166 | t.Error("RegretableReaderCloser ignores Close") 167 | } 168 | mb.Regret() 169 | mb.Close() 170 | if cc.closed != 2 { 171 | t.Error("RegretableReaderCloser does ignore Close after regret") 172 | } 173 | // TODO(elazar): return an error if client issues Close more than once after regret 174 | } 175 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/responses.go: -------------------------------------------------------------------------------- 1 | package goproxy 2 | 3 | import ( 4 | "bytes" 5 | "io/ioutil" 6 | "net/http" 7 | ) 8 | 9 | // Will generate a valid http response to the given request the response will have 10 | // the given contentType, and http status. 11 | // Typical usage, refuse to process requests to local addresses: 12 | // 13 | // proxy.OnRequest(IsLocalHost()).DoFunc(func(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request,*http.Response) { 14 | // return nil,NewResponse(r,goproxy.ContentTypeHtml,http.StatusUnauthorized, 15 | // `Can't use proxy for local addresses`) 16 | // }) 17 | func NewResponse(r *http.Request, contentType string, status int, body string) *http.Response { 18 | resp := &http.Response{} 19 | resp.Request = r 20 | resp.TransferEncoding = r.TransferEncoding 21 | resp.Header = make(http.Header) 22 | resp.Header.Add("Content-Type", contentType) 23 | resp.StatusCode = status 24 | buf := bytes.NewBufferString(body) 25 | resp.ContentLength = int64(buf.Len()) 26 | resp.Body = ioutil.NopCloser(buf) 27 | return resp 28 | } 29 | 30 | const ( 31 | ContentTypeText = "text/plain" 32 | ContentTypeHtml = "text/html" 33 | ) 34 | 35 | // Alias for NewResponse(r,ContentTypeText,http.StatusAccepted,text) 36 | func TextResponse(r *http.Request, text string) *http.Response { 37 | return NewResponse(r, ContentTypeText, http.StatusAccepted, text) 38 | } 39 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/signer.go: -------------------------------------------------------------------------------- 1 | package goproxy 2 | 3 | import ( 4 | "crypto/rsa" 5 | "crypto/sha1" 6 | "crypto/tls" 7 | "crypto/x509" 8 | "crypto/x509/pkix" 9 | "math/big" 10 | "net" 11 | "runtime" 12 | "sort" 13 | "time" 14 | ) 15 | 16 | func hashSorted(lst []string) []byte { 17 | c := make([]string, len(lst)) 18 | copy(c, lst) 19 | sort.Strings(c) 20 | h := sha1.New() 21 | for _, s := range c { 22 | h.Write([]byte(s + ",")) 23 | } 24 | return h.Sum(nil) 25 | } 26 | 27 | func hashSortedBigInt(lst []string) *big.Int { 28 | rv := new(big.Int) 29 | rv.SetBytes(hashSorted(lst)) 30 | return rv 31 | } 32 | 33 | var goproxySignerVersion = ":goroxy1" 34 | 35 | func signHost(ca tls.Certificate, hosts []string) (cert tls.Certificate, err error) { 36 | var x509ca *x509.Certificate 37 | 38 | // Use the provided ca and not the global GoproxyCa for certificate generation. 39 | if x509ca, err = x509.ParseCertificate(ca.Certificate[0]); err != nil { 40 | return 41 | } 42 | start := time.Unix(0, 0) 43 | end, err := time.Parse("2006-01-02", "2049-12-31") 44 | if err != nil { 45 | panic(err) 46 | } 47 | hash := hashSorted(append(hosts, goproxySignerVersion, ":"+runtime.Version())) 48 | serial := new(big.Int) 49 | serial.SetBytes(hash) 50 | template := x509.Certificate{ 51 | // TODO(elazar): instead of this ugly hack, just encode the certificate and hash the binary form. 52 | SerialNumber: serial, 53 | Issuer: x509ca.Subject, 54 | Subject: pkix.Name{ 55 | Organization: []string{"GoProxy untrusted MITM proxy Inc"}, 56 | }, 57 | NotBefore: start, 58 | NotAfter: end, 59 | 60 | KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, 61 | ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, 62 | BasicConstraintsValid: true, 63 | } 64 | for _, h := range hosts { 65 | if ip := net.ParseIP(h); ip != nil { 66 | template.IPAddresses = append(template.IPAddresses, ip) 67 | } else { 68 | template.DNSNames = append(template.DNSNames, h) 69 | } 70 | } 71 | var csprng CounterEncryptorRand 72 | if csprng, err = NewCounterEncryptorRandFromKey(ca.PrivateKey, hash); err != nil { 73 | return 74 | } 75 | var certpriv *rsa.PrivateKey 76 | if certpriv, err = rsa.GenerateKey(&csprng, 1024); err != nil { 77 | return 78 | } 79 | var derBytes []byte 80 | if derBytes, err = x509.CreateCertificate(&csprng, &template, x509ca, &certpriv.PublicKey, ca.PrivateKey); err != nil { 81 | return 82 | } 83 | return tls.Certificate{ 84 | Certificate: [][]byte{derBytes, ca.Certificate[0]}, 85 | PrivateKey: certpriv, 86 | }, nil 87 | } 88 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/signer_test.go: -------------------------------------------------------------------------------- 1 | package goproxy 2 | 3 | import ( 4 | "crypto/tls" 5 | "crypto/x509" 6 | "io/ioutil" 7 | "net/http" 8 | "net/http/httptest" 9 | "os" 10 | "os/exec" 11 | "strings" 12 | "testing" 13 | "time" 14 | ) 15 | 16 | func orFatal(msg string, err error, t *testing.T) { 17 | if err != nil { 18 | t.Fatal(msg, err) 19 | } 20 | } 21 | 22 | type ConstantHanlder string 23 | 24 | func (h ConstantHanlder) ServeHTTP(w http.ResponseWriter, r *http.Request) { 25 | w.Write([]byte(h)) 26 | } 27 | 28 | func getBrowser(args []string) string { 29 | for i, arg := range args { 30 | if arg == "-browser" && i+1 < len(arg) { 31 | return args[i+1] 32 | } 33 | if strings.HasPrefix(arg, "-browser=") { 34 | return arg[len("-browser="):] 35 | } 36 | } 37 | return "" 38 | } 39 | 40 | func TestSingerTls(t *testing.T) { 41 | cert, err := signHost(GoproxyCa, []string{"example.com", "1.1.1.1", "localhost"}) 42 | orFatal("singHost", err, t) 43 | cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]) 44 | orFatal("ParseCertificate", err, t) 45 | expected := "key verifies with Go" 46 | server := httptest.NewUnstartedServer(ConstantHanlder(expected)) 47 | defer server.Close() 48 | server.TLS = &tls.Config{Certificates: []tls.Certificate{cert, GoproxyCa}} 49 | server.TLS.BuildNameToCertificate() 50 | server.StartTLS() 51 | certpool := x509.NewCertPool() 52 | certpool.AddCert(GoproxyCa.Leaf) 53 | tr := &http.Transport{ 54 | TLSClientConfig: &tls.Config{RootCAs: certpool}, 55 | } 56 | asLocalhost := strings.Replace(server.URL, "127.0.0.1", "localhost", -1) 57 | req, err := http.NewRequest("GET", asLocalhost, nil) 58 | orFatal("NewRequest", err, t) 59 | resp, err := tr.RoundTrip(req) 60 | orFatal("RoundTrip", err, t) 61 | txt, err := ioutil.ReadAll(resp.Body) 62 | orFatal("ioutil.ReadAll", err, t) 63 | if string(txt) != expected { 64 | t.Errorf("Expected '%s' got '%s'", expected, string(txt)) 65 | } 66 | browser := getBrowser(os.Args) 67 | if browser != "" { 68 | exec.Command(browser, asLocalhost).Run() 69 | time.Sleep(10 * time.Second) 70 | } 71 | } 72 | 73 | func TestSingerX509(t *testing.T) { 74 | cert, err := signHost(GoproxyCa, []string{"example.com", "1.1.1.1", "localhost"}) 75 | orFatal("singHost", err, t) 76 | cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0]) 77 | orFatal("ParseCertificate", err, t) 78 | certpool := x509.NewCertPool() 79 | certpool.AddCert(GoproxyCa.Leaf) 80 | orFatal("VerifyHostname", cert.Leaf.VerifyHostname("example.com"), t) 81 | orFatal("CheckSignatureFrom", cert.Leaf.CheckSignatureFrom(GoproxyCa.Leaf), t) 82 | _, err = cert.Leaf.Verify(x509.VerifyOptions{ 83 | DNSName: "example.com", 84 | Roots: certpool, 85 | }) 86 | orFatal("Verify", err, t) 87 | } 88 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/test_data/baby.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesbcook/proxy-ng/ee3e213ab8d9498a6b7743f0acf5ff30a44ffb38/vendor/github.com/elazarl/goproxy/test_data/baby.jpg -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/test_data/football.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesbcook/proxy-ng/ee3e213ab8d9498a6b7743f0acf5ff30a44ffb38/vendor/github.com/elazarl/goproxy/test_data/football.png -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/test_data/panda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jamesbcook/proxy-ng/ee3e213ab8d9498a6b7743f0acf5ff30a44ffb38/vendor/github.com/elazarl/goproxy/test_data/panda.png -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/transport/roundtripper.go: -------------------------------------------------------------------------------- 1 | package transport 2 | import "net/http" 3 | type RoundTripper interface { 4 | // RoundTrip executes a single HTTP transaction, returning 5 | // the Response for the request req. RoundTrip should not 6 | // attempt to interpret the response. In particular, 7 | // RoundTrip must return err == nil if it obtained a response, 8 | // regardless of the response's HTTP status code. A non-nil 9 | // err should be reserved for failure to obtain a response. 10 | // Similarly, RoundTrip should not attempt to handle 11 | // higher-level protocol details such as redirects, 12 | // authentication, or cookies. 13 | // 14 | // RoundTrip should not modify the request, except for 15 | // consuming the Body. The request's URL and Header fields 16 | // are guaranteed to be initialized. 17 | RoundTrip(*http.Request) (*http.Response, error) 18 | DetailedRoundTrip(*http.Request) (*RoundTripDetails, *http.Response, error) 19 | } 20 | -------------------------------------------------------------------------------- /vendor/github.com/elazarl/goproxy/transport/util.go: -------------------------------------------------------------------------------- 1 | package transport 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | ) 7 | 8 | type badStringError struct { 9 | what string 10 | str string 11 | } 12 | 13 | func (e *badStringError) Error() string { return fmt.Sprintf("%s %q", e.what, e.str) } 14 | 15 | func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") } 16 | -------------------------------------------------------------------------------- /version.txt: -------------------------------------------------------------------------------- 1 | 0.2.0 --------------------------------------------------------------------------------