diff options
author | Katie Hockman <katie@golang.org> | 2021-06-07 12:31:32 -0400 |
---|---|---|
committer | Katie Hockman <katie@golang.org> | 2021-06-07 12:31:32 -0400 |
commit | 9647f89f2ac2a64acb502c594fc747f206842a86 (patch) | |
tree | e48b92008454a8aa6ffd1f4709578ac5b921a6a4 /src/net | |
parent | 03a15201e7e0f11c8f4021a181071040a04dc375 (diff) | |
parent | ab7f8297f9734b24a43a942930258cda411f16a3 (diff) | |
download | go-9647f89f2ac2a64acb502c594fc747f206842a86.tar.gz go-9647f89f2ac2a64acb502c594fc747f206842a86.zip |
[dev.boringcrypto.go1.15] all: merge go1.15.13 into dev.boringcrypto.go1.15
Change-Id: I90b28aa5938fe0bddf11201c6bdb851de5c654c3
Diffstat (limited to 'src/net')
-rw-r--r-- | src/net/dnsclient_unix_test.go | 158 | ||||
-rw-r--r-- | src/net/http/httputil/reverseproxy.go | 22 | ||||
-rw-r--r-- | src/net/http/httputil/reverseproxy_test.go | 63 | ||||
-rw-r--r-- | src/net/http/transport_test.go | 8 | ||||
-rw-r--r-- | src/net/lookup.go | 111 |
5 files changed, 328 insertions, 34 deletions
diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go index 06553636ee..f646629912 100644 --- a/src/net/dnsclient_unix_test.go +++ b/src/net/dnsclient_unix_test.go @@ -1799,3 +1799,161 @@ func TestPTRandNonPTR(t *testing.T) { t.Errorf("names = %q; want %q", names, want) } } + +func TestCVE202133195(t *testing.T) { + fake := fakeDNSServer{ + rh: func(n, _ string, q dnsmessage.Message, _ time.Time) (dnsmessage.Message, error) { + r := dnsmessage.Message{ + Header: dnsmessage.Header{ + ID: q.Header.ID, + Response: true, + RCode: dnsmessage.RCodeSuccess, + RecursionAvailable: true, + }, + Questions: q.Questions, + } + switch q.Questions[0].Type { + case dnsmessage.TypeCNAME: + r.Answers = []dnsmessage.Resource{} + case dnsmessage.TypeA: // CNAME lookup uses a A/AAAA as a proxy + r.Answers = append(r.Answers, + dnsmessage.Resource{ + Header: dnsmessage.ResourceHeader{ + Name: dnsmessage.MustNewName("<html>.golang.org."), + Type: dnsmessage.TypeA, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.AResource{ + A: TestAddr, + }, + }, + ) + case dnsmessage.TypeSRV: + n := q.Questions[0].Name + if n.String() == "_hdr._tcp.golang.org." { + n = dnsmessage.MustNewName("<html>.golang.org.") + } + r.Answers = append(r.Answers, + dnsmessage.Resource{ + Header: dnsmessage.ResourceHeader{ + Name: n, + Type: dnsmessage.TypeSRV, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.SRVResource{ + Target: dnsmessage.MustNewName("<html>.golang.org."), + }, + }, + ) + case dnsmessage.TypeMX: + r.Answers = append(r.Answers, + dnsmessage.Resource{ + Header: dnsmessage.ResourceHeader{ + Name: dnsmessage.MustNewName("<html>.golang.org."), + Type: dnsmessage.TypeMX, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.MXResource{ + MX: dnsmessage.MustNewName("<html>.golang.org."), + }, + }, + ) + case dnsmessage.TypeNS: + r.Answers = append(r.Answers, + dnsmessage.Resource{ + Header: dnsmessage.ResourceHeader{ + Name: dnsmessage.MustNewName("<html>.golang.org."), + Type: dnsmessage.TypeNS, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.NSResource{ + NS: dnsmessage.MustNewName("<html>.golang.org."), + }, + }, + ) + case dnsmessage.TypePTR: + r.Answers = append(r.Answers, + dnsmessage.Resource{ + Header: dnsmessage.ResourceHeader{ + Name: dnsmessage.MustNewName("<html>.golang.org."), + Type: dnsmessage.TypePTR, + Class: dnsmessage.ClassINET, + Length: 4, + }, + Body: &dnsmessage.PTRResource{ + PTR: dnsmessage.MustNewName("<html>.golang.org."), + }, + }, + ) + } + return r, nil + }, + } + + r := Resolver{PreferGo: true, Dial: fake.DialContext} + // Change the default resolver to match our manipulated resolver + originalDefault := DefaultResolver + DefaultResolver = &r + defer func() { DefaultResolver = originalDefault }() + // Redirect host file lookups. + defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath) + testHookHostsPath = "testdata/hosts" + + _, err := r.LookupCNAME(context.Background(), "golang.org") + if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected { + t.Errorf("Resolver.LookupCNAME returned unexpected error, got %q, want %q", err, expected) + } + _, err = LookupCNAME("golang.org") + if expected := "lookup golang.org: CNAME target is invalid"; err == nil || err.Error() != expected { + t.Errorf("LookupCNAME returned unexpected error, got %q, want %q", err, expected) + } + + _, _, err = r.LookupSRV(context.Background(), "target", "tcp", "golang.org") + if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected { + t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected) + } + _, _, err = LookupSRV("target", "tcp", "golang.org") + if expected := "lookup golang.org: SRV target is invalid"; err == nil || err.Error() != expected { + t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected) + } + + _, _, err = r.LookupSRV(context.Background(), "hdr", "tcp", "golang.org") + if expected := "lookup golang.org: SRV header name is invalid"; err == nil || err.Error() != expected { + t.Errorf("Resolver.LookupSRV returned unexpected error, got %q, want %q", err, expected) + } + _, _, err = LookupSRV("hdr", "tcp", "golang.org") + if expected := "lookup golang.org: SRV header name is invalid"; err == nil || err.Error() != expected { + t.Errorf("LookupSRV returned unexpected error, got %q, want %q", err, expected) + } + + _, err = r.LookupMX(context.Background(), "golang.org") + if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected { + t.Errorf("Resolver.LookupMX returned unexpected error, got %q, want %q", err, expected) + } + _, err = LookupMX("golang.org") + if expected := "lookup golang.org: MX target is invalid"; err == nil || err.Error() != expected { + t.Errorf("LookupMX returned unexpected error, got %q, want %q", err, expected) + } + + _, err = r.LookupNS(context.Background(), "golang.org") + if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected { + t.Errorf("Resolver.LookupNS returned unexpected error, got %q, want %q", err, expected) + } + _, err = LookupNS("golang.org") + if expected := "lookup golang.org: NS target is invalid"; err == nil || err.Error() != expected { + t.Errorf("LookupNS returned unexpected error, got %q, want %q", err, expected) + } + + _, err = r.LookupAddr(context.Background(), "192.0.2.42") + if expected := "lookup 192.0.2.42: PTR target is invalid"; err == nil || err.Error() != expected { + t.Errorf("Resolver.LookupAddr returned unexpected error, got %q, want %q", err, expected) + } + _, err = LookupAddr("192.0.2.42") + if expected := "lookup 192.0.2.42: PTR target is invalid"; err == nil || err.Error() != expected { + t.Errorf("LookupAddr returned unexpected error, got %q, want %q", err, expected) + } +} diff --git a/src/net/http/httputil/reverseproxy.go b/src/net/http/httputil/reverseproxy.go index 3f48fab544..f49cefbb4f 100644 --- a/src/net/http/httputil/reverseproxy.go +++ b/src/net/http/httputil/reverseproxy.go @@ -248,22 +248,18 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { // important is "Connection" because we want a persistent // connection, regardless of what the client sent to us. for _, h := range hopHeaders { - hv := outreq.Header.Get(h) - if hv == "" { - continue - } - if h == "Te" && hv == "trailers" { - // Issue 21096: tell backend applications that - // care about trailer support that we support - // trailers. (We do, but we don't go out of - // our way to advertise that unless the - // incoming client request thought it was - // worth mentioning) - continue - } outreq.Header.Del(h) } + // Issue 21096: tell backend applications that care about trailer support + // that we support trailers. (We do, but we don't go out of our way to + // advertise that unless the incoming client request thought it was worth + // mentioning.) Note that we look at req.Header, not outreq.Header, since + // the latter has passed through removeConnectionHeaders. + if httpguts.HeaderValuesContainsToken(req.Header["Te"], "trailers") { + outreq.Header.Set("Te", "trailers") + } + // After stripping all the hop-by-hop connection headers above, add back any // necessary for protocol upgrades, such as for websockets. if reqUpType != "" { diff --git a/src/net/http/httputil/reverseproxy_test.go b/src/net/http/httputil/reverseproxy_test.go index 764939fb0f..1f2dfb9867 100644 --- a/src/net/http/httputil/reverseproxy_test.go +++ b/src/net/http/httputil/reverseproxy_test.go @@ -91,8 +91,9 @@ func TestReverseProxy(t *testing.T) { getReq, _ := http.NewRequest("GET", frontend.URL, nil) getReq.Host = "some-name" - getReq.Header.Set("Connection", "close") - getReq.Header.Set("Te", "trailers") + getReq.Header.Set("Connection", "close, TE") + getReq.Header.Add("Te", "foo") + getReq.Header.Add("Te", "bar, trailers") getReq.Header.Set("Proxy-Connection", "should be deleted") getReq.Header.Set("Upgrade", "foo") getReq.Close = true @@ -236,6 +237,64 @@ func TestReverseProxyStripHeadersPresentInConnection(t *testing.T) { } } +func TestReverseProxyStripEmptyConnection(t *testing.T) { + // See Issue 46313. + const backendResponse = "I am the backend" + + // someConnHeader is some arbitrary header to be declared as a hop-by-hop header + // in the Request's Connection header. + const someConnHeader = "X-Some-Conn-Header" + + backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if c := r.Header.Values("Connection"); len(c) != 0 { + t.Errorf("handler got header %q = %v; want empty", "Connection", c) + } + if c := r.Header.Get(someConnHeader); c != "" { + t.Errorf("handler got header %q = %q; want empty", someConnHeader, c) + } + w.Header().Add("Connection", "") + w.Header().Add("Connection", someConnHeader) + w.Header().Set(someConnHeader, "should be deleted") + io.WriteString(w, backendResponse) + })) + defer backend.Close() + backendURL, err := url.Parse(backend.URL) + if err != nil { + t.Fatal(err) + } + proxyHandler := NewSingleHostReverseProxy(backendURL) + frontend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + proxyHandler.ServeHTTP(w, r) + if c := r.Header.Get(someConnHeader); c != "should be deleted" { + t.Errorf("handler modified header %q = %q; want %q", someConnHeader, c, "should be deleted") + } + })) + defer frontend.Close() + + getReq, _ := http.NewRequest("GET", frontend.URL, nil) + getReq.Header.Add("Connection", "") + getReq.Header.Add("Connection", someConnHeader) + getReq.Header.Set(someConnHeader, "should be deleted") + res, err := frontend.Client().Do(getReq) + if err != nil { + t.Fatalf("Get: %v", err) + } + defer res.Body.Close() + bodyBytes, err := ioutil.ReadAll(res.Body) + if err != nil { + t.Fatalf("reading body: %v", err) + } + if got, want := string(bodyBytes), backendResponse; got != want { + t.Errorf("got body %q; want %q", got, want) + } + if c := res.Header.Get("Connection"); c != "" { + t.Errorf("handler got header %q = %q; want empty", "Connection", c) + } + if c := res.Header.Get(someConnHeader); c != "" { + t.Errorf("handler got header %q = %q; want empty", someConnHeader, c) + } +} + func TestXForwardedFor(t *testing.T) { const prevForwardedFor = "client ip" const backendResponse = "I am the backend" diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index 3c7b9eb4de..faa77e9ccd 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -5270,7 +5270,6 @@ func TestMissingStatusNoPanic(t *testing.T) { ln := newLocalListener(t) addr := ln.Addr().String() - shutdown := make(chan bool, 1) done := make(chan bool) fullAddrURL := fmt.Sprintf("http://%s", addr) raw := "HTTP/1.1 400\r\n" + @@ -5282,10 +5281,7 @@ func TestMissingStatusNoPanic(t *testing.T) { "Aloha Olaa" go func() { - defer func() { - ln.Close() - close(done) - }() + defer close(done) conn, _ := ln.Accept() if conn != nil { @@ -5316,7 +5312,7 @@ func TestMissingStatusNoPanic(t *testing.T) { t.Errorf("got=%v want=%q", err, want) } - close(shutdown) + ln.Close() <-done } diff --git a/src/net/lookup.go b/src/net/lookup.go index 5f7119872a..0660268249 100644 --- a/src/net/lookup.go +++ b/src/net/lookup.go @@ -389,8 +389,11 @@ func (r *Resolver) LookupPort(ctx context.Context, network, service string) (por // LookupCNAME does not return an error if host does not // contain DNS "CNAME" records, as long as host resolves to // address records. +// +// The returned canonical name is validated to be a properly +// formatted presentation-format domain name. func LookupCNAME(host string) (cname string, err error) { - return DefaultResolver.lookupCNAME(context.Background(), host) + return DefaultResolver.LookupCNAME(context.Background(), host) } // LookupCNAME returns the canonical name for the given host. @@ -403,8 +406,18 @@ func LookupCNAME(host string) (cname string, err error) { // LookupCNAME does not return an error if host does not // contain DNS "CNAME" records, as long as host resolves to // address records. -func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, err error) { - return r.lookupCNAME(ctx, host) +// +// The returned canonical name is validated to be a properly +// formatted presentation-format domain name. +func (r *Resolver) LookupCNAME(ctx context.Context, host string) (string, error) { + cname, err := r.lookupCNAME(ctx, host) + if err != nil { + return "", err + } + if !isDomainName(cname) { + return "", &DNSError{Err: "CNAME target is invalid", Name: host} + } + return cname, nil } // LookupSRV tries to resolve an SRV query of the given service, @@ -416,8 +429,11 @@ func (r *Resolver) LookupCNAME(ctx context.Context, host string) (cname string, // That is, it looks up _service._proto.name. To accommodate services // publishing SRV records under non-standard names, if both service // and proto are empty strings, LookupSRV looks up name directly. +// +// The returned service names are validated to be properly +// formatted presentation-format domain names. func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { - return DefaultResolver.lookupSRV(context.Background(), service, proto, name) + return DefaultResolver.LookupSRV(context.Background(), service, proto, name) } // LookupSRV tries to resolve an SRV query of the given service, @@ -429,28 +445,82 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err // That is, it looks up _service._proto.name. To accommodate services // publishing SRV records under non-standard names, if both service // and proto are empty strings, LookupSRV looks up name directly. -func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*SRV, err error) { - return r.lookupSRV(ctx, service, proto, name) +// +// The returned service names are validated to be properly +// formatted presentation-format domain names. +func (r *Resolver) LookupSRV(ctx context.Context, service, proto, name string) (string, []*SRV, error) { + cname, addrs, err := r.lookupSRV(ctx, service, proto, name) + if err != nil { + return "", nil, err + } + if cname != "" && !isDomainName(cname) { + return "", nil, &DNSError{Err: "SRV header name is invalid", Name: name} + } + for _, addr := range addrs { + if addr == nil { + continue + } + if !isDomainName(addr.Target) { + return "", nil, &DNSError{Err: "SRV target is invalid", Name: name} + } + } + return cname, addrs, nil } // LookupMX returns the DNS MX records for the given domain name sorted by preference. +// +// The returned mail server names are validated to be properly +// formatted presentation-format domain names. func LookupMX(name string) ([]*MX, error) { - return DefaultResolver.lookupMX(context.Background(), name) + return DefaultResolver.LookupMX(context.Background(), name) } // LookupMX returns the DNS MX records for the given domain name sorted by preference. +// +// The returned mail server names are validated to be properly +// formatted presentation-format domain names. func (r *Resolver) LookupMX(ctx context.Context, name string) ([]*MX, error) { - return r.lookupMX(ctx, name) + records, err := r.lookupMX(ctx, name) + if err != nil { + return nil, err + } + for _, mx := range records { + if mx == nil { + continue + } + if !isDomainName(mx.Host) { + return nil, &DNSError{Err: "MX target is invalid", Name: name} + } + } + return records, nil } // LookupNS returns the DNS NS records for the given domain name. +// +// The returned name server names are validated to be properly +// formatted presentation-format domain names. func LookupNS(name string) ([]*NS, error) { - return DefaultResolver.lookupNS(context.Background(), name) + return DefaultResolver.LookupNS(context.Background(), name) } // LookupNS returns the DNS NS records for the given domain name. +// +// The returned name server names are validated to be properly +// formatted presentation-format domain names. func (r *Resolver) LookupNS(ctx context.Context, name string) ([]*NS, error) { - return r.lookupNS(ctx, name) + records, err := r.lookupNS(ctx, name) + if err != nil { + return nil, err + } + for _, ns := range records { + if ns == nil { + continue + } + if !isDomainName(ns.Host) { + return nil, &DNSError{Err: "NS target is invalid", Name: name} + } + } + return records, nil } // LookupTXT returns the DNS TXT records for the given domain name. @@ -466,14 +536,29 @@ func (r *Resolver) LookupTXT(ctx context.Context, name string) ([]string, error) // LookupAddr performs a reverse lookup for the given address, returning a list // of names mapping to that address. // +// The returned names are validated to be properly formatted presentation-format +// domain names. +// // When using the host C library resolver, at most one result will be // returned. To bypass the host resolver, use a custom Resolver. func LookupAddr(addr string) (names []string, err error) { - return DefaultResolver.lookupAddr(context.Background(), addr) + return DefaultResolver.LookupAddr(context.Background(), addr) } // LookupAddr performs a reverse lookup for the given address, returning a list // of names mapping to that address. -func (r *Resolver) LookupAddr(ctx context.Context, addr string) (names []string, err error) { - return r.lookupAddr(ctx, addr) +// +// The returned names are validated to be properly formatted presentation-format +// domain names. +func (r *Resolver) LookupAddr(ctx context.Context, addr string) ([]string, error) { + names, err := r.lookupAddr(ctx, addr) + if err != nil { + return nil, err + } + for _, name := range names { + if !isDomainName(name) { + return nil, &DNSError{Err: "PTR target is invalid", Name: addr} + } + } + return names, nil } |