diff --git a/conf/sower.toml b/conf/sower.toml index 665f9fb..6ef9197 100644 --- a/conf/sower.toml +++ b/conf/sower.toml @@ -18,13 +18,19 @@ blocklist=[ "**.ggpht.com", "**.googlevideo.com", "**.facebook.com", # facebook - "**.xx.fbcdn.net", + "**.fbcdn.net", "**.twitter.com", # twitter "**.twimg.com", "**.blogspot.com", # blogspot "**.appspot.com", "**.wikipedia.org", # wikipeida "*.cloudfront.net", + "**.amazon.com", + "**.amazonaws.com", + "*.githubusercontent.com", + "**.mozilla.com", + "**.mozilla.net", + "**.akadns.net", ] whitelist=[ "iamp.*.*.*", diff --git a/dns/dns.go b/dns/dns.go index 1baa518..d486316 100644 --- a/dns/dns.go +++ b/dns/dns.go @@ -3,6 +3,7 @@ package dns import ( "net" "strings" + "sync/atomic" "time" "github.com/golang/glog" @@ -16,7 +17,7 @@ const colon = byte(':') func StartDNS(dnsServer, listenIP string) { ip := net.ParseIP(listenIP) - suggest := &intelliSuggest{listenIP, 2 * time.Second, []string{"80", "443"}} + suggest := &intelliSuggest{listenIP, 2 * time.Second} mem.DefaultCache = mem.New(time.Hour) var dhcpCh chan struct{} if dnsServer != "" { @@ -93,11 +94,10 @@ func matchAndServe(w dns.ResponseWriter, r *dns.Msg, domain, listenIP, dnsServer type intelliSuggest struct { listenIP string timeout time.Duration - ports []string } func (i *intelliSuggest) GetOne(domain interface{}) (iface interface{}, e error) { - iface = struct{}{} + iface, e = struct{}{}, nil // kill deadloop, for ugly wildcard setting dns setting addr := strings.TrimSuffix(domain.(string), ".") @@ -105,36 +105,33 @@ func (i *intelliSuggest) GetOne(domain interface{}) (iface interface{}, e error) return } - for _, port := range i.ports { - // give local dial a hand, make it not so easy to be added into suggestions - <-util.HTTPPing(net.JoinHostPort(addr, port), addr, i.timeout/50) - localCh := util.HTTPPing(net.JoinHostPort(addr, port), addr, i.timeout) - remoteCh := util.HTTPPing(net.JoinHostPort(i.listenIP, port), addr, i.timeout) + // give local dial a hand, make it not so easy to be added into suggestions + util.HTTPPing(addr, addr, util.Http, i.timeout/50) - select { - case err := <-localCh: - if err == nil { - glog.V(2).Infoln("PING", addr, "local first, succ") - continue - } - if e := <-remoteCh; e != nil { - glog.V(2).Infoln("PING", addr, "local first, all fail:", err) - continue - } - glog.V(2).Infoln("PING", addr, "local first, remote succ") - conf.AddSuggest(addr) - - case err := <-remoteCh: + pings := []struct { + viaAddr string + port util.Port + }{ + {addr, util.Http}, + {addr, util.Https}, + {i.listenIP, util.Http}, + {i.listenIP, util.Https}, + } + var finish = new(uint32) + for idx := range pings { + go func(idx int) { + err := util.HTTPPing(pings[idx].viaAddr, addr, pings[idx].port, i.timeout) if err != nil { - glog.V(2).Infoln("PING", addr, "remote first, fail:", err) - continue + if atomic.LoadUint32(finish) == 0 { // fails before first succ + glog.V(1).Infof("PING %s via %s fail: %s", addr, pings[idx].viaAddr, err) + } + } else if atomic.CompareAndSwapUint32(finish, 0, 1) { // first succ + if pings[idx].viaAddr == i.listenIP { + conf.AddSuggest(addr) + glog.Infof("added suggest domain: %s\t via: %s", addr, pings[idx].viaAddr) + } } - glog.V(2).Infoln("PING", addr, "remote first, succ") - conf.AddSuggest(addr) - } - - glog.Infof("added suggest domain: %s", addr) - return + }(idx) } return } diff --git a/dns/util.go b/dns/util.go index 3d91e7d..a81ee67 100644 --- a/dns/util.go +++ b/dns/util.go @@ -35,7 +35,7 @@ func init() { func loadRules(name string, list []string) *util.Node { rule := util.NewNodeFromRules(".", list...) - glog.V(2).Infof("load %s rule:\n%s", name, rule) + glog.V(3).Infof("load %s rule:\n%s", name, rule) return rule } diff --git a/util/http_ping.go b/util/http_ping.go index ea89983..5acc4ad 100644 --- a/util/http_ping.go +++ b/util/http_ping.go @@ -10,36 +10,15 @@ import ( ) // HTTPPing try connect to a http(s) server with domain though the http addr -func HTTPPing(tcpAddr, domain string, timeout time.Duration) <-chan error { - errCh := make(chan error) - go func() { - errCh <- httpPing(tcpAddr, domain, timeout) - }() - return errCh -} - -func httpPing(tcpAddr, domain string, timeout time.Duration) error { - conn, err := net.DialTimeout("tcp", tcpAddr, timeout) +func HTTPPing(viaHost, domain string, port Port, timeout time.Duration) (err error) { + conn, err := net.DialTimeout("tcp", port.JoinAddr(viaHost), timeout) if err != nil { return err } defer conn.Close() - host, port, err := net.SplitHostPort(tcpAddr) - if err != nil { - return err - } - - var msg []byte - switch port { - case ":80": - msg = []byte("TRACE / HTTP/1.1\r\nHost: " + domain + "\r\n\r\n") - case ":443": - msg = NewClientHelloSNIMsg(domain) - } - conn.SetDeadline(time.Now().Add(timeout)) - if _, err = conn.Write(msg); err != nil { + if _, err = conn.Write(port.pingMsg(domain)); err != nil { return err } @@ -47,12 +26,43 @@ func httpPing(tcpAddr, domain string, timeout time.Duration) error { // err -> io.EOF: no such domain or connection refused // err -> timeout: tcp package has been dropped _, err = conn.Read(make([]byte, 1)) - if err == io.EOF && host == domain { + if err == io.EOF && viaHost == domain { return nil } return err } +// Port ========================== +type Port uint16 + +const ( + Http Port = iota + Https +) + +func (p Port) JoinAddr(addr string) string { + switch p { + case Http: + return addr + ":80" + case Https: + return addr + ":443" + default: + panic("invalid port") + } +} + +func (p Port) pingMsg(domain string) []byte { + switch p { + case Http: + return []byte("TRACE / HTTP/1.1\r\nHost: " + domain + "\r\n\r\n") + case Https: + return NewClientHelloSNIMsg(domain) + default: + panic("invalid port") + } +} + +// SNI ========================== type clientHelloSNI struct { ContentType uint8 Version uint16