func (d *MultiDialer) pickupTLSAddrs(addrs []string, n int) []string { if len(addrs) <= n { return addrs } type racer struct { addr string duration time.Duration } goodAddrs := make([]racer, 0) unknownAddrs := make([]string, 0) badAddrs := make([]string, 0) for _, addr := range addrs { if duration, ok := d.TLSConnDuration.GetNotStale(addr); ok { if d, ok := duration.(time.Duration); !ok { glog.Errorf("%#v for %#v is not a time.Duration", duration, addr) } else { goodAddrs = append(goodAddrs, racer{addr, d}) } } else if e, ok := d.TLSConnError.GetNotStale(addr); ok { if _, ok := e.(error); !ok { glog.Errorf("%#v for %#v is not a error", e, addr) } else { badAddrs = append(badAddrs, addr) } } else { unknownAddrs = append(unknownAddrs, addr) } } addrs1 := make([]string, 0, n) sort.Slice(goodAddrs, func(i, j int) bool { return goodAddrs[i].duration < goodAddrs[j].duration }) if len(goodAddrs) > n/2 { goodAddrs = goodAddrs[:n/2] } for _, r := range goodAddrs { addrs1 = append(addrs1, r.addr) } for _, addrs2 := range [][]string{unknownAddrs, badAddrs} { if len(addrs1) < n && len(addrs2) > 0 { m := n - len(addrs1) if len(addrs2) > m { ShuffleStringsN(addrs2, m) addrs2 = addrs2[:m] } addrs1 = append(addrs1, addrs2...) } } return addrs1 }
func pickupAddrs(addrs []string, n int, connDuration lrucache.Cache, connError lrucache.Cache) []string { if len(addrs) <= n { return addrs } goodAddrs := make([]racer, 0) unknownAddrs := make([]string, 0) badAddrs := make([]string, 0) for _, addr := range addrs { if d, ok := connDuration.GetQuiet(addr); ok { if d1, ok := d.(time.Duration); !ok { glog.Errorf("%#v for %#v is not a time.Duration", d, addr) } else { goodAddrs = append(goodAddrs, racer{addr, d1}) } } else if e, ok := connError.GetQuiet(addr); ok { if _, ok := e.(error); !ok { glog.Errorf("%#v for %#v is not a error", e, addr) } else { badAddrs = append(badAddrs, addr) } } else { unknownAddrs = append(unknownAddrs, addr) } } addrs1 := make([]string, 0, n) sort.Sort(racers(goodAddrs)) if len(goodAddrs) > n/2 { goodAddrs = goodAddrs[:n/2] } for _, r := range goodAddrs { addrs1 = append(addrs1, r.addr) } for _, addrs2 := range [][]string{unknownAddrs, badAddrs} { if len(addrs1) < n && len(addrs2) > 0 { m := n - len(addrs1) if len(addrs2) > m { helpers.ShuffleStringsN(addrs2, m) addrs2 = addrs2[:m] } addrs1 = append(addrs1, addrs2...) } } return addrs1 }
func forward(lconn net.Conn, raddr string) { if err := exec.Command("wakeonlan", "18:66:DA:17:A2:95").Run(); err != nil { glog.Warningf("exec wakeonlan error: %+v", err) } glog.Infof("try connect to %+v for %+v forwarding", raddr, lconn.RemoteAddr()) rconn, err := net.Dial("tcp", raddr) if err != nil { glog.Errorf("net.Dial(%#v) error: %v", raddr, err) return } glog.Infof("forward %+v to %+v", lconn.RemoteAddr(), rconn.RemoteAddr()) go func() { buf := bufpool.Get().([]byte) defer bufpool.Put(buf) defer rconn.Close() defer lconn.Close() io.CopyBuffer(rconn, lconn, buf) }() go func() { buf := bufpool.Get().([]byte) defer bufpool.Put(buf) defer lconn.Close() defer rconn.Close() io.CopyBuffer(lconn, rconn, buf) }() }
func (f *Filter) RoundTrip(ctx context.Context, req *http.Request) (context.Context, *http.Response, error) { switch req.Method { case "CONNECT": glog.V(2).Infof("%s \"DIRECT %s %s %s\" - -", req.RemoteAddr, req.Method, req.Host, req.Proto) rconn, err := f.transport.Dial("tcp", req.Host) if err != nil { return ctx, nil, err } rw := filters.GetResponseWriter(ctx) hijacker, ok := rw.(http.Hijacker) if !ok { return ctx, nil, fmt.Errorf("http.ResponseWriter(%#v) does not implments http.Hijacker", rw) } flusher, ok := rw.(http.Flusher) if !ok { return ctx, nil, fmt.Errorf("http.ResponseWriter(%#v) does not implments http.Flusher", rw) } rw.WriteHeader(http.StatusOK) flusher.Flush() lconn, _, err := hijacker.Hijack() if err != nil { return ctx, nil, fmt.Errorf("%#v.Hijack() error: %v", hijacker, err) } defer lconn.Close() go helpers.IoCopy(rconn, lconn) helpers.IoCopy(lconn, rconn) filters.SetHijacked(ctx, true) return ctx, nil, nil default: helpers.FixRequestURL(req) resp, err := f.transport.RoundTrip(req) if err != nil { glog.Errorf("%s \"DIRECT %s %s %s\" error: %s", req.RemoteAddr, req.Method, req.URL.String(), req.Proto, err) data := err.Error() resp = &http.Response{ StatusCode: http.StatusBadGateway, Header: http.Header{}, Request: req, Close: true, ContentLength: int64(len(data)), Body: ioutil.NopCloser(bytes.NewReader([]byte(data))), } err = nil } else { if req.RemoteAddr != "" { glog.V(2).Infof("%s \"DIRECT %s %s %s\" %d %s", req.RemoteAddr, req.Method, req.URL.String(), req.Proto, resp.StatusCode, resp.Header.Get("Content-Length")) } } return ctx, resp, err } }
func (d *MultiDialer) LookupAlias(alias string) (addrs []string, err error) { names, ok := d.HostMap[alias] if !ok { return nil, fmt.Errorf("alias %#v not exists", alias) } seen := make(map[string]struct{}, 0) expiry := time.Now().Add(d.DNSCacheExpiry) for _, name := range names { var addrs0 []string if net.ParseIP(name) != nil { addrs0 = []string{name} expiry = time.Time{} } else if addrs1, ok := d.DNSCache.Get(name); ok { addrs0 = addrs1.([]string) } else { if d.ForceIPv6 { addrs0, err = d.LookupHost2(name, d.DNSServers[0]) if err != nil { glog.Warningf("LookupHost2(%#v, %#v) error: %s", name, d.DNSServers[0], err) addrs0 = []string{} } } else { addrs0, err = d.LookupHost(name) if err != nil { glog.Warningf("LookupHost(%#v) error: %s", name, err) addrs0 = []string{} } } glog.V(2).Infof("LookupHost(%#v) return %v", name, addrs0) d.DNSCache.Set(name, addrs0, expiry) } for _, addr := range addrs0 { seen[addr] = struct{}{} } } if len(seen) == 0 { return nil, err } addrs = make([]string, 0) for addr, _ := range seen { if _, ok := d.IPBlackList.GetQuiet(addr); ok { continue } addrs = append(addrs, addr) } if len(addrs) == 0 { glog.Errorf("MULTIDIALER: LookupAlias(%#v) have no good ip addrs", alias) return nil, fmt.Errorf("MULTIDIALER: LookupAlias(%#v) have no good ip addrs", alias) } return addrs, nil }
func (f *Filter) RoundTrip(ctx context.Context, req *http.Request) (context.Context, *http.Response, error) { if ip, _, err := net.SplitHostPort(req.RemoteAddr); err == nil { if _, ok := f.WhiteList[ip]; ok { return ctx, nil, nil } } if auth := filters.String(ctx, authHeader); auth != "" { if _, ok := f.ByPassHeaders.Get(auth); ok { glog.V(3).Infof("auth filter hit bypass cache %#v", auth) return ctx, nil, nil } parts := strings.SplitN(auth, " ", 2) if len(parts) == 2 { switch parts[0] { case "Basic": if userpass, err := base64.StdEncoding.DecodeString(parts[1]); err == nil { parts := strings.Split(string(userpass), ":") user := parts[0] pass := parts[1] pass1, ok := f.Basic[user] if ok && pass == pass1 { f.ByPassHeaders.Set(auth, struct{}{}, time.Now().Add(time.Hour)) return ctx, nil, nil } } default: glog.Errorf("Unrecognized auth type: %#v", parts[0]) break } } } glog.V(1).Infof("UnAuthenticated URL %v from %#v", req.URL.String(), req.RemoteAddr) noAuthResponse := &http.Response{ Status: "407 Proxy Authentication Required", StatusCode: http.StatusProxyAuthRequired, Proto: "HTTP/1.1", ProtoMajor: 1, ProtoMinor: 1, Header: http.Header{}, Request: req, Close: true, ContentLength: -1, } return ctx, noAuthResponse, nil }
func (d *MultiDialer) LookupAlias(alias string) (addrs []string, err error) { names, ok := d.HostMap[alias] if !ok { return nil, fmt.Errorf("alias %#v not exists", alias) } seen := make(map[string]struct{}, 0) for _, name := range names { var addrs0 []string if net.ParseIP(name) != nil { addrs0 = []string{name} } else { addrs0, err = d.Resolver.LookupHost(name) if err != nil { glog.Warningf("LookupHost(%#v) error: %s", name, err) addrs0 = []string{} } } for _, addr := range addrs0 { seen[addr] = struct{}{} } } if len(seen) == 0 { return nil, err } addrs = make([]string, 0) for addr := range seen { if _, ok := d.IPBlackList.GetQuiet(addr); ok { continue } addrs = append(addrs, addr) } if len(addrs) == 0 { glog.Errorf("MULTIDIALER: LookupAlias(%#v) have no good ip addrs", alias) return nil, fmt.Errorf("MULTIDIALER: LookupAlias(%#v) have no good ip addrs", alias) } return addrs, nil }
func (f *Filter) ProxyPacRoundTrip(ctx context.Context, req *http.Request) (context.Context, *http.Response, error) { _, port, err := net.SplitHostPort(req.Host) if err != nil { port = "80" } if v, ok := f.ProxyPacCache.Get(req.RequestURI); ok { if s, ok := v.(string); ok { s = fixProxyPac(s, req) return ctx, &http.Response{ StatusCode: http.StatusOK, Header: http.Header{}, Request: req, Close: true, ContentLength: int64(len(s)), Body: ioutil.NopCloser(strings.NewReader(s)), }, nil } } filename := req.URL.Path[1:] buf := new(bytes.Buffer) resp, err := f.Store.Get(filename, -1, -1) switch { case os.IsNotExist(err), resp.StatusCode == http.StatusNotFound: glog.V(2).Infof("AUTOPROXY ProxyPac: generate %#v", filename) s := fmt.Sprintf(`// User-defined FindProxyForURL function FindProxyForURL(url, host) { if (isPlainHostName(host) || host.indexOf('127.') == 0 || host.indexOf('192.168.') == 0 || host.indexOf('10.') == 0 || shExpMatch(host, 'localhost.*')) { return 'DIRECT'; } if (shExpMatch(host, '*.google*.*')) { return 'PROXY localhost:%s'; } return 'DIRECT'; } `, port) f.Store.Put(filename, http.Header{}, ioutil.NopCloser(bytes.NewBufferString(s))) case err != nil: return ctx, nil, err case resp.Body != nil: resp.Body.Close() } if resp, err := f.Store.Get(filename, -1, -1); err == nil { defer resp.Body.Close() if b, err := ioutil.ReadAll(resp.Body); err == nil { if f.GFWListEnabled { b = []byte(strings.Replace(string(b), "function FindProxyForURL(", "function MyFindProxyForURL(", 1)) } buf.Write(b) } } if f.GFWListEnabled { resp, err := f.Store.Get(f.GFWList.Filename, -1, -1) if err != nil { glog.Errorf("GetObject(%#v) error: %v", f.GFWList.Filename, err) return ctx, nil, err } defer resp.Body.Close() sites, err := parseAutoProxy(resp.Body) if err != nil { glog.Errorf("parseAutoProxy(%#v) error: %v", f.GFWList.Filename, err) return ctx, nil, err } sort.Strings(sites) io.WriteString(buf, "\nvar sites = {\n") for _, site := range sites { io.WriteString(buf, "\""+site+"\":1,\n") } io.WriteString(buf, "\"google.com\":1\n") io.WriteString(buf, "}\n") io.WriteString(buf, ` function FindProxyForURL(url, host) { if ((p = MyFindProxyForURL(url, host)) != "DIRECT") { return p } var lastPos; do { if (sites.hasOwnProperty(host)) { return 'PROXY GOPROXY_ADDRESS'; } lastPos = host.indexOf('.') + 1; host = host.slice(lastPos); } while (lastPos >= 1); return 'DIRECT'; }`) } s := buf.String() f.ProxyPacCache.Set(req.RequestURI, s, time.Now().Add(15*time.Minute)) s = fixProxyPac(s, req) resp = &http.Response{ StatusCode: http.StatusOK, Header: http.Header{}, Request: req, Close: true, ContentLength: int64(len(s)), Body: ioutil.NopCloser(strings.NewReader(s)), } return ctx, resp, nil }
func NewRootCA(name string, vaildFor time.Duration, rsaBits int, certDir string, portable bool) (*RootCA, error) { keyFile := name + ".key" certFile := name + ".crt" var store storage.Store if portable { exe, err := os.Executable() if err != nil { glog.Fatalf("os.Executable() error: %+v", err) } store = &storage.FileStore{filepath.Dir(exe)} } else { store = &storage.FileStore{"."} } rootCA := &RootCA{ store: store, name: name, keyFile: keyFile, certFile: certFile, rsaBits: rsaBits, certDir: certDir, mu: new(sync.Mutex), } if storage.NotExist(store, certFile) { glog.Infof("Generating RootCA for %s/%s", keyFile, certFile) template := x509.Certificate{ IsCA: true, SerialNumber: big.NewInt(1), Subject: pkix.Name{ CommonName: name, Country: []string{"US"}, Province: []string{"California"}, Locality: []string{"Los Angeles"}, Organization: []string{name}, ExtraNames: []pkix.AttributeTypeAndValue{ { Type: []int{2, 5, 4, 42}, Value: name, }, }, }, DNSNames: []string{name}, NotBefore: time.Now().Add(-time.Duration(30 * 24 * time.Hour)), NotAfter: time.Now().Add(vaildFor), KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, BasicConstraintsValid: true, // AuthorityKeyId: sha1.New().Sum([]byte("phuslu")), // SubjectKeyId: sha1.New().Sum([]byte("phuslu")), } priv, err := rsa.GenerateKey(rand.Reader, rsaBits) if err != nil { return nil, err } derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) if err != nil { return nil, err } ca, err := x509.ParseCertificate(derBytes) if err != nil { return nil, err } rootCA.ca = ca rootCA.priv = priv rootCA.derBytes = derBytes keypem := &pem.Block{Type: "PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(rootCA.priv)} rc := ioutil.NopCloser(bytes.NewReader(pem.EncodeToMemory(keypem))) if _, err = store.Put(keyFile, http.Header{}, rc); err != nil { return nil, err } certpem := &pem.Block{Type: "CERTIFICATE", Bytes: rootCA.derBytes} rc = ioutil.NopCloser(bytes.NewReader(pem.EncodeToMemory(certpem))) if _, err = store.Put(certFile, http.Header{}, rc); err != nil { return nil, err } } else { for _, name := range []string{keyFile, certFile} { resp, err := store.Get(name) if err != nil { return nil, err } data, err := ioutil.ReadAll(resp.Body) resp.Body.Close() if err != nil { return nil, err } var b *pem.Block for { b, data = pem.Decode(data) if b == nil { break } switch b.Type { case "CERTIFICATE": rootCA.derBytes = b.Bytes ca, err := x509.ParseCertificate(rootCA.derBytes) if err != nil { return nil, err } rootCA.ca = ca case "PRIVATE KEY", "PRIVATE RSA KEY": priv, err := x509.ParsePKCS1PrivateKey(b.Bytes) if err != nil { return nil, err } rootCA.priv = priv } } } } switch runtime.GOOS { case "windows", "darwin": if _, err := rootCA.ca.Verify(x509.VerifyOptions{}); err != nil { glog.Warningf("Verify RootCA(%#v) error: %v, try import to system root", name, err) if err = helpers.RemoveCAFromSystemRoot(rootCA.name); err != nil { glog.Errorf("Remove Old RootCA(%#v) error: %v", name, err) } if err = helpers.ImportCAToSystemRoot(rootCA.ca); err != nil { glog.Errorf("Import RootCA(%#v) error: %v", name, err) } else { glog.Infof("Import RootCA(%s) OK", certFile) } if fs, err := store.List(certDir); err == nil { for _, f := range fs { if _, err = store.Delete(f); err != nil { glog.Errorf("%T.Delete(%#v) error: %v", store, f, err) } } } } } if fs, ok := store.(*storage.FileStore); ok { if storage.NotExist(store, certDir) { if err := os.Mkdir(filepath.Join(fs.Dirname, certDir), 0777); err != nil { return nil, err } } } return rootCA, nil }
func (h Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { var err error remoteAddr := req.RemoteAddr // Prepare filter.Context ctx := filters.NewContext(req.Context(), h, h.Listener, rw, h.Branding) req = req.WithContext(ctx) // Enable transport http proxy if req.Method != "CONNECT" && !req.URL.IsAbs() { if req.URL.Scheme == "" { if req.TLS != nil && req.ProtoMajor == 1 { req.URL.Scheme = "https" } else { req.URL.Scheme = "http" } } if req.TLS != nil { if req.Host == "" { if req.URL.Host != "" { req.Host = req.URL.Host } else { req.Host = req.TLS.ServerName } } if req.URL.Host == "" { if req.Host != "" { req.URL.Host = req.Host } else { req.URL.Host = req.TLS.ServerName } } } } // Filter Request for _, f := range h.RequestFilters { ctx, req, err = f.Request(ctx, req) if req == filters.DummyRequest { return } if err != nil { if err != io.EOF { glog.Errorf("%s Filter Request %T error: %+v", remoteAddr, f, err) } return } // Update context for request req = req.WithContext(ctx) } if req.Body != nil { defer req.Body.Close() } // Filter Request -> Response var resp *http.Response for _, f := range h.RoundTripFilters { ctx, resp, err = f.RoundTrip(ctx, req) if resp == filters.DummyResponse { return } // Unexcepted errors if err != nil { filters.SetRoundTripFilter(ctx, f) glog.Errorf("%s Filter RoundTrip %T error: %+v", remoteAddr, f, err) http.Error(rw, h.FormatError(ctx, err), http.StatusBadGateway) return } // Update context for request req = req.WithContext(ctx) // A roundtrip filter give a response if resp != nil { resp.Request = req filters.SetRoundTripFilter(ctx, f) break } } // Filter Response for _, f := range h.ResponseFilters { if resp == nil || resp == filters.DummyResponse { return } ctx, resp, err = f.Response(ctx, resp) if err != nil { glog.Errorln("%s Filter %T Response error: %+v", remoteAddr, f, err) http.Error(rw, h.FormatError(ctx, err), http.StatusBadGateway) return } // Update context for request req = req.WithContext(ctx) } if resp == nil { glog.Errorln("%s Handler %#v Response empty response", remoteAddr, h) http.Error(rw, h.FormatError(ctx, fmt.Errorf("empty response")), http.StatusBadGateway) return } if resp.Header.Get("Content-Length") == "" && resp.ContentLength >= 0 { resp.Header.Set("Content-Length", strconv.FormatInt(resp.ContentLength, 10)) } for key, values := range resp.Header { for _, value := range values { rw.Header().Add(key, value) } } rw.WriteHeader(resp.StatusCode) if resp.Body != nil { defer resp.Body.Close() n, err := helpers.IOCopy(rw, resp.Body) if err != nil { if isClosedConnError(err) { glog.Infof("IOCopy %#v return %#v %T(%v)", resp.Body, n, err, err) } else { glog.Warningf("IOCopy %#v return %#v %T(%v)", resp.Body, n, err, err) } } } }
func NewRootCA(name string, vaildFor time.Duration, rsaBits int, certDir string, portable bool) (*RootCA, error) { keyFile := name + ".key" certFile := name + ".crt" if portable { rootdir := filepath.Dir(os.Args[0]) keyFile = filepath.Join(rootdir, keyFile) certFile = filepath.Join(rootdir, certFile) certDir = filepath.Join(rootdir, certDir) } rootCA := &RootCA{ name: name, keyFile: keyFile, certFile: certFile, rsaBits: rsaBits, certDir: certDir, mu: new(sync.Mutex), } if _, err := os.Stat(certFile); os.IsNotExist(err) { glog.Infof("Generating RootCA for %s", certFile) template := x509.Certificate{ IsCA: true, SerialNumber: big.NewInt(1), Subject: pkix.Name{ CommonName: name, Organization: []string{name}, }, NotBefore: time.Now().Add(-time.Duration(30 * 24 * time.Hour)), NotAfter: time.Now().Add(vaildFor), KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, BasicConstraintsValid: true, } priv, err := rsa.GenerateKey(rand.Reader, rsaBits) if err != nil { return nil, err } derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) if err != nil { return nil, err } ca, err := x509.ParseCertificate(derBytes) if err != nil { return nil, err } rootCA.ca = ca rootCA.priv = priv rootCA.derBytes = derBytes keypem := &pem.Block{Type: "PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(rootCA.priv)} if err = ioutil.WriteFile(keyFile, pem.EncodeToMemory(keypem), 0755); err != nil { return nil, err } certpem := &pem.Block{Type: "CERTIFICATE", Bytes: rootCA.derBytes} if err = ioutil.WriteFile(certFile, pem.EncodeToMemory(certpem), 0755); err != nil { return nil, err } } else { data, err := ioutil.ReadFile(keyFile) if err != nil { return nil, err } var b *pem.Block for { b, data = pem.Decode(data) if b == nil { break } if b.Type == "CERTIFICATE" { rootCA.derBytes = b.Bytes ca, err := x509.ParseCertificate(rootCA.derBytes) if err != nil { return nil, err } rootCA.ca = ca } else if b.Type == "PRIVATE KEY" { priv, err := x509.ParsePKCS1PrivateKey(b.Bytes) if err != nil { return nil, err } rootCA.priv = priv } } data, err = ioutil.ReadFile(certFile) if err != nil { return nil, err } for { b, data = pem.Decode(data) if b == nil { break } if b.Type == "CERTIFICATE" { rootCA.derBytes = b.Bytes ca, err := x509.ParseCertificate(rootCA.derBytes) if err != nil { return nil, err } rootCA.ca = ca } else if b.Type == "PRIVATE KEY" { priv, err := x509.ParsePKCS1PrivateKey(b.Bytes) if err != nil { return nil, err } rootCA.priv = priv } } } switch runtime.GOOS { case "windows", "darwin": if _, err := rootCA.ca.Verify(x509.VerifyOptions{}); err != nil { glog.Warningf("Verify RootCA(%#v) error: %v, try import to system root", name, err) if err = helpers.RemoveCAFromSystemRoot(rootCA.name); err != nil { glog.Errorf("Remove Old RootCA(%#v) error: %v", name, err) } if err = helpers.ImportCAToSystemRoot(rootCA.ca); err != nil { glog.Errorf("Import RootCA(%#v) error: %v", name, err) } else { glog.Infof("Import RootCA(%s) OK", certFile) } if fis, err := ioutil.ReadDir(certDir); err == nil { for _, fi := range fis { if err = os.Remove(certDir + "/" + fi.Name()); err != nil { glog.Errorf("Remove(%#v) error: %v", fi.Name(), err) } } } } } if _, err := os.Stat(certDir); os.IsNotExist(err) { if err = os.Mkdir(certDir, 0755); err != nil { return nil, err } } return rootCA, nil }