mirror of https://github.com/status-im/consul.git
dns: fix memoryleak by upgrading outdated miekg/dns (#6748)
* Add updated github.com/miekg/dns to go modules
* Add updated github.com/miekg/dns to vendor
* Fix github.com/miekg/dns api breakage
* Decrease size when trimming UDP packets
Need more room for the header(?), if we don't decrease the size we get an
"overflow unpacking uint32" from the dns library
* Fix dns truncate tests with api changes
* Make windows build working again. Upgrade x/sys and x/crypto and vendor
This upgrade is needed because of API breakage in x/sys introduced
by the minimal x/sys dependency of miekg/dns
This API breakage has been fixed in commit
855e68c859
This commit is contained in:
parent
7d0f72c60a
commit
4f5d5020b8
|
@ -1019,7 +1019,7 @@ func trimUDPResponse(req, resp *dns.Msg, udpAnswerLimit int) (trimmed bool) {
|
|||
// uncompresses them.
|
||||
// Even when size is too big for one single record, try to send it anyway
|
||||
// (useful for 512 bytes messages)
|
||||
for len(resp.Answer) > 1 && resp.Len() > maxSize {
|
||||
for len(resp.Answer) > 1 && resp.Len() > maxSize-7 {
|
||||
// More than 100 bytes, find with a binary search
|
||||
if resp.Len()-maxSize > 100 {
|
||||
bestIndex := dnsBinaryTruncate(resp, maxSize, index, hasExtra)
|
||||
|
@ -1034,7 +1034,6 @@ func trimUDPResponse(req, resp *dns.Msg, udpAnswerLimit int) (trimmed bool) {
|
|||
// For 512 non-eDNS responses, while we compute size non-compressed,
|
||||
// we send result compressed
|
||||
resp.Compress = compress
|
||||
|
||||
return len(resp.Answer) < numAnswers
|
||||
}
|
||||
|
||||
|
@ -1735,7 +1734,7 @@ func (d *DNSServer) handleRecurse(resp dns.ResponseWriter, req *dns.Msg) {
|
|||
// If we still have recursors to forward the query to,
|
||||
// we move forward onto the next one else the loop ends
|
||||
continue
|
||||
} else if err == nil || err == dns.ErrTruncated {
|
||||
} else if err == nil || (r != nil && r.Truncated) {
|
||||
// Compress the response; we don't know if the incoming
|
||||
// response was compressed or not, so by not compressing
|
||||
// we might generate an invalid packet on the way out.
|
||||
|
|
|
@ -3267,7 +3267,7 @@ func TestDNS_Recurse_Truncation(t *testing.T) {
|
|||
|
||||
c := new(dns.Client)
|
||||
in, _, err := c.Exchange(m, a.DNSAddr())
|
||||
if err != dns.ErrTruncated {
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
if in.Truncated != true {
|
||||
|
@ -3952,10 +3952,17 @@ func TestDNS_TCP_and_UDP_Truncate(t *testing.T) {
|
|||
c.Net = protocol
|
||||
m.Compress = compress
|
||||
in, _, err := c.Exchange(m, a.DNSAddr())
|
||||
if err != nil && err != dns.ErrTruncated {
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// actually check if we need to have the truncate bit
|
||||
resbuf, err := in.Pack()
|
||||
if err != nil {
|
||||
t.Fatalf("Error while packing answer: %s", err)
|
||||
}
|
||||
if !in.Truncated && len(resbuf) > int(maxSz) {
|
||||
t.Fatalf("should have truncate bit %#v %#v", in, len(in.Answer))
|
||||
}
|
||||
// Check for the truncate bit
|
||||
buf, err := m.Pack()
|
||||
info := fmt.Sprintf("service %s question:=%s (%s) (%d total records) sz:= %d in %v",
|
||||
|
@ -4033,7 +4040,7 @@ func TestDNS_ServiceLookup_Truncate(t *testing.T) {
|
|||
|
||||
c := new(dns.Client)
|
||||
in, _, err := c.Exchange(m, a.DNSAddr())
|
||||
if err != nil && err != dns.ErrTruncated {
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
|
@ -4105,10 +4112,14 @@ func TestDNS_ServiceLookup_LargeResponses(t *testing.T) {
|
|||
|
||||
c := new(dns.Client)
|
||||
in, _, err := c.Exchange(m, a.DNSAddr())
|
||||
if err != nil && err != dns.ErrTruncated {
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
if !in.Truncated {
|
||||
t.Fatalf("should have truncate bit")
|
||||
}
|
||||
|
||||
// Make sure the response size is RFC 1035-compliant for UDP messages
|
||||
if in.Len() > 512 {
|
||||
t.Fatalf("Bad: %d", in.Len())
|
||||
|
|
8
go.mod
8
go.mod
|
@ -56,7 +56,7 @@ require (
|
|||
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d
|
||||
github.com/imdario/mergo v0.3.6
|
||||
github.com/kr/text v0.1.0
|
||||
github.com/miekg/dns v1.0.14
|
||||
github.com/miekg/dns v1.1.22
|
||||
github.com/mitchellh/cli v1.0.0
|
||||
github.com/mitchellh/copystructure v1.0.0
|
||||
github.com/mitchellh/go-testing-interface v1.0.0
|
||||
|
@ -73,10 +73,10 @@ require (
|
|||
github.com/spf13/pflag v1.0.3 // indirect
|
||||
github.com/stretchr/objx v0.1.1 // indirect
|
||||
github.com/stretchr/testify v1.3.0
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859
|
||||
golang.org/x/crypto v0.0.0-20191106202628-ed6320f186d4
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a
|
||||
golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4
|
||||
google.golang.org/grpc v1.23.0
|
||||
gopkg.in/square/go-jose.v2 v2.3.1
|
||||
|
|
15
go.sum
15
go.sum
|
@ -241,6 +241,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0j
|
|||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.0.14 h1:9jZdLNd/P4+SfEJ0TNyxYpsK8N4GtfylBLqtbYN1sbA=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.22 h1:Jm64b3bO9kP43ddLjL2EY3Io6bmy1qGb9Xxz6TqS6rc=
|
||||
github.com/miekg/dns v1.1.22/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||
github.com/mitchellh/cli v1.0.0 h1:iGBIsUe3+HZ/AD/Vd7DErOt5sU9fa8Uj7A2s1aggv1Y=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ=
|
||||
|
@ -349,6 +351,10 @@ golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnf
|
|||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392 h1:ACG4HJsFiNMf47Y4PeRoebLNy/2lXT9EtprMuTFWt1M=
|
||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
||||
golang.org/x/crypto v0.0.0-20191106202628-ed6320f186d4 h1:PDpCLFAH/YIX0QpHPf2eO7L4rC2OOirBrKtXTLLiNTY=
|
||||
golang.org/x/crypto v0.0.0-20191106202628-ed6320f186d4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
|
@ -368,6 +374,8 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c h1:uOCk1iQW6Vc18bnC13MfzScl+
|
|||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20170807180024-9a379c6b3e95/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
|
@ -392,6 +400,11 @@ golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5 h1:sM3evRHxE/1RuMe1FYAL3j7C7
|
|||
golang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd h1:3x5uuvBgE6oaXJjCOvpCC1IpgJogqQ+PqGGU3ZxAgII=
|
||||
golang.org/x/sys v0.0.0-20191105231009-c1f44814a5cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
|
@ -407,6 +420,8 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm
|
|||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.0.0-20180829000535-087779f1d2c9 h1:z1TeLUmxf9ws9KLICfmX+KGXTs+rjm+aGWzfsv7MZ9w=
|
||||
google.golang.org/api v0.0.0-20180829000535-087779f1d2c9/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0=
|
||||
google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs=
|
||||
|
|
|
@ -2,14 +2,12 @@ language: go
|
|||
sudo: false
|
||||
|
||||
go:
|
||||
- 1.10.x
|
||||
- 1.11.x
|
||||
- 1.12.x
|
||||
- tip
|
||||
|
||||
before_install:
|
||||
# don't use the miekg/dns when testing forks
|
||||
- mkdir -p $GOPATH/src/github.com/miekg
|
||||
- ln -s $TRAVIS_BUILD_DIR $GOPATH/src/github.com/miekg/ || true
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
|
||||
script:
|
||||
- go test -race -v -bench=. -coverprofile=coverage.txt -covermode=atomic ./...
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:6914c49eed986dfb8dffb33516fa129c49929d4d873f41e073c83c11c372b870"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = [
|
||||
"ed25519",
|
||||
"ed25519/internal/edwards25519",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "e3636079e1a4c1f337f212cc5cd2aca108f6c900"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:08e41d63f8dac84d83797368b56cf0b339e42d0224e5e56668963c28aec95685"
|
||||
name = "golang.org/x/net"
|
||||
packages = [
|
||||
"bpf",
|
||||
"context",
|
||||
"internal/iana",
|
||||
"internal/socket",
|
||||
"ipv4",
|
||||
"ipv6",
|
||||
]
|
||||
pruneopts = ""
|
||||
revision = "4dfa2610cdf3b287375bbba5b8f2a14d3b01d8de"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:b2ea75de0ccb2db2ac79356407f8a4cd8f798fe15d41b381c00abf3ae8e55ed1"
|
||||
name = "golang.org/x/sync"
|
||||
packages = ["errgroup"]
|
||||
pruneopts = ""
|
||||
revision = "1d60e4601c6fd243af51cc01ddf169918a5407ca"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:149a432fabebb8221a80f77731b1cd63597197ded4f14af606ebe3a0959004ec"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["unix"]
|
||||
pruneopts = ""
|
||||
revision = "e4b3c5e9061176387e7cea65e4dc5853801f3fb7"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
input-imports = [
|
||||
"golang.org/x/crypto/ed25519",
|
||||
"golang.org/x/net/ipv4",
|
||||
"golang.org/x/net/ipv6",
|
||||
"golang.org/x/sync/errgroup",
|
||||
"golang.org/x/sys/unix",
|
||||
]
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
|
@ -1,38 +0,0 @@
|
|||
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/crypto"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/net"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sync"
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
> Less is more.
|
||||
|
||||
Complete and usable DNS library. All widely used Resource Records are supported, including the
|
||||
DNSSEC types. It follows a lean and mean philosophy. If there is stuff you should know as a DNS
|
||||
programmer there isn't a convenience function for it. Server side and client side programming is
|
||||
supported, i.e. you can build servers and resolvers with it.
|
||||
Complete and usable DNS library. All Resource Records are supported, including the DNSSEC types.
|
||||
It follows a lean and mean philosophy. If there is stuff you should know as a DNS programmer there
|
||||
isn't a convenience function for it. Server side and client side programming is supported, i.e. you
|
||||
can build servers and resolvers with it.
|
||||
|
||||
We try to keep the "master" branch as sane as possible and at the bleeding edge of standards,
|
||||
avoiding breaking changes wherever reasonable. We support the last two versions of Go.
|
||||
|
@ -42,10 +42,9 @@ A not-so-up-to-date-list-that-may-be-actually-current:
|
|||
* https://github.com/tianon/rawdns
|
||||
* https://mesosphere.github.io/mesos-dns/
|
||||
* https://pulse.turbobytes.com/
|
||||
* https://play.google.com/store/apps/details?id=com.turbobytes.dig
|
||||
* https://github.com/fcambus/statzone
|
||||
* https://github.com/benschw/dns-clb-go
|
||||
* https://github.com/corny/dnscheck for http://public-dns.info/
|
||||
* https://github.com/corny/dnscheck for <http://public-dns.info/>
|
||||
* https://namesmith.io
|
||||
* https://github.com/miekg/unbound
|
||||
* https://github.com/miekg/exdns
|
||||
|
@ -56,7 +55,7 @@ A not-so-up-to-date-list-that-may-be-actually-current:
|
|||
* https://github.com/bamarni/dockness
|
||||
* https://github.com/fffaraz/microdns
|
||||
* http://kelda.io
|
||||
* https://github.com/ipdcode/hades (JD.COM)
|
||||
* https://github.com/ipdcode/hades <https://jd.com>
|
||||
* https://github.com/StackExchange/dnscontrol/
|
||||
* https://www.dnsperf.com/
|
||||
* https://dnssectest.net/
|
||||
|
@ -68,29 +67,30 @@ A not-so-up-to-date-list-that-may-be-actually-current:
|
|||
* https://github.com/rs/dnstrace
|
||||
* https://blitiri.com.ar/p/dnss ([github mirror](https://github.com/albertito/dnss))
|
||||
* https://github.com/semihalev/sdns
|
||||
* https://render.com
|
||||
* https://github.com/peterzen/goresolver
|
||||
* https://github.com/folbricht/routedns
|
||||
|
||||
Send pull request if you want to be listed here.
|
||||
|
||||
# Features
|
||||
|
||||
* UDP/TCP queries, IPv4 and IPv6;
|
||||
* RFC 1035 zone file parsing ($INCLUDE, $ORIGIN, $TTL and $GENERATE (for all record types) are supported;
|
||||
* Fast:
|
||||
* Reply speed around ~ 80K qps (faster hardware results in more qps);
|
||||
* Parsing RRs ~ 100K RR/s, that's 5M records in about 50 seconds;
|
||||
* Server side programming (mimicking the net/http package);
|
||||
* Client side programming;
|
||||
* DNSSEC: signing, validating and key generation for DSA, RSA, ECDSA and Ed25519;
|
||||
* EDNS0, NSID, Cookies;
|
||||
* AXFR/IXFR;
|
||||
* TSIG, SIG(0);
|
||||
* DNS over TLS: optional encrypted connection between client and server;
|
||||
* DNS name compression;
|
||||
* Depends only on the standard library.
|
||||
* UDP/TCP queries, IPv4 and IPv6
|
||||
* RFC 1035 zone file parsing ($INCLUDE, $ORIGIN, $TTL and $GENERATE (for all record types) are supported
|
||||
* Fast
|
||||
* Server side programming (mimicking the net/http package)
|
||||
* Client side programming
|
||||
* DNSSEC: signing, validating and key generation for DSA, RSA, ECDSA and Ed25519
|
||||
* EDNS0, NSID, Cookies
|
||||
* AXFR/IXFR
|
||||
* TSIG, SIG(0)
|
||||
* DNS over TLS (DoT): encrypted connection between client and server over TCP
|
||||
* DNS name compression
|
||||
|
||||
Have fun!
|
||||
|
||||
Miek Gieben - 2010-2012 - <miek@miek.nl>
|
||||
DNS Authors 2012-
|
||||
|
||||
# Building
|
||||
|
||||
|
@ -102,8 +102,8 @@ work:
|
|||
|
||||
## Examples
|
||||
|
||||
A short "how to use the API" is at the beginning of doc.go (this also will show
|
||||
when you call `godoc github.com/miekg/dns`).
|
||||
A short "how to use the API" is at the beginning of doc.go (this also will show when you call `godoc
|
||||
github.com/miekg/dns`).
|
||||
|
||||
Example programs can be found in the `github.com/miekg/exdns` repository.
|
||||
|
||||
|
@ -153,6 +153,7 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
|
|||
* 6844 - CAA record
|
||||
* 6891 - EDNS0 update
|
||||
* 6895 - DNS IANA considerations
|
||||
* 6944 - DNSSEC DNSKEY Algorithm Status
|
||||
* 6975 - Algorithm Understanding in DNSSEC
|
||||
* 7043 - EUI48/EUI64 records
|
||||
* 7314 - DNS (EDNS) EXPIRE Option
|
||||
|
@ -161,12 +162,13 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
|
|||
* 7553 - URI record
|
||||
* 7858 - DNS over TLS: Initiation and Performance Considerations
|
||||
* 7871 - EDNS0 Client Subnet
|
||||
* 7873 - Domain Name System (DNS) Cookies (draft-ietf-dnsop-cookies)
|
||||
* 7873 - Domain Name System (DNS) Cookies
|
||||
* 8080 - EdDSA for DNSSEC
|
||||
* 8499 - DNS Terminology
|
||||
|
||||
## Loosely based upon
|
||||
## Loosely Based Upon
|
||||
|
||||
* `ldns`
|
||||
* `NSD`
|
||||
* `Net::DNS`
|
||||
* `GRONG`
|
||||
* ldns - <https://nlnetlabs.nl/projects/ldns/about/>
|
||||
* NSD - <https://nlnetlabs.nl/projects/nsd/about/>
|
||||
* Net::DNS - <http://www.net-dns.org/>
|
||||
* GRONG - <https://github.com/bortzmeyer/grong>
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
package dns
|
||||
|
||||
// MsgAcceptFunc is used early in the server code to accept or reject a message with RcodeFormatError.
|
||||
// It returns a MsgAcceptAction to indicate what should happen with the message.
|
||||
type MsgAcceptFunc func(dh Header) MsgAcceptAction
|
||||
|
||||
// DefaultMsgAcceptFunc checks the request and will reject if:
|
||||
//
|
||||
// * isn't a request (don't respond in that case).
|
||||
// * opcode isn't OpcodeQuery or OpcodeNotify
|
||||
// * Zero bit isn't zero
|
||||
// * has more than 1 question in the question section
|
||||
// * has more than 1 RR in the Answer section
|
||||
// * has more than 0 RRs in the Authority section
|
||||
// * has more than 2 RRs in the Additional section
|
||||
var DefaultMsgAcceptFunc MsgAcceptFunc = defaultMsgAcceptFunc
|
||||
|
||||
// MsgAcceptAction represents the action to be taken.
|
||||
type MsgAcceptAction int
|
||||
|
||||
const (
|
||||
MsgAccept MsgAcceptAction = iota // Accept the message
|
||||
MsgReject // Reject the message with a RcodeFormatError
|
||||
MsgIgnore // Ignore the error and send nothing back.
|
||||
MsgRejectNotImplemented // Reject the message with a RcodeNotImplemented
|
||||
)
|
||||
|
||||
func defaultMsgAcceptFunc(dh Header) MsgAcceptAction {
|
||||
if isResponse := dh.Bits&_QR != 0; isResponse {
|
||||
return MsgIgnore
|
||||
}
|
||||
|
||||
// Don't allow dynamic updates, because then the sections can contain a whole bunch of RRs.
|
||||
opcode := int(dh.Bits>>11) & 0xF
|
||||
if opcode != OpcodeQuery && opcode != OpcodeNotify {
|
||||
return MsgRejectNotImplemented
|
||||
}
|
||||
|
||||
if dh.Qdcount != 1 {
|
||||
return MsgReject
|
||||
}
|
||||
// NOTIFY requests can have a SOA in the ANSWER section. See RFC 1996 Section 3.7 and 3.11.
|
||||
if dh.Ancount > 1 {
|
||||
return MsgReject
|
||||
}
|
||||
// IXFR request could have one SOA RR in the NS section. See RFC 1995, section 3.
|
||||
if dh.Nscount > 1 {
|
||||
return MsgReject
|
||||
}
|
||||
if dh.Arcount > 2 {
|
||||
return MsgReject
|
||||
}
|
||||
return MsgAccept
|
||||
}
|
|
@ -3,15 +3,12 @@ package dns
|
|||
// A client implementation.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
@ -19,8 +16,6 @@ import (
|
|||
const (
|
||||
dnsTimeout time.Duration = 2 * time.Second
|
||||
tcpIdleTimeout time.Duration = 8 * time.Second
|
||||
|
||||
dohMimeType = "application/dns-message"
|
||||
)
|
||||
|
||||
// A Conn represents a connection to a DNS server.
|
||||
|
@ -44,7 +39,6 @@ type Client struct {
|
|||
DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds, or net.Dialer.Timeout if expiring earlier - overridden by Timeout when that value is non-zero
|
||||
ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds - overridden by Timeout when that value is non-zero
|
||||
WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds - overridden by Timeout when that value is non-zero
|
||||
HTTPClient *http.Client // The http.Client to use for DNS-over-HTTPS
|
||||
TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2)
|
||||
SingleInflight bool // if true suppress multiple outstanding queries for the same Qname, Qtype and Qclass
|
||||
group singleflight
|
||||
|
@ -132,33 +126,18 @@ func (c *Client) Dial(address string) (conn *Conn, err error) {
|
|||
// attribute appropriately
|
||||
func (c *Client) Exchange(m *Msg, address string) (r *Msg, rtt time.Duration, err error) {
|
||||
if !c.SingleInflight {
|
||||
if c.Net == "https" {
|
||||
// TODO(tmthrgd): pipe timeouts into exchangeDOH
|
||||
return c.exchangeDOH(context.TODO(), m, address)
|
||||
}
|
||||
|
||||
return c.exchange(m, address)
|
||||
}
|
||||
|
||||
t := "nop"
|
||||
if t1, ok := TypeToString[m.Question[0].Qtype]; ok {
|
||||
t = t1
|
||||
}
|
||||
cl := "nop"
|
||||
if cl1, ok := ClassToString[m.Question[0].Qclass]; ok {
|
||||
cl = cl1
|
||||
}
|
||||
r, rtt, err, shared := c.group.Do(m.Question[0].Name+t+cl, func() (*Msg, time.Duration, error) {
|
||||
if c.Net == "https" {
|
||||
// TODO(tmthrgd): pipe timeouts into exchangeDOH
|
||||
return c.exchangeDOH(context.TODO(), m, address)
|
||||
}
|
||||
|
||||
q := m.Question[0]
|
||||
key := fmt.Sprintf("%s:%d:%d", q.Name, q.Qtype, q.Qclass)
|
||||
r, rtt, err, shared := c.group.Do(key, func() (*Msg, time.Duration, error) {
|
||||
return c.exchange(m, address)
|
||||
})
|
||||
if r != nil && shared {
|
||||
r = r.Copy()
|
||||
}
|
||||
|
||||
return r, rtt, err
|
||||
}
|
||||
|
||||
|
@ -199,67 +178,6 @@ func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err erro
|
|||
return r, rtt, err
|
||||
}
|
||||
|
||||
func (c *Client) exchangeDOH(ctx context.Context, m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
|
||||
p, err := m.Pack()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest(http.MethodPost, a, bytes.NewReader(p))
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", dohMimeType)
|
||||
req.Header.Set("Accept", dohMimeType)
|
||||
|
||||
hc := http.DefaultClient
|
||||
if c.HTTPClient != nil {
|
||||
hc = c.HTTPClient
|
||||
}
|
||||
|
||||
if ctx != context.Background() && ctx != context.TODO() {
|
||||
req = req.WithContext(ctx)
|
||||
}
|
||||
|
||||
t := time.Now()
|
||||
|
||||
resp, err := hc.Do(req)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
defer closeHTTPBody(resp.Body)
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, 0, fmt.Errorf("dns: server returned HTTP %d error: %q", resp.StatusCode, resp.Status)
|
||||
}
|
||||
|
||||
if ct := resp.Header.Get("Content-Type"); ct != dohMimeType {
|
||||
return nil, 0, fmt.Errorf("dns: unexpected Content-Type %q; expected %q", ct, dohMimeType)
|
||||
}
|
||||
|
||||
p, err = ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
rtt = time.Since(t)
|
||||
|
||||
r = new(Msg)
|
||||
if err := r.Unpack(p); err != nil {
|
||||
return r, 0, err
|
||||
}
|
||||
|
||||
// TODO: TSIG? Is it even supported over DoH?
|
||||
|
||||
return r, rtt, nil
|
||||
}
|
||||
|
||||
func closeHTTPBody(r io.ReadCloser) error {
|
||||
io.Copy(ioutil.Discard, io.LimitReader(r, 8<<20))
|
||||
return r.Close()
|
||||
}
|
||||
|
||||
// ReadMsg reads a message from the connection co.
|
||||
// If the received message contains a TSIG record the transaction signature
|
||||
// is verified. This method always tries to return the message, however if an
|
||||
|
@ -298,24 +216,21 @@ func (co *Conn) ReadMsgHeader(hdr *Header) ([]byte, error) {
|
|||
err error
|
||||
)
|
||||
|
||||
switch t := co.Conn.(type) {
|
||||
case *net.TCPConn, *tls.Conn:
|
||||
r := t.(io.Reader)
|
||||
|
||||
// First two bytes specify the length of the entire message.
|
||||
l, err := tcpMsgLen(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p = make([]byte, l)
|
||||
n, err = tcpRead(r, p)
|
||||
default:
|
||||
if _, ok := co.Conn.(net.PacketConn); ok {
|
||||
if co.UDPSize > MinMsgSize {
|
||||
p = make([]byte, co.UDPSize)
|
||||
} else {
|
||||
p = make([]byte, MinMsgSize)
|
||||
}
|
||||
n, err = co.Read(p)
|
||||
} else {
|
||||
var length uint16
|
||||
if err := binary.Read(co.Conn, binary.BigEndian, &length); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
p = make([]byte, length)
|
||||
n, err = io.ReadFull(co.Conn, p)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
@ -335,78 +250,26 @@ func (co *Conn) ReadMsgHeader(hdr *Header) ([]byte, error) {
|
|||
return p, err
|
||||
}
|
||||
|
||||
// tcpMsgLen is a helper func to read first two bytes of stream as uint16 packet length.
|
||||
func tcpMsgLen(t io.Reader) (int, error) {
|
||||
p := []byte{0, 0}
|
||||
n, err := t.Read(p)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// As seen with my local router/switch, returns 1 byte on the above read,
|
||||
// resulting a a ShortRead. Just write it out (instead of loop) and read the
|
||||
// other byte.
|
||||
if n == 1 {
|
||||
n1, err := t.Read(p[1:])
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
n += n1
|
||||
}
|
||||
|
||||
if n != 2 {
|
||||
return 0, ErrShortRead
|
||||
}
|
||||
l := binary.BigEndian.Uint16(p)
|
||||
if l == 0 {
|
||||
return 0, ErrShortRead
|
||||
}
|
||||
return int(l), nil
|
||||
}
|
||||
|
||||
// tcpRead calls TCPConn.Read enough times to fill allocated buffer.
|
||||
func tcpRead(t io.Reader, p []byte) (int, error) {
|
||||
n, err := t.Read(p)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
for n < len(p) {
|
||||
j, err := t.Read(p[n:])
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
n += j
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Read implements the net.Conn read method.
|
||||
func (co *Conn) Read(p []byte) (n int, err error) {
|
||||
if co.Conn == nil {
|
||||
return 0, ErrConnEmpty
|
||||
}
|
||||
if len(p) < 2 {
|
||||
|
||||
if _, ok := co.Conn.(net.PacketConn); ok {
|
||||
// UDP connection
|
||||
return co.Conn.Read(p)
|
||||
}
|
||||
|
||||
var length uint16
|
||||
if err := binary.Read(co.Conn, binary.BigEndian, &length); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if int(length) > len(p) {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
switch t := co.Conn.(type) {
|
||||
case *net.TCPConn, *tls.Conn:
|
||||
r := t.(io.Reader)
|
||||
|
||||
l, err := tcpMsgLen(r)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if l > len(p) {
|
||||
return int(l), io.ErrShortBuffer
|
||||
}
|
||||
return tcpRead(r, p[:l])
|
||||
}
|
||||
// UDP connection
|
||||
n, err = co.Conn.Read(p)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
return n, err
|
||||
return io.ReadFull(co.Conn, p[:length])
|
||||
}
|
||||
|
||||
// WriteMsg sends a message through the connection co.
|
||||
|
@ -428,33 +291,25 @@ func (co *Conn) WriteMsg(m *Msg) (err error) {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = co.Write(out); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
_, err = co.Write(out)
|
||||
return err
|
||||
}
|
||||
|
||||
// Write implements the net.Conn Write method.
|
||||
func (co *Conn) Write(p []byte) (n int, err error) {
|
||||
switch t := co.Conn.(type) {
|
||||
case *net.TCPConn, *tls.Conn:
|
||||
w := t.(io.Writer)
|
||||
|
||||
lp := len(p)
|
||||
if lp < 2 {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
if lp > MaxMsgSize {
|
||||
return 0, &Error{err: "message too large"}
|
||||
}
|
||||
l := make([]byte, 2, lp+2)
|
||||
binary.BigEndian.PutUint16(l, uint16(lp))
|
||||
p = append(l, p...)
|
||||
n, err := io.Copy(w, bytes.NewReader(p))
|
||||
return int(n), err
|
||||
func (co *Conn) Write(p []byte) (int, error) {
|
||||
if len(p) > MaxMsgSize {
|
||||
return 0, &Error{err: "message too large"}
|
||||
}
|
||||
n, err = co.Conn.Write(p)
|
||||
return n, err
|
||||
|
||||
if _, ok := co.Conn.(net.PacketConn); ok {
|
||||
return co.Conn.Write(p)
|
||||
}
|
||||
|
||||
l := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(l, uint16(len(p)))
|
||||
|
||||
n, err := (&net.Buffers{l, p}).WriteTo(co.Conn)
|
||||
return int(n), err
|
||||
}
|
||||
|
||||
// Return the appropriate timeout for a specific request
|
||||
|
@ -497,7 +352,7 @@ func ExchangeContext(ctx context.Context, m *Msg, a string) (r *Msg, err error)
|
|||
|
||||
// ExchangeConn performs a synchronous query. It sends the message m via the connection
|
||||
// c and waits for a reply. The connection c is not closed by ExchangeConn.
|
||||
// This function is going away, but can easily be mimicked:
|
||||
// Deprecated: This function is going away, but can easily be mimicked:
|
||||
//
|
||||
// co := &dns.Conn{Conn: c} // c is your net.Conn
|
||||
// co.WriteMsg(m)
|
||||
|
@ -521,11 +376,7 @@ func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) {
|
|||
// DialTimeout acts like Dial but takes a timeout.
|
||||
func DialTimeout(network, address string, timeout time.Duration) (conn *Conn, err error) {
|
||||
client := Client{Net: network, Dialer: &net.Dialer{Timeout: timeout}}
|
||||
conn, err = client.Dial(address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
return client.Dial(address)
|
||||
}
|
||||
|
||||
// DialWithTLS connects to the address on the named network with TLS.
|
||||
|
@ -534,12 +385,7 @@ func DialWithTLS(network, address string, tlsConfig *tls.Config) (conn *Conn, er
|
|||
network += "-tls"
|
||||
}
|
||||
client := Client{Net: network, TLSConfig: tlsConfig}
|
||||
conn, err = client.Dial(address)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
return client.Dial(address)
|
||||
}
|
||||
|
||||
// DialTimeoutWithTLS acts like DialWithTLS but takes a timeout.
|
||||
|
@ -548,21 +394,13 @@ func DialTimeoutWithTLS(network, address string, tlsConfig *tls.Config, timeout
|
|||
network += "-tls"
|
||||
}
|
||||
client := Client{Net: network, Dialer: &net.Dialer{Timeout: timeout}, TLSConfig: tlsConfig}
|
||||
conn, err = client.Dial(address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
return client.Dial(address)
|
||||
}
|
||||
|
||||
// ExchangeContext acts like Exchange, but honors the deadline on the provided
|
||||
// context, if present. If there is both a context deadline and a configured
|
||||
// timeout on the client, the earliest of the two takes effect.
|
||||
func (c *Client) ExchangeContext(ctx context.Context, m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
|
||||
if !c.SingleInflight && c.Net == "https" {
|
||||
return c.exchangeDOH(ctx, m, a)
|
||||
}
|
||||
|
||||
var timeout time.Duration
|
||||
if deadline, ok := ctx.Deadline(); !ok {
|
||||
timeout = 0
|
||||
|
@ -571,7 +409,7 @@ func (c *Client) ExchangeContext(ctx context.Context, m *Msg, a string) (r *Msg,
|
|||
}
|
||||
// not passing the context to the underlying calls, as the API does not support
|
||||
// context. For timeouts you should set up Client.Dialer and call Client.Exchange.
|
||||
// TODO(tmthrgd): this is a race condition
|
||||
// TODO(tmthrgd,miekg): this is a race condition.
|
||||
c.Dialer = &net.Dialer{Timeout: timeout}
|
||||
return c.Exchange(m, a)
|
||||
}
|
||||
|
|
|
@ -68,14 +68,10 @@ func ClientConfigFromReader(resolvconf io.Reader) (*ClientConfig, error) {
|
|||
}
|
||||
|
||||
case "search": // set search path to given servers
|
||||
c.Search = make([]string, len(f)-1)
|
||||
for i := 0; i < len(c.Search); i++ {
|
||||
c.Search[i] = f[i+1]
|
||||
}
|
||||
c.Search = append([]string(nil), f[1:]...)
|
||||
|
||||
case "options": // magic options
|
||||
for i := 1; i < len(f); i++ {
|
||||
s := f[i]
|
||||
for _, s := range f[1:] {
|
||||
switch {
|
||||
case len(s) >= 6 && s[:6] == "ndots:":
|
||||
n, _ := strconv.Atoi(s[6:])
|
||||
|
|
|
@ -1,198 +0,0 @@
|
|||
//+build ignore
|
||||
|
||||
// compression_generate.go is meant to run with go generate. It will use
|
||||
// go/{importer,types} to track down all the RR struct types. Then for each type
|
||||
// it will look to see if there are (compressible) names, if so it will add that
|
||||
// type to compressionLenHelperType and comressionLenSearchType which "fake" the
|
||||
// compression so that Len() is fast.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"go/importer"
|
||||
"go/types"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
var packageHdr = `
|
||||
// Code generated by "go run compress_generate.go"; DO NOT EDIT.
|
||||
|
||||
package dns
|
||||
|
||||
`
|
||||
|
||||
// getTypeStruct will take a type and the package scope, and return the
|
||||
// (innermost) struct if the type is considered a RR type (currently defined as
|
||||
// those structs beginning with a RR_Header, could be redefined as implementing
|
||||
// the RR interface). The bool return value indicates if embedded structs were
|
||||
// resolved.
|
||||
func getTypeStruct(t types.Type, scope *types.Scope) (*types.Struct, bool) {
|
||||
st, ok := t.Underlying().(*types.Struct)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
if st.Field(0).Type() == scope.Lookup("RR_Header").Type() {
|
||||
return st, false
|
||||
}
|
||||
if st.Field(0).Anonymous() {
|
||||
st, _ := getTypeStruct(st.Field(0).Type(), scope)
|
||||
return st, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Import and type-check the package
|
||||
pkg, err := importer.Default().Import("github.com/miekg/dns")
|
||||
fatalIfErr(err)
|
||||
scope := pkg.Scope()
|
||||
|
||||
var domainTypes []string // Types that have a domain name in them (either compressible or not).
|
||||
var cdomainTypes []string // Types that have a compressible domain name in them (subset of domainType)
|
||||
Names:
|
||||
for _, name := range scope.Names() {
|
||||
o := scope.Lookup(name)
|
||||
if o == nil || !o.Exported() {
|
||||
continue
|
||||
}
|
||||
st, _ := getTypeStruct(o.Type(), scope)
|
||||
if st == nil {
|
||||
continue
|
||||
}
|
||||
if name == "PrivateRR" {
|
||||
continue
|
||||
}
|
||||
|
||||
if scope.Lookup("Type"+o.Name()) == nil && o.Name() != "RFC3597" {
|
||||
log.Fatalf("Constant Type%s does not exist.", o.Name())
|
||||
}
|
||||
|
||||
for i := 1; i < st.NumFields(); i++ {
|
||||
if _, ok := st.Field(i).Type().(*types.Slice); ok {
|
||||
if st.Tag(i) == `dns:"domain-name"` {
|
||||
domainTypes = append(domainTypes, o.Name())
|
||||
continue Names
|
||||
}
|
||||
if st.Tag(i) == `dns:"cdomain-name"` {
|
||||
cdomainTypes = append(cdomainTypes, o.Name())
|
||||
domainTypes = append(domainTypes, o.Name())
|
||||
continue Names
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
switch {
|
||||
case st.Tag(i) == `dns:"domain-name"`:
|
||||
domainTypes = append(domainTypes, o.Name())
|
||||
continue Names
|
||||
case st.Tag(i) == `dns:"cdomain-name"`:
|
||||
cdomainTypes = append(cdomainTypes, o.Name())
|
||||
domainTypes = append(domainTypes, o.Name())
|
||||
continue Names
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
b.WriteString(packageHdr)
|
||||
|
||||
// compressionLenHelperType - all types that have domain-name/cdomain-name can be used for compressing names
|
||||
|
||||
fmt.Fprint(b, "func compressionLenHelperType(c map[string]int, r RR, initLen int) int {\n")
|
||||
fmt.Fprint(b, "currentLen := initLen\n")
|
||||
fmt.Fprint(b, "switch x := r.(type) {\n")
|
||||
for _, name := range domainTypes {
|
||||
o := scope.Lookup(name)
|
||||
st, _ := getTypeStruct(o.Type(), scope)
|
||||
|
||||
fmt.Fprintf(b, "case *%s:\n", name)
|
||||
for i := 1; i < st.NumFields(); i++ {
|
||||
out := func(s string) {
|
||||
fmt.Fprintf(b, "currentLen -= len(x.%s) + 1\n", st.Field(i).Name())
|
||||
fmt.Fprintf(b, "currentLen += compressionLenHelper(c, x.%s, currentLen)\n", st.Field(i).Name())
|
||||
}
|
||||
|
||||
if _, ok := st.Field(i).Type().(*types.Slice); ok {
|
||||
switch st.Tag(i) {
|
||||
case `dns:"domain-name"`:
|
||||
fallthrough
|
||||
case `dns:"cdomain-name"`:
|
||||
// For HIP we need to slice over the elements in this slice.
|
||||
fmt.Fprintf(b, `for i := range x.%s {
|
||||
currentLen -= len(x.%s[i]) + 1
|
||||
}
|
||||
`, st.Field(i).Name(), st.Field(i).Name())
|
||||
fmt.Fprintf(b, `for i := range x.%s {
|
||||
currentLen += compressionLenHelper(c, x.%s[i], currentLen)
|
||||
}
|
||||
`, st.Field(i).Name(), st.Field(i).Name())
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
switch {
|
||||
case st.Tag(i) == `dns:"cdomain-name"`:
|
||||
fallthrough
|
||||
case st.Tag(i) == `dns:"domain-name"`:
|
||||
out(st.Field(i).Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Fprintln(b, "}\nreturn currentLen - initLen\n}\n\n")
|
||||
|
||||
// compressionLenSearchType - search cdomain-tags types for compressible names.
|
||||
|
||||
fmt.Fprint(b, "func compressionLenSearchType(c map[string]int, r RR) (int, bool, int) {\n")
|
||||
fmt.Fprint(b, "switch x := r.(type) {\n")
|
||||
for _, name := range cdomainTypes {
|
||||
o := scope.Lookup(name)
|
||||
st, _ := getTypeStruct(o.Type(), scope)
|
||||
|
||||
fmt.Fprintf(b, "case *%s:\n", name)
|
||||
j := 1
|
||||
for i := 1; i < st.NumFields(); i++ {
|
||||
out := func(s string, j int) {
|
||||
fmt.Fprintf(b, "k%d, ok%d, sz%d := compressionLenSearch(c, x.%s)\n", j, j, j, st.Field(i).Name())
|
||||
}
|
||||
|
||||
// There are no slice types with names that can be compressed.
|
||||
|
||||
switch {
|
||||
case st.Tag(i) == `dns:"cdomain-name"`:
|
||||
out(st.Field(i).Name(), j)
|
||||
j++
|
||||
}
|
||||
}
|
||||
k := "k1"
|
||||
ok := "ok1"
|
||||
sz := "sz1"
|
||||
for i := 2; i < j; i++ {
|
||||
k += fmt.Sprintf(" + k%d", i)
|
||||
ok += fmt.Sprintf(" && ok%d", i)
|
||||
sz += fmt.Sprintf(" + sz%d", i)
|
||||
}
|
||||
fmt.Fprintf(b, "return %s, %s, %s\n", k, ok, sz)
|
||||
}
|
||||
fmt.Fprintln(b, "}\nreturn 0, false, 0\n}\n\n")
|
||||
|
||||
// gofmt
|
||||
res, err := format.Source(b.Bytes())
|
||||
if err != nil {
|
||||
b.WriteTo(os.Stderr)
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
f, err := os.Create("zcompress.go")
|
||||
fatalIfErr(err)
|
||||
defer f.Close()
|
||||
f.Write(res)
|
||||
}
|
||||
|
||||
func fatalIfErr(err error) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ import (
|
|||
"errors"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const hexDigit = "0123456789abcdef"
|
||||
|
@ -145,10 +146,9 @@ func (dns *Msg) IsTsig() *TSIG {
|
|||
// record in the additional section will do. It returns the OPT record
|
||||
// found or nil.
|
||||
func (dns *Msg) IsEdns0() *OPT {
|
||||
// EDNS0 is at the end of the additional section, start there.
|
||||
// We might want to change this to *only* look at the last two
|
||||
// records. So we see TSIG and/or OPT - this a slightly bigger
|
||||
// change though.
|
||||
// RFC 6891, Section 6.1.1 allows the OPT record to appear
|
||||
// anywhere in the additional record section, but it's usually at
|
||||
// the end so start there.
|
||||
for i := len(dns.Extra) - 1; i >= 0; i-- {
|
||||
if dns.Extra[i].Header().Rrtype == TypeOPT {
|
||||
return dns.Extra[i].(*OPT)
|
||||
|
@ -157,17 +157,93 @@ func (dns *Msg) IsEdns0() *OPT {
|
|||
return nil
|
||||
}
|
||||
|
||||
// popEdns0 is like IsEdns0, but it removes the record from the message.
|
||||
func (dns *Msg) popEdns0() *OPT {
|
||||
// RFC 6891, Section 6.1.1 allows the OPT record to appear
|
||||
// anywhere in the additional record section, but it's usually at
|
||||
// the end so start there.
|
||||
for i := len(dns.Extra) - 1; i >= 0; i-- {
|
||||
if dns.Extra[i].Header().Rrtype == TypeOPT {
|
||||
opt := dns.Extra[i].(*OPT)
|
||||
dns.Extra = append(dns.Extra[:i], dns.Extra[i+1:]...)
|
||||
return opt
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsDomainName checks if s is a valid domain name, it returns the number of
|
||||
// labels and true, when a domain name is valid. Note that non fully qualified
|
||||
// domain name is considered valid, in this case the last label is counted in
|
||||
// the number of labels. When false is returned the number of labels is not
|
||||
// defined. Also note that this function is extremely liberal; almost any
|
||||
// string is a valid domain name as the DNS is 8 bit protocol. It checks if each
|
||||
// label fits in 63 characters, but there is no length check for the entire
|
||||
// string s. I.e. a domain name longer than 255 characters is considered valid.
|
||||
// label fits in 63 characters and that the entire name will fit into the 255
|
||||
// octet wire format limit.
|
||||
func IsDomainName(s string) (labels int, ok bool) {
|
||||
_, labels, err := packDomainName(s, nil, 0, nil, false)
|
||||
return labels, err == nil
|
||||
// XXX: The logic in this function was copied from packDomainName and
|
||||
// should be kept in sync with that function.
|
||||
|
||||
const lenmsg = 256
|
||||
|
||||
if len(s) == 0 { // Ok, for instance when dealing with update RR without any rdata.
|
||||
return 0, false
|
||||
}
|
||||
|
||||
s = Fqdn(s)
|
||||
|
||||
// Each dot ends a segment of the name. Except for escaped dots (\.), which
|
||||
// are normal dots.
|
||||
|
||||
var (
|
||||
off int
|
||||
begin int
|
||||
wasDot bool
|
||||
)
|
||||
for i := 0; i < len(s); i++ {
|
||||
switch s[i] {
|
||||
case '\\':
|
||||
if off+1 > lenmsg {
|
||||
return labels, false
|
||||
}
|
||||
|
||||
// check for \DDD
|
||||
if i+3 < len(s) && isDigit(s[i+1]) && isDigit(s[i+2]) && isDigit(s[i+3]) {
|
||||
i += 3
|
||||
begin += 3
|
||||
} else {
|
||||
i++
|
||||
begin++
|
||||
}
|
||||
|
||||
wasDot = false
|
||||
case '.':
|
||||
if wasDot {
|
||||
// two dots back to back is not legal
|
||||
return labels, false
|
||||
}
|
||||
wasDot = true
|
||||
|
||||
labelLen := i - begin
|
||||
if labelLen >= 1<<6 { // top two bits of length must be clear
|
||||
return labels, false
|
||||
}
|
||||
|
||||
// off can already (we're in a loop) be bigger than lenmsg
|
||||
// this happens when a name isn't fully qualified
|
||||
off += 1 + labelLen
|
||||
if off > lenmsg {
|
||||
return labels, false
|
||||
}
|
||||
|
||||
labels++
|
||||
begin = i + 1
|
||||
default:
|
||||
wasDot = false
|
||||
}
|
||||
}
|
||||
|
||||
return labels, true
|
||||
}
|
||||
|
||||
// IsSubDomain checks if child is indeed a child of the parent. If child and parent
|
||||
|
@ -181,7 +257,7 @@ func IsSubDomain(parent, child string) bool {
|
|||
// The checking is performed on the binary payload.
|
||||
func IsMsg(buf []byte) error {
|
||||
// Header
|
||||
if len(buf) < 12 {
|
||||
if len(buf) < headerSize {
|
||||
return errors.New("dns: bad message header")
|
||||
}
|
||||
// Header: Opcode
|
||||
|
@ -191,11 +267,18 @@ func IsMsg(buf []byte) error {
|
|||
|
||||
// IsFqdn checks if a domain name is fully qualified.
|
||||
func IsFqdn(s string) bool {
|
||||
l := len(s)
|
||||
if l == 0 {
|
||||
s2 := strings.TrimSuffix(s, ".")
|
||||
if s == s2 {
|
||||
return false
|
||||
}
|
||||
return s[l-1] == '.'
|
||||
|
||||
i := strings.LastIndexFunc(s2, func(r rune) bool {
|
||||
return r != '\\'
|
||||
})
|
||||
|
||||
// Test whether we have an even number of escape sequences before
|
||||
// the dot or none.
|
||||
return (len(s2)-i)%2 != 0
|
||||
}
|
||||
|
||||
// IsRRset checks if a set of RRs is a valid RRset as defined by RFC 2181.
|
||||
|
@ -244,12 +327,19 @@ func ReverseAddr(addr string) (arpa string, err error) {
|
|||
if ip == nil {
|
||||
return "", &Error{err: "unrecognized address: " + addr}
|
||||
}
|
||||
if ip.To4() != nil {
|
||||
return strconv.Itoa(int(ip[15])) + "." + strconv.Itoa(int(ip[14])) + "." + strconv.Itoa(int(ip[13])) + "." +
|
||||
strconv.Itoa(int(ip[12])) + ".in-addr.arpa.", nil
|
||||
if v4 := ip.To4(); v4 != nil {
|
||||
buf := make([]byte, 0, net.IPv4len*4+len("in-addr.arpa."))
|
||||
// Add it, in reverse, to the buffer
|
||||
for i := len(v4) - 1; i >= 0; i-- {
|
||||
buf = strconv.AppendInt(buf, int64(v4[i]), 10)
|
||||
buf = append(buf, '.')
|
||||
}
|
||||
// Append "in-addr.arpa." and return (buf already has the final .)
|
||||
buf = append(buf, "in-addr.arpa."...)
|
||||
return string(buf), nil
|
||||
}
|
||||
// Must be IPv6
|
||||
buf := make([]byte, 0, len(ip)*4+len("ip6.arpa."))
|
||||
buf := make([]byte, 0, net.IPv6len*4+len("ip6.arpa."))
|
||||
// Add it, in reverse, to the buffer
|
||||
for i := len(ip) - 1; i >= 0; i-- {
|
||||
v := ip[i]
|
||||
|
|
|
@ -34,10 +34,30 @@ type RR interface {
|
|||
|
||||
// copy returns a copy of the RR
|
||||
copy() RR
|
||||
// len returns the length (in octets) of the uncompressed RR in wire format.
|
||||
len() int
|
||||
// pack packs an RR into wire format.
|
||||
pack([]byte, int, map[string]int, bool) (int, error)
|
||||
|
||||
// len returns the length (in octets) of the compressed or uncompressed RR in wire format.
|
||||
//
|
||||
// If compression is nil, the uncompressed size will be returned, otherwise the compressed
|
||||
// size will be returned and domain names will be added to the map for future compression.
|
||||
len(off int, compression map[string]struct{}) int
|
||||
|
||||
// pack packs the records RDATA into wire format. The header will
|
||||
// already have been packed into msg.
|
||||
pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error)
|
||||
|
||||
// unpack unpacks an RR from wire format.
|
||||
//
|
||||
// This will only be called on a new and empty RR type with only the header populated. It
|
||||
// will only be called if the record's RDATA is non-empty.
|
||||
unpack(msg []byte, off int) (off1 int, err error)
|
||||
|
||||
// parse parses an RR from zone file format.
|
||||
//
|
||||
// This will only be called on a new and empty RR type with only the header populated.
|
||||
parse(c *zlexer, origin string) *ParseError
|
||||
|
||||
// isDuplicate returns whether the two RRs are duplicates.
|
||||
isDuplicate(r2 RR) bool
|
||||
}
|
||||
|
||||
// RR_Header is the header all DNS resource records share.
|
||||
|
@ -70,28 +90,45 @@ func (h *RR_Header) String() string {
|
|||
return s
|
||||
}
|
||||
|
||||
func (h *RR_Header) len() int {
|
||||
l := len(h.Name) + 1
|
||||
func (h *RR_Header) len(off int, compression map[string]struct{}) int {
|
||||
l := domainNameLen(h.Name, off, compression, true)
|
||||
l += 10 // rrtype(2) + class(2) + ttl(4) + rdlength(2)
|
||||
return l
|
||||
}
|
||||
|
||||
func (h *RR_Header) pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) {
|
||||
// RR_Header has no RDATA to pack.
|
||||
return off, nil
|
||||
}
|
||||
|
||||
func (h *RR_Header) unpack(msg []byte, off int) (int, error) {
|
||||
panic("dns: internal error: unpack should never be called on RR_Header")
|
||||
}
|
||||
|
||||
func (h *RR_Header) parse(c *zlexer, origin string) *ParseError {
|
||||
panic("dns: internal error: parse should never be called on RR_Header")
|
||||
}
|
||||
|
||||
// ToRFC3597 converts a known RR to the unknown RR representation from RFC 3597.
|
||||
func (rr *RFC3597) ToRFC3597(r RR) error {
|
||||
buf := make([]byte, r.len()*2)
|
||||
off, err := PackRR(r, buf, 0, nil, false)
|
||||
buf := make([]byte, Len(r)*2)
|
||||
headerEnd, off, err := packRR(r, buf, 0, compressionMap{}, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf = buf[:off]
|
||||
if int(r.Header().Rdlength) > off {
|
||||
return ErrBuf
|
||||
|
||||
*rr = RFC3597{Hdr: *r.Header()}
|
||||
rr.Hdr.Rdlength = uint16(off - headerEnd)
|
||||
|
||||
if noRdata(rr.Hdr) {
|
||||
return nil
|
||||
}
|
||||
|
||||
rfc3597, _, err := unpackRFC3597(*r.Header(), buf, off-int(r.Header().Rdlength))
|
||||
_, err = rr.unpack(buf, headerEnd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*rr = *rfc3597.(*RFC3597)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -67,9 +67,6 @@ var AlgorithmToString = map[uint8]string{
|
|||
PRIVATEOID: "PRIVATEOID",
|
||||
}
|
||||
|
||||
// StringToAlgorithm is the reverse of AlgorithmToString.
|
||||
var StringToAlgorithm = reverseInt8(AlgorithmToString)
|
||||
|
||||
// AlgorithmToHash is a map of algorithm crypto hash IDs to crypto.Hash's.
|
||||
var AlgorithmToHash = map[uint8]crypto.Hash{
|
||||
RSAMD5: crypto.MD5, // Deprecated in RFC 6725
|
||||
|
@ -102,9 +99,6 @@ var HashToString = map[uint8]string{
|
|||
SHA512: "SHA512",
|
||||
}
|
||||
|
||||
// StringToHash is a map of names to hash IDs.
|
||||
var StringToHash = reverseInt8(HashToString)
|
||||
|
||||
// DNSKEY flag values.
|
||||
const (
|
||||
SEP = 1
|
||||
|
@ -147,8 +141,8 @@ func (k *DNSKEY) KeyTag() uint16 {
|
|||
switch k.Algorithm {
|
||||
case RSAMD5:
|
||||
// Look at the bottom two bytes of the modules, which the last
|
||||
// item in the pubkey. We could do this faster by looking directly
|
||||
// at the base64 values. But I'm lazy.
|
||||
// item in the pubkey.
|
||||
// This algorithm has been deprecated, but keep this key-tag calculation.
|
||||
modulus, _ := fromBase64([]byte(k.PublicKey))
|
||||
if len(modulus) > 1 {
|
||||
x := binary.BigEndian.Uint16(modulus[len(modulus)-2:])
|
||||
|
@ -268,16 +262,17 @@ func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error {
|
|||
return ErrKey
|
||||
}
|
||||
|
||||
h0 := rrset[0].Header()
|
||||
rr.Hdr.Rrtype = TypeRRSIG
|
||||
rr.Hdr.Name = rrset[0].Header().Name
|
||||
rr.Hdr.Class = rrset[0].Header().Class
|
||||
rr.Hdr.Name = h0.Name
|
||||
rr.Hdr.Class = h0.Class
|
||||
if rr.OrigTtl == 0 { // If set don't override
|
||||
rr.OrigTtl = rrset[0].Header().Ttl
|
||||
rr.OrigTtl = h0.Ttl
|
||||
}
|
||||
rr.TypeCovered = rrset[0].Header().Rrtype
|
||||
rr.Labels = uint8(CountLabel(rrset[0].Header().Name))
|
||||
rr.TypeCovered = h0.Rrtype
|
||||
rr.Labels = uint8(CountLabel(h0.Name))
|
||||
|
||||
if strings.HasPrefix(rrset[0].Header().Name, "*") {
|
||||
if strings.HasPrefix(h0.Name, "*") {
|
||||
rr.Labels-- // wildcard, remove from label count
|
||||
}
|
||||
|
||||
|
@ -323,6 +318,9 @@ func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error {
|
|||
}
|
||||
|
||||
rr.Signature = toBase64(signature)
|
||||
case RSAMD5, DSA, DSANSEC3SHA1:
|
||||
// See RFC 6944.
|
||||
return ErrAlg
|
||||
default:
|
||||
h := hash.New()
|
||||
h.Write(signdata)
|
||||
|
@ -401,7 +399,7 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
|
|||
if rr.Algorithm != k.Algorithm {
|
||||
return ErrKey
|
||||
}
|
||||
if strings.ToLower(rr.SignerName) != strings.ToLower(k.Hdr.Name) {
|
||||
if !strings.EqualFold(rr.SignerName, k.Hdr.Name) {
|
||||
return ErrKey
|
||||
}
|
||||
if k.Protocol != 3 {
|
||||
|
@ -411,10 +409,7 @@ func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
|
|||
// IsRRset checked that we have at least one RR and that the RRs in
|
||||
// the set have consistent type, class, and name. Also check that type and
|
||||
// class matches the RRSIG record.
|
||||
if rrset[0].Header().Class != rr.Hdr.Class {
|
||||
return ErrRRset
|
||||
}
|
||||
if rrset[0].Header().Rrtype != rr.TypeCovered {
|
||||
if h0 := rrset[0].Header(); h0.Class != rr.Hdr.Class || h0.Rrtype != rr.TypeCovered {
|
||||
return ErrRRset
|
||||
}
|
||||
|
||||
|
@ -563,20 +558,19 @@ func (k *DNSKEY) publicKeyRSA() *rsa.PublicKey {
|
|||
|
||||
pubkey := new(rsa.PublicKey)
|
||||
|
||||
expo := uint64(0)
|
||||
for i := 0; i < int(explen); i++ {
|
||||
var expo uint64
|
||||
// The exponent of length explen is between keyoff and modoff.
|
||||
for _, v := range keybuf[keyoff:modoff] {
|
||||
expo <<= 8
|
||||
expo |= uint64(keybuf[keyoff+i])
|
||||
expo |= uint64(v)
|
||||
}
|
||||
if expo > 1<<31-1 {
|
||||
// Larger exponent than supported by the crypto package.
|
||||
return nil
|
||||
}
|
||||
|
||||
pubkey.E = int(expo)
|
||||
|
||||
pubkey.N = big.NewInt(0)
|
||||
pubkey.N.SetBytes(keybuf[modoff:])
|
||||
|
||||
pubkey.N = new(big.Int).SetBytes(keybuf[modoff:])
|
||||
return pubkey
|
||||
}
|
||||
|
||||
|
@ -601,10 +595,8 @@ func (k *DNSKEY) publicKeyECDSA() *ecdsa.PublicKey {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
pubkey.X = big.NewInt(0)
|
||||
pubkey.X.SetBytes(keybuf[:len(keybuf)/2])
|
||||
pubkey.Y = big.NewInt(0)
|
||||
pubkey.Y.SetBytes(keybuf[len(keybuf)/2:])
|
||||
pubkey.X = new(big.Int).SetBytes(keybuf[:len(keybuf)/2])
|
||||
pubkey.Y = new(big.Int).SetBytes(keybuf[len(keybuf)/2:])
|
||||
return pubkey
|
||||
}
|
||||
|
||||
|
@ -625,10 +617,10 @@ func (k *DNSKEY) publicKeyDSA() *dsa.PublicKey {
|
|||
p, keybuf := keybuf[:size], keybuf[size:]
|
||||
g, y := keybuf[:size], keybuf[size:]
|
||||
pubkey := new(dsa.PublicKey)
|
||||
pubkey.Parameters.Q = big.NewInt(0).SetBytes(q)
|
||||
pubkey.Parameters.P = big.NewInt(0).SetBytes(p)
|
||||
pubkey.Parameters.G = big.NewInt(0).SetBytes(g)
|
||||
pubkey.Y = big.NewInt(0).SetBytes(y)
|
||||
pubkey.Parameters.Q = new(big.Int).SetBytes(q)
|
||||
pubkey.Parameters.P = new(big.Int).SetBytes(p)
|
||||
pubkey.Parameters.G = new(big.Int).SetBytes(g)
|
||||
pubkey.Y = new(big.Int).SetBytes(y)
|
||||
return pubkey
|
||||
}
|
||||
|
||||
|
@ -658,15 +650,16 @@ func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) {
|
|||
wires := make(wireSlice, len(rrset))
|
||||
for i, r := range rrset {
|
||||
r1 := r.copy()
|
||||
r1.Header().Ttl = s.OrigTtl
|
||||
labels := SplitDomainName(r1.Header().Name)
|
||||
h := r1.Header()
|
||||
h.Ttl = s.OrigTtl
|
||||
labels := SplitDomainName(h.Name)
|
||||
// 6.2. Canonical RR Form. (4) - wildcards
|
||||
if len(labels) > int(s.Labels) {
|
||||
// Wildcard
|
||||
r1.Header().Name = "*." + strings.Join(labels[len(labels)-int(s.Labels):], ".") + "."
|
||||
h.Name = "*." + strings.Join(labels[len(labels)-int(s.Labels):], ".") + "."
|
||||
}
|
||||
// RFC 4034: 6.2. Canonical RR Form. (2) - domain name to lowercase
|
||||
r1.Header().Name = strings.ToLower(r1.Header().Name)
|
||||
h.Name = strings.ToLower(h.Name)
|
||||
// 6.2. Canonical RR Form. (3) - domain rdata to lowercase.
|
||||
// NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
|
||||
// HINFO, MINFO, MX, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX,
|
||||
|
@ -724,7 +717,7 @@ func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) {
|
|||
x.Target = strings.ToLower(x.Target)
|
||||
}
|
||||
// 6.2. Canonical RR Form. (5) - origTTL
|
||||
wire := make([]byte, r1.len()+1) // +1 to be safe(r)
|
||||
wire := make([]byte, Len(r1)+1) // +1 to be safe(r)
|
||||
off, err1 := PackRR(r1, wire, 0, nil, false)
|
||||
if err1 != nil {
|
||||
return nil, err1
|
||||
|
|
|
@ -2,7 +2,6 @@ package dns
|
|||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/dsa"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
|
@ -20,11 +19,9 @@ import (
|
|||
// bits should be set to the size of the algorithm.
|
||||
func (k *DNSKEY) Generate(bits int) (crypto.PrivateKey, error) {
|
||||
switch k.Algorithm {
|
||||
case DSA, DSANSEC3SHA1:
|
||||
if bits != 1024 {
|
||||
return nil, ErrKeySize
|
||||
}
|
||||
case RSAMD5, RSASHA1, RSASHA256, RSASHA1NSEC3SHA1:
|
||||
case RSAMD5, DSA, DSANSEC3SHA1:
|
||||
return nil, ErrAlg
|
||||
case RSASHA1, RSASHA256, RSASHA1NSEC3SHA1:
|
||||
if bits < 512 || bits > 4096 {
|
||||
return nil, ErrKeySize
|
||||
}
|
||||
|
@ -47,20 +44,7 @@ func (k *DNSKEY) Generate(bits int) (crypto.PrivateKey, error) {
|
|||
}
|
||||
|
||||
switch k.Algorithm {
|
||||
case DSA, DSANSEC3SHA1:
|
||||
params := new(dsa.Parameters)
|
||||
if err := dsa.GenerateParameters(params, rand.Reader, dsa.L1024N160); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
priv := new(dsa.PrivateKey)
|
||||
priv.PublicKey.Parameters = *params
|
||||
err := dsa.GenerateKey(priv, rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
k.setPublicKeyDSA(params.Q, params.P, params.G, priv.PublicKey.Y)
|
||||
return priv, nil
|
||||
case RSAMD5, RSASHA1, RSASHA256, RSASHA512, RSASHA1NSEC3SHA1:
|
||||
case RSASHA1, RSASHA256, RSASHA512, RSASHA1NSEC3SHA1:
|
||||
priv, err := rsa.GenerateKey(rand.Reader, bits)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -120,16 +104,6 @@ func (k *DNSKEY) setPublicKeyECDSA(_X, _Y *big.Int) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// Set the public key for DSA
|
||||
func (k *DNSKEY) setPublicKeyDSA(_Q, _P, _G, _Y *big.Int) bool {
|
||||
if _Q == nil || _P == nil || _G == nil || _Y == nil {
|
||||
return false
|
||||
}
|
||||
buf := dsaToBuf(_Q, _P, _G, _Y)
|
||||
k.PublicKey = toBase64(buf)
|
||||
return true
|
||||
}
|
||||
|
||||
// Set the public key for Ed25519
|
||||
func (k *DNSKEY) setPublicKeyED25519(_K ed25519.PublicKey) bool {
|
||||
if _K == nil {
|
||||
|
@ -164,15 +138,3 @@ func curveToBuf(_X, _Y *big.Int, intlen int) []byte {
|
|||
buf = append(buf, intToBytes(_Y, intlen)...)
|
||||
return buf
|
||||
}
|
||||
|
||||
// Set the public key for X and Y for Curve. The two
|
||||
// values are just concatenated.
|
||||
func dsaToBuf(_Q, _P, _G, _Y *big.Int) []byte {
|
||||
t := divRoundUp(divRoundUp(_G.BitLen(), 8)-64, 8)
|
||||
buf := []byte{byte(t)}
|
||||
buf = append(buf, intToBytes(_Q, 20)...)
|
||||
buf = append(buf, intToBytes(_P, 64+t*8)...)
|
||||
buf = append(buf, intToBytes(_G, 64+t*8)...)
|
||||
buf = append(buf, intToBytes(_Y, 64+t*8)...)
|
||||
return buf
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package dns
|
|||
import (
|
||||
"bufio"
|
||||
"crypto"
|
||||
"crypto/dsa"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rsa"
|
||||
"io"
|
||||
|
@ -44,19 +43,8 @@ func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (crypto.PrivateKey, er
|
|||
return nil, ErrPrivKey
|
||||
}
|
||||
switch uint8(algo) {
|
||||
case DSA:
|
||||
priv, err := readPrivateKeyDSA(m)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pub := k.publicKeyDSA()
|
||||
if pub == nil {
|
||||
return nil, ErrKey
|
||||
}
|
||||
priv.PublicKey = *pub
|
||||
return priv, nil
|
||||
case RSAMD5:
|
||||
fallthrough
|
||||
case RSAMD5, DSA, DSANSEC3SHA1:
|
||||
return nil, ErrAlg
|
||||
case RSASHA1:
|
||||
fallthrough
|
||||
case RSASHA1NSEC3SHA1:
|
||||
|
@ -109,21 +97,16 @@ func readPrivateKeyRSA(m map[string]string) (*rsa.PrivateKey, error) {
|
|||
}
|
||||
switch k {
|
||||
case "modulus":
|
||||
p.PublicKey.N = big.NewInt(0)
|
||||
p.PublicKey.N.SetBytes(v1)
|
||||
p.PublicKey.N = new(big.Int).SetBytes(v1)
|
||||
case "publicexponent":
|
||||
i := big.NewInt(0)
|
||||
i.SetBytes(v1)
|
||||
i := new(big.Int).SetBytes(v1)
|
||||
p.PublicKey.E = int(i.Int64()) // int64 should be large enough
|
||||
case "privateexponent":
|
||||
p.D = big.NewInt(0)
|
||||
p.D.SetBytes(v1)
|
||||
p.D = new(big.Int).SetBytes(v1)
|
||||
case "prime1":
|
||||
p.Primes[0] = big.NewInt(0)
|
||||
p.Primes[0].SetBytes(v1)
|
||||
p.Primes[0] = new(big.Int).SetBytes(v1)
|
||||
case "prime2":
|
||||
p.Primes[1] = big.NewInt(0)
|
||||
p.Primes[1].SetBytes(v1)
|
||||
p.Primes[1] = new(big.Int).SetBytes(v1)
|
||||
}
|
||||
case "exponent1", "exponent2", "coefficient":
|
||||
// not used in Go (yet)
|
||||
|
@ -134,27 +117,9 @@ func readPrivateKeyRSA(m map[string]string) (*rsa.PrivateKey, error) {
|
|||
return p, nil
|
||||
}
|
||||
|
||||
func readPrivateKeyDSA(m map[string]string) (*dsa.PrivateKey, error) {
|
||||
p := new(dsa.PrivateKey)
|
||||
p.X = big.NewInt(0)
|
||||
for k, v := range m {
|
||||
switch k {
|
||||
case "private_value(x)":
|
||||
v1, err := fromBase64([]byte(v))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.X.SetBytes(v1)
|
||||
case "created", "publish", "activate":
|
||||
/* not used in Go (yet) */
|
||||
}
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func readPrivateKeyECDSA(m map[string]string) (*ecdsa.PrivateKey, error) {
|
||||
p := new(ecdsa.PrivateKey)
|
||||
p.D = big.NewInt(0)
|
||||
p.D = new(big.Int)
|
||||
// TODO: validate that the required flags are present
|
||||
for k, v := range m {
|
||||
switch k {
|
||||
|
@ -322,6 +287,11 @@ func (kl *klexer) Next() (lex, bool) {
|
|||
commt = false
|
||||
}
|
||||
|
||||
if kl.key && str.Len() == 0 {
|
||||
// ignore empty lines
|
||||
break
|
||||
}
|
||||
|
||||
kl.key = true
|
||||
|
||||
l.value = zValue
|
||||
|
|
|
@ -13,6 +13,8 @@ import (
|
|||
|
||||
const format = "Private-key-format: v1.3\n"
|
||||
|
||||
var bigIntOne = big.NewInt(1)
|
||||
|
||||
// PrivateKeyString converts a PrivateKey to a string. This string has the same
|
||||
// format as the private-key-file of BIND9 (Private-key-format: v1.3).
|
||||
// It needs some info from the key (the algorithm), so its a method of the DNSKEY
|
||||
|
@ -31,12 +33,11 @@ func (r *DNSKEY) PrivateKeyString(p crypto.PrivateKey) string {
|
|||
prime2 := toBase64(p.Primes[1].Bytes())
|
||||
// Calculate Exponent1/2 and Coefficient as per: http://en.wikipedia.org/wiki/RSA#Using_the_Chinese_remainder_algorithm
|
||||
// and from: http://code.google.com/p/go/issues/detail?id=987
|
||||
one := big.NewInt(1)
|
||||
p1 := big.NewInt(0).Sub(p.Primes[0], one)
|
||||
q1 := big.NewInt(0).Sub(p.Primes[1], one)
|
||||
exp1 := big.NewInt(0).Mod(p.D, p1)
|
||||
exp2 := big.NewInt(0).Mod(p.D, q1)
|
||||
coeff := big.NewInt(0).ModInverse(p.Primes[1], p.Primes[0])
|
||||
p1 := new(big.Int).Sub(p.Primes[0], bigIntOne)
|
||||
q1 := new(big.Int).Sub(p.Primes[1], bigIntOne)
|
||||
exp1 := new(big.Int).Mod(p.D, p1)
|
||||
exp2 := new(big.Int).Mod(p.D, q1)
|
||||
coeff := new(big.Int).ModInverse(p.Primes[1], p.Primes[0])
|
||||
|
||||
exponent1 := toBase64(exp1.Bytes())
|
||||
exponent2 := toBase64(exp2.Bytes())
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
/*
|
||||
Package dns implements a full featured interface to the Domain Name System.
|
||||
Server- and client-side programming is supported.
|
||||
The package allows complete control over what is sent out to the DNS. The package
|
||||
API follows the less-is-more principle, by presenting a small, clean interface.
|
||||
Both server- and client-side programming is supported. The package allows
|
||||
complete control over what is sent out to the DNS. The API follows the
|
||||
less-is-more principle, by presenting a small, clean interface.
|
||||
|
||||
The package dns supports (asynchronous) querying/replying, incoming/outgoing zone transfers,
|
||||
It supports (asynchronous) querying/replying, incoming/outgoing zone transfers,
|
||||
TSIG, EDNS0, dynamic updates, notifies and DNSSEC validation/signing.
|
||||
Note that domain names MUST be fully qualified, before sending them, unqualified
|
||||
|
||||
Note that domain names MUST be fully qualified before sending them, unqualified
|
||||
names in a message will result in a packing failure.
|
||||
|
||||
Resource records are native types. They are not stored in wire format.
|
||||
Basic usage pattern for creating a new resource record:
|
||||
Resource records are native types. They are not stored in wire format. Basic
|
||||
usage pattern for creating a new resource record:
|
||||
|
||||
r := new(dns.MX)
|
||||
r.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeMX,
|
||||
Class: dns.ClassINET, Ttl: 3600}
|
||||
r.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: 3600}
|
||||
r.Preference = 10
|
||||
r.Mx = "mx.miek.nl."
|
||||
|
||||
|
@ -30,8 +30,8 @@ Or even:
|
|||
|
||||
mx, err := dns.NewRR("$ORIGIN nl.\nmiek 1H IN MX 10 mx.miek")
|
||||
|
||||
In the DNS messages are exchanged, these messages contain resource
|
||||
records (sets). Use pattern for creating a message:
|
||||
In the DNS messages are exchanged, these messages contain resource records
|
||||
(sets). Use pattern for creating a message:
|
||||
|
||||
m := new(dns.Msg)
|
||||
m.SetQuestion("miek.nl.", dns.TypeMX)
|
||||
|
@ -40,8 +40,8 @@ Or when not certain if the domain name is fully qualified:
|
|||
|
||||
m.SetQuestion(dns.Fqdn("miek.nl"), dns.TypeMX)
|
||||
|
||||
The message m is now a message with the question section set to ask
|
||||
the MX records for the miek.nl. zone.
|
||||
The message m is now a message with the question section set to ask the MX
|
||||
records for the miek.nl. zone.
|
||||
|
||||
The following is slightly more verbose, but more flexible:
|
||||
|
||||
|
@ -51,9 +51,8 @@ The following is slightly more verbose, but more flexible:
|
|||
m1.Question = make([]dns.Question, 1)
|
||||
m1.Question[0] = dns.Question{"miek.nl.", dns.TypeMX, dns.ClassINET}
|
||||
|
||||
After creating a message it can be sent.
|
||||
Basic use pattern for synchronous querying the DNS at a
|
||||
server configured on 127.0.0.1 and port 53:
|
||||
After creating a message it can be sent. Basic use pattern for synchronous
|
||||
querying the DNS at a server configured on 127.0.0.1 and port 53:
|
||||
|
||||
c := new(dns.Client)
|
||||
in, rtt, err := c.Exchange(m1, "127.0.0.1:53")
|
||||
|
@ -99,25 +98,24 @@ the Answer section:
|
|||
|
||||
Domain Name and TXT Character String Representations
|
||||
|
||||
Both domain names and TXT character strings are converted to presentation
|
||||
form both when unpacked and when converted to strings.
|
||||
Both domain names and TXT character strings are converted to presentation form
|
||||
both when unpacked and when converted to strings.
|
||||
|
||||
For TXT character strings, tabs, carriage returns and line feeds will be
|
||||
converted to \t, \r and \n respectively. Back slashes and quotations marks
|
||||
will be escaped. Bytes below 32 and above 127 will be converted to \DDD
|
||||
form.
|
||||
converted to \t, \r and \n respectively. Back slashes and quotations marks will
|
||||
be escaped. Bytes below 32 and above 127 will be converted to \DDD form.
|
||||
|
||||
For domain names, in addition to the above rules brackets, periods,
|
||||
spaces, semicolons and the at symbol are escaped.
|
||||
For domain names, in addition to the above rules brackets, periods, spaces,
|
||||
semicolons and the at symbol are escaped.
|
||||
|
||||
DNSSEC
|
||||
|
||||
DNSSEC (DNS Security Extension) adds a layer of security to the DNS. It
|
||||
uses public key cryptography to sign resource records. The
|
||||
public keys are stored in DNSKEY records and the signatures in RRSIG records.
|
||||
DNSSEC (DNS Security Extension) adds a layer of security to the DNS. It uses
|
||||
public key cryptography to sign resource records. The public keys are stored in
|
||||
DNSKEY records and the signatures in RRSIG records.
|
||||
|
||||
Requesting DNSSEC information for a zone is done by adding the DO (DNSSEC OK) bit
|
||||
to a request.
|
||||
Requesting DNSSEC information for a zone is done by adding the DO (DNSSEC OK)
|
||||
bit to a request.
|
||||
|
||||
m := new(dns.Msg)
|
||||
m.SetEdns0(4096, true)
|
||||
|
@ -126,9 +124,9 @@ Signature generation, signature verification and key generation are all supporte
|
|||
|
||||
DYNAMIC UPDATES
|
||||
|
||||
Dynamic updates reuses the DNS message format, but renames three of
|
||||
the sections. Question is Zone, Answer is Prerequisite, Authority is
|
||||
Update, only the Additional is not renamed. See RFC 2136 for the gory details.
|
||||
Dynamic updates reuses the DNS message format, but renames three of the
|
||||
sections. Question is Zone, Answer is Prerequisite, Authority is Update, only
|
||||
the Additional is not renamed. See RFC 2136 for the gory details.
|
||||
|
||||
You can set a rather complex set of rules for the existence of absence of
|
||||
certain resource records or names in a zone to specify if resource records
|
||||
|
@ -145,10 +143,9 @@ DNS function shows which functions exist to specify the prerequisites.
|
|||
NONE rrset empty RRset does not exist dns.RRsetNotUsed
|
||||
zone rrset rr RRset exists (value dep) dns.Used
|
||||
|
||||
The prerequisite section can also be left empty.
|
||||
If you have decided on the prerequisites you can tell what RRs should
|
||||
be added or deleted. The next table shows the options you have and
|
||||
what functions to call.
|
||||
The prerequisite section can also be left empty. If you have decided on the
|
||||
prerequisites you can tell what RRs should be added or deleted. The next table
|
||||
shows the options you have and what functions to call.
|
||||
|
||||
3.4.2.6 - Table Of Metavalues Used In Update Section
|
||||
|
||||
|
@ -181,10 +178,10 @@ changes to the RRset after calling SetTsig() the signature will be incorrect.
|
|||
...
|
||||
// When sending the TSIG RR is calculated and filled in before sending
|
||||
|
||||
When requesting an zone transfer (almost all TSIG usage is when requesting zone transfers), with
|
||||
TSIG, this is the basic use pattern. In this example we request an AXFR for
|
||||
miek.nl. with TSIG key named "axfr." and secret "so6ZGir4GPAqINNh9U5c3A=="
|
||||
and using the server 176.58.119.54:
|
||||
When requesting an zone transfer (almost all TSIG usage is when requesting zone
|
||||
transfers), with TSIG, this is the basic use pattern. In this example we
|
||||
request an AXFR for miek.nl. with TSIG key named "axfr." and secret
|
||||
"so6ZGir4GPAqINNh9U5c3A==" and using the server 176.58.119.54:
|
||||
|
||||
t := new(dns.Transfer)
|
||||
m := new(dns.Msg)
|
||||
|
@ -194,8 +191,8 @@ and using the server 176.58.119.54:
|
|||
c, err := t.In(m, "176.58.119.54:53")
|
||||
for r := range c { ... }
|
||||
|
||||
You can now read the records from the transfer as they come in. Each envelope is checked with TSIG.
|
||||
If something is not correct an error is returned.
|
||||
You can now read the records from the transfer as they come in. Each envelope
|
||||
is checked with TSIG. If something is not correct an error is returned.
|
||||
|
||||
Basic use pattern validating and replying to a message that has TSIG set.
|
||||
|
||||
|
@ -220,29 +217,30 @@ Basic use pattern validating and replying to a message that has TSIG set.
|
|||
|
||||
PRIVATE RRS
|
||||
|
||||
RFC 6895 sets aside a range of type codes for private use. This range
|
||||
is 65,280 - 65,534 (0xFF00 - 0xFFFE). When experimenting with new Resource Records these
|
||||
RFC 6895 sets aside a range of type codes for private use. This range is 65,280
|
||||
- 65,534 (0xFF00 - 0xFFFE). When experimenting with new Resource Records these
|
||||
can be used, before requesting an official type code from IANA.
|
||||
|
||||
see http://miek.nl/2014/September/21/idn-and-private-rr-in-go-dns/ for more
|
||||
See https://miek.nl/2014/September/21/idn-and-private-rr-in-go-dns/ for more
|
||||
information.
|
||||
|
||||
EDNS0
|
||||
|
||||
EDNS0 is an extension mechanism for the DNS defined in RFC 2671 and updated
|
||||
by RFC 6891. It defines an new RR type, the OPT RR, which is then completely
|
||||
EDNS0 is an extension mechanism for the DNS defined in RFC 2671 and updated by
|
||||
RFC 6891. It defines an new RR type, the OPT RR, which is then completely
|
||||
abused.
|
||||
|
||||
Basic use pattern for creating an (empty) OPT RR:
|
||||
|
||||
o := new(dns.OPT)
|
||||
o.Hdr.Name = "." // MUST be the root zone, per definition.
|
||||
o.Hdr.Rrtype = dns.TypeOPT
|
||||
|
||||
The rdata of an OPT RR consists out of a slice of EDNS0 (RFC 6891)
|
||||
interfaces. Currently only a few have been standardized: EDNS0_NSID
|
||||
(RFC 5001) and EDNS0_SUBNET (draft-vandergaast-edns-client-subnet-02). Note
|
||||
that these options may be combined in an OPT RR.
|
||||
Basic use pattern for a server to check if (and which) options are set:
|
||||
The rdata of an OPT RR consists out of a slice of EDNS0 (RFC 6891) interfaces.
|
||||
Currently only a few have been standardized: EDNS0_NSID (RFC 5001) and
|
||||
EDNS0_SUBNET (draft-vandergaast-edns-client-subnet-02). Note that these options
|
||||
may be combined in an OPT RR. Basic use pattern for a server to check if (and
|
||||
which) options are set:
|
||||
|
||||
// o is a dns.OPT
|
||||
for _, s := range o.Option {
|
||||
|
@ -262,10 +260,9 @@ From RFC 2931:
|
|||
... protection for glue records, DNS requests, protection for message headers
|
||||
on requests and responses, and protection of the overall integrity of a response.
|
||||
|
||||
It works like TSIG, except that SIG(0) uses public key cryptography, instead of the shared
|
||||
secret approach in TSIG.
|
||||
Supported algorithms: DSA, ECDSAP256SHA256, ECDSAP384SHA384, RSASHA1, RSASHA256 and
|
||||
RSASHA512.
|
||||
It works like TSIG, except that SIG(0) uses public key cryptography, instead of
|
||||
the shared secret approach in TSIG. Supported algorithms: DSA, ECDSAP256SHA256,
|
||||
ECDSAP384SHA384, RSASHA1, RSASHA256 and RSASHA512.
|
||||
|
||||
Signing subsequent messages in multi-message sessions is not implemented.
|
||||
*/
|
||||
|
|
|
@ -7,19 +7,32 @@ package dns
|
|||
// is so, otherwise false.
|
||||
// It's is a protocol violation to have identical RRs in a message.
|
||||
func IsDuplicate(r1, r2 RR) bool {
|
||||
if r1.Header().Class != r2.Header().Class {
|
||||
// Check whether the record header is identical.
|
||||
if !r1.Header().isDuplicate(r2.Header()) {
|
||||
return false
|
||||
}
|
||||
if r1.Header().Rrtype != r2.Header().Rrtype {
|
||||
|
||||
// Check whether the RDATA is identical.
|
||||
return r1.isDuplicate(r2)
|
||||
}
|
||||
|
||||
func (r1 *RR_Header) isDuplicate(_r2 RR) bool {
|
||||
r2, ok := _r2.(*RR_Header)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
if !isDulicateName(r1.Header().Name, r2.Header().Name) {
|
||||
if r1.Class != r2.Class {
|
||||
return false
|
||||
}
|
||||
if r1.Rrtype != r2.Rrtype {
|
||||
return false
|
||||
}
|
||||
if !isDuplicateName(r1.Name, r2.Name) {
|
||||
return false
|
||||
}
|
||||
// ignore TTL
|
||||
|
||||
return isDuplicateRdata(r1, r2)
|
||||
return true
|
||||
}
|
||||
|
||||
// isDulicateName checks if the domain names s1 and s2 are equal.
|
||||
func isDulicateName(s1, s2 string) bool { return equal(s1, s2) }
|
||||
// isDuplicateName checks if the domain names s1 and s2 are equal.
|
||||
func isDuplicateName(s1, s2 string) bool { return equal(s1, s2) }
|
||||
|
|
|
@ -57,10 +57,7 @@ func main() {
|
|||
continue
|
||||
}
|
||||
|
||||
if name == "PrivateRR" || name == "RFC3597" {
|
||||
continue
|
||||
}
|
||||
if name == "OPT" || name == "ANY" || name == "IXFR" || name == "AXFR" {
|
||||
if name == "PrivateRR" || name == "OPT" {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -70,22 +67,6 @@ func main() {
|
|||
b := &bytes.Buffer{}
|
||||
b.WriteString(packageHdr)
|
||||
|
||||
// Generate the giant switch that calls the correct function for each type.
|
||||
fmt.Fprint(b, "// isDuplicateRdata calls the rdata specific functions\n")
|
||||
fmt.Fprint(b, "func isDuplicateRdata(r1, r2 RR) bool {\n")
|
||||
fmt.Fprint(b, "switch r1.Header().Rrtype {\n")
|
||||
|
||||
for _, name := range namedTypes {
|
||||
|
||||
o := scope.Lookup(name)
|
||||
_, isEmbedded := getTypeStruct(o.Type(), scope)
|
||||
if isEmbedded {
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(b, "case Type%s:\nreturn isDuplicate%s(r1.(*%s), r2.(*%s))\n", name, name, name, name)
|
||||
}
|
||||
fmt.Fprintf(b, "}\nreturn false\n}\n")
|
||||
|
||||
// Generate the duplicate check for each type.
|
||||
fmt.Fprint(b, "// isDuplicate() functions\n\n")
|
||||
for _, name := range namedTypes {
|
||||
|
@ -95,7 +76,10 @@ func main() {
|
|||
if isEmbedded {
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(b, "func isDuplicate%s(r1, r2 *%s) bool {\n", name, name)
|
||||
fmt.Fprintf(b, "func (r1 *%s) isDuplicate(_r2 RR) bool {\n", name)
|
||||
fmt.Fprintf(b, "r2, ok := _r2.(*%s)\n", name)
|
||||
fmt.Fprint(b, "if !ok { return false }\n")
|
||||
fmt.Fprint(b, "_ = r2\n")
|
||||
for i := 1; i < st.NumFields(); i++ {
|
||||
field := st.Field(i).Name()
|
||||
o2 := func(s string) { fmt.Fprintf(b, s+"\n", field, field) }
|
||||
|
@ -103,12 +87,12 @@ func main() {
|
|||
|
||||
// For some reason, a and aaaa don't pop up as *types.Slice here (mostly like because the are
|
||||
// *indirectly* defined as a slice in the net package).
|
||||
if _, ok := st.Field(i).Type().(*types.Slice); ok || st.Tag(i) == `dns:"a"` || st.Tag(i) == `dns:"aaaa"` {
|
||||
if _, ok := st.Field(i).Type().(*types.Slice); ok {
|
||||
o2("if len(r1.%s) != len(r2.%s) {\nreturn false\n}")
|
||||
|
||||
if st.Tag(i) == `dns:"cdomain-name"` || st.Tag(i) == `dns:"domain-name"` {
|
||||
o3(`for i := 0; i < len(r1.%s); i++ {
|
||||
if !isDulicateName(r1.%s[i], r2.%s[i]) {
|
||||
if !isDuplicateName(r1.%s[i], r2.%s[i]) {
|
||||
return false
|
||||
}
|
||||
}`)
|
||||
|
@ -128,8 +112,10 @@ func main() {
|
|||
switch st.Tag(i) {
|
||||
case `dns:"-"`:
|
||||
// ignored
|
||||
case `dns:"a"`, `dns:"aaaa"`:
|
||||
o2("if !r1.%s.Equal(r2.%s) {\nreturn false\n}")
|
||||
case `dns:"cdomain-name"`, `dns:"domain-name"`:
|
||||
o2("if !isDulicateName(r1.%s, r2.%s) {\nreturn false\n}")
|
||||
o2("if !isDuplicateName(r1.%s, r2.%s) {\nreturn false\n}")
|
||||
default:
|
||||
o2("if r1.%s != r2.%s {\nreturn false\n}")
|
||||
}
|
||||
|
|
|
@ -78,16 +78,22 @@ func (rr *OPT) String() string {
|
|||
return s
|
||||
}
|
||||
|
||||
func (rr *OPT) len() int {
|
||||
l := rr.Hdr.len()
|
||||
for i := 0; i < len(rr.Option); i++ {
|
||||
func (rr *OPT) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
for _, o := range rr.Option {
|
||||
l += 4 // Account for 2-byte option code and 2-byte option length.
|
||||
lo, _ := rr.Option[i].pack()
|
||||
lo, _ := o.pack()
|
||||
l += len(lo)
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
func (rr *OPT) parse(c *zlexer, origin string) *ParseError {
|
||||
panic("dns: internal error: parse should never be called on OPT")
|
||||
}
|
||||
|
||||
func (r1 *OPT) isDuplicate(r2 RR) bool { return false }
|
||||
|
||||
// return the old value -> delete SetVersion?
|
||||
|
||||
// Version returns the EDNS version used. Only zero is defined.
|
||||
|
@ -102,15 +108,14 @@ func (rr *OPT) SetVersion(v uint8) {
|
|||
|
||||
// ExtendedRcode returns the EDNS extended RCODE field (the upper 8 bits of the TTL).
|
||||
func (rr *OPT) ExtendedRcode() int {
|
||||
return int(rr.Hdr.Ttl&0xFF000000>>24) + 15
|
||||
return int(rr.Hdr.Ttl&0xFF000000>>24) << 4
|
||||
}
|
||||
|
||||
// SetExtendedRcode sets the EDNS extended RCODE field.
|
||||
func (rr *OPT) SetExtendedRcode(v uint8) {
|
||||
if v < RcodeBadVers { // Smaller than 16.. Use the 4 bits you have!
|
||||
return
|
||||
}
|
||||
rr.Hdr.Ttl = rr.Hdr.Ttl&0x00FFFFFF | uint32(v-15)<<24
|
||||
//
|
||||
// If the RCODE is not an extended RCODE, will reset the extended RCODE field to 0.
|
||||
func (rr *OPT) SetExtendedRcode(v uint16) {
|
||||
rr.Hdr.Ttl = rr.Hdr.Ttl&0x00FFFFFF | uint32(v>>4)<<24
|
||||
}
|
||||
|
||||
// UDPSize returns the UDP buffer size.
|
||||
|
@ -154,6 +159,8 @@ type EDNS0 interface {
|
|||
unpack([]byte) error
|
||||
// String returns the string representation of the option.
|
||||
String() string
|
||||
// copy returns a deep-copy of the option.
|
||||
copy() EDNS0
|
||||
}
|
||||
|
||||
// EDNS0_NSID option is used to retrieve a nameserver
|
||||
|
@ -184,7 +191,8 @@ func (e *EDNS0_NSID) pack() ([]byte, error) {
|
|||
// Option implements the EDNS0 interface.
|
||||
func (e *EDNS0_NSID) Option() uint16 { return EDNS0NSID } // Option returns the option code.
|
||||
func (e *EDNS0_NSID) unpack(b []byte) error { e.Nsid = hex.EncodeToString(b); return nil }
|
||||
func (e *EDNS0_NSID) String() string { return string(e.Nsid) }
|
||||
func (e *EDNS0_NSID) String() string { return e.Nsid }
|
||||
func (e *EDNS0_NSID) copy() EDNS0 { return &EDNS0_NSID{e.Code, e.Nsid} }
|
||||
|
||||
// EDNS0_SUBNET is the subnet option that is used to give the remote nameserver
|
||||
// an idea of where the client lives. See RFC 7871. It can then give back a different
|
||||
|
@ -274,22 +282,16 @@ func (e *EDNS0_SUBNET) unpack(b []byte) error {
|
|||
if e.SourceNetmask > net.IPv4len*8 || e.SourceScope > net.IPv4len*8 {
|
||||
return errors.New("dns: bad netmask")
|
||||
}
|
||||
addr := make([]byte, net.IPv4len)
|
||||
for i := 0; i < net.IPv4len && 4+i < len(b); i++ {
|
||||
addr[i] = b[4+i]
|
||||
}
|
||||
e.Address = net.IPv4(addr[0], addr[1], addr[2], addr[3])
|
||||
addr := make(net.IP, net.IPv4len)
|
||||
copy(addr, b[4:])
|
||||
e.Address = addr.To16()
|
||||
case 2:
|
||||
if e.SourceNetmask > net.IPv6len*8 || e.SourceScope > net.IPv6len*8 {
|
||||
return errors.New("dns: bad netmask")
|
||||
}
|
||||
addr := make([]byte, net.IPv6len)
|
||||
for i := 0; i < net.IPv6len && 4+i < len(b); i++ {
|
||||
addr[i] = b[4+i]
|
||||
}
|
||||
e.Address = net.IP{addr[0], addr[1], addr[2], addr[3], addr[4],
|
||||
addr[5], addr[6], addr[7], addr[8], addr[9], addr[10],
|
||||
addr[11], addr[12], addr[13], addr[14], addr[15]}
|
||||
addr := make(net.IP, net.IPv6len)
|
||||
copy(addr, b[4:])
|
||||
e.Address = addr
|
||||
default:
|
||||
return errors.New("dns: bad address family")
|
||||
}
|
||||
|
@ -308,6 +310,16 @@ func (e *EDNS0_SUBNET) String() (s string) {
|
|||
return
|
||||
}
|
||||
|
||||
func (e *EDNS0_SUBNET) copy() EDNS0 {
|
||||
return &EDNS0_SUBNET{
|
||||
e.Code,
|
||||
e.Family,
|
||||
e.SourceNetmask,
|
||||
e.SourceScope,
|
||||
e.Address,
|
||||
}
|
||||
}
|
||||
|
||||
// The EDNS0_COOKIE option is used to add a DNS Cookie to a message.
|
||||
//
|
||||
// o := new(dns.OPT)
|
||||
|
@ -343,6 +355,7 @@ func (e *EDNS0_COOKIE) pack() ([]byte, error) {
|
|||
func (e *EDNS0_COOKIE) Option() uint16 { return EDNS0COOKIE }
|
||||
func (e *EDNS0_COOKIE) unpack(b []byte) error { e.Cookie = hex.EncodeToString(b); return nil }
|
||||
func (e *EDNS0_COOKIE) String() string { return e.Cookie }
|
||||
func (e *EDNS0_COOKIE) copy() EDNS0 { return &EDNS0_COOKIE{e.Code, e.Cookie} }
|
||||
|
||||
// The EDNS0_UL (Update Lease) (draft RFC) option is used to tell the server to set
|
||||
// an expiration on an update RR. This is helpful for clients that cannot clean
|
||||
|
@ -364,6 +377,7 @@ type EDNS0_UL struct {
|
|||
// Option implements the EDNS0 interface.
|
||||
func (e *EDNS0_UL) Option() uint16 { return EDNS0UL }
|
||||
func (e *EDNS0_UL) String() string { return strconv.FormatUint(uint64(e.Lease), 10) }
|
||||
func (e *EDNS0_UL) copy() EDNS0 { return &EDNS0_UL{e.Code, e.Lease} }
|
||||
|
||||
// Copied: http://golang.org/src/pkg/net/dnsmsg.go
|
||||
func (e *EDNS0_UL) pack() ([]byte, error) {
|
||||
|
@ -418,10 +432,13 @@ func (e *EDNS0_LLQ) unpack(b []byte) error {
|
|||
|
||||
func (e *EDNS0_LLQ) String() string {
|
||||
s := strconv.FormatUint(uint64(e.Version), 10) + " " + strconv.FormatUint(uint64(e.Opcode), 10) +
|
||||
" " + strconv.FormatUint(uint64(e.Error), 10) + " " + strconv.FormatUint(uint64(e.Id), 10) +
|
||||
" " + strconv.FormatUint(uint64(e.Error), 10) + " " + strconv.FormatUint(e.Id, 10) +
|
||||
" " + strconv.FormatUint(uint64(e.LeaseLife), 10)
|
||||
return s
|
||||
}
|
||||
func (e *EDNS0_LLQ) copy() EDNS0 {
|
||||
return &EDNS0_LLQ{e.Code, e.Version, e.Opcode, e.Error, e.Id, e.LeaseLife}
|
||||
}
|
||||
|
||||
// EDNS0_DUA implements the EDNS0 "DNSSEC Algorithm Understood" option. See RFC 6975.
|
||||
type EDNS0_DAU struct {
|
||||
|
@ -436,15 +453,16 @@ func (e *EDNS0_DAU) unpack(b []byte) error { e.AlgCode = b; return nil }
|
|||
|
||||
func (e *EDNS0_DAU) String() string {
|
||||
s := ""
|
||||
for i := 0; i < len(e.AlgCode); i++ {
|
||||
if a, ok := AlgorithmToString[e.AlgCode[i]]; ok {
|
||||
for _, alg := range e.AlgCode {
|
||||
if a, ok := AlgorithmToString[alg]; ok {
|
||||
s += " " + a
|
||||
} else {
|
||||
s += " " + strconv.Itoa(int(e.AlgCode[i]))
|
||||
s += " " + strconv.Itoa(int(alg))
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
func (e *EDNS0_DAU) copy() EDNS0 { return &EDNS0_DAU{e.Code, e.AlgCode} }
|
||||
|
||||
// EDNS0_DHU implements the EDNS0 "DS Hash Understood" option. See RFC 6975.
|
||||
type EDNS0_DHU struct {
|
||||
|
@ -459,15 +477,16 @@ func (e *EDNS0_DHU) unpack(b []byte) error { e.AlgCode = b; return nil }
|
|||
|
||||
func (e *EDNS0_DHU) String() string {
|
||||
s := ""
|
||||
for i := 0; i < len(e.AlgCode); i++ {
|
||||
if a, ok := HashToString[e.AlgCode[i]]; ok {
|
||||
for _, alg := range e.AlgCode {
|
||||
if a, ok := HashToString[alg]; ok {
|
||||
s += " " + a
|
||||
} else {
|
||||
s += " " + strconv.Itoa(int(e.AlgCode[i]))
|
||||
s += " " + strconv.Itoa(int(alg))
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
func (e *EDNS0_DHU) copy() EDNS0 { return &EDNS0_DHU{e.Code, e.AlgCode} }
|
||||
|
||||
// EDNS0_N3U implements the EDNS0 "NSEC3 Hash Understood" option. See RFC 6975.
|
||||
type EDNS0_N3U struct {
|
||||
|
@ -483,15 +502,16 @@ func (e *EDNS0_N3U) unpack(b []byte) error { e.AlgCode = b; return nil }
|
|||
func (e *EDNS0_N3U) String() string {
|
||||
// Re-use the hash map
|
||||
s := ""
|
||||
for i := 0; i < len(e.AlgCode); i++ {
|
||||
if a, ok := HashToString[e.AlgCode[i]]; ok {
|
||||
for _, alg := range e.AlgCode {
|
||||
if a, ok := HashToString[alg]; ok {
|
||||
s += " " + a
|
||||
} else {
|
||||
s += " " + strconv.Itoa(int(e.AlgCode[i]))
|
||||
s += " " + strconv.Itoa(int(alg))
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
func (e *EDNS0_N3U) copy() EDNS0 { return &EDNS0_N3U{e.Code, e.AlgCode} }
|
||||
|
||||
// EDNS0_EXPIRE implementes the EDNS0 option as described in RFC 7314.
|
||||
type EDNS0_EXPIRE struct {
|
||||
|
@ -502,13 +522,11 @@ type EDNS0_EXPIRE struct {
|
|||
// Option implements the EDNS0 interface.
|
||||
func (e *EDNS0_EXPIRE) Option() uint16 { return EDNS0EXPIRE }
|
||||
func (e *EDNS0_EXPIRE) String() string { return strconv.FormatUint(uint64(e.Expire), 10) }
|
||||
func (e *EDNS0_EXPIRE) copy() EDNS0 { return &EDNS0_EXPIRE{e.Code, e.Expire} }
|
||||
|
||||
func (e *EDNS0_EXPIRE) pack() ([]byte, error) {
|
||||
b := make([]byte, 4)
|
||||
b[0] = byte(e.Expire >> 24)
|
||||
b[1] = byte(e.Expire >> 16)
|
||||
b[2] = byte(e.Expire >> 8)
|
||||
b[3] = byte(e.Expire)
|
||||
binary.BigEndian.PutUint32(b, e.Expire)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
|
@ -543,6 +561,11 @@ func (e *EDNS0_LOCAL) Option() uint16 { return e.Code }
|
|||
func (e *EDNS0_LOCAL) String() string {
|
||||
return strconv.FormatInt(int64(e.Code), 10) + ":0x" + hex.EncodeToString(e.Data)
|
||||
}
|
||||
func (e *EDNS0_LOCAL) copy() EDNS0 {
|
||||
b := make([]byte, len(e.Data))
|
||||
copy(b, e.Data)
|
||||
return &EDNS0_LOCAL{e.Code, b}
|
||||
}
|
||||
|
||||
func (e *EDNS0_LOCAL) pack() ([]byte, error) {
|
||||
b := make([]byte, len(e.Data))
|
||||
|
@ -615,6 +638,7 @@ func (e *EDNS0_TCP_KEEPALIVE) String() (s string) {
|
|||
}
|
||||
return
|
||||
}
|
||||
func (e *EDNS0_TCP_KEEPALIVE) copy() EDNS0 { return &EDNS0_TCP_KEEPALIVE{e.Code, e.Length, e.Timeout} }
|
||||
|
||||
// EDNS0_PADDING option is used to add padding to a request/response. The default
|
||||
// value of padding SHOULD be 0x0 but other values MAY be used, for instance if
|
||||
|
@ -628,3 +652,8 @@ func (e *EDNS0_PADDING) Option() uint16 { return EDNS0PADDING }
|
|||
func (e *EDNS0_PADDING) pack() ([]byte, error) { return e.Padding, nil }
|
||||
func (e *EDNS0_PADDING) unpack(b []byte) error { e.Padding = b; return nil }
|
||||
func (e *EDNS0_PADDING) String() string { return fmt.Sprintf("%0X", e.Padding) }
|
||||
func (e *EDNS0_PADDING) copy() EDNS0 {
|
||||
b := make([]byte, len(e.Padding))
|
||||
copy(b, e.Padding)
|
||||
return &EDNS0_PADDING{b}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ func Field(r RR, i int) string {
|
|||
return ""
|
||||
}
|
||||
d := reflect.ValueOf(r).Elem().Field(i)
|
||||
switch k := d.Kind(); k {
|
||||
switch d.Kind() {
|
||||
case reflect.String:
|
||||
return d.String()
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
|
@ -31,6 +31,9 @@ func Field(r RR, i int) string {
|
|||
switch reflect.ValueOf(r).Elem().Type().Field(i).Tag {
|
||||
case `dns:"a"`:
|
||||
// TODO(miek): Hmm store this as 16 bytes
|
||||
if d.Len() < net.IPv4len {
|
||||
return ""
|
||||
}
|
||||
if d.Len() < net.IPv6len {
|
||||
return net.IPv4(byte(d.Index(0).Uint()),
|
||||
byte(d.Index(1).Uint()),
|
||||
|
@ -42,6 +45,9 @@ func Field(r RR, i int) string {
|
|||
byte(d.Index(14).Uint()),
|
||||
byte(d.Index(15).Uint())).String()
|
||||
case `dns:"aaaa"`:
|
||||
if d.Len() < net.IPv6len {
|
||||
return ""
|
||||
}
|
||||
return net.IP{
|
||||
byte(d.Index(0).Uint()),
|
||||
byte(d.Index(1).Uint()),
|
||||
|
|
|
@ -49,11 +49,15 @@ func (zp *ZoneParser) generate(l lex) (RR, bool) {
|
|||
if err != nil {
|
||||
return zp.setParseError("bad stop in $GENERATE range", l)
|
||||
}
|
||||
if end < 0 || start < 0 || end < start {
|
||||
if end < 0 || start < 0 || end < start || (end-start)/step > 65535 {
|
||||
return zp.setParseError("bad range in $GENERATE range", l)
|
||||
}
|
||||
|
||||
zp.c.Next() // _BLANK
|
||||
// _BLANK
|
||||
l, ok := zp.c.Next()
|
||||
if !ok || l.value != zBlank {
|
||||
return zp.setParseError("garbage after $GENERATE range", l)
|
||||
}
|
||||
|
||||
// Create a complete new string, which we then parse again.
|
||||
var s string
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
module github.com/miekg/dns
|
||||
|
||||
go 1.12
|
||||
|
||||
require (
|
||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe
|
||||
golang.org/x/text v0.3.2 // indirect
|
||||
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18 // indirect
|
||||
)
|
|
@ -0,0 +1,33 @@
|
|||
golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4 h1:Vk3wNqEZwyGyei9yq5ekj7frek2u7HUfffJ1/opblzc=
|
||||
golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472 h1:Gv7RPwsi3eZ2Fgewe3CBsuOebPwO27PoXzRpJPsvSSM=
|
||||
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392 h1:ACG4HJsFiNMf47Y4PeRoebLNy/2lXT9EtprMuTFWt1M=
|
||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
||||
golang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3 h1:dgd4x4kJt7G4k4m93AYLzM8Ni6h2qLTfh9n9vXJT3/0=
|
||||
golang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180928133829-e4b3c5e90611 h1:O33LKL7WyJgjN9CvxfTIomjIClbd/Kq86/iipowHQU0=
|
||||
golang.org/x/sys v0.0.0-20180928133829-e4b3c5e90611/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd h1:DBH9mDw0zluJT/R+nGuV3jWFWLFaHyYZWD4tOT+cjn0=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe h1:6fAMxZRR6sl1Uq8U61gxU+kPTs2tR8uOySCbBP7BN/M=
|
||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
@ -16,7 +16,7 @@ func SplitDomainName(s string) (labels []string) {
|
|||
fqdnEnd := 0 // offset of the final '.' or the length of the name
|
||||
idx := Split(s)
|
||||
begin := 0
|
||||
if s[len(s)-1] == '.' {
|
||||
if IsFqdn(s) {
|
||||
fqdnEnd = len(s) - 1
|
||||
} else {
|
||||
fqdnEnd = len(s)
|
||||
|
@ -28,16 +28,13 @@ func SplitDomainName(s string) (labels []string) {
|
|||
case 1:
|
||||
// no-op
|
||||
default:
|
||||
end := 0
|
||||
for i := 1; i < len(idx); i++ {
|
||||
end = idx[i]
|
||||
for _, end := range idx[1:] {
|
||||
labels = append(labels, s[begin:end-1])
|
||||
begin = end
|
||||
}
|
||||
}
|
||||
|
||||
labels = append(labels, s[begin:fqdnEnd])
|
||||
return labels
|
||||
return append(labels, s[begin:fqdnEnd])
|
||||
}
|
||||
|
||||
// CompareDomainName compares the names s1 and s2 and
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -80,13 +80,7 @@ func main() {
|
|||
o := scope.Lookup(name)
|
||||
st, _ := getTypeStruct(o.Type(), scope)
|
||||
|
||||
fmt.Fprintf(b, "func (rr *%s) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {\n", name)
|
||||
fmt.Fprint(b, `off, err := rr.Hdr.pack(msg, off, compression, compress)
|
||||
if err != nil {
|
||||
return off, err
|
||||
}
|
||||
headerEnd := off
|
||||
`)
|
||||
fmt.Fprintf(b, "func (rr *%s) pack(msg []byte, off int, compression compressionMap, compress bool) (off1 int, err error) {\n", name)
|
||||
for i := 1; i < st.NumFields(); i++ {
|
||||
o := func(s string) {
|
||||
fmt.Fprintf(b, s, st.Field(i).Name())
|
||||
|
@ -106,7 +100,7 @@ return off, err
|
|||
case `dns:"nsec"`:
|
||||
o("off, err = packDataNsec(rr.%s, msg, off)\n")
|
||||
case `dns:"domain-name"`:
|
||||
o("off, err = packDataDomainNames(rr.%s, msg, off, compression, compress)\n")
|
||||
o("off, err = packDataDomainNames(rr.%s, msg, off, compression, false)\n")
|
||||
default:
|
||||
log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
|
||||
}
|
||||
|
@ -116,9 +110,9 @@ return off, err
|
|||
switch {
|
||||
case st.Tag(i) == `dns:"-"`: // ignored
|
||||
case st.Tag(i) == `dns:"cdomain-name"`:
|
||||
o("off, err = PackDomainName(rr.%s, msg, off, compression, compress)\n")
|
||||
o("off, err = packDomainName(rr.%s, msg, off, compression, compress)\n")
|
||||
case st.Tag(i) == `dns:"domain-name"`:
|
||||
o("off, err = PackDomainName(rr.%s, msg, off, compression, false)\n")
|
||||
o("off, err = packDomainName(rr.%s, msg, off, compression, false)\n")
|
||||
case st.Tag(i) == `dns:"a"`:
|
||||
o("off, err = packDataA(rr.%s, msg, off)\n")
|
||||
case st.Tag(i) == `dns:"aaaa"`:
|
||||
|
@ -154,7 +148,8 @@ if rr.%s != "-" {
|
|||
fallthrough
|
||||
case st.Tag(i) == `dns:"hex"`:
|
||||
o("off, err = packStringHex(rr.%s, msg, off)\n")
|
||||
|
||||
case st.Tag(i) == `dns:"any"`:
|
||||
o("off, err = packStringAny(rr.%s, msg, off)\n")
|
||||
case st.Tag(i) == `dns:"octet"`:
|
||||
o("off, err = packStringOctet(rr.%s, msg, off)\n")
|
||||
case st.Tag(i) == "":
|
||||
|
@ -176,8 +171,6 @@ if rr.%s != "-" {
|
|||
log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
|
||||
}
|
||||
}
|
||||
// We have packed everything, only now we know the rdlength of this RR
|
||||
fmt.Fprintln(b, "rr.Header().Rdlength = uint16(off-headerEnd)")
|
||||
fmt.Fprintln(b, "return off, nil }\n")
|
||||
}
|
||||
|
||||
|
@ -186,14 +179,8 @@ if rr.%s != "-" {
|
|||
o := scope.Lookup(name)
|
||||
st, _ := getTypeStruct(o.Type(), scope)
|
||||
|
||||
fmt.Fprintf(b, "func unpack%s(h RR_Header, msg []byte, off int) (RR, int, error) {\n", name)
|
||||
fmt.Fprintf(b, "rr := new(%s)\n", name)
|
||||
fmt.Fprint(b, "rr.Hdr = h\n")
|
||||
fmt.Fprint(b, `if noRdata(h) {
|
||||
return rr, off, nil
|
||||
}
|
||||
var err error
|
||||
rdStart := off
|
||||
fmt.Fprintf(b, "func (rr *%s) unpack(msg []byte, off int) (off1 int, err error) {\n", name)
|
||||
fmt.Fprint(b, `rdStart := off
|
||||
_ = rdStart
|
||||
|
||||
`)
|
||||
|
@ -201,7 +188,7 @@ _ = rdStart
|
|||
o := func(s string) {
|
||||
fmt.Fprintf(b, s, st.Field(i).Name())
|
||||
fmt.Fprint(b, `if err != nil {
|
||||
return rr, off, err
|
||||
return off, err
|
||||
}
|
||||
`)
|
||||
}
|
||||
|
@ -221,7 +208,7 @@ return rr, off, err
|
|||
log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
|
||||
}
|
||||
fmt.Fprint(b, `if err != nil {
|
||||
return rr, off, err
|
||||
return off, err
|
||||
}
|
||||
`)
|
||||
continue
|
||||
|
@ -264,6 +251,8 @@ return rr, off, err
|
|||
o("rr.%s, off, err = unpackStringBase64(msg, off, rdStart + int(rr.Hdr.Rdlength))\n")
|
||||
case `dns:"hex"`:
|
||||
o("rr.%s, off, err = unpackStringHex(msg, off, rdStart + int(rr.Hdr.Rdlength))\n")
|
||||
case `dns:"any"`:
|
||||
o("rr.%s, off, err = unpackStringAny(msg, off, rdStart + int(rr.Hdr.Rdlength))\n")
|
||||
case `dns:"octet"`:
|
||||
o("rr.%s, off, err = unpackStringOctet(msg, off)\n")
|
||||
case "":
|
||||
|
@ -287,22 +276,13 @@ return rr, off, err
|
|||
// If we've hit len(msg) we return without error.
|
||||
if i < st.NumFields()-1 {
|
||||
fmt.Fprintf(b, `if off == len(msg) {
|
||||
return rr, off, nil
|
||||
return off, nil
|
||||
}
|
||||
`)
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(b, "return rr, off, err }\n\n")
|
||||
fmt.Fprintf(b, "return off, nil }\n\n")
|
||||
}
|
||||
// Generate typeToUnpack map
|
||||
fmt.Fprintln(b, "var typeToUnpack = map[uint16]func(RR_Header, []byte, int) (RR, int, error){")
|
||||
for _, name := range namedTypes {
|
||||
if name == "RFC3597" {
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(b, "Type%s: unpack%s,\n", name, name)
|
||||
}
|
||||
fmt.Fprintln(b, "}\n")
|
||||
|
||||
// gofmt
|
||||
res, err := format.Source(b.Bytes())
|
||||
|
|
|
@ -25,12 +25,13 @@ func unpackDataA(msg []byte, off int) (net.IP, int, error) {
|
|||
}
|
||||
|
||||
func packDataA(a net.IP, msg []byte, off int) (int, error) {
|
||||
// It must be a slice of 4, even if it is 16, we encode only the first 4
|
||||
if off+net.IPv4len > len(msg) {
|
||||
return len(msg), &Error{err: "overflow packing a"}
|
||||
}
|
||||
switch len(a) {
|
||||
case net.IPv4len, net.IPv6len:
|
||||
// It must be a slice of 4, even if it is 16, we encode only the first 4
|
||||
if off+net.IPv4len > len(msg) {
|
||||
return len(msg), &Error{err: "overflow packing a"}
|
||||
}
|
||||
|
||||
copy(msg[off:], a.To4())
|
||||
off += net.IPv4len
|
||||
case 0:
|
||||
|
@ -51,12 +52,12 @@ func unpackDataAAAA(msg []byte, off int) (net.IP, int, error) {
|
|||
}
|
||||
|
||||
func packDataAAAA(aaaa net.IP, msg []byte, off int) (int, error) {
|
||||
if off+net.IPv6len > len(msg) {
|
||||
return len(msg), &Error{err: "overflow packing aaaa"}
|
||||
}
|
||||
|
||||
switch len(aaaa) {
|
||||
case net.IPv6len:
|
||||
if off+net.IPv6len > len(msg) {
|
||||
return len(msg), &Error{err: "overflow packing aaaa"}
|
||||
}
|
||||
|
||||
copy(msg[off:], aaaa)
|
||||
off += net.IPv6len
|
||||
case 0:
|
||||
|
@ -99,14 +100,14 @@ func unpackHeader(msg []byte, off int) (rr RR_Header, off1 int, truncmsg []byte,
|
|||
return hdr, off, msg, err
|
||||
}
|
||||
|
||||
// pack packs an RR header, returning the offset to the end of the header.
|
||||
// packHeader packs an RR header, returning the offset to the end of the header.
|
||||
// See PackDomainName for documentation about the compression.
|
||||
func (hdr RR_Header) pack(msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
|
||||
func (hdr RR_Header) packHeader(msg []byte, off int, compression compressionMap, compress bool) (int, error) {
|
||||
if off == len(msg) {
|
||||
return off, nil
|
||||
}
|
||||
|
||||
off, err = PackDomainName(hdr.Name, msg, off, compression, compress)
|
||||
off, err := packDomainName(hdr.Name, msg, off, compression, compress)
|
||||
if err != nil {
|
||||
return len(msg), err
|
||||
}
|
||||
|
@ -122,7 +123,7 @@ func (hdr RR_Header) pack(msg []byte, off int, compression map[string]int, compr
|
|||
if err != nil {
|
||||
return len(msg), err
|
||||
}
|
||||
off, err = packUint16(hdr.Rdlength, msg, off)
|
||||
off, err = packUint16(0, msg, off) // The RDLENGTH field will be set later in packRR.
|
||||
if err != nil {
|
||||
return len(msg), err
|
||||
}
|
||||
|
@ -177,14 +178,14 @@ func unpackUint8(msg []byte, off int) (i uint8, off1 int, err error) {
|
|||
if off+1 > len(msg) {
|
||||
return 0, len(msg), &Error{err: "overflow unpacking uint8"}
|
||||
}
|
||||
return uint8(msg[off]), off + 1, nil
|
||||
return msg[off], off + 1, nil
|
||||
}
|
||||
|
||||
func packUint8(i uint8, msg []byte, off int) (off1 int, err error) {
|
||||
if off+1 > len(msg) {
|
||||
return len(msg), &Error{err: "overflow packing uint8"}
|
||||
}
|
||||
msg[off] = byte(i)
|
||||
msg[off] = i
|
||||
return off + 1, nil
|
||||
}
|
||||
|
||||
|
@ -223,8 +224,8 @@ func unpackUint48(msg []byte, off int) (i uint64, off1 int, err error) {
|
|||
return 0, len(msg), &Error{err: "overflow unpacking uint64 as uint48"}
|
||||
}
|
||||
// Used in TSIG where the last 48 bits are occupied, so for now, assume a uint48 (6 bytes)
|
||||
i = uint64(uint64(msg[off])<<40 | uint64(msg[off+1])<<32 | uint64(msg[off+2])<<24 | uint64(msg[off+3])<<16 |
|
||||
uint64(msg[off+4])<<8 | uint64(msg[off+5]))
|
||||
i = uint64(msg[off])<<40 | uint64(msg[off+1])<<32 | uint64(msg[off+2])<<24 | uint64(msg[off+3])<<16 |
|
||||
uint64(msg[off+4])<<8 | uint64(msg[off+5])
|
||||
off += 6
|
||||
return i, off, nil
|
||||
}
|
||||
|
@ -264,24 +265,36 @@ func unpackString(msg []byte, off int) (string, int, error) {
|
|||
return "", off, &Error{err: "overflow unpacking txt"}
|
||||
}
|
||||
l := int(msg[off])
|
||||
if off+l+1 > len(msg) {
|
||||
off++
|
||||
if off+l > len(msg) {
|
||||
return "", off, &Error{err: "overflow unpacking txt"}
|
||||
}
|
||||
var s strings.Builder
|
||||
s.Grow(l)
|
||||
for _, b := range msg[off+1 : off+1+l] {
|
||||
consumed := 0
|
||||
for i, b := range msg[off : off+l] {
|
||||
switch {
|
||||
case b == '"' || b == '\\':
|
||||
if consumed == 0 {
|
||||
s.Grow(l * 2)
|
||||
}
|
||||
s.Write(msg[off+consumed : off+i])
|
||||
s.WriteByte('\\')
|
||||
s.WriteByte(b)
|
||||
consumed = i + 1
|
||||
case b < ' ' || b > '~': // unprintable
|
||||
writeEscapedByte(&s, b)
|
||||
default:
|
||||
s.WriteByte(b)
|
||||
if consumed == 0 {
|
||||
s.Grow(l * 2)
|
||||
}
|
||||
s.Write(msg[off+consumed : off+i])
|
||||
s.WriteString(escapeByte(b))
|
||||
consumed = i + 1
|
||||
}
|
||||
}
|
||||
off += 1 + l
|
||||
return s.String(), off, nil
|
||||
if consumed == 0 { // no escaping needed
|
||||
return string(msg[off : off+l]), off + l, nil
|
||||
}
|
||||
s.Write(msg[off+consumed : off+l])
|
||||
return s.String(), off + l, nil
|
||||
}
|
||||
|
||||
func packString(s string, msg []byte, off int) (int, error) {
|
||||
|
@ -363,6 +376,22 @@ func packStringHex(s string, msg []byte, off int) (int, error) {
|
|||
return off, nil
|
||||
}
|
||||
|
||||
func unpackStringAny(msg []byte, off, end int) (string, int, error) {
|
||||
if end > len(msg) {
|
||||
return "", len(msg), &Error{err: "overflow unpacking anything"}
|
||||
}
|
||||
return string(msg[off:end]), end, nil
|
||||
}
|
||||
|
||||
func packStringAny(s string, msg []byte, off int) (int, error) {
|
||||
if off+len(s) > len(msg) {
|
||||
return len(msg), &Error{err: "overflow packing anything"}
|
||||
}
|
||||
copy(msg[off:off+len(s)], s)
|
||||
off += len(s)
|
||||
return off, nil
|
||||
}
|
||||
|
||||
func unpackStringTxt(msg []byte, off int) ([]string, int, error) {
|
||||
txt, off, err := unpackTxt(msg, off)
|
||||
if err != nil {
|
||||
|
@ -383,7 +412,7 @@ func packStringTxt(s []string, msg []byte, off int) (int, error) {
|
|||
func unpackDataOpt(msg []byte, off int) ([]EDNS0, int, error) {
|
||||
var edns []EDNS0
|
||||
Option:
|
||||
code := uint16(0)
|
||||
var code uint16
|
||||
if off+4 > len(msg) {
|
||||
return nil, len(msg), &Error{err: "overflow unpacking opt"}
|
||||
}
|
||||
|
@ -478,7 +507,7 @@ Option:
|
|||
func packDataOpt(options []EDNS0, msg []byte, off int) (int, error) {
|
||||
for _, el := range options {
|
||||
b, err := el.pack()
|
||||
if err != nil || off+3 > len(msg) {
|
||||
if err != nil || off+4 > len(msg) {
|
||||
return len(msg), &Error{err: "overflow packing opt"}
|
||||
}
|
||||
binary.BigEndian.PutUint16(msg[off:], el.Option()) // Option code
|
||||
|
@ -537,8 +566,7 @@ func unpackDataNsec(msg []byte, off int) ([]uint16, int, error) {
|
|||
}
|
||||
|
||||
// Walk the bytes in the window and extract the type bits
|
||||
for j := 0; j < length; j++ {
|
||||
b := msg[off+j]
|
||||
for j, b := range msg[off : off+length] {
|
||||
// Check the bits one by one, and set the type
|
||||
if b&0x80 == 0x80 {
|
||||
nsec = append(nsec, uint16(window*256+j*8+0))
|
||||
|
@ -571,13 +599,35 @@ func unpackDataNsec(msg []byte, off int) ([]uint16, int, error) {
|
|||
return nsec, off, nil
|
||||
}
|
||||
|
||||
// typeBitMapLen is a helper function which computes the "maximum" length of
|
||||
// a the NSEC Type BitMap field.
|
||||
func typeBitMapLen(bitmap []uint16) int {
|
||||
var l int
|
||||
var lastwindow, lastlength uint16
|
||||
for _, t := range bitmap {
|
||||
window := t / 256
|
||||
length := (t-window*256)/8 + 1
|
||||
if window > lastwindow && lastlength != 0 { // New window, jump to the new offset
|
||||
l += int(lastlength) + 2
|
||||
lastlength = 0
|
||||
}
|
||||
if window < lastwindow || length < lastlength {
|
||||
// packDataNsec would return Error{err: "nsec bits out of order"} here, but
|
||||
// when computing the length, we want do be liberal.
|
||||
continue
|
||||
}
|
||||
lastwindow, lastlength = window, length
|
||||
}
|
||||
l += int(lastlength) + 2
|
||||
return l
|
||||
}
|
||||
|
||||
func packDataNsec(bitmap []uint16, msg []byte, off int) (int, error) {
|
||||
if len(bitmap) == 0 {
|
||||
return off, nil
|
||||
}
|
||||
var lastwindow, lastlength uint16
|
||||
for j := 0; j < len(bitmap); j++ {
|
||||
t := bitmap[j]
|
||||
for _, t := range bitmap {
|
||||
window := t / 256
|
||||
length := (t-window*256)/8 + 1
|
||||
if window > lastwindow && lastlength != 0 { // New window, jump to the new offset
|
||||
|
@ -621,10 +671,10 @@ func unpackDataDomainNames(msg []byte, off, end int) ([]string, int, error) {
|
|||
return servers, off, nil
|
||||
}
|
||||
|
||||
func packDataDomainNames(names []string, msg []byte, off int, compression map[string]int, compress bool) (int, error) {
|
||||
func packDataDomainNames(names []string, msg []byte, off int, compression compressionMap, compress bool) (int, error) {
|
||||
var err error
|
||||
for j := 0; j < len(names); j++ {
|
||||
off, err = PackDomainName(names[j], msg, off, compression, false && compress)
|
||||
for _, name := range names {
|
||||
off, err = packDomainName(name, msg, off, compression, compress)
|
||||
if err != nil {
|
||||
return len(msg), err
|
||||
}
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
package dns
|
||||
|
||||
// Truncate ensures the reply message will fit into the requested buffer
|
||||
// size by removing records that exceed the requested size.
|
||||
//
|
||||
// It will first check if the reply fits without compression and then with
|
||||
// compression. If it won't fit with compression, Truncate then walks the
|
||||
// record adding as many records as possible without exceeding the
|
||||
// requested buffer size.
|
||||
//
|
||||
// The TC bit will be set if any records were excluded from the message.
|
||||
// This indicates to that the client should retry over TCP.
|
||||
//
|
||||
// According to RFC 2181, the TC bit should only be set if not all of the
|
||||
// "required" RRs can be included in the response. Unfortunately, we have
|
||||
// no way of knowing which RRs are required so we set the TC bit if any RR
|
||||
// had to be omitted from the response.
|
||||
//
|
||||
// The appropriate buffer size can be retrieved from the requests OPT
|
||||
// record, if present, and is transport specific otherwise. dns.MinMsgSize
|
||||
// should be used for UDP requests without an OPT record, and
|
||||
// dns.MaxMsgSize for TCP requests without an OPT record.
|
||||
func (dns *Msg) Truncate(size int) {
|
||||
if dns.IsTsig() != nil {
|
||||
// To simplify this implementation, we don't perform
|
||||
// truncation on responses with a TSIG record.
|
||||
return
|
||||
}
|
||||
|
||||
// RFC 6891 mandates that the payload size in an OPT record
|
||||
// less than 512 bytes must be treated as equal to 512 bytes.
|
||||
//
|
||||
// For ease of use, we impose that restriction here.
|
||||
if size < 512 {
|
||||
size = 512
|
||||
}
|
||||
|
||||
l := msgLenWithCompressionMap(dns, nil) // uncompressed length
|
||||
if l <= size {
|
||||
// Don't waste effort compressing this message.
|
||||
dns.Compress = false
|
||||
return
|
||||
}
|
||||
|
||||
dns.Compress = true
|
||||
|
||||
edns0 := dns.popEdns0()
|
||||
if edns0 != nil {
|
||||
// Account for the OPT record that gets added at the end,
|
||||
// by subtracting that length from our budget.
|
||||
//
|
||||
// The EDNS(0) OPT record must have the root domain and
|
||||
// it's length is thus unaffected by compression.
|
||||
size -= Len(edns0)
|
||||
}
|
||||
|
||||
compression := make(map[string]struct{})
|
||||
|
||||
l = headerSize
|
||||
for _, r := range dns.Question {
|
||||
l += r.len(l, compression)
|
||||
}
|
||||
|
||||
var numAnswer int
|
||||
if l < size {
|
||||
l, numAnswer = truncateLoop(dns.Answer, size, l, compression)
|
||||
}
|
||||
|
||||
var numNS int
|
||||
if l < size {
|
||||
l, numNS = truncateLoop(dns.Ns, size, l, compression)
|
||||
}
|
||||
|
||||
var numExtra int
|
||||
if l < size {
|
||||
l, numExtra = truncateLoop(dns.Extra, size, l, compression)
|
||||
}
|
||||
|
||||
// See the function documentation for when we set this.
|
||||
dns.Truncated = len(dns.Answer) > numAnswer ||
|
||||
len(dns.Ns) > numNS || len(dns.Extra) > numExtra
|
||||
|
||||
dns.Answer = dns.Answer[:numAnswer]
|
||||
dns.Ns = dns.Ns[:numNS]
|
||||
dns.Extra = dns.Extra[:numExtra]
|
||||
|
||||
if edns0 != nil {
|
||||
// Add the OPT record back onto the additional section.
|
||||
dns.Extra = append(dns.Extra, edns0)
|
||||
}
|
||||
}
|
||||
|
||||
func truncateLoop(rrs []RR, size, l int, compression map[string]struct{}) (int, int) {
|
||||
for i, r := range rrs {
|
||||
if r == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
l += r.len(l, compression)
|
||||
if l > size {
|
||||
// Return size, rather than l prior to this record,
|
||||
// to prevent any further records being added.
|
||||
return size, i
|
||||
}
|
||||
if l == size {
|
||||
return l, i + 1
|
||||
}
|
||||
}
|
||||
|
||||
return l, len(rrs)
|
||||
}
|
|
@ -2,49 +2,44 @@ package dns
|
|||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"hash"
|
||||
"encoding/hex"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type saltWireFmt struct {
|
||||
Salt string `dns:"size-hex"`
|
||||
}
|
||||
|
||||
// HashName hashes a string (label) according to RFC 5155. It returns the hashed string in uppercase.
|
||||
func HashName(label string, ha uint8, iter uint16, salt string) string {
|
||||
saltwire := new(saltWireFmt)
|
||||
saltwire.Salt = salt
|
||||
wire := make([]byte, DefaultMsgSize)
|
||||
n, err := packSaltWire(saltwire, wire)
|
||||
if ha != SHA1 {
|
||||
return ""
|
||||
}
|
||||
|
||||
wireSalt := make([]byte, hex.DecodedLen(len(salt)))
|
||||
n, err := packStringHex(salt, wireSalt, 0)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
wire = wire[:n]
|
||||
wireSalt = wireSalt[:n]
|
||||
|
||||
name := make([]byte, 255)
|
||||
off, err := PackDomainName(strings.ToLower(label), name, 0, nil, false)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
name = name[:off]
|
||||
var s hash.Hash
|
||||
switch ha {
|
||||
case SHA1:
|
||||
s = sha1.New()
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
|
||||
s := sha1.New()
|
||||
// k = 0
|
||||
s.Write(name)
|
||||
s.Write(wire)
|
||||
s.Write(wireSalt)
|
||||
nsec3 := s.Sum(nil)
|
||||
|
||||
// k > 0
|
||||
for k := uint16(0); k < iter; k++ {
|
||||
s.Reset()
|
||||
s.Write(nsec3)
|
||||
s.Write(wire)
|
||||
s.Write(wireSalt)
|
||||
nsec3 = s.Sum(nsec3[:0])
|
||||
}
|
||||
|
||||
return toBase32(nsec3)
|
||||
}
|
||||
|
||||
|
@ -63,8 +58,10 @@ func (rr *NSEC3) Cover(name string) bool {
|
|||
}
|
||||
|
||||
nextHash := rr.NextDomain
|
||||
if ownerHash == nextHash { // empty interval
|
||||
return false
|
||||
|
||||
// if empty interval found, try cover wildcard hashes so nameHash shouldn't match with ownerHash
|
||||
if ownerHash == nextHash && nameHash != ownerHash { // empty interval
|
||||
return true
|
||||
}
|
||||
if ownerHash > nextHash { // end of zone
|
||||
if nameHash > ownerHash { // covered since there is nothing after ownerHash
|
||||
|
@ -96,11 +93,3 @@ func (rr *NSEC3) Match(name string) bool {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func packSaltWire(sw *saltWireFmt, msg []byte) (int, error) {
|
||||
off, err := packStringHex(sw.Salt, msg, 0)
|
||||
if err != nil {
|
||||
return off, err
|
||||
}
|
||||
return off, nil
|
||||
}
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
import "strings"
|
||||
|
||||
// PrivateRdata is an interface used for implementing "Private Use" RR types, see
|
||||
// RFC 6895. This allows one to experiment with new RR types, without requesting an
|
||||
|
@ -18,7 +15,7 @@ type PrivateRdata interface {
|
|||
// Unpack is used when unpacking a private RR from a buffer.
|
||||
// TODO(miek): diff. signature than Pack, see edns0.go for instance.
|
||||
Unpack([]byte) (int, error)
|
||||
// Copy copies the Rdata.
|
||||
// Copy copies the Rdata into the PrivateRdata argument.
|
||||
Copy(PrivateRdata) error
|
||||
// Len returns the length in octets of the Rdata.
|
||||
Len() int
|
||||
|
@ -29,21 +26,8 @@ type PrivateRdata interface {
|
|||
type PrivateRR struct {
|
||||
Hdr RR_Header
|
||||
Data PrivateRdata
|
||||
}
|
||||
|
||||
func mkPrivateRR(rrtype uint16) *PrivateRR {
|
||||
// Panics if RR is not an instance of PrivateRR.
|
||||
rrfunc, ok := TypeToRR[rrtype]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("dns: invalid operation with Private RR type %d", rrtype))
|
||||
}
|
||||
|
||||
anyrr := rrfunc()
|
||||
switch rr := anyrr.(type) {
|
||||
case *PrivateRR:
|
||||
return rr
|
||||
}
|
||||
panic(fmt.Sprintf("dns: RR is not a PrivateRR, TypeToRR[%d] generator returned %T", rrtype, anyrr))
|
||||
generator func() PrivateRdata // for copy
|
||||
}
|
||||
|
||||
// Header return the RR header of r.
|
||||
|
@ -52,86 +36,71 @@ func (r *PrivateRR) Header() *RR_Header { return &r.Hdr }
|
|||
func (r *PrivateRR) String() string { return r.Hdr.String() + r.Data.String() }
|
||||
|
||||
// Private len and copy parts to satisfy RR interface.
|
||||
func (r *PrivateRR) len() int { return r.Hdr.len() + r.Data.Len() }
|
||||
func (r *PrivateRR) len(off int, compression map[string]struct{}) int {
|
||||
l := r.Hdr.len(off, compression)
|
||||
l += r.Data.Len()
|
||||
return l
|
||||
}
|
||||
|
||||
func (r *PrivateRR) copy() RR {
|
||||
// make new RR like this:
|
||||
rr := mkPrivateRR(r.Hdr.Rrtype)
|
||||
rr.Hdr = r.Hdr
|
||||
rr := &PrivateRR{r.Hdr, r.generator(), r.generator}
|
||||
|
||||
err := r.Data.Copy(rr.Data)
|
||||
if err != nil {
|
||||
panic("dns: got value that could not be used to copy Private rdata")
|
||||
if err := r.Data.Copy(rr.Data); err != nil {
|
||||
panic("dns: got value that could not be used to copy Private rdata: " + err.Error())
|
||||
}
|
||||
|
||||
return rr
|
||||
}
|
||||
func (r *PrivateRR) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
|
||||
off, err := r.Hdr.pack(msg, off, compression, compress)
|
||||
if err != nil {
|
||||
return off, err
|
||||
}
|
||||
headerEnd := off
|
||||
|
||||
func (r *PrivateRR) pack(msg []byte, off int, compression compressionMap, compress bool) (int, error) {
|
||||
n, err := r.Data.Pack(msg[off:])
|
||||
if err != nil {
|
||||
return len(msg), err
|
||||
}
|
||||
off += n
|
||||
r.Header().Rdlength = uint16(off - headerEnd)
|
||||
return off, nil
|
||||
}
|
||||
|
||||
func (r *PrivateRR) unpack(msg []byte, off int) (int, error) {
|
||||
off1, err := r.Data.Unpack(msg[off:])
|
||||
off += off1
|
||||
return off, err
|
||||
}
|
||||
|
||||
func (r *PrivateRR) parse(c *zlexer, origin string) *ParseError {
|
||||
var l lex
|
||||
text := make([]string, 0, 2) // could be 0..N elements, median is probably 1
|
||||
Fetch:
|
||||
for {
|
||||
// TODO(miek): we could also be returning _QUOTE, this might or might not
|
||||
// be an issue (basically parsing TXT becomes hard)
|
||||
switch l, _ = c.Next(); l.value {
|
||||
case zNewline, zEOF:
|
||||
break Fetch
|
||||
case zString:
|
||||
text = append(text, l.token)
|
||||
}
|
||||
}
|
||||
|
||||
err := r.Data.Parse(text)
|
||||
if err != nil {
|
||||
return &ParseError{"", err.Error(), l}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r1 *PrivateRR) isDuplicate(r2 RR) bool { return false }
|
||||
|
||||
// PrivateHandle registers a private resource record type. It requires
|
||||
// string and numeric representation of private RR type and generator function as argument.
|
||||
func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) {
|
||||
rtypestr = strings.ToUpper(rtypestr)
|
||||
|
||||
TypeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator()} }
|
||||
TypeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator(), generator} }
|
||||
TypeToString[rtype] = rtypestr
|
||||
StringToType[rtypestr] = rtype
|
||||
|
||||
typeToUnpack[rtype] = func(h RR_Header, msg []byte, off int) (RR, int, error) {
|
||||
if noRdata(h) {
|
||||
return &h, off, nil
|
||||
}
|
||||
var err error
|
||||
|
||||
rr := mkPrivateRR(h.Rrtype)
|
||||
rr.Hdr = h
|
||||
|
||||
off1, err := rr.Data.Unpack(msg[off:])
|
||||
off += off1
|
||||
if err != nil {
|
||||
return rr, off, err
|
||||
}
|
||||
return rr, off, err
|
||||
}
|
||||
|
||||
setPrivateRR := func(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
|
||||
rr := mkPrivateRR(h.Rrtype)
|
||||
rr.Hdr = h
|
||||
|
||||
var l lex
|
||||
text := make([]string, 0, 2) // could be 0..N elements, median is probably 1
|
||||
Fetch:
|
||||
for {
|
||||
// TODO(miek): we could also be returning _QUOTE, this might or might not
|
||||
// be an issue (basically parsing TXT becomes hard)
|
||||
switch l, _ = c.Next(); l.value {
|
||||
case zNewline, zEOF:
|
||||
break Fetch
|
||||
case zString:
|
||||
text = append(text, l.token)
|
||||
}
|
||||
}
|
||||
|
||||
err := rr.Data.Parse(text)
|
||||
if err != nil {
|
||||
return nil, &ParseError{f, err.Error(), l}, ""
|
||||
}
|
||||
|
||||
return rr, nil, ""
|
||||
}
|
||||
|
||||
typeToparserFunc[rtype] = parserFunc{setPrivateRR, true}
|
||||
}
|
||||
|
||||
// PrivateHandleRemove removes definitions required to support private RR type.
|
||||
|
@ -140,8 +109,6 @@ func PrivateHandleRemove(rtype uint16) {
|
|||
if ok {
|
||||
delete(TypeToRR, rtype)
|
||||
delete(TypeToString, rtype)
|
||||
delete(typeToparserFunc, rtype)
|
||||
delete(StringToType, rtypestr)
|
||||
delete(typeToUnpack, rtype)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
package dns
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
// rawSetRdlength sets the rdlength in the header of
|
||||
// the RR. The offset 'off' must be positioned at the
|
||||
// start of the header of the RR, 'end' must be the
|
||||
// end of the RR.
|
||||
func rawSetRdlength(msg []byte, off, end int) bool {
|
||||
l := len(msg)
|
||||
Loop:
|
||||
for {
|
||||
if off+1 > l {
|
||||
return false
|
||||
}
|
||||
c := int(msg[off])
|
||||
off++
|
||||
switch c & 0xC0 {
|
||||
case 0x00:
|
||||
if c == 0x00 {
|
||||
// End of the domainname
|
||||
break Loop
|
||||
}
|
||||
if off+c > l {
|
||||
return false
|
||||
}
|
||||
off += c
|
||||
|
||||
case 0xC0:
|
||||
// pointer, next byte included, ends domainname
|
||||
off++
|
||||
break Loop
|
||||
}
|
||||
}
|
||||
// The domainname has been seen, we at the start of the fixed part in the header.
|
||||
// Type is 2 bytes, class is 2 bytes, ttl 4 and then 2 bytes for the length.
|
||||
off += 2 + 2 + 4
|
||||
if off+2 > l {
|
||||
return false
|
||||
}
|
||||
//off+1 is the end of the header, 'end' is the end of the rr
|
||||
//so 'end' - 'off+2' is the length of the rdata
|
||||
rdatalen := end - (off + 2)
|
||||
if rdatalen > 0xFFFF {
|
||||
return false
|
||||
}
|
||||
binary.BigEndian.PutUint16(msg[off:], uint16(rdatalen))
|
||||
return true
|
||||
}
|
|
@ -12,6 +12,20 @@ var StringToOpcode = reverseInt(OpcodeToString)
|
|||
// StringToRcode is a map of rcodes to strings.
|
||||
var StringToRcode = reverseInt(RcodeToString)
|
||||
|
||||
func init() {
|
||||
// Preserve previous NOTIMP typo, see github.com/miekg/dns/issues/733.
|
||||
StringToRcode["NOTIMPL"] = RcodeNotImplemented
|
||||
}
|
||||
|
||||
// StringToAlgorithm is the reverse of AlgorithmToString.
|
||||
var StringToAlgorithm = reverseInt8(AlgorithmToString)
|
||||
|
||||
// StringToHash is a map of names to hash IDs.
|
||||
var StringToHash = reverseInt8(HashToString)
|
||||
|
||||
// StringToCertType is the reverseof CertTypeToString.
|
||||
var StringToCertType = reverseInt16(CertTypeToString)
|
||||
|
||||
// Reverse a map
|
||||
func reverseInt8(m map[uint8]string) map[string]uint8 {
|
||||
n := make(map[string]uint8, len(m))
|
||||
|
|
|
@ -15,10 +15,11 @@ func Dedup(rrs []RR, m map[string]RR) []RR {
|
|||
for _, r := range rrs {
|
||||
key := normalizedString(r)
|
||||
keys = append(keys, &key)
|
||||
if _, ok := m[key]; ok {
|
||||
if mr, ok := m[key]; ok {
|
||||
// Shortest TTL wins.
|
||||
if m[key].Header().Ttl > r.Header().Ttl {
|
||||
m[key].Header().Ttl = r.Header().Ttl
|
||||
rh, mrh := r.Header(), mr.Header()
|
||||
if mrh.Ttl > rh.Ttl {
|
||||
mrh.Ttl = rh.Ttl
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -79,13 +79,12 @@ func (e *ParseError) Error() (s string) {
|
|||
}
|
||||
|
||||
type lex struct {
|
||||
token string // text of the token
|
||||
err bool // when true, token text has lexer error
|
||||
value uint8 // value: zString, _BLANK, etc.
|
||||
torc uint16 // type or class as parsed in the lexer, we only need to look this up in the grammar
|
||||
line int // line in the file
|
||||
column int // column in the file
|
||||
comment string // any comment text seen
|
||||
token string // text of the token
|
||||
err bool // when true, token text has lexer error
|
||||
value uint8 // value: zString, _BLANK, etc.
|
||||
torc uint16 // type or class as parsed in the lexer, we only need to look this up in the grammar
|
||||
line int // line in the file
|
||||
column int // column in the file
|
||||
}
|
||||
|
||||
// Token holds the token that are returned when a zone file is parsed.
|
||||
|
@ -135,7 +134,7 @@ func ReadRR(r io.Reader, file string) (RR, error) {
|
|||
}
|
||||
|
||||
// ParseZone reads a RFC 1035 style zonefile from r. It returns
|
||||
// *Tokens on the returned channel, each consisting of either a
|
||||
// Tokens on the returned channel, each consisting of either a
|
||||
// parsed RR and optional comment or a nil RR and an error. The
|
||||
// channel is closed by ParseZone when the end of r is reached.
|
||||
//
|
||||
|
@ -144,7 +143,8 @@ func ReadRR(r io.Reader, file string) (RR, error) {
|
|||
// origin, as if the file would start with an $ORIGIN directive.
|
||||
//
|
||||
// The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are all
|
||||
// supported.
|
||||
// supported. Note that $GENERATE's range support up to a maximum of
|
||||
// of 65535 steps.
|
||||
//
|
||||
// Basic usage pattern when reading from a string (z) containing the
|
||||
// zone data:
|
||||
|
@ -204,6 +204,7 @@ func parseZone(r io.Reader, origin, file string, t chan *Token) {
|
|||
//
|
||||
// The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are all
|
||||
// supported. Although $INCLUDE is disabled by default.
|
||||
// Note that $GENERATE's range support up to a maximum of 65535 steps.
|
||||
//
|
||||
// Basic usage pattern when reading from a string (z) containing the
|
||||
// zone data:
|
||||
|
@ -244,8 +245,6 @@ type ZoneParser struct {
|
|||
sub *ZoneParser
|
||||
osFile *os.File
|
||||
|
||||
com string
|
||||
|
||||
includeDepth uint8
|
||||
|
||||
includeAllowed bool
|
||||
|
@ -318,12 +317,19 @@ func (zp *ZoneParser) setParseError(err string, l lex) (RR, bool) {
|
|||
// Comment returns an optional text comment that occurred alongside
|
||||
// the RR.
|
||||
func (zp *ZoneParser) Comment() string {
|
||||
return zp.com
|
||||
if zp.parseErr != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
if zp.sub != nil {
|
||||
return zp.sub.Comment()
|
||||
}
|
||||
|
||||
return zp.c.Comment()
|
||||
}
|
||||
|
||||
func (zp *ZoneParser) subNext() (RR, bool) {
|
||||
if rr, ok := zp.sub.Next(); ok {
|
||||
zp.com = zp.sub.com
|
||||
return rr, true
|
||||
}
|
||||
|
||||
|
@ -347,8 +353,6 @@ func (zp *ZoneParser) subNext() (RR, bool) {
|
|||
// error. After Next returns (nil, false), the Err method will return
|
||||
// any error that occurred during parsing.
|
||||
func (zp *ZoneParser) Next() (RR, bool) {
|
||||
zp.com = ""
|
||||
|
||||
if zp.parseErr != nil {
|
||||
return nil, false
|
||||
}
|
||||
|
@ -501,9 +505,8 @@ func (zp *ZoneParser) Next() (RR, bool) {
|
|||
return zp.setParseError("expecting $TTL value, not this...", l)
|
||||
}
|
||||
|
||||
if e, _ := slurpRemainder(zp.c, zp.file); e != nil {
|
||||
zp.parseErr = e
|
||||
return nil, false
|
||||
if err := slurpRemainder(zp.c); err != nil {
|
||||
return zp.setParseError(err.err, err.lex)
|
||||
}
|
||||
|
||||
ttl, ok := stringToTTL(l.token)
|
||||
|
@ -525,9 +528,8 @@ func (zp *ZoneParser) Next() (RR, bool) {
|
|||
return zp.setParseError("expecting $ORIGIN value, not this...", l)
|
||||
}
|
||||
|
||||
if e, _ := slurpRemainder(zp.c, zp.file); e != nil {
|
||||
zp.parseErr = e
|
||||
return nil, false
|
||||
if err := slurpRemainder(zp.c); err != nil {
|
||||
return zp.setParseError(err.err, err.lex)
|
||||
}
|
||||
|
||||
name, ok := toAbsoluteName(l.token, zp.origin)
|
||||
|
@ -648,20 +650,44 @@ func (zp *ZoneParser) Next() (RR, bool) {
|
|||
|
||||
st = zExpectRdata
|
||||
case zExpectRdata:
|
||||
r, e, c1 := setRR(*h, zp.c, zp.origin, zp.file)
|
||||
if e != nil {
|
||||
// If e.lex is nil than we have encounter a unknown RR type
|
||||
// in that case we substitute our current lex token
|
||||
if e.lex.token == "" && e.lex.value == 0 {
|
||||
e.lex = l // Uh, dirty
|
||||
}
|
||||
|
||||
zp.parseErr = e
|
||||
return nil, false
|
||||
var rr RR
|
||||
if newFn, ok := TypeToRR[h.Rrtype]; ok && canParseAsRR(h.Rrtype) {
|
||||
rr = newFn()
|
||||
*rr.Header() = *h
|
||||
} else {
|
||||
rr = &RFC3597{Hdr: *h}
|
||||
}
|
||||
|
||||
zp.com = c1
|
||||
return r, true
|
||||
_, isPrivate := rr.(*PrivateRR)
|
||||
if !isPrivate && zp.c.Peek().token == "" {
|
||||
// This is a dynamic update rr.
|
||||
|
||||
// TODO(tmthrgd): Previously slurpRemainder was only called
|
||||
// for certain RR types, which may have been important.
|
||||
if err := slurpRemainder(zp.c); err != nil {
|
||||
return zp.setParseError(err.err, err.lex)
|
||||
}
|
||||
|
||||
return rr, true
|
||||
} else if l.value == zNewline {
|
||||
return zp.setParseError("unexpected newline", l)
|
||||
}
|
||||
|
||||
if err := rr.parse(zp.c, zp.origin); err != nil {
|
||||
// err is a concrete *ParseError without the file field set.
|
||||
// The setParseError call below will construct a new
|
||||
// *ParseError with file set to zp.file.
|
||||
|
||||
// If err.lex is nil than we have encounter an unknown RR type
|
||||
// in that case we substitute our current lex token.
|
||||
if err.lex == (lex{}) {
|
||||
return zp.setParseError(err.err, l)
|
||||
}
|
||||
|
||||
return zp.setParseError(err.err, err.lex)
|
||||
}
|
||||
|
||||
return rr, true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -670,6 +696,18 @@ func (zp *ZoneParser) Next() (RR, bool) {
|
|||
return nil, false
|
||||
}
|
||||
|
||||
// canParseAsRR returns true if the record type can be parsed as a
|
||||
// concrete RR. It blacklists certain record types that must be parsed
|
||||
// according to RFC 3597 because they lack a presentation format.
|
||||
func canParseAsRR(rrtype uint16) bool {
|
||||
switch rrtype {
|
||||
case TypeANY, TypeNULL, TypeOPT, TypeTSIG:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
type zlexer struct {
|
||||
br io.ByteReader
|
||||
|
||||
|
@ -678,9 +716,11 @@ type zlexer struct {
|
|||
line int
|
||||
column int
|
||||
|
||||
com string
|
||||
comBuf string
|
||||
comment string
|
||||
|
||||
l lex
|
||||
l lex
|
||||
cachedL *lex
|
||||
|
||||
brace int
|
||||
quote bool
|
||||
|
@ -746,13 +786,37 @@ func (zl *zlexer) readByte() (byte, bool) {
|
|||
return c, true
|
||||
}
|
||||
|
||||
func (zl *zlexer) Peek() lex {
|
||||
if zl.nextL {
|
||||
return zl.l
|
||||
}
|
||||
|
||||
l, ok := zl.Next()
|
||||
if !ok {
|
||||
return l
|
||||
}
|
||||
|
||||
if zl.nextL {
|
||||
// Cache l. Next returns zl.cachedL then zl.l.
|
||||
zl.cachedL = &l
|
||||
} else {
|
||||
// In this case l == zl.l, so we just tell Next to return zl.l.
|
||||
zl.nextL = true
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func (zl *zlexer) Next() (lex, bool) {
|
||||
l := &zl.l
|
||||
if zl.nextL {
|
||||
switch {
|
||||
case zl.cachedL != nil:
|
||||
l, zl.cachedL = zl.cachedL, nil
|
||||
return *l, true
|
||||
case zl.nextL:
|
||||
zl.nextL = false
|
||||
return *l, true
|
||||
}
|
||||
if l.err {
|
||||
case l.err:
|
||||
// Parsing errors should be sticky.
|
||||
return lex{value: zEOF}, false
|
||||
}
|
||||
|
@ -767,14 +831,15 @@ func (zl *zlexer) Next() (lex, bool) {
|
|||
escape bool
|
||||
)
|
||||
|
||||
if zl.com != "" {
|
||||
comi = copy(com[:], zl.com)
|
||||
zl.com = ""
|
||||
if zl.comBuf != "" {
|
||||
comi = copy(com[:], zl.comBuf)
|
||||
zl.comBuf = ""
|
||||
}
|
||||
|
||||
zl.comment = ""
|
||||
|
||||
for x, ok := zl.readByte(); ok; x, ok = zl.readByte() {
|
||||
l.line, l.column = zl.line, zl.column
|
||||
l.comment = ""
|
||||
|
||||
if stri >= len(str) {
|
||||
l.token = "token length insufficient for parsing"
|
||||
|
@ -898,20 +963,25 @@ func (zl *zlexer) Next() (lex, bool) {
|
|||
}
|
||||
|
||||
zl.commt = true
|
||||
zl.com = ""
|
||||
zl.comBuf = ""
|
||||
|
||||
if comi > 1 {
|
||||
// A newline was previously seen inside a comment that
|
||||
// was inside braces and we delayed adding it until now.
|
||||
com[comi] = ' ' // convert newline to space
|
||||
comi++
|
||||
if comi >= len(com) {
|
||||
l.token = "comment length insufficient for parsing"
|
||||
l.err = true
|
||||
return *l, true
|
||||
}
|
||||
}
|
||||
|
||||
com[comi] = ';'
|
||||
comi++
|
||||
|
||||
if stri > 0 {
|
||||
zl.com = string(com[:comi])
|
||||
zl.comBuf = string(com[:comi])
|
||||
|
||||
l.value = zString
|
||||
l.token = string(str[:stri])
|
||||
|
@ -947,11 +1017,11 @@ func (zl *zlexer) Next() (lex, bool) {
|
|||
|
||||
l.value = zNewline
|
||||
l.token = "\n"
|
||||
l.comment = string(com[:comi])
|
||||
zl.comment = string(com[:comi])
|
||||
return *l, true
|
||||
}
|
||||
|
||||
zl.com = string(com[:comi])
|
||||
zl.comBuf = string(com[:comi])
|
||||
break
|
||||
}
|
||||
|
||||
|
@ -977,9 +1047,9 @@ func (zl *zlexer) Next() (lex, bool) {
|
|||
|
||||
l.value = zNewline
|
||||
l.token = "\n"
|
||||
l.comment = zl.com
|
||||
|
||||
zl.com = ""
|
||||
zl.comment = zl.comBuf
|
||||
zl.comBuf = ""
|
||||
zl.rrtype = false
|
||||
zl.owner = true
|
||||
|
||||
|
@ -1115,7 +1185,7 @@ func (zl *zlexer) Next() (lex, bool) {
|
|||
// Send remainder of com
|
||||
l.value = zNewline
|
||||
l.token = "\n"
|
||||
l.comment = string(com[:comi])
|
||||
zl.comment = string(com[:comi])
|
||||
|
||||
if retL != (lex{}) {
|
||||
zl.nextL = true
|
||||
|
@ -1126,7 +1196,6 @@ func (zl *zlexer) Next() (lex, bool) {
|
|||
}
|
||||
|
||||
if zl.brace != 0 {
|
||||
l.comment = "" // in case there was left over string and comment
|
||||
l.token = "unbalanced brace"
|
||||
l.err = true
|
||||
return *l, true
|
||||
|
@ -1135,6 +1204,14 @@ func (zl *zlexer) Next() (lex, bool) {
|
|||
return lex{value: zEOF}, false
|
||||
}
|
||||
|
||||
func (zl *zlexer) Comment() string {
|
||||
if zl.l.err {
|
||||
return ""
|
||||
}
|
||||
|
||||
return zl.comment
|
||||
}
|
||||
|
||||
// Extract the class number from CLASSxx
|
||||
func classToInt(token string) (uint16, bool) {
|
||||
offset := 5
|
||||
|
@ -1163,8 +1240,7 @@ func typeToInt(token string) (uint16, bool) {
|
|||
|
||||
// stringToTTL parses things like 2w, 2m, etc, and returns the time in seconds.
|
||||
func stringToTTL(token string) (uint32, bool) {
|
||||
s := uint32(0)
|
||||
i := uint32(0)
|
||||
var s, i uint32
|
||||
for _, c := range token {
|
||||
switch c {
|
||||
case 's', 'S':
|
||||
|
@ -1252,7 +1328,7 @@ func toAbsoluteName(name, origin string) (absolute string, ok bool) {
|
|||
}
|
||||
|
||||
// check if name is already absolute
|
||||
if name[len(name)-1] == '.' {
|
||||
if IsFqdn(name) {
|
||||
return name, true
|
||||
}
|
||||
|
||||
|
@ -1292,24 +1368,21 @@ func locCheckEast(token string, longitude uint32) (uint32, bool) {
|
|||
return longitude, false
|
||||
}
|
||||
|
||||
// "Eat" the rest of the "line". Return potential comments
|
||||
func slurpRemainder(c *zlexer, f string) (*ParseError, string) {
|
||||
// "Eat" the rest of the "line"
|
||||
func slurpRemainder(c *zlexer) *ParseError {
|
||||
l, _ := c.Next()
|
||||
com := ""
|
||||
switch l.value {
|
||||
case zBlank:
|
||||
l, _ = c.Next()
|
||||
com = l.comment
|
||||
if l.value != zNewline && l.value != zEOF {
|
||||
return &ParseError{f, "garbage after rdata", l}, ""
|
||||
return &ParseError{"", "garbage after rdata", l}
|
||||
}
|
||||
case zNewline:
|
||||
com = l.comment
|
||||
case zEOF:
|
||||
default:
|
||||
return &ParseError{f, "garbage after rdata", l}, ""
|
||||
return &ParseError{"", "garbage after rdata", l}
|
||||
}
|
||||
return nil, com
|
||||
return nil
|
||||
}
|
||||
|
||||
// Parse a 64 bit-like ipv6 address: "0014:4fff:ff20:ee64"
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -36,33 +36,9 @@ func (mux *ServeMux) match(q string, t uint16) Handler {
|
|||
return nil
|
||||
}
|
||||
|
||||
q = strings.ToLower(q)
|
||||
|
||||
var handler Handler
|
||||
|
||||
// TODO(tmthrgd): Once https://go-review.googlesource.com/c/go/+/137575
|
||||
// lands in a go release, replace the following with strings.ToLower.
|
||||
var sb strings.Builder
|
||||
for i := 0; i < len(q); i++ {
|
||||
c := q[i]
|
||||
if !(c >= 'A' && c <= 'Z') {
|
||||
continue
|
||||
}
|
||||
|
||||
sb.Grow(len(q))
|
||||
sb.WriteString(q[:i])
|
||||
|
||||
for ; i < len(q); i++ {
|
||||
c := q[i]
|
||||
if c >= 'A' && c <= 'Z' {
|
||||
c += 'a' - 'A'
|
||||
}
|
||||
|
||||
sb.WriteByte(c)
|
||||
}
|
||||
|
||||
q = sb.String()
|
||||
break
|
||||
}
|
||||
|
||||
for off, end := 0, false; !end; off, end = NextLabel(q, off) {
|
||||
if h, ok := mux.z[q[off:]]; ok {
|
||||
if t != TypeDS {
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/binary"
|
||||
|
@ -12,26 +11,12 @@ import (
|
|||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Default maximum number of TCP queries before we close the socket.
|
||||
const maxTCPQueries = 128
|
||||
|
||||
// The maximum number of idle workers.
|
||||
//
|
||||
// This controls the maximum number of workers that are allowed to stay
|
||||
// idle waiting for incoming requests before being torn down.
|
||||
//
|
||||
// If this limit is reached, the server will just keep spawning new
|
||||
// workers (goroutines) for each incoming request. In this case, each
|
||||
// worker will only be used for a single request.
|
||||
const maxIdleWorkersCount = 10000
|
||||
|
||||
// The maximum length of time a worker may idle for before being destroyed.
|
||||
const idleWorkerTimeout = 10 * time.Second
|
||||
|
||||
// aLongTimeAgo is a non-zero time, far in the past, used for
|
||||
// immediate cancelation of network operations.
|
||||
var aLongTimeAgo = time.Unix(1, 0)
|
||||
|
@ -81,7 +66,7 @@ type ConnectionStater interface {
|
|||
}
|
||||
|
||||
type response struct {
|
||||
msg []byte
|
||||
closed bool // connection has been closed
|
||||
hijacked bool // connection has been hijacked by handler
|
||||
tsigTimersOnly bool
|
||||
tsigStatus error
|
||||
|
@ -91,7 +76,6 @@ type response struct {
|
|||
tcp net.Conn // i/o connection if TCP was used
|
||||
udpSession *SessionUDP // oob data to get egress interface right
|
||||
writer Writer // writer to output the raw DNS bits
|
||||
wg *sync.WaitGroup // for gracefull shutdown
|
||||
}
|
||||
|
||||
// HandleFailed returns a HandlerFunc that returns SERVFAIL for every request it gets.
|
||||
|
@ -161,11 +145,11 @@ type defaultReader struct {
|
|||
*Server
|
||||
}
|
||||
|
||||
func (dr *defaultReader) ReadTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
|
||||
func (dr defaultReader) ReadTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
|
||||
return dr.readTCP(conn, timeout)
|
||||
}
|
||||
|
||||
func (dr *defaultReader) ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) {
|
||||
func (dr defaultReader) ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) {
|
||||
return dr.readUDP(conn, timeout)
|
||||
}
|
||||
|
||||
|
@ -202,9 +186,6 @@ type Server struct {
|
|||
IdleTimeout func() time.Duration
|
||||
// Secret(s) for Tsig map[<zonename>]<base64 secret>. The zonename must be in canonical form (lowercase, fqdn, see RFC 4034 Section 6.2).
|
||||
TsigSecret map[string]string
|
||||
// Unsafe instructs the server to disregard any sanity checks and directly hand the message to
|
||||
// the handler. It will specifically not check if the query has the QR bit not set.
|
||||
Unsafe bool
|
||||
// If NotifyStartedFunc is set it is called once the server has started listening.
|
||||
NotifyStartedFunc func()
|
||||
// DecorateReader is optional, allows customization of the process that reads raw DNS messages.
|
||||
|
@ -216,11 +197,9 @@ type Server struct {
|
|||
// Whether to set the SO_REUSEPORT socket option, allowing multiple listeners to be bound to a single address.
|
||||
// It is only supported on go1.11+ and when using ListenAndServe.
|
||||
ReusePort bool
|
||||
|
||||
// UDP packet or TCP connection queue
|
||||
queue chan *response
|
||||
// Workers count
|
||||
workersCount int32
|
||||
// AcceptMsgFunc will check the incoming message and will reject it early in the process.
|
||||
// By default DefaultMsgAcceptFunc will be used.
|
||||
MsgAcceptFunc MsgAcceptFunc
|
||||
|
||||
// Shutdown handling
|
||||
lock sync.RWMutex
|
||||
|
@ -239,51 +218,6 @@ func (srv *Server) isStarted() bool {
|
|||
return started
|
||||
}
|
||||
|
||||
func (srv *Server) worker(w *response) {
|
||||
srv.serve(w)
|
||||
|
||||
for {
|
||||
count := atomic.LoadInt32(&srv.workersCount)
|
||||
if count > maxIdleWorkersCount {
|
||||
return
|
||||
}
|
||||
if atomic.CompareAndSwapInt32(&srv.workersCount, count, count+1) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
defer atomic.AddInt32(&srv.workersCount, -1)
|
||||
|
||||
inUse := false
|
||||
timeout := time.NewTimer(idleWorkerTimeout)
|
||||
defer timeout.Stop()
|
||||
LOOP:
|
||||
for {
|
||||
select {
|
||||
case w, ok := <-srv.queue:
|
||||
if !ok {
|
||||
break LOOP
|
||||
}
|
||||
inUse = true
|
||||
srv.serve(w)
|
||||
case <-timeout.C:
|
||||
if !inUse {
|
||||
break LOOP
|
||||
}
|
||||
inUse = false
|
||||
timeout.Reset(idleWorkerTimeout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (srv *Server) spawnWorker(w *response) {
|
||||
select {
|
||||
case srv.queue <- w:
|
||||
default:
|
||||
go srv.worker(w)
|
||||
}
|
||||
}
|
||||
|
||||
func makeUDPBuffer(size int) func() interface{} {
|
||||
return func() interface{} {
|
||||
return make([]byte, size)
|
||||
|
@ -291,14 +225,18 @@ func makeUDPBuffer(size int) func() interface{} {
|
|||
}
|
||||
|
||||
func (srv *Server) init() {
|
||||
srv.queue = make(chan *response)
|
||||
|
||||
srv.shutdown = make(chan struct{})
|
||||
srv.conns = make(map[net.Conn]struct{})
|
||||
|
||||
if srv.UDPSize == 0 {
|
||||
srv.UDPSize = MinMsgSize
|
||||
}
|
||||
if srv.MsgAcceptFunc == nil {
|
||||
srv.MsgAcceptFunc = DefaultMsgAcceptFunc
|
||||
}
|
||||
if srv.Handler == nil {
|
||||
srv.Handler = DefaultServeMux
|
||||
}
|
||||
|
||||
srv.udpPool.New = makeUDPBuffer(srv.UDPSize)
|
||||
}
|
||||
|
@ -324,7 +262,6 @@ func (srv *Server) ListenAndServe() error {
|
|||
}
|
||||
|
||||
srv.init()
|
||||
defer close(srv.queue)
|
||||
|
||||
switch srv.Net {
|
||||
case "tcp", "tcp4", "tcp6":
|
||||
|
@ -379,7 +316,6 @@ func (srv *Server) ActivateAndServe() error {
|
|||
}
|
||||
|
||||
srv.init()
|
||||
defer close(srv.queue)
|
||||
|
||||
pConn := srv.PacketConn
|
||||
l := srv.Listener
|
||||
|
@ -459,11 +395,10 @@ var testShutdownNotify *sync.Cond
|
|||
|
||||
// getReadTimeout is a helper func to use system timeout if server did not intend to change it.
|
||||
func (srv *Server) getReadTimeout() time.Duration {
|
||||
rtimeout := dnsTimeout
|
||||
if srv.ReadTimeout != 0 {
|
||||
rtimeout = srv.ReadTimeout
|
||||
return srv.ReadTimeout
|
||||
}
|
||||
return rtimeout
|
||||
return dnsTimeout
|
||||
}
|
||||
|
||||
// serveTCP starts a TCP listener for the server.
|
||||
|
@ -496,11 +431,7 @@ func (srv *Server) serveTCP(l net.Listener) error {
|
|||
srv.conns[rw] = struct{}{}
|
||||
srv.lock.Unlock()
|
||||
wg.Add(1)
|
||||
srv.spawnWorker(&response{
|
||||
tsigSecret: srv.TsigSecret,
|
||||
tcp: rw,
|
||||
wg: &wg,
|
||||
})
|
||||
go srv.serveTCPConn(&wg, rw)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -514,7 +445,7 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
|
|||
srv.NotifyStartedFunc()
|
||||
}
|
||||
|
||||
reader := Reader(&defaultReader{srv})
|
||||
reader := Reader(defaultReader{srv})
|
||||
if srv.DecorateReader != nil {
|
||||
reader = srv.DecorateReader(reader)
|
||||
}
|
||||
|
@ -545,46 +476,22 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
|
|||
continue
|
||||
}
|
||||
wg.Add(1)
|
||||
srv.spawnWorker(&response{
|
||||
msg: m,
|
||||
tsigSecret: srv.TsigSecret,
|
||||
udp: l,
|
||||
udpSession: s,
|
||||
wg: &wg,
|
||||
})
|
||||
go srv.serveUDPPacket(&wg, m, l, s)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (srv *Server) serve(w *response) {
|
||||
// Serve a new TCP connection.
|
||||
func (srv *Server) serveTCPConn(wg *sync.WaitGroup, rw net.Conn) {
|
||||
w := &response{tsigSecret: srv.TsigSecret, tcp: rw}
|
||||
if srv.DecorateWriter != nil {
|
||||
w.writer = srv.DecorateWriter(w)
|
||||
} else {
|
||||
w.writer = w
|
||||
}
|
||||
|
||||
if w.udp != nil {
|
||||
// serve UDP
|
||||
srv.serveDNS(w)
|
||||
|
||||
w.wg.Done()
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if !w.hijacked {
|
||||
w.Close()
|
||||
}
|
||||
|
||||
srv.lock.Lock()
|
||||
delete(srv.conns, w.tcp)
|
||||
srv.lock.Unlock()
|
||||
|
||||
w.wg.Done()
|
||||
}()
|
||||
|
||||
reader := Reader(&defaultReader{srv})
|
||||
reader := Reader(defaultReader{srv})
|
||||
if srv.DecorateReader != nil {
|
||||
reader = srv.DecorateReader(reader)
|
||||
}
|
||||
|
@ -602,14 +509,13 @@ func (srv *Server) serve(w *response) {
|
|||
}
|
||||
|
||||
for q := 0; (q < limit || limit == -1) && srv.isStarted(); q++ {
|
||||
var err error
|
||||
w.msg, err = reader.ReadTCP(w.tcp, timeout)
|
||||
m, err := reader.ReadTCP(w.tcp, timeout)
|
||||
if err != nil {
|
||||
// TODO(tmthrgd): handle error
|
||||
break
|
||||
}
|
||||
srv.serveDNS(w)
|
||||
if w.tcp == nil {
|
||||
srv.serveDNS(m, w)
|
||||
if w.closed {
|
||||
break // Close() was called
|
||||
}
|
||||
if w.hijacked {
|
||||
|
@ -619,25 +525,67 @@ func (srv *Server) serve(w *response) {
|
|||
// idle timeout.
|
||||
timeout = idleTimeout
|
||||
}
|
||||
}
|
||||
|
||||
func (srv *Server) disposeBuffer(w *response) {
|
||||
if w.udp != nil && cap(w.msg) == srv.UDPSize {
|
||||
srv.udpPool.Put(w.msg[:srv.UDPSize])
|
||||
if !w.hijacked {
|
||||
w.Close()
|
||||
}
|
||||
w.msg = nil
|
||||
|
||||
srv.lock.Lock()
|
||||
delete(srv.conns, w.tcp)
|
||||
srv.lock.Unlock()
|
||||
|
||||
wg.Done()
|
||||
}
|
||||
|
||||
func (srv *Server) serveDNS(w *response) {
|
||||
// Serve a new UDP request.
|
||||
func (srv *Server) serveUDPPacket(wg *sync.WaitGroup, m []byte, u *net.UDPConn, s *SessionUDP) {
|
||||
w := &response{tsigSecret: srv.TsigSecret, udp: u, udpSession: s}
|
||||
if srv.DecorateWriter != nil {
|
||||
w.writer = srv.DecorateWriter(w)
|
||||
} else {
|
||||
w.writer = w
|
||||
}
|
||||
|
||||
srv.serveDNS(m, w)
|
||||
wg.Done()
|
||||
}
|
||||
|
||||
func (srv *Server) serveDNS(m []byte, w *response) {
|
||||
dh, off, err := unpackMsgHdr(m, 0)
|
||||
if err != nil {
|
||||
// Let client hang, they are sending crap; any reply can be used to amplify.
|
||||
return
|
||||
}
|
||||
|
||||
req := new(Msg)
|
||||
err := req.Unpack(w.msg)
|
||||
if err != nil { // Send a FormatError back
|
||||
x := new(Msg)
|
||||
x.SetRcodeFormatError(req)
|
||||
w.WriteMsg(x)
|
||||
}
|
||||
if err != nil || !srv.Unsafe && req.Response {
|
||||
srv.disposeBuffer(w)
|
||||
req.setHdr(dh)
|
||||
|
||||
switch action := srv.MsgAcceptFunc(dh); action {
|
||||
case MsgAccept:
|
||||
if req.unpack(dh, m, off) == nil {
|
||||
break
|
||||
}
|
||||
|
||||
fallthrough
|
||||
case MsgReject, MsgRejectNotImplemented:
|
||||
opcode := req.Opcode
|
||||
req.SetRcodeFormatError(req)
|
||||
req.Zero = false
|
||||
if action == MsgRejectNotImplemented {
|
||||
req.Opcode = opcode
|
||||
req.Rcode = RcodeNotImplemented
|
||||
}
|
||||
|
||||
// Are we allowed to delete any OPT records here?
|
||||
req.Ns, req.Answer, req.Extra = nil, nil, nil
|
||||
|
||||
w.WriteMsg(req)
|
||||
fallthrough
|
||||
case MsgIgnore:
|
||||
if w.udp != nil && cap(m) == srv.UDPSize {
|
||||
srv.udpPool.Put(m[:srv.UDPSize])
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -645,7 +593,7 @@ func (srv *Server) serveDNS(w *response) {
|
|||
if w.tsigSecret != nil {
|
||||
if t := req.IsTsig(); t != nil {
|
||||
if secret, ok := w.tsigSecret[t.Hdr.Name]; ok {
|
||||
w.tsigStatus = TsigVerify(w.msg, secret, "", false)
|
||||
w.tsigStatus = TsigVerify(m, secret, "", false)
|
||||
} else {
|
||||
w.tsigStatus = ErrSecret
|
||||
}
|
||||
|
@ -654,14 +602,11 @@ func (srv *Server) serveDNS(w *response) {
|
|||
}
|
||||
}
|
||||
|
||||
srv.disposeBuffer(w)
|
||||
|
||||
handler := srv.Handler
|
||||
if handler == nil {
|
||||
handler = DefaultServeMux
|
||||
if w.udp != nil && cap(m) == srv.UDPSize {
|
||||
srv.udpPool.Put(m[:srv.UDPSize])
|
||||
}
|
||||
|
||||
handler.ServeDNS(w, req) // Writes back to the client
|
||||
srv.Handler.ServeDNS(w, req) // Writes back to the client
|
||||
}
|
||||
|
||||
func (srv *Server) readTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
|
||||
|
@ -675,36 +620,16 @@ func (srv *Server) readTCP(conn net.Conn, timeout time.Duration) ([]byte, error)
|
|||
}
|
||||
srv.lock.RUnlock()
|
||||
|
||||
l := make([]byte, 2)
|
||||
n, err := conn.Read(l)
|
||||
if err != nil || n != 2 {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, ErrShortRead
|
||||
var length uint16
|
||||
if err := binary.Read(conn, binary.BigEndian, &length); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
length := binary.BigEndian.Uint16(l)
|
||||
if length == 0 {
|
||||
return nil, ErrShortRead
|
||||
|
||||
m := make([]byte, length)
|
||||
if _, err := io.ReadFull(conn, m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
m := make([]byte, int(length))
|
||||
n, err = conn.Read(m[:int(length)])
|
||||
if err != nil || n == 0 {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, ErrShortRead
|
||||
}
|
||||
i := n
|
||||
for i < int(length) {
|
||||
j, err := conn.Read(m[i:int(length)])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i += j
|
||||
}
|
||||
n = i
|
||||
m = m[:n]
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
|
@ -728,6 +653,10 @@ func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *S
|
|||
|
||||
// WriteMsg implements the ResponseWriter.WriteMsg method.
|
||||
func (w *response) WriteMsg(m *Msg) (err error) {
|
||||
if w.closed {
|
||||
return &Error{err: "WriteMsg called after Close"}
|
||||
}
|
||||
|
||||
var data []byte
|
||||
if w.tsigSecret != nil { // if no secrets, dont check for the tsig (which is a longer check)
|
||||
if t := m.IsTsig(); t != nil {
|
||||
|
@ -749,26 +678,25 @@ func (w *response) WriteMsg(m *Msg) (err error) {
|
|||
|
||||
// Write implements the ResponseWriter.Write method.
|
||||
func (w *response) Write(m []byte) (int, error) {
|
||||
if w.closed {
|
||||
return 0, &Error{err: "Write called after Close"}
|
||||
}
|
||||
|
||||
switch {
|
||||
case w.udp != nil:
|
||||
n, err := WriteToSessionUDP(w.udp, m, w.udpSession)
|
||||
return n, err
|
||||
return WriteToSessionUDP(w.udp, m, w.udpSession)
|
||||
case w.tcp != nil:
|
||||
lm := len(m)
|
||||
if lm < 2 {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
if lm > MaxMsgSize {
|
||||
if len(m) > MaxMsgSize {
|
||||
return 0, &Error{err: "message too large"}
|
||||
}
|
||||
l := make([]byte, 2, 2+lm)
|
||||
binary.BigEndian.PutUint16(l, uint16(lm))
|
||||
m = append(l, m...)
|
||||
|
||||
n, err := io.Copy(w.tcp, bytes.NewReader(m))
|
||||
l := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(l, uint16(len(m)))
|
||||
|
||||
n, err := (&net.Buffers{l, m}).WriteTo(w.tcp)
|
||||
return int(n), err
|
||||
default:
|
||||
panic("dns: Write called after Close")
|
||||
panic("dns: internal error: udp and tcp both nil")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -780,7 +708,7 @@ func (w *response) LocalAddr() net.Addr {
|
|||
case w.tcp != nil:
|
||||
return w.tcp.LocalAddr()
|
||||
default:
|
||||
panic("dns: LocalAddr called after Close")
|
||||
panic("dns: internal error: udp and tcp both nil")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -792,7 +720,7 @@ func (w *response) RemoteAddr() net.Addr {
|
|||
case w.tcp != nil:
|
||||
return w.tcp.RemoteAddr()
|
||||
default:
|
||||
panic("dns: RemoteAddr called after Close")
|
||||
panic("dns: internal error: udpSession and tcp both nil")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -807,13 +735,20 @@ func (w *response) Hijack() { w.hijacked = true }
|
|||
|
||||
// Close implements the ResponseWriter.Close method
|
||||
func (w *response) Close() error {
|
||||
// Can't close the udp conn, as that is actually the listener.
|
||||
if w.tcp != nil {
|
||||
e := w.tcp.Close()
|
||||
w.tcp = nil
|
||||
return e
|
||||
if w.closed {
|
||||
return &Error{err: "connection already closed"}
|
||||
}
|
||||
w.closed = true
|
||||
|
||||
switch {
|
||||
case w.udp != nil:
|
||||
// Can't close the udp conn, as that is actually the listener.
|
||||
return nil
|
||||
case w.tcp != nil:
|
||||
return w.tcp.Close()
|
||||
default:
|
||||
panic("dns: internal error: udp and tcp both nil")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConnectionState() implements the ConnectionStater.ConnectionState() interface.
|
||||
|
|
|
@ -21,15 +21,11 @@ func (rr *SIG) Sign(k crypto.Signer, m *Msg) ([]byte, error) {
|
|||
if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 {
|
||||
return nil, ErrKey
|
||||
}
|
||||
rr.Header().Rrtype = TypeSIG
|
||||
rr.Header().Class = ClassANY
|
||||
rr.Header().Ttl = 0
|
||||
rr.Header().Name = "."
|
||||
rr.OrigTtl = 0
|
||||
rr.TypeCovered = 0
|
||||
rr.Labels = 0
|
||||
|
||||
buf := make([]byte, m.Len()+rr.len())
|
||||
rr.Hdr = RR_Header{Name: ".", Rrtype: TypeSIG, Class: ClassANY, Ttl: 0}
|
||||
rr.OrigTtl, rr.TypeCovered, rr.Labels = 0, 0, 0
|
||||
|
||||
buf := make([]byte, m.Len()+Len(rr))
|
||||
mbuf, err := m.PackBuffer(buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -107,7 +103,7 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
|
|||
anc := binary.BigEndian.Uint16(buf[6:])
|
||||
auc := binary.BigEndian.Uint16(buf[8:])
|
||||
adc := binary.BigEndian.Uint16(buf[10:])
|
||||
offset := 12
|
||||
offset := headerSize
|
||||
var err error
|
||||
for i := uint16(0); i < qdc && offset < buflen; i++ {
|
||||
_, offset, err = UnpackDomainName(buf, offset)
|
||||
|
@ -167,7 +163,7 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
|
|||
}
|
||||
// If key has come from the DNS name compression might
|
||||
// have mangled the case of the name
|
||||
if strings.ToLower(signername) != strings.ToLower(k.Header().Name) {
|
||||
if !strings.EqualFold(signername, k.Header().Name) {
|
||||
return &Error{err: "signer name doesn't match key name"}
|
||||
}
|
||||
sigend := offset
|
||||
|
@ -185,10 +181,8 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
|
|||
case DSA:
|
||||
pk := k.publicKeyDSA()
|
||||
sig = sig[1:]
|
||||
r := big.NewInt(0)
|
||||
r.SetBytes(sig[:len(sig)/2])
|
||||
s := big.NewInt(0)
|
||||
s.SetBytes(sig[len(sig)/2:])
|
||||
r := new(big.Int).SetBytes(sig[:len(sig)/2])
|
||||
s := new(big.Int).SetBytes(sig[len(sig)/2:])
|
||||
if pk != nil {
|
||||
if dsa.Verify(pk, hashed, r, s) {
|
||||
return nil
|
||||
|
@ -202,10 +196,8 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
|
|||
}
|
||||
case ECDSAP256SHA256, ECDSAP384SHA384:
|
||||
pk := k.publicKeyECDSA()
|
||||
r := big.NewInt(0)
|
||||
r.SetBytes(sig[:len(sig)/2])
|
||||
s := big.NewInt(0)
|
||||
s.SetBytes(sig[len(sig)/2:])
|
||||
r := new(big.Int).SetBytes(sig[:len(sig)/2])
|
||||
s := new(big.Int).SetBytes(sig[len(sig)/2:])
|
||||
if pk != nil {
|
||||
if ecdsa.Verify(pk, hashed, r, s) {
|
||||
return nil
|
||||
|
|
|
@ -23,6 +23,8 @@ type call struct {
|
|||
type singleflight struct {
|
||||
sync.Mutex // protects m
|
||||
m map[string]*call // lazily initialized
|
||||
|
||||
dontDeleteForTesting bool // this is only to be used by TestConcurrentExchanges
|
||||
}
|
||||
|
||||
// Do executes and returns the results of the given function, making
|
||||
|
@ -49,9 +51,11 @@ func (g *singleflight) Do(key string, fn func() (*Msg, time.Duration, error)) (v
|
|||
c.val, c.rtt, c.err = fn()
|
||||
c.wg.Done()
|
||||
|
||||
g.Lock()
|
||||
delete(g.m, key)
|
||||
g.Unlock()
|
||||
if !g.dontDeleteForTesting {
|
||||
g.Lock()
|
||||
delete(g.m, key)
|
||||
g.Unlock()
|
||||
}
|
||||
|
||||
return c.val, c.rtt, c.err, c.dups > 0
|
||||
}
|
||||
|
|
|
@ -14,10 +14,7 @@ func (r *SMIMEA) Sign(usage, selector, matchingType int, cert *x509.Certificate)
|
|||
r.MatchingType = uint8(matchingType)
|
||||
|
||||
r.Certificate, err = CertificateToDANE(r.Selector, r.MatchingType, cert)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
// Verify verifies a SMIMEA record against an SSL certificate. If it is OK
|
||||
|
|
|
@ -14,10 +14,7 @@ func (r *TLSA) Sign(usage, selector, matchingType int, cert *x509.Certificate) (
|
|||
r.MatchingType = uint8(matchingType)
|
||||
|
||||
r.Certificate, err = CertificateToDANE(r.Selector, r.MatchingType, cert)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
// Verify verifies a TLSA record against an SSL certificate. If it is OK
|
||||
|
|
|
@ -54,6 +54,10 @@ func (rr *TSIG) String() string {
|
|||
return s
|
||||
}
|
||||
|
||||
func (rr *TSIG) parse(c *zlexer, origin string) *ParseError {
|
||||
panic("dns: internal error: parse should never be called on TSIG")
|
||||
}
|
||||
|
||||
// The following values must be put in wireformat, so that the MAC can be calculated.
|
||||
// RFC 2845, section 3.4.2. TSIG Variables.
|
||||
type tsigWireFmt struct {
|
||||
|
@ -113,13 +117,13 @@ func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, s
|
|||
var h hash.Hash
|
||||
switch strings.ToLower(rr.Algorithm) {
|
||||
case HmacMD5:
|
||||
h = hmac.New(md5.New, []byte(rawsecret))
|
||||
h = hmac.New(md5.New, rawsecret)
|
||||
case HmacSHA1:
|
||||
h = hmac.New(sha1.New, []byte(rawsecret))
|
||||
h = hmac.New(sha1.New, rawsecret)
|
||||
case HmacSHA256:
|
||||
h = hmac.New(sha256.New, []byte(rawsecret))
|
||||
h = hmac.New(sha256.New, rawsecret)
|
||||
case HmacSHA512:
|
||||
h = hmac.New(sha512.New, []byte(rawsecret))
|
||||
h = hmac.New(sha512.New, rawsecret)
|
||||
default:
|
||||
return nil, "", ErrKeyAlg
|
||||
}
|
||||
|
@ -133,13 +137,12 @@ func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, s
|
|||
t.Algorithm = rr.Algorithm
|
||||
t.OrigId = m.Id
|
||||
|
||||
tbuf := make([]byte, t.len())
|
||||
if off, err := PackRR(t, tbuf, 0, nil, false); err == nil {
|
||||
tbuf = tbuf[:off] // reset to actual size used
|
||||
} else {
|
||||
tbuf := make([]byte, Len(t))
|
||||
off, err := PackRR(t, tbuf, 0, nil, false)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
mbuf = append(mbuf, tbuf...)
|
||||
mbuf = append(mbuf, tbuf[:off]...)
|
||||
// Update the ArCount directly in the buffer.
|
||||
binary.BigEndian.PutUint16(mbuf[10:], uint16(len(m.Extra)+1))
|
||||
|
||||
|
|
|
@ -205,9 +205,6 @@ var CertTypeToString = map[uint16]string{
|
|||
CertOID: "OID",
|
||||
}
|
||||
|
||||
// StringToCertType is the reverseof CertTypeToString.
|
||||
var StringToCertType = reverseInt16(CertTypeToString)
|
||||
|
||||
//go:generate go run types_generate.go
|
||||
|
||||
// Question holds a DNS question. There can be multiple questions in the
|
||||
|
@ -218,8 +215,10 @@ type Question struct {
|
|||
Qclass uint16
|
||||
}
|
||||
|
||||
func (q *Question) len() int {
|
||||
return len(q.Name) + 1 + 2 + 2
|
||||
func (q *Question) len(off int, compression map[string]struct{}) int {
|
||||
l := domainNameLen(q.Name, off, compression, true)
|
||||
l += 2 + 2
|
||||
return l
|
||||
}
|
||||
|
||||
func (q *Question) String() (s string) {
|
||||
|
@ -239,6 +238,25 @@ type ANY struct {
|
|||
|
||||
func (rr *ANY) String() string { return rr.Hdr.String() }
|
||||
|
||||
func (rr *ANY) parse(c *zlexer, origin string) *ParseError {
|
||||
panic("dns: internal error: parse should never be called on ANY")
|
||||
}
|
||||
|
||||
// NULL RR. See RFC 1035.
|
||||
type NULL struct {
|
||||
Hdr RR_Header
|
||||
Data string `dns:"any"`
|
||||
}
|
||||
|
||||
func (rr *NULL) String() string {
|
||||
// There is no presentation format; prefix string with a comment.
|
||||
return ";" + rr.Hdr.String() + rr.Data
|
||||
}
|
||||
|
||||
func (rr *NULL) parse(c *zlexer, origin string) *ParseError {
|
||||
panic("dns: internal error: parse should never be called on NULL")
|
||||
}
|
||||
|
||||
// CNAME RR. See RFC 1034.
|
||||
type CNAME struct {
|
||||
Hdr RR_Header
|
||||
|
@ -351,7 +369,7 @@ func (rr *X25) String() string {
|
|||
type RT struct {
|
||||
Hdr RR_Header
|
||||
Preference uint16
|
||||
Host string `dns:"cdomain-name"`
|
||||
Host string `dns:"domain-name"` // RFC 3597 prohibits compressing records not defined in RFC 1035.
|
||||
}
|
||||
|
||||
func (rr *RT) String() string {
|
||||
|
@ -386,7 +404,7 @@ type RP struct {
|
|||
}
|
||||
|
||||
func (rr *RP) String() string {
|
||||
return rr.Hdr.String() + rr.Mbox + " " + sprintTxt([]string{rr.Txt})
|
||||
return rr.Hdr.String() + sprintName(rr.Mbox) + " " + sprintName(rr.Txt)
|
||||
}
|
||||
|
||||
// SOA RR. See RFC 1035.
|
||||
|
@ -420,25 +438,54 @@ func (rr *TXT) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
|
|||
|
||||
func sprintName(s string) string {
|
||||
var dst strings.Builder
|
||||
dst.Grow(len(s))
|
||||
|
||||
for i := 0; i < len(s); {
|
||||
if i+1 < len(s) && s[i] == '\\' && s[i+1] == '.' {
|
||||
dst.WriteString(s[i : i+2])
|
||||
if dst.Len() != 0 {
|
||||
dst.WriteString(s[i : i+2])
|
||||
}
|
||||
i += 2
|
||||
continue
|
||||
}
|
||||
|
||||
b, n := nextByte(s, i)
|
||||
switch {
|
||||
case n == 0:
|
||||
i++ // dangling back slash
|
||||
case b == '.':
|
||||
dst.WriteByte('.')
|
||||
if n == 0 {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if b == '.' {
|
||||
if dst.Len() != 0 {
|
||||
dst.WriteByte('.')
|
||||
}
|
||||
i += n
|
||||
continue
|
||||
}
|
||||
switch b {
|
||||
case ' ', '\'', '@', ';', '(', ')', '"', '\\': // additional chars to escape
|
||||
if dst.Len() == 0 {
|
||||
dst.Grow(len(s) * 2)
|
||||
dst.WriteString(s[:i])
|
||||
}
|
||||
dst.WriteByte('\\')
|
||||
dst.WriteByte(b)
|
||||
default:
|
||||
writeDomainNameByte(&dst, b)
|
||||
if ' ' <= b && b <= '~' {
|
||||
if dst.Len() != 0 {
|
||||
dst.WriteByte(b)
|
||||
}
|
||||
} else {
|
||||
if dst.Len() == 0 {
|
||||
dst.Grow(len(s) * 2)
|
||||
dst.WriteString(s[:i])
|
||||
}
|
||||
dst.WriteString(escapeByte(b))
|
||||
}
|
||||
}
|
||||
i += n
|
||||
}
|
||||
if dst.Len() == 0 {
|
||||
return s
|
||||
}
|
||||
return dst.String()
|
||||
}
|
||||
|
||||
|
@ -460,7 +507,7 @@ func sprintTxtOctet(s string) string {
|
|||
case b == '.':
|
||||
dst.WriteByte('.')
|
||||
case b < ' ' || b > '~':
|
||||
writeEscapedByte(&dst, b)
|
||||
dst.WriteString(escapeByte(b))
|
||||
default:
|
||||
dst.WriteByte(b)
|
||||
}
|
||||
|
@ -492,36 +539,50 @@ func sprintTxt(txt []string) string {
|
|||
return out.String()
|
||||
}
|
||||
|
||||
func writeDomainNameByte(s *strings.Builder, b byte) {
|
||||
switch b {
|
||||
case '.', ' ', '\'', '@', ';', '(', ')': // additional chars to escape
|
||||
s.WriteByte('\\')
|
||||
s.WriteByte(b)
|
||||
default:
|
||||
writeTXTStringByte(s, b)
|
||||
}
|
||||
}
|
||||
|
||||
func writeTXTStringByte(s *strings.Builder, b byte) {
|
||||
switch {
|
||||
case b == '"' || b == '\\':
|
||||
s.WriteByte('\\')
|
||||
s.WriteByte(b)
|
||||
case b < ' ' || b > '~':
|
||||
writeEscapedByte(s, b)
|
||||
s.WriteString(escapeByte(b))
|
||||
default:
|
||||
s.WriteByte(b)
|
||||
}
|
||||
}
|
||||
|
||||
func writeEscapedByte(s *strings.Builder, b byte) {
|
||||
var buf [3]byte
|
||||
bufs := strconv.AppendInt(buf[:0], int64(b), 10)
|
||||
s.WriteByte('\\')
|
||||
for i := len(bufs); i < 3; i++ {
|
||||
s.WriteByte('0')
|
||||
const (
|
||||
escapedByteSmall = "" +
|
||||
`\000\001\002\003\004\005\006\007\008\009` +
|
||||
`\010\011\012\013\014\015\016\017\018\019` +
|
||||
`\020\021\022\023\024\025\026\027\028\029` +
|
||||
`\030\031`
|
||||
escapedByteLarge = `\127\128\129` +
|
||||
`\130\131\132\133\134\135\136\137\138\139` +
|
||||
`\140\141\142\143\144\145\146\147\148\149` +
|
||||
`\150\151\152\153\154\155\156\157\158\159` +
|
||||
`\160\161\162\163\164\165\166\167\168\169` +
|
||||
`\170\171\172\173\174\175\176\177\178\179` +
|
||||
`\180\181\182\183\184\185\186\187\188\189` +
|
||||
`\190\191\192\193\194\195\196\197\198\199` +
|
||||
`\200\201\202\203\204\205\206\207\208\209` +
|
||||
`\210\211\212\213\214\215\216\217\218\219` +
|
||||
`\220\221\222\223\224\225\226\227\228\229` +
|
||||
`\230\231\232\233\234\235\236\237\238\239` +
|
||||
`\240\241\242\243\244\245\246\247\248\249` +
|
||||
`\250\251\252\253\254\255`
|
||||
)
|
||||
|
||||
// escapeByte returns the \DDD escaping of b which must
|
||||
// satisfy b < ' ' || b > '~'.
|
||||
func escapeByte(b byte) string {
|
||||
if b < ' ' {
|
||||
return escapedByteSmall[b*4 : b*4+4]
|
||||
}
|
||||
s.Write(bufs)
|
||||
|
||||
b -= '~' + 1
|
||||
// The cast here is needed as b*4 may overflow byte.
|
||||
return escapedByteLarge[int(b)*4 : int(b)*4+4]
|
||||
}
|
||||
|
||||
func nextByte(s string, offset int) (byte, int) {
|
||||
|
@ -803,22 +864,16 @@ type NSEC struct {
|
|||
|
||||
func (rr *NSEC) String() string {
|
||||
s := rr.Hdr.String() + sprintName(rr.NextDomain)
|
||||
for i := 0; i < len(rr.TypeBitMap); i++ {
|
||||
s += " " + Type(rr.TypeBitMap[i]).String()
|
||||
for _, t := range rr.TypeBitMap {
|
||||
s += " " + Type(t).String()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (rr *NSEC) len() int {
|
||||
l := rr.Hdr.len() + len(rr.NextDomain) + 1
|
||||
lastwindow := uint32(2 ^ 32 + 1)
|
||||
for _, t := range rr.TypeBitMap {
|
||||
window := t / 256
|
||||
if uint32(window) != lastwindow {
|
||||
l += 1 + 32
|
||||
}
|
||||
lastwindow = uint32(window)
|
||||
}
|
||||
func (rr *NSEC) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += domainNameLen(rr.NextDomain, off+l, compression, false)
|
||||
l += typeBitMapLen(rr.TypeBitMap)
|
||||
return l
|
||||
}
|
||||
|
||||
|
@ -968,22 +1023,16 @@ func (rr *NSEC3) String() string {
|
|||
" " + strconv.Itoa(int(rr.Iterations)) +
|
||||
" " + saltToString(rr.Salt) +
|
||||
" " + rr.NextDomain
|
||||
for i := 0; i < len(rr.TypeBitMap); i++ {
|
||||
s += " " + Type(rr.TypeBitMap[i]).String()
|
||||
for _, t := range rr.TypeBitMap {
|
||||
s += " " + Type(t).String()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (rr *NSEC3) len() int {
|
||||
l := rr.Hdr.len() + 6 + len(rr.Salt)/2 + 1 + len(rr.NextDomain) + 1
|
||||
lastwindow := uint32(2 ^ 32 + 1)
|
||||
for _, t := range rr.TypeBitMap {
|
||||
window := t / 256
|
||||
if uint32(window) != lastwindow {
|
||||
l += 1 + 32
|
||||
}
|
||||
lastwindow = uint32(window)
|
||||
}
|
||||
func (rr *NSEC3) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 6 + len(rr.Salt)/2 + 1 + len(rr.NextDomain) + 1
|
||||
l += typeBitMapLen(rr.TypeBitMap)
|
||||
return l
|
||||
}
|
||||
|
||||
|
@ -1022,10 +1071,16 @@ type TKEY struct {
|
|||
|
||||
// TKEY has no official presentation format, but this will suffice.
|
||||
func (rr *TKEY) String() string {
|
||||
s := "\n;; TKEY PSEUDOSECTION:\n"
|
||||
s += rr.Hdr.String() + " " + rr.Algorithm + " " +
|
||||
strconv.Itoa(int(rr.KeySize)) + " " + rr.Key + " " +
|
||||
strconv.Itoa(int(rr.OtherLen)) + " " + rr.OtherData
|
||||
s := ";" + rr.Hdr.String() +
|
||||
" " + rr.Algorithm +
|
||||
" " + TimeToString(rr.Inception) +
|
||||
" " + TimeToString(rr.Expiration) +
|
||||
" " + strconv.Itoa(int(rr.Mode)) +
|
||||
" " + strconv.Itoa(int(rr.Error)) +
|
||||
" " + strconv.Itoa(int(rr.KeySize)) +
|
||||
" " + rr.Key +
|
||||
" " + strconv.Itoa(int(rr.OtherLen)) +
|
||||
" " + rr.OtherData
|
||||
return s
|
||||
}
|
||||
|
||||
|
@ -1285,22 +1340,16 @@ type CSYNC struct {
|
|||
func (rr *CSYNC) String() string {
|
||||
s := rr.Hdr.String() + strconv.FormatInt(int64(rr.Serial), 10) + " " + strconv.Itoa(int(rr.Flags))
|
||||
|
||||
for i := 0; i < len(rr.TypeBitMap); i++ {
|
||||
s += " " + Type(rr.TypeBitMap[i]).String()
|
||||
for _, t := range rr.TypeBitMap {
|
||||
s += " " + Type(t).String()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (rr *CSYNC) len() int {
|
||||
l := rr.Hdr.len() + 4 + 2
|
||||
lastwindow := uint32(2 ^ 32 + 1)
|
||||
for _, t := range rr.TypeBitMap {
|
||||
window := t / 256
|
||||
if uint32(window) != lastwindow {
|
||||
l += 1 + 32
|
||||
}
|
||||
lastwindow = uint32(window)
|
||||
}
|
||||
func (rr *CSYNC) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 4 + 2
|
||||
l += typeBitMapLen(rr.TypeBitMap)
|
||||
return l
|
||||
}
|
||||
|
||||
|
|
|
@ -153,8 +153,8 @@ func main() {
|
|||
if isEmbedded {
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(b, "func (rr *%s) len() int {\n", name)
|
||||
fmt.Fprintf(b, "l := rr.Hdr.len()\n")
|
||||
fmt.Fprintf(b, "func (rr *%s) len(off int, compression map[string]struct{}) int {\n", name)
|
||||
fmt.Fprintf(b, "l := rr.Hdr.len(off, compression)\n")
|
||||
for i := 1; i < st.NumFields(); i++ {
|
||||
o := func(s string) { fmt.Fprintf(b, s, st.Field(i).Name()) }
|
||||
|
||||
|
@ -162,7 +162,11 @@ func main() {
|
|||
switch st.Tag(i) {
|
||||
case `dns:"-"`:
|
||||
// ignored
|
||||
case `dns:"cdomain-name"`, `dns:"domain-name"`, `dns:"txt"`:
|
||||
case `dns:"cdomain-name"`:
|
||||
o("for _, x := range rr.%s { l += domainNameLen(x, off+l, compression, true) }\n")
|
||||
case `dns:"domain-name"`:
|
||||
o("for _, x := range rr.%s { l += domainNameLen(x, off+l, compression, false) }\n")
|
||||
case `dns:"txt"`:
|
||||
o("for _, x := range rr.%s { l += len(x) + 1 }\n")
|
||||
default:
|
||||
log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
|
||||
|
@ -173,8 +177,10 @@ func main() {
|
|||
switch {
|
||||
case st.Tag(i) == `dns:"-"`:
|
||||
// ignored
|
||||
case st.Tag(i) == `dns:"cdomain-name"`, st.Tag(i) == `dns:"domain-name"`:
|
||||
o("l += len(rr.%s) + 1\n")
|
||||
case st.Tag(i) == `dns:"cdomain-name"`:
|
||||
o("l += domainNameLen(rr.%s, off+l, compression, true)\n")
|
||||
case st.Tag(i) == `dns:"domain-name"`:
|
||||
o("l += domainNameLen(rr.%s, off+l, compression, false)\n")
|
||||
case st.Tag(i) == `dns:"octet"`:
|
||||
o("l += len(rr.%s)\n")
|
||||
case strings.HasPrefix(st.Tag(i), `dns:"size-base64`):
|
||||
|
@ -183,14 +189,14 @@ func main() {
|
|||
o("l += base64.StdEncoding.DecodedLen(len(rr.%s))\n")
|
||||
case strings.HasPrefix(st.Tag(i), `dns:"size-hex:`): // this has an extra field where the length is stored
|
||||
o("l += len(rr.%s)/2\n")
|
||||
case strings.HasPrefix(st.Tag(i), `dns:"size-hex`):
|
||||
fallthrough
|
||||
case st.Tag(i) == `dns:"hex"`:
|
||||
o("l += len(rr.%s)/2 + 1\n")
|
||||
o("l += len(rr.%s)/2\n")
|
||||
case st.Tag(i) == `dns:"any"`:
|
||||
o("l += len(rr.%s)\n")
|
||||
case st.Tag(i) == `dns:"a"`:
|
||||
o("l += net.IPv4len // %s\n")
|
||||
o("if len(rr.%s) != 0 { l += net.IPv4len }\n")
|
||||
case st.Tag(i) == `dns:"aaaa"`:
|
||||
o("l += net.IPv6len // %s\n")
|
||||
o("if len(rr.%s) != 0 { l += net.IPv6len }\n")
|
||||
case st.Tag(i) == `dns:"txt"`:
|
||||
o("for _, t := range rr.%s { l += len(t) + 1 }\n")
|
||||
case st.Tag(i) == `dns:"uint48"`:
|
||||
|
@ -236,6 +242,13 @@ func main() {
|
|||
splits := strings.Split(t, ".")
|
||||
t = splits[len(splits)-1]
|
||||
}
|
||||
// For the EDNS0 interface (used in the OPT RR), we need to call the copy method on each element.
|
||||
if t == "EDNS0" {
|
||||
fmt.Fprintf(b, "%s := make([]%s, len(rr.%s));\nfor i,e := range rr.%s {\n %s[i] = e.copy()\n}\n",
|
||||
f, t, f, f, f)
|
||||
fields = append(fields, f)
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(b, "%s := make([]%s, len(rr.%s)); copy(%s, rr.%s)\n",
|
||||
f, t, f, f, f)
|
||||
fields = append(fields, f)
|
||||
|
|
|
@ -20,15 +20,13 @@ func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
|
|||
if err != nil {
|
||||
return n, nil, err
|
||||
}
|
||||
session := &SessionUDP{raddr.(*net.UDPAddr)}
|
||||
return n, session, err
|
||||
return n, &SessionUDP{raddr.(*net.UDPAddr)}, err
|
||||
}
|
||||
|
||||
// WriteToSessionUDP acts just like net.UDPConn.WriteTo(), but uses a *SessionUDP instead of a net.Addr.
|
||||
// TODO(fastest963): Once go1.10 is released, use WriteMsgUDP.
|
||||
func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) {
|
||||
n, err := conn.WriteTo(b, session.raddr)
|
||||
return n, err
|
||||
return conn.WriteTo(b, session.raddr)
|
||||
}
|
||||
|
||||
// TODO(fastest963): Once go1.10 is released and we can use *MsgUDP methods
|
||||
|
|
|
@ -44,7 +44,8 @@ func (u *Msg) RRsetUsed(rr []RR) {
|
|||
u.Answer = make([]RR, 0, len(rr))
|
||||
}
|
||||
for _, r := range rr {
|
||||
u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}})
|
||||
h := r.Header()
|
||||
u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: h.Name, Ttl: 0, Rrtype: h.Rrtype, Class: ClassANY}})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,7 +56,8 @@ func (u *Msg) RRsetNotUsed(rr []RR) {
|
|||
u.Answer = make([]RR, 0, len(rr))
|
||||
}
|
||||
for _, r := range rr {
|
||||
u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassNONE}})
|
||||
h := r.Header()
|
||||
u.Answer = append(u.Answer, &ANY{Hdr: RR_Header{Name: h.Name, Ttl: 0, Rrtype: h.Rrtype, Class: ClassNONE}})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,7 +81,8 @@ func (u *Msg) RemoveRRset(rr []RR) {
|
|||
u.Ns = make([]RR, 0, len(rr))
|
||||
}
|
||||
for _, r := range rr {
|
||||
u.Ns = append(u.Ns, &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}})
|
||||
h := r.Header()
|
||||
u.Ns = append(u.Ns, &ANY{Hdr: RR_Header{Name: h.Name, Ttl: 0, Rrtype: h.Rrtype, Class: ClassANY}})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,8 +102,9 @@ func (u *Msg) Remove(rr []RR) {
|
|||
u.Ns = make([]RR, 0, len(rr))
|
||||
}
|
||||
for _, r := range rr {
|
||||
r.Header().Class = ClassNONE
|
||||
r.Header().Ttl = 0
|
||||
h := r.Header()
|
||||
h.Class = ClassNONE
|
||||
h.Ttl = 0
|
||||
u.Ns = append(u.Ns, r)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package dns
|
|||
import "fmt"
|
||||
|
||||
// Version is current version of this library.
|
||||
var Version = V{1, 0, 14}
|
||||
var Version = V{1, 1, 22}
|
||||
|
||||
// V holds the version of this library.
|
||||
type V struct {
|
||||
|
|
|
@ -35,30 +35,36 @@ type Transfer struct {
|
|||
// channel, err := transfer.In(message, master)
|
||||
//
|
||||
func (t *Transfer) In(q *Msg, a string) (env chan *Envelope, err error) {
|
||||
switch q.Question[0].Qtype {
|
||||
case TypeAXFR, TypeIXFR:
|
||||
default:
|
||||
return nil, &Error{"unsupported question type"}
|
||||
}
|
||||
|
||||
timeout := dnsTimeout
|
||||
if t.DialTimeout != 0 {
|
||||
timeout = t.DialTimeout
|
||||
}
|
||||
|
||||
if t.Conn == nil {
|
||||
t.Conn, err = DialTimeout("tcp", a, timeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := t.WriteMsg(q); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
env = make(chan *Envelope)
|
||||
go func() {
|
||||
if q.Question[0].Qtype == TypeAXFR {
|
||||
go t.inAxfr(q, env)
|
||||
return
|
||||
}
|
||||
if q.Question[0].Qtype == TypeIXFR {
|
||||
go t.inIxfr(q, env)
|
||||
return
|
||||
}
|
||||
}()
|
||||
switch q.Question[0].Qtype {
|
||||
case TypeAXFR:
|
||||
go t.inAxfr(q, env)
|
||||
case TypeIXFR:
|
||||
go t.inIxfr(q, env)
|
||||
}
|
||||
|
||||
return env, nil
|
||||
}
|
||||
|
||||
|
@ -111,7 +117,7 @@ func (t *Transfer) inAxfr(q *Msg, c chan *Envelope) {
|
|||
}
|
||||
|
||||
func (t *Transfer) inIxfr(q *Msg, c chan *Envelope) {
|
||||
serial := uint32(0) // The first serial seen is the current server serial
|
||||
var serial uint32 // The first serial seen is the current server serial
|
||||
axfr := true
|
||||
n := 0
|
||||
qser := q.Ns[0].(*SOA).Serial
|
||||
|
@ -192,11 +198,14 @@ func (t *Transfer) Out(w ResponseWriter, q *Msg, ch chan *Envelope) error {
|
|||
r.Authoritative = true
|
||||
// assume it fits TODO(miek): fix
|
||||
r.Answer = append(r.Answer, x.RR...)
|
||||
if tsig := q.IsTsig(); tsig != nil && w.TsigStatus() == nil {
|
||||
r.SetTsig(tsig.Hdr.Name, tsig.Algorithm, tsig.Fudge, time.Now().Unix())
|
||||
}
|
||||
if err := w.WriteMsg(r); err != nil {
|
||||
return err
|
||||
}
|
||||
w.TsigTimersOnly(true)
|
||||
}
|
||||
w.TsigTimersOnly(true)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -237,24 +246,18 @@ func (t *Transfer) WriteMsg(m *Msg) (err error) {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = t.Write(out); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
_, err = t.Write(out)
|
||||
return err
|
||||
}
|
||||
|
||||
func isSOAFirst(in *Msg) bool {
|
||||
if len(in.Answer) > 0 {
|
||||
return in.Answer[0].Header().Rrtype == TypeSOA
|
||||
}
|
||||
return false
|
||||
return len(in.Answer) > 0 &&
|
||||
in.Answer[0].Header().Rrtype == TypeSOA
|
||||
}
|
||||
|
||||
func isSOALast(in *Msg) bool {
|
||||
if len(in.Answer) > 0 {
|
||||
return in.Answer[len(in.Answer)-1].Header().Rrtype == TypeSOA
|
||||
}
|
||||
return false
|
||||
return len(in.Answer) > 0 &&
|
||||
in.Answer[len(in.Answer)-1].Header().Rrtype == TypeSOA
|
||||
}
|
||||
|
||||
const errXFR = "bad xfr rcode: %d"
|
||||
|
|
|
@ -1,152 +0,0 @@
|
|||
// Code generated by "go run compress_generate.go"; DO NOT EDIT.
|
||||
|
||||
package dns
|
||||
|
||||
func compressionLenHelperType(c map[string]int, r RR, initLen int) int {
|
||||
currentLen := initLen
|
||||
switch x := r.(type) {
|
||||
case *AFSDB:
|
||||
currentLen -= len(x.Hostname) + 1
|
||||
currentLen += compressionLenHelper(c, x.Hostname, currentLen)
|
||||
case *CNAME:
|
||||
currentLen -= len(x.Target) + 1
|
||||
currentLen += compressionLenHelper(c, x.Target, currentLen)
|
||||
case *DNAME:
|
||||
currentLen -= len(x.Target) + 1
|
||||
currentLen += compressionLenHelper(c, x.Target, currentLen)
|
||||
case *HIP:
|
||||
for i := range x.RendezvousServers {
|
||||
currentLen -= len(x.RendezvousServers[i]) + 1
|
||||
}
|
||||
for i := range x.RendezvousServers {
|
||||
currentLen += compressionLenHelper(c, x.RendezvousServers[i], currentLen)
|
||||
}
|
||||
case *KX:
|
||||
currentLen -= len(x.Exchanger) + 1
|
||||
currentLen += compressionLenHelper(c, x.Exchanger, currentLen)
|
||||
case *LP:
|
||||
currentLen -= len(x.Fqdn) + 1
|
||||
currentLen += compressionLenHelper(c, x.Fqdn, currentLen)
|
||||
case *MB:
|
||||
currentLen -= len(x.Mb) + 1
|
||||
currentLen += compressionLenHelper(c, x.Mb, currentLen)
|
||||
case *MD:
|
||||
currentLen -= len(x.Md) + 1
|
||||
currentLen += compressionLenHelper(c, x.Md, currentLen)
|
||||
case *MF:
|
||||
currentLen -= len(x.Mf) + 1
|
||||
currentLen += compressionLenHelper(c, x.Mf, currentLen)
|
||||
case *MG:
|
||||
currentLen -= len(x.Mg) + 1
|
||||
currentLen += compressionLenHelper(c, x.Mg, currentLen)
|
||||
case *MINFO:
|
||||
currentLen -= len(x.Rmail) + 1
|
||||
currentLen += compressionLenHelper(c, x.Rmail, currentLen)
|
||||
currentLen -= len(x.Email) + 1
|
||||
currentLen += compressionLenHelper(c, x.Email, currentLen)
|
||||
case *MR:
|
||||
currentLen -= len(x.Mr) + 1
|
||||
currentLen += compressionLenHelper(c, x.Mr, currentLen)
|
||||
case *MX:
|
||||
currentLen -= len(x.Mx) + 1
|
||||
currentLen += compressionLenHelper(c, x.Mx, currentLen)
|
||||
case *NAPTR:
|
||||
currentLen -= len(x.Replacement) + 1
|
||||
currentLen += compressionLenHelper(c, x.Replacement, currentLen)
|
||||
case *NS:
|
||||
currentLen -= len(x.Ns) + 1
|
||||
currentLen += compressionLenHelper(c, x.Ns, currentLen)
|
||||
case *NSAPPTR:
|
||||
currentLen -= len(x.Ptr) + 1
|
||||
currentLen += compressionLenHelper(c, x.Ptr, currentLen)
|
||||
case *NSEC:
|
||||
currentLen -= len(x.NextDomain) + 1
|
||||
currentLen += compressionLenHelper(c, x.NextDomain, currentLen)
|
||||
case *PTR:
|
||||
currentLen -= len(x.Ptr) + 1
|
||||
currentLen += compressionLenHelper(c, x.Ptr, currentLen)
|
||||
case *PX:
|
||||
currentLen -= len(x.Map822) + 1
|
||||
currentLen += compressionLenHelper(c, x.Map822, currentLen)
|
||||
currentLen -= len(x.Mapx400) + 1
|
||||
currentLen += compressionLenHelper(c, x.Mapx400, currentLen)
|
||||
case *RP:
|
||||
currentLen -= len(x.Mbox) + 1
|
||||
currentLen += compressionLenHelper(c, x.Mbox, currentLen)
|
||||
currentLen -= len(x.Txt) + 1
|
||||
currentLen += compressionLenHelper(c, x.Txt, currentLen)
|
||||
case *RRSIG:
|
||||
currentLen -= len(x.SignerName) + 1
|
||||
currentLen += compressionLenHelper(c, x.SignerName, currentLen)
|
||||
case *RT:
|
||||
currentLen -= len(x.Host) + 1
|
||||
currentLen += compressionLenHelper(c, x.Host, currentLen)
|
||||
case *SIG:
|
||||
currentLen -= len(x.SignerName) + 1
|
||||
currentLen += compressionLenHelper(c, x.SignerName, currentLen)
|
||||
case *SOA:
|
||||
currentLen -= len(x.Ns) + 1
|
||||
currentLen += compressionLenHelper(c, x.Ns, currentLen)
|
||||
currentLen -= len(x.Mbox) + 1
|
||||
currentLen += compressionLenHelper(c, x.Mbox, currentLen)
|
||||
case *SRV:
|
||||
currentLen -= len(x.Target) + 1
|
||||
currentLen += compressionLenHelper(c, x.Target, currentLen)
|
||||
case *TALINK:
|
||||
currentLen -= len(x.PreviousName) + 1
|
||||
currentLen += compressionLenHelper(c, x.PreviousName, currentLen)
|
||||
currentLen -= len(x.NextName) + 1
|
||||
currentLen += compressionLenHelper(c, x.NextName, currentLen)
|
||||
case *TKEY:
|
||||
currentLen -= len(x.Algorithm) + 1
|
||||
currentLen += compressionLenHelper(c, x.Algorithm, currentLen)
|
||||
case *TSIG:
|
||||
currentLen -= len(x.Algorithm) + 1
|
||||
currentLen += compressionLenHelper(c, x.Algorithm, currentLen)
|
||||
}
|
||||
return currentLen - initLen
|
||||
}
|
||||
|
||||
func compressionLenSearchType(c map[string]int, r RR) (int, bool, int) {
|
||||
switch x := r.(type) {
|
||||
case *CNAME:
|
||||
k1, ok1, sz1 := compressionLenSearch(c, x.Target)
|
||||
return k1, ok1, sz1
|
||||
case *MB:
|
||||
k1, ok1, sz1 := compressionLenSearch(c, x.Mb)
|
||||
return k1, ok1, sz1
|
||||
case *MD:
|
||||
k1, ok1, sz1 := compressionLenSearch(c, x.Md)
|
||||
return k1, ok1, sz1
|
||||
case *MF:
|
||||
k1, ok1, sz1 := compressionLenSearch(c, x.Mf)
|
||||
return k1, ok1, sz1
|
||||
case *MG:
|
||||
k1, ok1, sz1 := compressionLenSearch(c, x.Mg)
|
||||
return k1, ok1, sz1
|
||||
case *MINFO:
|
||||
k1, ok1, sz1 := compressionLenSearch(c, x.Rmail)
|
||||
k2, ok2, sz2 := compressionLenSearch(c, x.Email)
|
||||
return k1 + k2, ok1 && ok2, sz1 + sz2
|
||||
case *MR:
|
||||
k1, ok1, sz1 := compressionLenSearch(c, x.Mr)
|
||||
return k1, ok1, sz1
|
||||
case *MX:
|
||||
k1, ok1, sz1 := compressionLenSearch(c, x.Mx)
|
||||
return k1, ok1, sz1
|
||||
case *NS:
|
||||
k1, ok1, sz1 := compressionLenSearch(c, x.Ns)
|
||||
return k1, ok1, sz1
|
||||
case *PTR:
|
||||
k1, ok1, sz1 := compressionLenSearch(c, x.Ptr)
|
||||
return k1, ok1, sz1
|
||||
case *RT:
|
||||
k1, ok1, sz1 := compressionLenSearch(c, x.Host)
|
||||
return k1, ok1, sz1
|
||||
case *SOA:
|
||||
k1, ok1, sz1 := compressionLenSearch(c, x.Ns)
|
||||
k2, ok2, sz2 := compressionLenSearch(c, x.Mbox)
|
||||
return k1 + k2, ok1 && ok2, sz1 + sz2
|
||||
}
|
||||
return 0, false, 0
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -54,6 +54,7 @@ var TypeToRR = map[uint16]func() RR{
|
|||
TypeNSEC: func() RR { return new(NSEC) },
|
||||
TypeNSEC3: func() RR { return new(NSEC3) },
|
||||
TypeNSEC3PARAM: func() RR { return new(NSEC3PARAM) },
|
||||
TypeNULL: func() RR { return new(NULL) },
|
||||
TypeOPENPGPKEY: func() RR { return new(OPENPGPKEY) },
|
||||
TypeOPT: func() RR { return new(OPT) },
|
||||
TypePTR: func() RR { return new(PTR) },
|
||||
|
@ -209,6 +210,7 @@ func (rr *NSAPPTR) Header() *RR_Header { return &rr.Hdr }
|
|||
func (rr *NSEC) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NSEC3) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NSEC3PARAM) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NULL) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *OPENPGPKEY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *OPT) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *PTR) Header() *RR_Header { return &rr.Hdr }
|
||||
|
@ -236,144 +238,150 @@ func (rr *URI) Header() *RR_Header { return &rr.Hdr }
|
|||
func (rr *X25) Header() *RR_Header { return &rr.Hdr }
|
||||
|
||||
// len() functions
|
||||
func (rr *A) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += net.IPv4len // A
|
||||
func (rr *A) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
if len(rr.A) != 0 {
|
||||
l += net.IPv4len
|
||||
}
|
||||
return l
|
||||
}
|
||||
func (rr *AAAA) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += net.IPv6len // AAAA
|
||||
func (rr *AAAA) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
if len(rr.AAAA) != 0 {
|
||||
l += net.IPv6len
|
||||
}
|
||||
return l
|
||||
}
|
||||
func (rr *AFSDB) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *AFSDB) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 2 // Subtype
|
||||
l += len(rr.Hostname) + 1
|
||||
l += domainNameLen(rr.Hostname, off+l, compression, false)
|
||||
return l
|
||||
}
|
||||
func (rr *ANY) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *ANY) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
return l
|
||||
}
|
||||
func (rr *AVC) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *AVC) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
for _, x := range rr.Txt {
|
||||
l += len(x) + 1
|
||||
}
|
||||
return l
|
||||
}
|
||||
func (rr *CAA) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *CAA) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l++ // Flag
|
||||
l += len(rr.Tag) + 1
|
||||
l += len(rr.Value)
|
||||
return l
|
||||
}
|
||||
func (rr *CERT) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *CERT) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 2 // Type
|
||||
l += 2 // KeyTag
|
||||
l++ // Algorithm
|
||||
l += base64.StdEncoding.DecodedLen(len(rr.Certificate))
|
||||
return l
|
||||
}
|
||||
func (rr *CNAME) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Target) + 1
|
||||
func (rr *CNAME) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += domainNameLen(rr.Target, off+l, compression, true)
|
||||
return l
|
||||
}
|
||||
func (rr *DHCID) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *DHCID) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += base64.StdEncoding.DecodedLen(len(rr.Digest))
|
||||
return l
|
||||
}
|
||||
func (rr *DNAME) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Target) + 1
|
||||
func (rr *DNAME) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += domainNameLen(rr.Target, off+l, compression, false)
|
||||
return l
|
||||
}
|
||||
func (rr *DNSKEY) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *DNSKEY) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 2 // Flags
|
||||
l++ // Protocol
|
||||
l++ // Algorithm
|
||||
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||
return l
|
||||
}
|
||||
func (rr *DS) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *DS) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 2 // KeyTag
|
||||
l++ // Algorithm
|
||||
l++ // DigestType
|
||||
l += len(rr.Digest)/2 + 1
|
||||
l += len(rr.Digest) / 2
|
||||
return l
|
||||
}
|
||||
func (rr *EID) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Endpoint)/2 + 1
|
||||
func (rr *EID) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += len(rr.Endpoint) / 2
|
||||
return l
|
||||
}
|
||||
func (rr *EUI48) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *EUI48) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 6 // Address
|
||||
return l
|
||||
}
|
||||
func (rr *EUI64) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *EUI64) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 8 // Address
|
||||
return l
|
||||
}
|
||||
func (rr *GID) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *GID) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 4 // Gid
|
||||
return l
|
||||
}
|
||||
func (rr *GPOS) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *GPOS) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += len(rr.Longitude) + 1
|
||||
l += len(rr.Latitude) + 1
|
||||
l += len(rr.Altitude) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *HINFO) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *HINFO) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += len(rr.Cpu) + 1
|
||||
l += len(rr.Os) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *HIP) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *HIP) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l++ // HitLength
|
||||
l++ // PublicKeyAlgorithm
|
||||
l += 2 // PublicKeyLength
|
||||
l += len(rr.Hit) / 2
|
||||
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||
for _, x := range rr.RendezvousServers {
|
||||
l += len(x) + 1
|
||||
l += domainNameLen(x, off+l, compression, false)
|
||||
}
|
||||
return l
|
||||
}
|
||||
func (rr *KX) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *KX) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 2 // Preference
|
||||
l += len(rr.Exchanger) + 1
|
||||
l += domainNameLen(rr.Exchanger, off+l, compression, false)
|
||||
return l
|
||||
}
|
||||
func (rr *L32) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Preference
|
||||
l += net.IPv4len // Locator32
|
||||
func (rr *L32) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 2 // Preference
|
||||
if len(rr.Locator32) != 0 {
|
||||
l += net.IPv4len
|
||||
}
|
||||
return l
|
||||
}
|
||||
func (rr *L64) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *L64) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 2 // Preference
|
||||
l += 8 // Locator64
|
||||
return l
|
||||
}
|
||||
func (rr *LOC) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *LOC) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l++ // Version
|
||||
l++ // Size
|
||||
l++ // HorizPre
|
||||
|
@ -383,89 +391,89 @@ func (rr *LOC) len() int {
|
|||
l += 4 // Altitude
|
||||
return l
|
||||
}
|
||||
func (rr *LP) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *LP) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 2 // Preference
|
||||
l += len(rr.Fqdn) + 1
|
||||
l += domainNameLen(rr.Fqdn, off+l, compression, false)
|
||||
return l
|
||||
}
|
||||
func (rr *MB) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Mb) + 1
|
||||
func (rr *MB) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += domainNameLen(rr.Mb, off+l, compression, true)
|
||||
return l
|
||||
}
|
||||
func (rr *MD) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Md) + 1
|
||||
func (rr *MD) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += domainNameLen(rr.Md, off+l, compression, true)
|
||||
return l
|
||||
}
|
||||
func (rr *MF) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Mf) + 1
|
||||
func (rr *MF) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += domainNameLen(rr.Mf, off+l, compression, true)
|
||||
return l
|
||||
}
|
||||
func (rr *MG) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Mg) + 1
|
||||
func (rr *MG) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += domainNameLen(rr.Mg, off+l, compression, true)
|
||||
return l
|
||||
}
|
||||
func (rr *MINFO) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Rmail) + 1
|
||||
l += len(rr.Email) + 1
|
||||
func (rr *MINFO) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += domainNameLen(rr.Rmail, off+l, compression, true)
|
||||
l += domainNameLen(rr.Email, off+l, compression, true)
|
||||
return l
|
||||
}
|
||||
func (rr *MR) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Mr) + 1
|
||||
func (rr *MR) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += domainNameLen(rr.Mr, off+l, compression, true)
|
||||
return l
|
||||
}
|
||||
func (rr *MX) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *MX) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 2 // Preference
|
||||
l += len(rr.Mx) + 1
|
||||
l += domainNameLen(rr.Mx, off+l, compression, true)
|
||||
return l
|
||||
}
|
||||
func (rr *NAPTR) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *NAPTR) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 2 // Order
|
||||
l += 2 // Preference
|
||||
l += len(rr.Flags) + 1
|
||||
l += len(rr.Service) + 1
|
||||
l += len(rr.Regexp) + 1
|
||||
l += len(rr.Replacement) + 1
|
||||
l += domainNameLen(rr.Replacement, off+l, compression, false)
|
||||
return l
|
||||
}
|
||||
func (rr *NID) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *NID) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 2 // Preference
|
||||
l += 8 // NodeID
|
||||
return l
|
||||
}
|
||||
func (rr *NIMLOC) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Locator)/2 + 1
|
||||
func (rr *NIMLOC) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += len(rr.Locator) / 2
|
||||
return l
|
||||
}
|
||||
func (rr *NINFO) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *NINFO) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
for _, x := range rr.ZSData {
|
||||
l += len(x) + 1
|
||||
}
|
||||
return l
|
||||
}
|
||||
func (rr *NS) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Ns) + 1
|
||||
func (rr *NS) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += domainNameLen(rr.Ns, off+l, compression, true)
|
||||
return l
|
||||
}
|
||||
func (rr *NSAPPTR) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Ptr) + 1
|
||||
func (rr *NSAPPTR) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += domainNameLen(rr.Ptr, off+l, compression, false)
|
||||
return l
|
||||
}
|
||||
func (rr *NSEC3PARAM) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *NSEC3PARAM) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l++ // Hash
|
||||
l++ // Flags
|
||||
l += 2 // Iterations
|
||||
|
@ -473,44 +481,49 @@ func (rr *NSEC3PARAM) len() int {
|
|||
l += len(rr.Salt) / 2
|
||||
return l
|
||||
}
|
||||
func (rr *OPENPGPKEY) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *NULL) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += len(rr.Data)
|
||||
return l
|
||||
}
|
||||
func (rr *OPENPGPKEY) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||
return l
|
||||
}
|
||||
func (rr *PTR) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Ptr) + 1
|
||||
func (rr *PTR) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += domainNameLen(rr.Ptr, off+l, compression, true)
|
||||
return l
|
||||
}
|
||||
func (rr *PX) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *PX) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 2 // Preference
|
||||
l += len(rr.Map822) + 1
|
||||
l += len(rr.Mapx400) + 1
|
||||
l += domainNameLen(rr.Map822, off+l, compression, false)
|
||||
l += domainNameLen(rr.Mapx400, off+l, compression, false)
|
||||
return l
|
||||
}
|
||||
func (rr *RFC3597) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Rdata)/2 + 1
|
||||
func (rr *RFC3597) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += len(rr.Rdata) / 2
|
||||
return l
|
||||
}
|
||||
func (rr *RKEY) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *RKEY) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 2 // Flags
|
||||
l++ // Protocol
|
||||
l++ // Algorithm
|
||||
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||
return l
|
||||
}
|
||||
func (rr *RP) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Mbox) + 1
|
||||
l += len(rr.Txt) + 1
|
||||
func (rr *RP) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += domainNameLen(rr.Mbox, off+l, compression, false)
|
||||
l += domainNameLen(rr.Txt, off+l, compression, false)
|
||||
return l
|
||||
}
|
||||
func (rr *RRSIG) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *RRSIG) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 2 // TypeCovered
|
||||
l++ // Algorithm
|
||||
l++ // Labels
|
||||
|
@ -518,28 +531,28 @@ func (rr *RRSIG) len() int {
|
|||
l += 4 // Expiration
|
||||
l += 4 // Inception
|
||||
l += 2 // KeyTag
|
||||
l += len(rr.SignerName) + 1
|
||||
l += domainNameLen(rr.SignerName, off+l, compression, false)
|
||||
l += base64.StdEncoding.DecodedLen(len(rr.Signature))
|
||||
return l
|
||||
}
|
||||
func (rr *RT) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *RT) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 2 // Preference
|
||||
l += len(rr.Host) + 1
|
||||
l += domainNameLen(rr.Host, off+l, compression, false)
|
||||
return l
|
||||
}
|
||||
func (rr *SMIMEA) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *SMIMEA) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l++ // Usage
|
||||
l++ // Selector
|
||||
l++ // MatchingType
|
||||
l += len(rr.Certificate)/2 + 1
|
||||
l += len(rr.Certificate) / 2
|
||||
return l
|
||||
}
|
||||
func (rr *SOA) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Ns) + 1
|
||||
l += len(rr.Mbox) + 1
|
||||
func (rr *SOA) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += domainNameLen(rr.Ns, off+l, compression, true)
|
||||
l += domainNameLen(rr.Mbox, off+l, compression, true)
|
||||
l += 4 // Serial
|
||||
l += 4 // Refresh
|
||||
l += 4 // Retry
|
||||
|
@ -547,45 +560,45 @@ func (rr *SOA) len() int {
|
|||
l += 4 // Minttl
|
||||
return l
|
||||
}
|
||||
func (rr *SPF) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *SPF) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
for _, x := range rr.Txt {
|
||||
l += len(x) + 1
|
||||
}
|
||||
return l
|
||||
}
|
||||
func (rr *SRV) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *SRV) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 2 // Priority
|
||||
l += 2 // Weight
|
||||
l += 2 // Port
|
||||
l += len(rr.Target) + 1
|
||||
l += domainNameLen(rr.Target, off+l, compression, false)
|
||||
return l
|
||||
}
|
||||
func (rr *SSHFP) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *SSHFP) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l++ // Algorithm
|
||||
l++ // Type
|
||||
l += len(rr.FingerPrint)/2 + 1
|
||||
l += len(rr.FingerPrint) / 2
|
||||
return l
|
||||
}
|
||||
func (rr *TA) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *TA) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 2 // KeyTag
|
||||
l++ // Algorithm
|
||||
l++ // DigestType
|
||||
l += len(rr.Digest)/2 + 1
|
||||
l += len(rr.Digest) / 2
|
||||
return l
|
||||
}
|
||||
func (rr *TALINK) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.PreviousName) + 1
|
||||
l += len(rr.NextName) + 1
|
||||
func (rr *TALINK) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += domainNameLen(rr.PreviousName, off+l, compression, false)
|
||||
l += domainNameLen(rr.NextName, off+l, compression, false)
|
||||
return l
|
||||
}
|
||||
func (rr *TKEY) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Algorithm) + 1
|
||||
func (rr *TKEY) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += domainNameLen(rr.Algorithm, off+l, compression, false)
|
||||
l += 4 // Inception
|
||||
l += 4 // Expiration
|
||||
l += 2 // Mode
|
||||
|
@ -596,17 +609,17 @@ func (rr *TKEY) len() int {
|
|||
l += len(rr.OtherData) / 2
|
||||
return l
|
||||
}
|
||||
func (rr *TLSA) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *TLSA) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l++ // Usage
|
||||
l++ // Selector
|
||||
l++ // MatchingType
|
||||
l += len(rr.Certificate)/2 + 1
|
||||
l += len(rr.Certificate) / 2
|
||||
return l
|
||||
}
|
||||
func (rr *TSIG) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Algorithm) + 1
|
||||
func (rr *TSIG) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += domainNameLen(rr.Algorithm, off+l, compression, false)
|
||||
l += 6 // TimeSigned
|
||||
l += 2 // Fudge
|
||||
l += 2 // MACSize
|
||||
|
@ -617,32 +630,32 @@ func (rr *TSIG) len() int {
|
|||
l += len(rr.OtherData) / 2
|
||||
return l
|
||||
}
|
||||
func (rr *TXT) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *TXT) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
for _, x := range rr.Txt {
|
||||
l += len(x) + 1
|
||||
}
|
||||
return l
|
||||
}
|
||||
func (rr *UID) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *UID) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 4 // Uid
|
||||
return l
|
||||
}
|
||||
func (rr *UINFO) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *UINFO) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += len(rr.Uinfo) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *URI) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *URI) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += 2 // Priority
|
||||
l += 2 // Weight
|
||||
l += len(rr.Target)
|
||||
return l
|
||||
}
|
||||
func (rr *X25) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *X25) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
l += len(rr.PSDNAddress) + 1
|
||||
return l
|
||||
}
|
||||
|
@ -783,12 +796,17 @@ func (rr *NSEC3) copy() RR {
|
|||
func (rr *NSEC3PARAM) copy() RR {
|
||||
return &NSEC3PARAM{rr.Hdr, rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt}
|
||||
}
|
||||
func (rr *NULL) copy() RR {
|
||||
return &NULL{rr.Hdr, rr.Data}
|
||||
}
|
||||
func (rr *OPENPGPKEY) copy() RR {
|
||||
return &OPENPGPKEY{rr.Hdr, rr.PublicKey}
|
||||
}
|
||||
func (rr *OPT) copy() RR {
|
||||
Option := make([]EDNS0, len(rr.Option))
|
||||
copy(Option, rr.Option)
|
||||
for i, e := range rr.Option {
|
||||
Option[i] = e.copy()
|
||||
}
|
||||
return &OPT{rr.Hdr, Option}
|
||||
}
|
||||
func (rr *PTR) copy() RR {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !ppc64le,!arm64,!s390x arm64,!go1.11 gccgo appengine
|
||||
// +build !arm64,!s390x,!ppc64le arm64,!go1.11 gccgo appengine
|
||||
|
||||
package chacha20
|
||||
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
|
||||
package chacha20
|
||||
|
||||
import "encoding/binary"
|
||||
import (
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
const (
|
||||
bufSize = 256
|
||||
|
@ -14,14 +16,15 @@ const (
|
|||
)
|
||||
|
||||
//go:noescape
|
||||
func chaCha20_ctr32_vmx(out, inp *byte, len int, key *[8]uint32, counter *uint32)
|
||||
func chaCha20_ctr32_vsx(out, inp *byte, len int, key *[8]uint32, counter *uint32)
|
||||
|
||||
func (c *Cipher) xorKeyStreamAsm(dst, src []byte) {
|
||||
// This implementation can handle buffers that aren't multiples of
|
||||
// 256.
|
||||
if len(src) >= bufSize {
|
||||
chaCha20_ctr32_vmx(&dst[0], &src[0], len(src)-len(src)%bufSize, &c.key, &c.counter)
|
||||
}
|
||||
if len(src)%bufSize != 0 {
|
||||
chaCha20_ctr32_vmx(&c.buf[0], &c.buf[0], bufSize, &c.key, &c.counter)
|
||||
chaCha20_ctr32_vsx(&dst[0], &src[0], len(src), &c.key, &c.counter)
|
||||
} else if len(src)%bufSize != 0 {
|
||||
chaCha20_ctr32_vsx(&c.buf[0], &c.buf[0], bufSize, &c.key, &c.counter)
|
||||
start := len(src) - len(src)%bufSize
|
||||
ts, td, tb := src[start:], dst[start:], c.buf[:]
|
||||
// Unroll loop to XOR 32 bytes per iteration.
|
||||
|
@ -46,7 +49,6 @@ func (c *Cipher) xorKeyStreamAsm(dst, src []byte) {
|
|||
td[i] = tb[i] ^ v
|
||||
}
|
||||
c.len = bufSize - (len(src) % bufSize)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -58,6 +58,14 @@ var serverForbiddenKexAlgos = map[string]struct{}{
|
|||
kexAlgoDHGEXSHA256: {}, // server half implementation is only minimal to satisfy the automated tests
|
||||
}
|
||||
|
||||
// preferredKexAlgos specifies the default preference for key-exchange algorithms
|
||||
// in preference order.
|
||||
var preferredKexAlgos = []string{
|
||||
kexAlgoCurve25519SHA256,
|
||||
kexAlgoECDH256, kexAlgoECDH384, kexAlgoECDH521,
|
||||
kexAlgoDH14SHA1,
|
||||
}
|
||||
|
||||
// supportedHostKeyAlgos specifies the supported host-key algorithms (i.e. methods
|
||||
// of authenticating servers) in preference order.
|
||||
var supportedHostKeyAlgos = []string{
|
||||
|
@ -246,7 +254,7 @@ func (c *Config) SetDefaults() {
|
|||
c.Ciphers = ciphers
|
||||
|
||||
if c.KeyExchanges == nil {
|
||||
c.KeyExchanges = supportedKexAlgos
|
||||
c.KeyExchanges = preferredKexAlgos
|
||||
}
|
||||
|
||||
if c.MACs == nil {
|
||||
|
|
|
@ -150,7 +150,7 @@ func appendIndexed(dst []byte, i uint64) []byte {
|
|||
// extended buffer.
|
||||
//
|
||||
// If f.Sensitive is true, "Never Indexed" representation is used. If
|
||||
// f.Sensitive is false and indexing is true, "Inremental Indexing"
|
||||
// f.Sensitive is false and indexing is true, "Incremental Indexing"
|
||||
// representation is used.
|
||||
func appendNewName(dst []byte, f HeaderField, indexing bool) []byte {
|
||||
dst = append(dst, encodeTypeByte(indexing, f.Sensitive))
|
||||
|
|
|
@ -52,10 +52,11 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
prefaceTimeout = 10 * time.Second
|
||||
firstSettingsTimeout = 2 * time.Second // should be in-flight with preface anyway
|
||||
handlerChunkWriteSize = 4 << 10
|
||||
defaultMaxStreams = 250 // TODO: make this 100 as the GFE seems to?
|
||||
prefaceTimeout = 10 * time.Second
|
||||
firstSettingsTimeout = 2 * time.Second // should be in-flight with preface anyway
|
||||
handlerChunkWriteSize = 4 << 10
|
||||
defaultMaxStreams = 250 // TODO: make this 100 as the GFE seems to?
|
||||
maxQueuedControlFrames = 10000
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -163,6 +164,15 @@ func (s *Server) maxConcurrentStreams() uint32 {
|
|||
return defaultMaxStreams
|
||||
}
|
||||
|
||||
// maxQueuedControlFrames is the maximum number of control frames like
|
||||
// SETTINGS, PING and RST_STREAM that will be queued for writing before
|
||||
// the connection is closed to prevent memory exhaustion attacks.
|
||||
func (s *Server) maxQueuedControlFrames() int {
|
||||
// TODO: if anybody asks, add a Server field, and remember to define the
|
||||
// behavior of negative values.
|
||||
return maxQueuedControlFrames
|
||||
}
|
||||
|
||||
type serverInternalState struct {
|
||||
mu sync.Mutex
|
||||
activeConns map[*serverConn]struct{}
|
||||
|
@ -312,7 +322,7 @@ type ServeConnOpts struct {
|
|||
}
|
||||
|
||||
func (o *ServeConnOpts) context() context.Context {
|
||||
if o.Context != nil {
|
||||
if o != nil && o.Context != nil {
|
||||
return o.Context
|
||||
}
|
||||
return context.Background()
|
||||
|
@ -506,6 +516,7 @@ type serverConn struct {
|
|||
sawFirstSettings bool // got the initial SETTINGS frame after the preface
|
||||
needToSendSettingsAck bool
|
||||
unackedSettings int // how many SETTINGS have we sent without ACKs?
|
||||
queuedControlFrames int // control frames in the writeSched queue
|
||||
clientMaxStreams uint32 // SETTINGS_MAX_CONCURRENT_STREAMS from client (our PUSH_PROMISE limit)
|
||||
advMaxStreams uint32 // our SETTINGS_MAX_CONCURRENT_STREAMS advertised the client
|
||||
curClientStreams uint32 // number of open streams initiated by the client
|
||||
|
@ -894,6 +905,14 @@ func (sc *serverConn) serve() {
|
|||
}
|
||||
}
|
||||
|
||||
// If the peer is causing us to generate a lot of control frames,
|
||||
// but not reading them from us, assume they are trying to make us
|
||||
// run out of memory.
|
||||
if sc.queuedControlFrames > sc.srv.maxQueuedControlFrames() {
|
||||
sc.vlogf("http2: too many control frames in send queue, closing connection")
|
||||
return
|
||||
}
|
||||
|
||||
// Start the shutdown timer after sending a GOAWAY. When sending GOAWAY
|
||||
// with no error code (graceful shutdown), don't start the timer until
|
||||
// all open streams have been completed.
|
||||
|
@ -1093,6 +1112,14 @@ func (sc *serverConn) writeFrame(wr FrameWriteRequest) {
|
|||
}
|
||||
|
||||
if !ignoreWrite {
|
||||
if wr.isControl() {
|
||||
sc.queuedControlFrames++
|
||||
// For extra safety, detect wraparounds, which should not happen,
|
||||
// and pull the plug.
|
||||
if sc.queuedControlFrames < 0 {
|
||||
sc.conn.Close()
|
||||
}
|
||||
}
|
||||
sc.writeSched.Push(wr)
|
||||
}
|
||||
sc.scheduleFrameWrite()
|
||||
|
@ -1210,10 +1237,8 @@ func (sc *serverConn) wroteFrame(res frameWriteResult) {
|
|||
// If a frame is already being written, nothing happens. This will be called again
|
||||
// when the frame is done being written.
|
||||
//
|
||||
// If a frame isn't being written we need to send one, the best frame
|
||||
// to send is selected, preferring first things that aren't
|
||||
// stream-specific (e.g. ACKing settings), and then finding the
|
||||
// highest priority stream.
|
||||
// If a frame isn't being written and we need to send one, the best frame
|
||||
// to send is selected by writeSched.
|
||||
//
|
||||
// If a frame isn't being written and there's nothing else to send, we
|
||||
// flush the write buffer.
|
||||
|
@ -1241,6 +1266,9 @@ func (sc *serverConn) scheduleFrameWrite() {
|
|||
}
|
||||
if !sc.inGoAway || sc.goAwayCode == ErrCodeNo {
|
||||
if wr, ok := sc.writeSched.Pop(); ok {
|
||||
if wr.isControl() {
|
||||
sc.queuedControlFrames--
|
||||
}
|
||||
sc.startFrameWrite(wr)
|
||||
continue
|
||||
}
|
||||
|
@ -1533,6 +1561,8 @@ func (sc *serverConn) processSettings(f *SettingsFrame) error {
|
|||
if err := f.ForeachSetting(sc.processSetting); err != nil {
|
||||
return err
|
||||
}
|
||||
// TODO: judging by RFC 7540, Section 6.5.3 each SETTINGS frame should be
|
||||
// acknowledged individually, even if multiple are received before the ACK.
|
||||
sc.needToSendSettingsAck = true
|
||||
sc.scheduleFrameWrite()
|
||||
return nil
|
||||
|
@ -2494,7 +2524,7 @@ const TrailerPrefix = "Trailer:"
|
|||
// trailers. That worked for a while, until we found the first major
|
||||
// user of Trailers in the wild: gRPC (using them only over http2),
|
||||
// and gRPC libraries permit setting trailers mid-stream without
|
||||
// predeclarnig them. So: change of plans. We still permit the old
|
||||
// predeclaring them. So: change of plans. We still permit the old
|
||||
// way, but we also permit this hack: if a Header() key begins with
|
||||
// "Trailer:", the suffix of that key is a Trailer. Because ':' is an
|
||||
// invalid token byte anyway, there is no ambiguity. (And it's already
|
||||
|
@ -2794,7 +2824,7 @@ func (sc *serverConn) startPush(msg *startPushRequest) {
|
|||
// PUSH_PROMISE frames MUST only be sent on a peer-initiated stream that
|
||||
// is in either the "open" or "half-closed (remote)" state.
|
||||
if msg.parent.state != stateOpen && msg.parent.state != stateHalfClosedRemote {
|
||||
// responseWriter.Push checks that the stream is peer-initiaed.
|
||||
// responseWriter.Push checks that the stream is peer-initiated.
|
||||
msg.done <- errStreamClosed
|
||||
return
|
||||
}
|
||||
|
|
|
@ -992,7 +992,7 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf
|
|||
req.Method != "HEAD" {
|
||||
// Request gzip only, not deflate. Deflate is ambiguous and
|
||||
// not as universally supported anyway.
|
||||
// See: http://www.gzip.org/zlib/zlib_faq.html#faq38
|
||||
// See: https://zlib.net/zlib_faq.html#faq39
|
||||
//
|
||||
// Note that we don't request this for HEAD requests,
|
||||
// due to a bug in nginx:
|
||||
|
@ -1216,6 +1216,8 @@ var (
|
|||
|
||||
// abort request body write, but send stream reset of cancel.
|
||||
errStopReqBodyWriteAndCancel = errors.New("http2: canceling request")
|
||||
|
||||
errReqBodyTooLong = errors.New("http2: request body larger than specified content length")
|
||||
)
|
||||
|
||||
func (cs *clientStream) writeRequestBody(body io.Reader, bodyCloser io.Closer) (err error) {
|
||||
|
@ -1238,10 +1240,32 @@ func (cs *clientStream) writeRequestBody(body io.Reader, bodyCloser io.Closer) (
|
|||
|
||||
req := cs.req
|
||||
hasTrailers := req.Trailer != nil
|
||||
remainLen := actualContentLength(req)
|
||||
hasContentLen := remainLen != -1
|
||||
|
||||
var sawEOF bool
|
||||
for !sawEOF {
|
||||
n, err := body.Read(buf)
|
||||
n, err := body.Read(buf[:len(buf)-1])
|
||||
if hasContentLen {
|
||||
remainLen -= int64(n)
|
||||
if remainLen == 0 && err == nil {
|
||||
// The request body's Content-Length was predeclared and
|
||||
// we just finished reading it all, but the underlying io.Reader
|
||||
// returned the final chunk with a nil error (which is one of
|
||||
// the two valid things a Reader can do at EOF). Because we'd prefer
|
||||
// to send the END_STREAM bit early, double-check that we're actually
|
||||
// at EOF. Subsequent reads should return (0, EOF) at this point.
|
||||
// If either value is different, we return an error in one of two ways below.
|
||||
var n1 int
|
||||
n1, err = body.Read(buf[n:])
|
||||
remainLen -= int64(n1)
|
||||
}
|
||||
if remainLen < 0 {
|
||||
err = errReqBodyTooLong
|
||||
cc.writeStreamReset(cs.ID, ErrCodeCancel, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err == io.EOF {
|
||||
sawEOF = true
|
||||
err = nil
|
||||
|
|
|
@ -32,7 +32,7 @@ type WriteScheduler interface {
|
|||
|
||||
// Pop dequeues the next frame to write. Returns false if no frames can
|
||||
// be written. Frames with a given wr.StreamID() are Pop'd in the same
|
||||
// order they are Push'd.
|
||||
// order they are Push'd. No frames should be discarded except by CloseStream.
|
||||
Pop() (wr FrameWriteRequest, ok bool)
|
||||
}
|
||||
|
||||
|
@ -76,6 +76,12 @@ func (wr FrameWriteRequest) StreamID() uint32 {
|
|||
return wr.stream.id
|
||||
}
|
||||
|
||||
// isControl reports whether wr is a control frame for MaxQueuedControlFrames
|
||||
// purposes. That includes non-stream frames and RST_STREAM frames.
|
||||
func (wr FrameWriteRequest) isControl() bool {
|
||||
return wr.stream == nil
|
||||
}
|
||||
|
||||
// DataSize returns the number of flow control bytes that must be consumed
|
||||
// to write this entire frame. This is 0 for non-DATA frames.
|
||||
func (wr FrameWriteRequest) DataSize() int {
|
||||
|
|
|
@ -149,7 +149,7 @@ func (n *priorityNode) addBytes(b int64) {
|
|||
}
|
||||
|
||||
// walkReadyInOrder iterates over the tree in priority order, calling f for each node
|
||||
// with a non-empty write queue. When f returns true, this funcion returns true and the
|
||||
// with a non-empty write queue. When f returns true, this function returns true and the
|
||||
// walk halts. tmp is used as scratch space for sorting.
|
||||
//
|
||||
// f(n, openParent) takes two arguments: the node to visit, n, and a bool that is true
|
||||
|
|
|
@ -31,7 +31,6 @@ type sockaddrInet6 C.struct_sockaddr_in6
|
|||
const (
|
||||
sizeofIovec = C.sizeof_struct_iovec
|
||||
sizeofMsghdr = C.sizeof_struct_msghdr
|
||||
sizeofMmsghdr = C.sizeof_struct_mmsghdr
|
||||
sizeofCmsghdr = C.sizeof_struct_cmsghdr
|
||||
|
||||
sizeofSockaddrInet = C.sizeof_struct_sockaddr_in
|
||||
|
|
|
@ -33,7 +33,6 @@ type sockaddrInet6 C.struct_sockaddr_in6
|
|||
const (
|
||||
sizeofIovec = C.sizeof_struct_iovec
|
||||
sizeofMsghdr = C.sizeof_struct_msghdr
|
||||
sizeofMmsghdr = C.sizeof_struct_mmsghdr
|
||||
sizeofCmsghdr = C.sizeof_struct_cmsghdr
|
||||
|
||||
sizeofSockaddrInet = C.sizeof_struct_sockaddr_in
|
||||
|
|
|
@ -31,7 +31,6 @@ type sockaddrInet6 C.struct_sockaddr_in6
|
|||
const (
|
||||
sizeofIovec = C.sizeof_struct_iovec
|
||||
sizeofMsghdr = C.sizeof_struct_msghdr
|
||||
sizeofMmsghdr = C.sizeof_struct_mmsghdr
|
||||
sizeofCmsghdr = C.sizeof_struct_cmsghdr
|
||||
|
||||
sizeofSockaddrInet = C.sizeof_struct_sockaddr_in
|
||||
|
|
|
@ -53,7 +53,6 @@ type sockaddrInet6 struct {
|
|||
const (
|
||||
sizeofIovec = 0x10
|
||||
sizeofMsghdr = 0x30
|
||||
sizeofMmsghdr = 0x38
|
||||
sizeofCmsghdr = 0xc
|
||||
|
||||
sizeofSockaddrInet = 0x10
|
||||
|
|
|
@ -47,7 +47,6 @@ type sockaddrInet6 struct {
|
|||
const (
|
||||
sizeofIovec = 0x8
|
||||
sizeofMsghdr = 0x1c
|
||||
sizeofMmsghdr = 0x20
|
||||
sizeofCmsghdr = 0xc
|
||||
|
||||
sizeofSockaddrInet = 0x10
|
||||
|
|
|
@ -50,7 +50,6 @@ type sockaddrInet6 struct {
|
|||
const (
|
||||
sizeofIovec = 0x10
|
||||
sizeofMsghdr = 0x38
|
||||
sizeofMmsghdr = 0x40
|
||||
sizeofCmsghdr = 0x10
|
||||
|
||||
sizeofSockaddrInet = 0x10
|
||||
|
|
|
@ -45,9 +45,9 @@ type sockaddrInet6 struct {
|
|||
}
|
||||
|
||||
const (
|
||||
sizeofIovec = 0x8
|
||||
sizeofMsghdr = 0x1c
|
||||
sizeofMmsghdr = 0x20
|
||||
sizeofIovec = 0x8
|
||||
sizeofMsghdr = 0x1c
|
||||
|
||||
sizeofCmsghdr = 0xc
|
||||
|
||||
sizeofSockaddrInet = 0x10
|
||||
|
|
|
@ -48,9 +48,9 @@ type sockaddrInet6 struct {
|
|||
}
|
||||
|
||||
const (
|
||||
sizeofIovec = 0x10
|
||||
sizeofMsghdr = 0x38
|
||||
sizeofMmsghdr = 0x40
|
||||
sizeofIovec = 0x10
|
||||
sizeofMsghdr = 0x38
|
||||
|
||||
sizeofCmsghdr = 0x10
|
||||
|
||||
sizeofSockaddrInet = 0x10
|
||||
|
|
|
@ -45,9 +45,9 @@ type sockaddrInet6 struct {
|
|||
}
|
||||
|
||||
const (
|
||||
sizeofIovec = 0x8
|
||||
sizeofMsghdr = 0x1c
|
||||
sizeofMmsghdr = 0x20
|
||||
sizeofIovec = 0x8
|
||||
sizeofMsghdr = 0x1c
|
||||
|
||||
sizeofCmsghdr = 0xc
|
||||
|
||||
sizeofSockaddrInet = 0x10
|
||||
|
|
|
@ -48,9 +48,9 @@ type sockaddrInet6 struct {
|
|||
}
|
||||
|
||||
const (
|
||||
sizeofIovec = 0x10
|
||||
sizeofMsghdr = 0x38
|
||||
sizeofMmsghdr = 0x40
|
||||
sizeofIovec = 0x10
|
||||
sizeofMsghdr = 0x38
|
||||
|
||||
sizeofCmsghdr = 0x10
|
||||
|
||||
sizeofSockaddrInet = 0x10
|
||||
|
|
|
@ -48,9 +48,9 @@ type sockaddrInet6 struct {
|
|||
}
|
||||
|
||||
const (
|
||||
sizeofIovec = 0x10
|
||||
sizeofMsghdr = 0x38
|
||||
sizeofMmsghdr = 0x40
|
||||
sizeofIovec = 0x10
|
||||
sizeofMsghdr = 0x38
|
||||
|
||||
sizeofCmsghdr = 0x10
|
||||
|
||||
sizeofSockaddrInet = 0x10
|
||||
|
|
|
@ -45,9 +45,9 @@ type sockaddrInet6 struct {
|
|||
}
|
||||
|
||||
const (
|
||||
sizeofIovec = 0x8
|
||||
sizeofMsghdr = 0x1c
|
||||
sizeofMmsghdr = 0x20
|
||||
sizeofIovec = 0x8
|
||||
sizeofMsghdr = 0x1c
|
||||
|
||||
sizeofCmsghdr = 0xc
|
||||
|
||||
sizeofSockaddrInet = 0x10
|
||||
|
|
|
@ -48,9 +48,9 @@ type sockaddrInet6 struct {
|
|||
}
|
||||
|
||||
const (
|
||||
sizeofIovec = 0x10
|
||||
sizeofMsghdr = 0x38
|
||||
sizeofMmsghdr = 0x40
|
||||
sizeofIovec = 0x10
|
||||
sizeofMsghdr = 0x38
|
||||
|
||||
sizeofCmsghdr = 0x10
|
||||
|
||||
sizeofSockaddrInet = 0x10
|
||||
|
|
|
@ -48,9 +48,9 @@ type sockaddrInet6 struct {
|
|||
}
|
||||
|
||||
const (
|
||||
sizeofIovec = 0x10
|
||||
sizeofMsghdr = 0x38
|
||||
sizeofMmsghdr = 0x40
|
||||
sizeofIovec = 0x10
|
||||
sizeofMsghdr = 0x38
|
||||
|
||||
sizeofCmsghdr = 0x10
|
||||
|
||||
sizeofSockaddrInet = 0x10
|
||||
|
|
|
@ -49,9 +49,9 @@ type sockaddrInet6 struct {
|
|||
}
|
||||
|
||||
const (
|
||||
sizeofIovec = 0x10
|
||||
sizeofMsghdr = 0x38
|
||||
sizeofMmsghdr = 0x40
|
||||
sizeofIovec = 0x10
|
||||
sizeofMsghdr = 0x38
|
||||
|
||||
sizeofCmsghdr = 0x10
|
||||
|
||||
sizeofSockaddrInet = 0x10
|
||||
|
|
|
@ -48,9 +48,9 @@ type sockaddrInet6 struct {
|
|||
}
|
||||
|
||||
const (
|
||||
sizeofIovec = 0x10
|
||||
sizeofMsghdr = 0x38
|
||||
sizeofMmsghdr = 0x40
|
||||
sizeofIovec = 0x10
|
||||
sizeofMsghdr = 0x38
|
||||
|
||||
sizeofCmsghdr = 0x10
|
||||
|
||||
sizeofSockaddrInet = 0x10
|
||||
|
|
|
@ -47,9 +47,9 @@ type sockaddrInet6 struct {
|
|||
}
|
||||
|
||||
const (
|
||||
sizeofIovec = 0x8
|
||||
sizeofMsghdr = 0x1c
|
||||
sizeofMmsghdr = 0x20
|
||||
sizeofIovec = 0x8
|
||||
sizeofMsghdr = 0x1c
|
||||
|
||||
sizeofCmsghdr = 0xc
|
||||
|
||||
sizeofSockaddrInet = 0x10
|
||||
|
|
|
@ -50,9 +50,9 @@ type sockaddrInet6 struct {
|
|||
}
|
||||
|
||||
const (
|
||||
sizeofIovec = 0x10
|
||||
sizeofMsghdr = 0x30
|
||||
sizeofMmsghdr = 0x40
|
||||
sizeofIovec = 0x10
|
||||
sizeofMsghdr = 0x30
|
||||
|
||||
sizeofCmsghdr = 0xc
|
||||
|
||||
sizeofSockaddrInet = 0x10
|
||||
|
|
|
@ -47,9 +47,9 @@ type sockaddrInet6 struct {
|
|||
}
|
||||
|
||||
const (
|
||||
sizeofIovec = 0x8
|
||||
sizeofMsghdr = 0x1c
|
||||
sizeofMmsghdr = 0x20
|
||||
sizeofIovec = 0x8
|
||||
sizeofMsghdr = 0x1c
|
||||
|
||||
sizeofCmsghdr = 0xc
|
||||
|
||||
sizeofSockaddrInet = 0x10
|
||||
|
|
|
@ -52,7 +52,6 @@ type sockaddrInet6 struct {
|
|||
const (
|
||||
sizeofIovec = 0x10
|
||||
sizeofMsghdr = 0x30
|
||||
sizeofMmsghdr = 0x40
|
||||
sizeofCmsghdr = 0xc
|
||||
|
||||
sizeofSockaddrInet = 0x10
|
||||
|
|
|
@ -127,7 +127,7 @@ type Dialer struct {
|
|||
// establishing the transport connection.
|
||||
ProxyDial func(context.Context, string, string) (net.Conn, error)
|
||||
|
||||
// AuthMethods specifies the list of request authention
|
||||
// AuthMethods specifies the list of request authentication
|
||||
// methods.
|
||||
// If empty, SOCKS client requests only AuthMethodNotRequired.
|
||||
AuthMethods []AuthMethod
|
||||
|
|
|
@ -5,26 +5,56 @@
|
|||
package cpu
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// byteOrder is a subset of encoding/binary.ByteOrder.
|
||||
type byteOrder interface {
|
||||
Uint32([]byte) uint32
|
||||
Uint64([]byte) uint64
|
||||
}
|
||||
|
||||
type littleEndian struct{}
|
||||
type bigEndian struct{}
|
||||
|
||||
func (littleEndian) Uint32(b []byte) uint32 {
|
||||
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
|
||||
}
|
||||
|
||||
func (littleEndian) Uint64(b []byte) uint64 {
|
||||
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
|
||||
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
|
||||
}
|
||||
|
||||
func (bigEndian) Uint32(b []byte) uint32 {
|
||||
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
|
||||
}
|
||||
|
||||
func (bigEndian) Uint64(b []byte) uint64 {
|
||||
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
|
||||
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
|
||||
}
|
||||
|
||||
// hostByteOrder returns binary.LittleEndian on little-endian machines and
|
||||
// binary.BigEndian on big-endian machines.
|
||||
func hostByteOrder() binary.ByteOrder {
|
||||
func hostByteOrder() byteOrder {
|
||||
switch runtime.GOARCH {
|
||||
case "386", "amd64", "amd64p32",
|
||||
"arm", "arm64",
|
||||
"mipsle", "mips64le", "mips64p32le",
|
||||
"ppc64le",
|
||||
"riscv", "riscv64":
|
||||
return binary.LittleEndian
|
||||
return littleEndian{}
|
||||
case "armbe", "arm64be",
|
||||
"mips", "mips64", "mips64p32",
|
||||
"ppc", "ppc64",
|
||||
"s390", "s390x",
|
||||
"sparc", "sparc64":
|
||||
return binary.BigEndian
|
||||
return bigEndian{}
|
||||
}
|
||||
panic("unknown architecture")
|
||||
}
|
||||
|
|
|
@ -78,6 +78,42 @@ var ARM64 struct {
|
|||
_ CacheLinePad
|
||||
}
|
||||
|
||||
// ARM contains the supported CPU features of the current ARM (32-bit) platform.
|
||||
// All feature flags are false if:
|
||||
// 1. the current platform is not arm, or
|
||||
// 2. the current operating system is not Linux.
|
||||
var ARM struct {
|
||||
_ CacheLinePad
|
||||
HasSWP bool // SWP instruction support
|
||||
HasHALF bool // Half-word load and store support
|
||||
HasTHUMB bool // ARM Thumb instruction set
|
||||
Has26BIT bool // Address space limited to 26-bits
|
||||
HasFASTMUL bool // 32-bit operand, 64-bit result multiplication support
|
||||
HasFPA bool // Floating point arithmetic support
|
||||
HasVFP bool // Vector floating point support
|
||||
HasEDSP bool // DSP Extensions support
|
||||
HasJAVA bool // Java instruction set
|
||||
HasIWMMXT bool // Intel Wireless MMX technology support
|
||||
HasCRUNCH bool // MaverickCrunch context switching and handling
|
||||
HasTHUMBEE bool // Thumb EE instruction set
|
||||
HasNEON bool // NEON instruction set
|
||||
HasVFPv3 bool // Vector floating point version 3 support
|
||||
HasVFPv3D16 bool // Vector floating point version 3 D8-D15
|
||||
HasTLS bool // Thread local storage support
|
||||
HasVFPv4 bool // Vector floating point version 4 support
|
||||
HasIDIVA bool // Integer divide instruction support in ARM mode
|
||||
HasIDIVT bool // Integer divide instruction support in Thumb mode
|
||||
HasVFPD32 bool // Vector floating point version 3 D15-D31
|
||||
HasLPAE bool // Large Physical Address Extensions
|
||||
HasEVTSTRM bool // Event stream support
|
||||
HasAES bool // AES hardware implementation
|
||||
HasPMULL bool // Polynomial multiplication instruction set
|
||||
HasSHA1 bool // SHA1 hardware implementation
|
||||
HasSHA2 bool // SHA2 hardware implementation
|
||||
HasCRC32 bool // CRC32 hardware implementation
|
||||
_ CacheLinePad
|
||||
}
|
||||
|
||||
// PPC64 contains the supported CPU features of the current ppc64/ppc64le platforms.
|
||||
// If the current platform is not ppc64/ppc64le then all feature flags are false.
|
||||
//
|
||||
|
|
|
@ -6,4 +6,35 @@ package cpu
|
|||
|
||||
const cacheLineSize = 32
|
||||
|
||||
func doinit() {}
|
||||
// HWCAP/HWCAP2 bits.
|
||||
// These are specific to Linux.
|
||||
const (
|
||||
hwcap_SWP = 1 << 0
|
||||
hwcap_HALF = 1 << 1
|
||||
hwcap_THUMB = 1 << 2
|
||||
hwcap_26BIT = 1 << 3
|
||||
hwcap_FAST_MULT = 1 << 4
|
||||
hwcap_FPA = 1 << 5
|
||||
hwcap_VFP = 1 << 6
|
||||
hwcap_EDSP = 1 << 7
|
||||
hwcap_JAVA = 1 << 8
|
||||
hwcap_IWMMXT = 1 << 9
|
||||
hwcap_CRUNCH = 1 << 10
|
||||
hwcap_THUMBEE = 1 << 11
|
||||
hwcap_NEON = 1 << 12
|
||||
hwcap_VFPv3 = 1 << 13
|
||||
hwcap_VFPv3D16 = 1 << 14
|
||||
hwcap_TLS = 1 << 15
|
||||
hwcap_VFPv4 = 1 << 16
|
||||
hwcap_IDIVA = 1 << 17
|
||||
hwcap_IDIVT = 1 << 18
|
||||
hwcap_VFPD32 = 1 << 19
|
||||
hwcap_LPAE = 1 << 20
|
||||
hwcap_EVTSTRM = 1 << 21
|
||||
|
||||
hwcap2_AES = 1 << 0
|
||||
hwcap2_PMULL = 1 << 1
|
||||
hwcap2_SHA1 = 1 << 2
|
||||
hwcap2_SHA2 = 1 << 3
|
||||
hwcap2_CRC32 = 1 << 4
|
||||
)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//+build !amd64,!amd64p32,!386
|
||||
// +build !amd64,!amd64p32,!386
|
||||
|
||||
package cpu
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cpu
|
||||
|
||||
func doinit() {
|
||||
ARM.HasSWP = isSet(hwCap, hwcap_SWP)
|
||||
ARM.HasHALF = isSet(hwCap, hwcap_HALF)
|
||||
ARM.HasTHUMB = isSet(hwCap, hwcap_THUMB)
|
||||
ARM.Has26BIT = isSet(hwCap, hwcap_26BIT)
|
||||
ARM.HasFASTMUL = isSet(hwCap, hwcap_FAST_MULT)
|
||||
ARM.HasFPA = isSet(hwCap, hwcap_FPA)
|
||||
ARM.HasVFP = isSet(hwCap, hwcap_VFP)
|
||||
ARM.HasEDSP = isSet(hwCap, hwcap_EDSP)
|
||||
ARM.HasJAVA = isSet(hwCap, hwcap_JAVA)
|
||||
ARM.HasIWMMXT = isSet(hwCap, hwcap_IWMMXT)
|
||||
ARM.HasCRUNCH = isSet(hwCap, hwcap_CRUNCH)
|
||||
ARM.HasTHUMBEE = isSet(hwCap, hwcap_THUMBEE)
|
||||
ARM.HasNEON = isSet(hwCap, hwcap_NEON)
|
||||
ARM.HasVFPv3 = isSet(hwCap, hwcap_VFPv3)
|
||||
ARM.HasVFPv3D16 = isSet(hwCap, hwcap_VFPv3D16)
|
||||
ARM.HasTLS = isSet(hwCap, hwcap_TLS)
|
||||
ARM.HasVFPv4 = isSet(hwCap, hwcap_VFPv4)
|
||||
ARM.HasIDIVA = isSet(hwCap, hwcap_IDIVA)
|
||||
ARM.HasIDIVT = isSet(hwCap, hwcap_IDIVT)
|
||||
ARM.HasVFPD32 = isSet(hwCap, hwcap_VFPD32)
|
||||
ARM.HasLPAE = isSet(hwCap, hwcap_LPAE)
|
||||
ARM.HasEVTSTRM = isSet(hwCap, hwcap_EVTSTRM)
|
||||
ARM.HasAES = isSet(hwCap2, hwcap2_AES)
|
||||
ARM.HasPMULL = isSet(hwCap2, hwcap2_PMULL)
|
||||
ARM.HasSHA1 = isSet(hwCap2, hwcap2_SHA1)
|
||||
ARM.HasSHA2 = isSet(hwCap2, hwcap2_SHA2)
|
||||
ARM.HasCRC32 = isSet(hwCap2, hwcap2_CRC32)
|
||||
}
|
||||
|
||||
func isSet(hwc uint, value uint) bool {
|
||||
return hwc&value != 0
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
package unix
|
||||
|
||||
import (
|
||||
"math/bits"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
|
@ -79,50 +80,7 @@ func (s *CPUSet) IsSet(cpu int) bool {
|
|||
func (s *CPUSet) Count() int {
|
||||
c := 0
|
||||
for _, b := range s {
|
||||
c += onesCount64(uint64(b))
|
||||
c += bits.OnesCount64(uint64(b))
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// onesCount64 is a copy of Go 1.9's math/bits.OnesCount64.
|
||||
// Once this package can require Go 1.9, we can delete this
|
||||
// and update the caller to use bits.OnesCount64.
|
||||
func onesCount64(x uint64) int {
|
||||
const m0 = 0x5555555555555555 // 01010101 ...
|
||||
const m1 = 0x3333333333333333 // 00110011 ...
|
||||
const m2 = 0x0f0f0f0f0f0f0f0f // 00001111 ...
|
||||
|
||||
// Unused in this function, but definitions preserved for
|
||||
// documentation purposes:
|
||||
//
|
||||
// const m3 = 0x00ff00ff00ff00ff // etc.
|
||||
// const m4 = 0x0000ffff0000ffff
|
||||
//
|
||||
// Implementation: Parallel summing of adjacent bits.
|
||||
// See "Hacker's Delight", Chap. 5: Counting Bits.
|
||||
// The following pattern shows the general approach:
|
||||
//
|
||||
// x = x>>1&(m0&m) + x&(m0&m)
|
||||
// x = x>>2&(m1&m) + x&(m1&m)
|
||||
// x = x>>4&(m2&m) + x&(m2&m)
|
||||
// x = x>>8&(m3&m) + x&(m3&m)
|
||||
// x = x>>16&(m4&m) + x&(m4&m)
|
||||
// x = x>>32&(m5&m) + x&(m5&m)
|
||||
// return int(x)
|
||||
//
|
||||
// Masking (& operations) can be left away when there's no
|
||||
// danger that a field's sum will carry over into the next
|
||||
// field: Since the result cannot be > 64, 8 bits is enough
|
||||
// and we can ignore the masks for the shifts by 8 and up.
|
||||
// Per "Hacker's Delight", the first line can be simplified
|
||||
// more, but it saves at best one instruction, so we leave
|
||||
// it alone for clarity.
|
||||
const m = 1<<64 - 1
|
||||
x = x>>1&(m0&m) + x&(m0&m)
|
||||
x = x>>2&(m1&m) + x&(m1&m)
|
||||
x = (x>>4 + x) & (m2 & m)
|
||||
x += x >> 8
|
||||
x += x >> 16
|
||||
x += x >> 32
|
||||
return int(x) & (1<<7 - 1)
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ const (
|
|||
HCI_CHANNEL_USER = 1
|
||||
HCI_CHANNEL_MONITOR = 2
|
||||
HCI_CHANNEL_CONTROL = 3
|
||||
HCI_CHANNEL_LOGGING = 4
|
||||
)
|
||||
|
||||
// Socketoption Level
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
|
||||
package unix
|
||||
|
||||
// Set adds fd to the set fds.
|
||||
func (fds *FdSet) Set(fd int) {
|
||||
fds.Bits[fd/NFDBITS] |= (1 << (uintptr(fd) % NFDBITS))
|
||||
}
|
||||
|
||||
// Clear removes fd from the set fds.
|
||||
func (fds *FdSet) Clear(fd int) {
|
||||
fds.Bits[fd/NFDBITS] &^= (1 << (uintptr(fd) % NFDBITS))
|
||||
}
|
||||
|
||||
// IsSet returns whether fd is in the set fds.
|
||||
func (fds *FdSet) IsSet(fd int) bool {
|
||||
return fds.Bits[fd/NFDBITS]&(1<<(uintptr(fd)%NFDBITS)) != 0
|
||||
}
|
||||
|
||||
// Zero clears the set fds.
|
||||
func (fds *FdSet) Zero() {
|
||||
for i := range fds.Bits {
|
||||
fds.Bits[i] = 0
|
||||
}
|
||||
}
|
|
@ -6,7 +6,19 @@
|
|||
|
||||
package unix
|
||||
|
||||
import "runtime"
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// ioctl itself should not be exposed directly, but additional get/set
|
||||
// functions for specific types are permissible.
|
||||
|
||||
// IoctlSetInt performs an ioctl operation which sets an integer value
|
||||
// on fd, using the specified request number.
|
||||
func IoctlSetInt(fd int, req uint, value int) error {
|
||||
return ioctl(fd, req, uintptr(value))
|
||||
}
|
||||
|
||||
// IoctlSetWinsize performs an ioctl on fd with a *Winsize argument.
|
||||
//
|
||||
|
@ -14,7 +26,7 @@ import "runtime"
|
|||
func IoctlSetWinsize(fd int, req uint, value *Winsize) error {
|
||||
// TODO: if we get the chance, remove the req parameter and
|
||||
// hardcode TIOCSWINSZ.
|
||||
err := ioctlSetWinsize(fd, req, value)
|
||||
err := ioctl(fd, req, uintptr(unsafe.Pointer(value)))
|
||||
runtime.KeepAlive(value)
|
||||
return err
|
||||
}
|
||||
|
@ -24,7 +36,30 @@ func IoctlSetWinsize(fd int, req uint, value *Winsize) error {
|
|||
// The req value will usually be TCSETA or TIOCSETA.
|
||||
func IoctlSetTermios(fd int, req uint, value *Termios) error {
|
||||
// TODO: if we get the chance, remove the req parameter.
|
||||
err := ioctlSetTermios(fd, req, value)
|
||||
err := ioctl(fd, req, uintptr(unsafe.Pointer(value)))
|
||||
runtime.KeepAlive(value)
|
||||
return err
|
||||
}
|
||||
|
||||
// IoctlGetInt performs an ioctl operation which gets an integer value
|
||||
// from fd, using the specified request number.
|
||||
//
|
||||
// A few ioctl requests use the return value as an output parameter;
|
||||
// for those, IoctlRetInt should be used instead of this function.
|
||||
func IoctlGetInt(fd int, req uint) (int, error) {
|
||||
var value int
|
||||
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
|
||||
return value, err
|
||||
}
|
||||
|
||||
func IoctlGetWinsize(fd int, req uint) (*Winsize, error) {
|
||||
var value Winsize
|
||||
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
|
||||
return &value, err
|
||||
}
|
||||
|
||||
func IoctlGetTermios(fd int, req uint) (*Termios, error) {
|
||||
var value Termios
|
||||
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
|
||||
return &value, err
|
||||
}
|
||||
|
|
|
@ -212,9 +212,11 @@ esac
|
|||
echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in && gofmt -w zsyscall_$GOOSARCH.go && gofmt -w zsyscall_"$GOOSARCH"_gccgo.go && gofmt -w zsyscall_"$GOOSARCH"_gc.go " ;
|
||||
elif [ "$GOOS" == "darwin" ]; then
|
||||
# pre-1.12, direct syscalls
|
||||
echo "$mksyscall -tags $GOOS,$GOARCH,!go1.12 $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.1_11.go";
|
||||
echo "$mksyscall -tags $GOOS,$GOARCH,!go1.12 $syscall_goos syscall_darwin_${GOARCH}.1_11.go $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.1_11.go";
|
||||
# 1.12 and later, syscalls via libSystem
|
||||
echo "$mksyscall -tags $GOOS,$GOARCH,go1.12 $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go";
|
||||
# 1.13 and later, syscalls via libSystem (including syscallPtr)
|
||||
echo "$mksyscall -tags $GOOS,$GOARCH,go1.13 syscall_darwin.1_13.go |gofmt >zsyscall_$GOOSARCH.1_13.go";
|
||||
else
|
||||
echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go";
|
||||
fi
|
||||
|
|
|
@ -17,6 +17,34 @@ import (
|
|||
"strings"
|
||||
)
|
||||
|
||||
func writeASMFile(in string, fileName string, buildTags string) {
|
||||
trampolines := map[string]bool{}
|
||||
|
||||
var out bytes.Buffer
|
||||
|
||||
fmt.Fprintf(&out, "// go run mkasm_darwin.go %s\n", strings.Join(os.Args[1:], " "))
|
||||
fmt.Fprintf(&out, "// Code generated by the command above; DO NOT EDIT.\n")
|
||||
fmt.Fprintf(&out, "\n")
|
||||
fmt.Fprintf(&out, "// +build %s\n", buildTags)
|
||||
fmt.Fprintf(&out, "\n")
|
||||
fmt.Fprintf(&out, "#include \"textflag.h\"\n")
|
||||
for _, line := range strings.Split(in, "\n") {
|
||||
if !strings.HasPrefix(line, "func ") || !strings.HasSuffix(line, "_trampoline()") {
|
||||
continue
|
||||
}
|
||||
fn := line[5 : len(line)-13]
|
||||
if !trampolines[fn] {
|
||||
trampolines[fn] = true
|
||||
fmt.Fprintf(&out, "TEXT ·%s_trampoline(SB),NOSPLIT,$0-0\n", fn)
|
||||
fmt.Fprintf(&out, "\tJMP\t%s(SB)\n", fn)
|
||||
}
|
||||
}
|
||||
err := ioutil.WriteFile(fileName, out.Bytes(), 0644)
|
||||
if err != nil {
|
||||
log.Fatalf("can't write %s: %s", fileName, err)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
in1, err := ioutil.ReadFile("syscall_darwin.go")
|
||||
if err != nil {
|
||||
|
@ -33,29 +61,18 @@ func main() {
|
|||
}
|
||||
in := string(in1) + string(in2) + string(in3)
|
||||
|
||||
trampolines := map[string]bool{}
|
||||
writeASMFile(in, fmt.Sprintf("zsyscall_darwin_%s.s", arch), "go1.12")
|
||||
|
||||
var out bytes.Buffer
|
||||
|
||||
fmt.Fprintf(&out, "// go run mkasm_darwin.go %s\n", strings.Join(os.Args[1:], " "))
|
||||
fmt.Fprintf(&out, "// Code generated by the command above; DO NOT EDIT.\n")
|
||||
fmt.Fprintf(&out, "\n")
|
||||
fmt.Fprintf(&out, "// +build go1.12\n")
|
||||
fmt.Fprintf(&out, "\n")
|
||||
fmt.Fprintf(&out, "#include \"textflag.h\"\n")
|
||||
for _, line := range strings.Split(in, "\n") {
|
||||
if !strings.HasPrefix(line, "func ") || !strings.HasSuffix(line, "_trampoline()") {
|
||||
continue
|
||||
}
|
||||
fn := line[5 : len(line)-13]
|
||||
if !trampolines[fn] {
|
||||
trampolines[fn] = true
|
||||
fmt.Fprintf(&out, "TEXT ·%s_trampoline(SB),NOSPLIT,$0-0\n", fn)
|
||||
fmt.Fprintf(&out, "\tJMP\t%s(SB)\n", fn)
|
||||
}
|
||||
}
|
||||
err = ioutil.WriteFile(fmt.Sprintf("zsyscall_darwin_%s.s", arch), out.Bytes(), 0644)
|
||||
in1, err = ioutil.ReadFile("syscall_darwin.1_13.go")
|
||||
if err != nil {
|
||||
log.Fatalf("can't write zsyscall_darwin_%s.s: %s", arch, err)
|
||||
log.Fatalf("can't open syscall_darwin.1_13.go: %s", err)
|
||||
}
|
||||
in2, err = ioutil.ReadFile(fmt.Sprintf("zsyscall_darwin_%s.1_13.go", arch))
|
||||
if err != nil {
|
||||
log.Fatalf("can't open zsyscall_darwin_%s.1_13.go: %s", arch, err)
|
||||
}
|
||||
|
||||
in = string(in1) + string(in2)
|
||||
|
||||
writeASMFile(in, fmt.Sprintf("zsyscall_darwin_%s.1_13.s", arch), "go1.13")
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ includes_Darwin='
|
|||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
@ -80,6 +81,7 @@ includes_Darwin='
|
|||
includes_DragonFly='
|
||||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/stat.h>
|
||||
|
@ -103,6 +105,7 @@ includes_FreeBSD='
|
|||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/stat.h>
|
||||
|
@ -179,24 +182,32 @@ struct ltchars {
|
|||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/xattr.h>
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/can.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/cryptouser.h>
|
||||
#include <linux/devlink.h>
|
||||
#include <linux/errqueue.h>
|
||||
#include <linux/falloc.h>
|
||||
#include <linux/fanotify.h>
|
||||
#include <linux/filter.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/genetlink.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <linux/icmpv6.h>
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_addr.h>
|
||||
#include <linux/if_alg.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_ppp.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <linux/if_addr.h>
|
||||
#include <linux/falloc.h>
|
||||
#include <linux/fanotify.h>
|
||||
#include <linux/filter.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/if_xdp.h>
|
||||
#include <linux/kexec.h>
|
||||
#include <linux/keyctl.h>
|
||||
#include <linux/loop.h>
|
||||
|
@ -206,26 +217,23 @@ struct ltchars {
|
|||
#include <linux/netfilter/nfnetlink.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/net_namespace.h>
|
||||
#include <linux/nsfs.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/seccomp.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/icmpv6.h>
|
||||
#include <linux/serial.h>
|
||||
#include <linux/can.h>
|
||||
#include <linux/vm_sockets.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <linux/taskstats.h>
|
||||
#include <linux/genetlink.h>
|
||||
#include <linux/tipc.h>
|
||||
#include <linux/vm_sockets.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/watchdog.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/if_xdp.h>
|
||||
#include <linux/cryptouser.h>
|
||||
|
||||
#include <mtd/ubi-user.h>
|
||||
#include <net/route.h>
|
||||
|
||||
|
@ -264,6 +272,11 @@ struct ltchars {
|
|||
#define FS_KEY_DESC_PREFIX "fscrypt:"
|
||||
#define FS_KEY_DESC_PREFIX_SIZE 8
|
||||
#define FS_MAX_KEY_SIZE 64
|
||||
|
||||
// The code generator produces -0x1 for (~0), but an unsigned value is necessary
|
||||
// for the tipc_subscr timeout __u32 field.
|
||||
#undef TIPC_WAIT_FOREVER
|
||||
#define TIPC_WAIT_FOREVER 0xffffffff
|
||||
'
|
||||
|
||||
includes_NetBSD='
|
||||
|
@ -273,6 +286,7 @@ includes_NetBSD='
|
|||
#include <sys/extattr.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
@ -299,6 +313,7 @@ includes_OpenBSD='
|
|||
#include <sys/event.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/stat.h>
|
||||
|
@ -335,6 +350,7 @@ includes_OpenBSD='
|
|||
includes_SunOS='
|
||||
#include <limits.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/stat.h>
|
||||
|
@ -427,6 +443,7 @@ ccflags="$@"
|
|||
$2 == "XCASE" ||
|
||||
$2 == "ALTWERASE" ||
|
||||
$2 == "NOKERNINFO" ||
|
||||
$2 == "NFDBITS" ||
|
||||
$2 ~ /^PAR/ ||
|
||||
$2 ~ /^SIG[^_]/ ||
|
||||
$2 ~ /^O[CNPFPL][A-Z]+[^_][A-Z]+$/ ||
|
||||
|
@ -451,6 +468,7 @@ ccflags="$@"
|
|||
$2 ~ /^SYSCTL_VERS/ ||
|
||||
$2 !~ "MNT_BITS" &&
|
||||
$2 ~ /^(MS|MNT|UMOUNT)_/ ||
|
||||
$2 ~ /^NS_GET_/ ||
|
||||
$2 ~ /^TUN(SET|GET|ATTACH|DETACH)/ ||
|
||||
$2 ~ /^(O|F|[ES]?FD|NAME|S|PTRACE|PT)_/ ||
|
||||
$2 ~ /^KEXEC_/ ||
|
||||
|
@ -506,6 +524,8 @@ ccflags="$@"
|
|||
$2 ~ /^XDP_/ ||
|
||||
$2 ~ /^(HDIO|WIN|SMART)_/ ||
|
||||
$2 ~ /^CRYPTO_/ ||
|
||||
$2 ~ /^TIPC_/ ||
|
||||
$2 ~ /^DEVLINK_/ ||
|
||||
$2 !~ "WMESGLEN" &&
|
||||
$2 ~ /^W[A-Z0-9]+$/ ||
|
||||
$2 ~/^PPPIOC/ ||
|
||||
|
|
|
@ -121,7 +121,7 @@ func main() {
|
|||
}
|
||||
|
||||
libc := false
|
||||
if goos == "darwin" && strings.Contains(buildTags(), ",go1.12") {
|
||||
if goos == "darwin" && (strings.Contains(buildTags(), ",go1.12") || strings.Contains(buildTags(), ",go1.13")) {
|
||||
libc = true
|
||||
}
|
||||
trampolines := map[string]bool{}
|
||||
|
@ -292,11 +292,6 @@ func main() {
|
|||
asm = "syscall_" + strings.ToLower(asm[:1]) + asm[1:] // internal syscall call
|
||||
sysname = strings.TrimPrefix(sysname, "SYS_") // remove SYS_
|
||||
sysname = strings.ToLower(sysname) // lowercase
|
||||
if sysname == "getdirentries64" {
|
||||
// Special case - libSystem name and
|
||||
// raw syscall name don't match.
|
||||
sysname = "__getdirentries64"
|
||||
}
|
||||
libcFn = sysname
|
||||
sysname = "funcPC(libc_" + sysname + "_trampoline)"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package unix
|
||||
|
||||
// Round the length of a raw sockaddr up to align it properly.
|
||||
func cmsgAlignOf(salen int) int {
|
||||
salign := SizeofPtr
|
||||
if SizeofPtr == 8 && !supportsABI(_dragonflyABIChangeVersion) {
|
||||
// 64-bit Dragonfly before the September 2019 ABI changes still requires
|
||||
// 32-bit aligned access to network subsystem.
|
||||
salign = 4
|
||||
}
|
||||
return (salen + salign - 1) & ^(salign - 1)
|
||||
}
|
|
@ -17,7 +17,7 @@ func UnixCredentials(ucred *Ucred) []byte {
|
|||
h.Level = SOL_SOCKET
|
||||
h.Type = SCM_CREDENTIALS
|
||||
h.SetLen(CmsgLen(SizeofUcred))
|
||||
*((*Ucred)(cmsgData(h))) = *ucred
|
||||
*(*Ucred)(h.data(0)) = *ucred
|
||||
return b
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue