func NewFilter(config *Config) (filters.Filter, error) { dnsServers := make([]net.IP, 0) for _, s := range config.DNSServers { if ip := net.ParseIP(s); ip != nil { dnsServers = append(dnsServers, ip) } } GoogleG2PKP, err := base64.StdEncoding.DecodeString(config.GoogleG2PKP) if err != nil { return nil, err } googleTLSConfig := &tls.Config{ MinVersion: tls.VersionTLS12, InsecureSkipVerify: true, ServerName: "www.microsoft.com", ClientSessionCache: tls.NewLRUClientSessionCache(config.TLSConfig.ClientSessionCacheSize), CipherSuites: []uint16{ tls.TLS_RSA_WITH_AES_128_CBC_SHA, tls.TLS_RSA_WITH_AES_256_CBC_SHA, tls.TLS_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_RSA_WITH_AES_256_GCM_SHA384, tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, }, } switch config.TLSConfig.Version { case "TLSv12", "TLSv1.2": googleTLSConfig.MinVersion = tls.VersionTLS12 case "TLSv11", "TLSv1.1": googleTLSConfig.MinVersion = tls.VersionTLS11 default: googleTLSConfig.MinVersion = tls.VersionTLS10 } pickupCiphers := func(names []string) []uint16 { ciphers := make([]uint16, 0) for _, name := range names { cipher := helpers.Cipher(name) if cipher == 0 { glog.Fatalf("GAE: cipher %#v is not supported.", name) } ciphers = append(ciphers, cipher) } helpers.ShuffleUint16s(ciphers) ciphers = ciphers[:1+rand.Intn(len(ciphers))] ciphers1 := []uint16{} for _, name := range []string{ "TLS_RSA_WITH_AES_256_CBC_SHA256", "TLS_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", } { if !helpers.ContainsString(names, name) { if c := helpers.Cipher(name); c != 0 { ciphers1 = append(ciphers1, c) } } } helpers.ShuffleUint16s(ciphers1) ciphers1 = ciphers1[:rand.Intn(len(ciphers1))] ciphers = append(ciphers, ciphers1...) helpers.ShuffleUint16s(ciphers) return ciphers } googleTLSConfig.CipherSuites = pickupCiphers(config.TLSConfig.Ciphers) if len(config.TLSConfig.ServerName) > 0 { googleTLSConfig.ServerName = config.TLSConfig.ServerName[rand.Intn(len(config.TLSConfig.ServerName))] } if !config.DisableHTTP2 { googleTLSConfig.NextProtos = []string{"h2", "h2-14", "http/1.1"} } if config.Site2Alias == nil { config.Site2Alias = make(map[string]string) } for key, value := range config.SiteToAlias { config.Site2Alias[key] = value } config.SiteToAlias = config.Site2Alias hostmap := map[string][]string{} for key, value := range config.HostMap { hostmap[key] = helpers.UniqueStrings(value) } d := &net.Dialer{ KeepAlive: time.Duration(config.Transport.Dialer.KeepAlive) * time.Second, Timeout: time.Duration(config.Transport.Dialer.Timeout) * time.Second, DualStack: config.Transport.Dialer.DualStack, } md := &dialer.MultiDialer{ Dialer: d, DisableIPv6: config.DisableIPv6, ForceIPv6: config.ForceIPv6, SSLVerify: config.SSLVerify, EnableRemoteDNS: config.EnableRemoteDNS, LogToStderr: flag.Lookup("logtostderr") != nil, TLSConfig: nil, SiteToAlias: helpers.NewHostMatcherWithString(config.SiteToAlias), IPBlackList: lrucache.NewLRUCache(1024), HostMap: hostmap, GoogleTLSConfig: googleTLSConfig, GoogleG2PKP: GoogleG2PKP, DNSServers: dnsServers, DNSCache: lrucache.NewLRUCache(config.Transport.Dialer.DNSCacheSize), DNSCacheExpiry: time.Duration(config.Transport.Dialer.DNSCacheExpiry) * time.Second, TLSConnDuration: lrucache.NewLRUCache(8192), TLSConnError: lrucache.NewLRUCache(8192), TLSConnReadBuffer: config.Transport.Dialer.SocketReadBuffer, ConnExpiry: 5 * time.Minute, Level: config.Transport.Dialer.Level, } for _, ip := range config.IPBlackList { md.IPBlackList.Set(ip, struct{}{}, time.Time{}) } var tr http.RoundTripper t1 := &http.Transport{ Dial: md.Dial, DialTLS: md.DialTLS, DisableKeepAlives: config.Transport.DisableKeepAlives, DisableCompression: config.Transport.DisableCompression, ResponseHeaderTimeout: time.Duration(config.Transport.ResponseHeaderTimeout) * time.Second, IdleConnTimeout: time.Duration(config.Transport.IdleConnTimeout) * time.Second, MaxIdleConnsPerHost: config.Transport.MaxIdleConnsPerHost, } if config.Transport.Proxy.Enabled { fixedURL, err := url.Parse(config.Transport.Proxy.URL) if err != nil { glog.Fatalf("url.Parse(%#v) error: %s", config.Transport.Proxy.URL, err) } dialer, err := proxy.FromURL(fixedURL, d, &dialer.MultiResolver{md}) if err != nil { glog.Fatalf("proxy.FromURL(%#v) error: %s", fixedURL.String(), err) } t1.Dial = dialer.Dial t1.DialTLS = nil t1.Proxy = nil t1.TLSClientConfig = md.GoogleTLSConfig } switch { case config.DisableHTTP2 && config.ForceHTTP2: glog.Fatalf("GAE: DisableHTTP2=%v and ForceHTTP2=%v is conflict!", config.DisableHTTP2, config.ForceHTTP2) case config.Transport.Proxy.Enabled && config.ForceHTTP2: glog.Fatalf("GAE: Proxy.Enabled=%v and ForceHTTP2=%v is conflict!", config.Transport.Proxy.Enabled, config.ForceHTTP2) case config.ForceHTTP2: tr = &http2.Transport{ DialTLS: md.DialTLS2, TLSClientConfig: md.GoogleTLSConfig, DisableCompression: config.Transport.DisableCompression, } case !config.DisableHTTP2: err := http2.ConfigureTransport(t1) if err != nil { glog.Warningf("GAE: Error enabling Transport HTTP/2 support: %v", err) } tr = t1 default: tr = t1 } forceHTTPSMatcherStrings := make([]string, 0) for key, value := range config.SiteToAlias { if strings.HasPrefix(value, "google_") { forceHTTPSMatcherStrings = append(forceHTTPSMatcherStrings, key) } } forceGAEStrings := make([]string, 0) forceGAESuffixs := make([]string, 0) forceGAEMatcherStrings := make([]string, 0) for _, s := range config.ForceGAE { if strings.Contains(s, "/") { if strings.HasSuffix(s, "$") { forceGAESuffixs = append(forceGAESuffixs, strings.TrimRight(s, "$")) } else { forceGAEStrings = append(forceGAEStrings, s) } } else { forceGAEMatcherStrings = append(forceGAEMatcherStrings, s) } } if config.EnableDeadProbe && !config.Transport.Proxy.Enabled { go func() { probe := func() { req, _ := http.NewRequest(http.MethodGet, "https://clients3.google.com/generate_204", nil) ctx, cancel := context.WithTimeout(req.Context(), 3*time.Second) defer cancel() req = req.WithContext(ctx) resp, err := tr.RoundTrip(req) if resp != nil && resp.Body != nil { glog.V(3).Infof("GAE EnableDeadProbe \"%s %s\" %d -", req.Method, req.URL.String(), resp.StatusCode) resp.Body.Close() } if err != nil { glog.V(2).Infof("GAE EnableDeadProbe \"%s %s\" error: %v", req.Method, req.URL.String(), err) s := strings.ToLower(err.Error()) if strings.HasPrefix(s, "net/http: request canceled") || strings.Contains(s, "timeout") { helpers.TryCloseConnections(tr) } } } for { time.Sleep(time.Duration(5+rand.Intn(6)) * time.Second) probe() } }() } helpers.ShuffleStrings(config.AppIDs) f := &Filter{ Config: *config, GAETransport: &Transport{ RoundTripper: tr, MultiDialer: md, Servers: NewServers(config.AppIDs, config.Password, config.SSLVerify, time.Duration(config.Transport.ResponseHeaderTimeout-4)*time.Second), RetryDelay: time.Duration(config.Transport.RetryDelay*1000) * time.Second, RetryTimes: config.Transport.RetryTimes, }, DirectTransport: tr, ForceHTTPSMatcher: helpers.NewHostMatcher(forceHTTPSMatcherStrings), ForceGAEMatcher: helpers.NewHostMatcher(forceGAEMatcherStrings), ForceGAEStrings: forceGAEStrings, ForceGAESuffixs: forceGAESuffixs, ForceDeflateMatcher: helpers.NewHostMatcher(config.ForceDeflate), FakeOptionsMatcher: helpers.NewHostMatcherWithStrings(config.FakeOptions), SiteMatcher: helpers.NewHostMatcher(config.Sites), DirectSiteMatcher: helpers.NewHostMatcherWithString(config.Site2Alias), } if config.Transport.Proxy.Enabled { f.GAETransport.MultiDialer = nil } return f, nil }
func NewFilter(config *Config) (filters.Filter, error) { servers := make([]Server, 0) for _, s := range config.Servers { u, err := url.Parse(s.URL) if err != nil { return nil, err } server := Server{ URL: u, Password: s.Password, SSLVerify: s.SSLVerify, Host: s.Host, } servers = append(servers, server) } d := &dialer.Dialer{ Dialer: net.Dialer{ KeepAlive: time.Duration(config.Transport.Dialer.KeepAlive) * time.Second, Timeout: time.Duration(config.Transport.Dialer.Timeout) * time.Second, DualStack: config.Transport.Dialer.DualStack, }, RetryTimes: config.Transport.Dialer.RetryTimes, RetryDelay: time.Duration(config.Transport.Dialer.RetryDelay*1000) * time.Second, DNSCache: lrucache.NewLRUCache(config.Transport.Dialer.DNSCacheSize), DNSCacheExpiry: time.Duration(config.Transport.Dialer.DNSCacheExpiry) * time.Second, LoopbackAddrs: nil, Level: 2, } for _, server := range servers { if server.Host != "" { host := server.URL.Host if _, _, err := net.SplitHostPort(host); err != nil { if server.URL.Scheme == "https" { host += ":443" } else { host += ":80" } } host1 := server.Host if _, _, err := net.SplitHostPort(host1); err != nil { if server.URL.Scheme == "https" { host1 += ":443" } else { host1 += ":80" } } d.DNSCache.Set(host, host1, time.Time{}) } } tr := &http.Transport{ Dial: d.Dial, TLSClientConfig: &tls.Config{ InsecureSkipVerify: false, ClientSessionCache: tls.NewLRUClientSessionCache(1000), }, TLSHandshakeTimeout: time.Duration(config.Transport.TLSHandshakeTimeout) * time.Second, MaxIdleConnsPerHost: config.Transport.MaxIdleConnsPerHost, } if tr.TLSClientConfig != nil { err := http2.ConfigureTransport(tr) if err != nil { glog.Warningf("PHP: Error enabling Transport HTTP/2 support: %v", err) } } return &Filter{ Config: *config, Transport: &Transport{ RoundTripper: tr, Servers: servers, }, Sites: helpers.NewHostMatcher(config.Sites), }, nil }
func NewFilter(config *Config) (filters.Filter, error) { servers := make([]Server, 0) for _, s := range config.Servers { u, err := url.Parse(s.URL) if err != nil { return nil, err } server := Server{ URL: u, Password: s.Password, SSLVerify: s.SSLVerify, Host: s.Host, } servers = append(servers, server) } d0 := &net.Dialer{ KeepAlive: time.Duration(config.Transport.Dialer.KeepAlive) * time.Second, Timeout: time.Duration(config.Transport.Dialer.Timeout) * time.Second, DualStack: config.Transport.Dialer.DualStack, } d := &helpers.Dialer{ Dialer: d0, Resolver: &helpers.Resolver{ LRUCache: lrucache.NewLRUCache(config.Transport.Dialer.DNSCacheSize), DNSExpiry: time.Duration(config.Transport.Dialer.DNSCacheExpiry) * time.Second, }, Level: 2, } for _, server := range servers { if server.Host != "" { d.Resolver.LRUCache.Set(server.URL.Hostname(), server.Host, time.Time{}) } } tr := &http.Transport{ Dial: d.Dial, TLSClientConfig: &tls.Config{ InsecureSkipVerify: false, ClientSessionCache: tls.NewLRUClientSessionCache(1000), }, TLSHandshakeTimeout: time.Duration(config.Transport.TLSHandshakeTimeout) * time.Second, MaxIdleConnsPerHost: config.Transport.MaxIdleConnsPerHost, } if config.Transport.Proxy.Enabled { fixedURL, err := url.Parse(config.Transport.Proxy.URL) if err != nil { glog.Fatalf("url.Parse(%#v) error: %s", config.Transport.Proxy.URL, err) } switch fixedURL.Scheme { case "http", "https": tr.Proxy = http.ProxyURL(fixedURL) tr.Dial = nil tr.DialTLS = nil default: dialer, err := proxy.FromURL(fixedURL, d, nil) if err != nil { glog.Fatalf("proxy.FromURL(%#v) error: %s", fixedURL.String(), err) } tr.Dial = dialer.Dial tr.DialTLS = nil tr.Proxy = nil } } if tr.TLSClientConfig != nil { err := http2.ConfigureTransport(tr) if err != nil { glog.Warningf("PHP: Error enabling Transport HTTP/2 support: %v", err) } } return &Filter{ Config: *config, Transport: &Transport{ RoundTripper: tr, Servers: servers, }, }, nil }