Update deps

This commit is contained in:
Frank Denis 2018-11-15 13:38:08 +01:00
parent 0c3e47ff89
commit 9c17f476f3
168 changed files with 10012 additions and 6844 deletions

View file

@ -1,21 +1,18 @@
language: go
sudo: false
go:
- 1.10.x
- 1.11.x
- tip
env:
- TESTS="-race -v -bench=. -coverprofile=coverage.txt -covermode=atomic"
- TESTS="-race -v ./..."
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
script:
- go test $TESTS
- go test -race -v -bench=. -coverprofile=coverage.txt -covermode=atomic ./...
after_success:
- bash <(curl -s https://codecov.io/bash)

View file

@ -3,31 +3,55 @@
[[projects]]
branch = "master"
digest = "1:6914c49eed986dfb8dffb33516fa129c49929d4d873f41e073c83c11c372b870"
name = "golang.org/x/crypto"
packages = ["ed25519","ed25519/internal/edwards25519"]
revision = "b47b1587369238182299fe4dad77d05b8b461e06"
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"]
revision = "1e491301e022f8f977054da4c2d852decd59571f"
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
inputs-digest = "89261d224d04ffe1530fb9e91fcf649ef0e571531482d043fdad683898871768"
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

View file

@ -24,3 +24,15 @@
[[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"

View file

@ -67,6 +67,7 @@ A not-so-up-to-date-list-that-may-be-actually-current:
* https://github.com/xor-gate/sshfp
* https://github.com/rs/dnstrace
* https://blitiri.com.ar/p/dnss ([github mirror](https://github.com/albertito/dnss))
* https://github.com/semihalev/sdns
Send pull request if you want to be listed here.

View file

@ -7,11 +7,8 @@ import (
"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,11 +126,6 @@ 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)
}
@ -149,11 +138,6 @@ func (c *Client) Exchange(m *Msg, address string) (r *Msg, rtt time.Duration, er
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)
}
return c.exchange(m, address)
})
if r != nil && shared {
@ -199,67 +183,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
@ -559,10 +482,6 @@ func DialTimeoutWithTLS(network, address string, tlsConfig *tls.Config, timeout
// 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 +490,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)
}

View file

@ -1,6 +1,7 @@
package dns
import (
"bufio"
"crypto"
"crypto/dsa"
"crypto/ecdsa"
@ -194,23 +195,12 @@ func readPrivateKeyED25519(m map[string]string) (ed25519.PrivateKey, error) {
// parseKey reads a private key from r. It returns a map[string]string,
// with the key-value pairs, or an error when the file is not correct.
func parseKey(r io.Reader, file string) (map[string]string, error) {
s, cancel := scanInit(r)
m := make(map[string]string)
c := make(chan lex)
k := ""
defer func() {
cancel()
// zlexer can send up to two tokens, the next one and possibly 1 remainders.
// Do a non-blocking read.
_, ok := <-c
_, ok = <-c
if !ok {
// too bad
}
}()
// Start the lexer
go klexer(s, c)
for l := range c {
var k string
c := newKLexer(r)
for l, ok := c.Next(); ok; l, ok = c.Next() {
// It should alternate
switch l.value {
case zKey:
@ -219,41 +209,111 @@ func parseKey(r io.Reader, file string) (map[string]string, error) {
if k == "" {
return nil, &ParseError{file, "no private key seen", l}
}
//println("Setting", strings.ToLower(k), "to", l.token, "b")
m[strings.ToLower(k)] = l.token
k = ""
}
}
// Surface any read errors from r.
if err := c.Err(); err != nil {
return nil, &ParseError{file: file, err: err.Error()}
}
return m, nil
}
// klexer scans the sourcefile and returns tokens on the channel c.
func klexer(s *scan, c chan lex) {
var l lex
str := "" // Hold the current read text
commt := false
key := true
x, err := s.tokenText()
defer close(c)
for err == nil {
l.column = s.position.Column
l.line = s.position.Line
type klexer struct {
br io.ByteReader
readErr error
line int
column int
key bool
eol bool // end-of-line
}
func newKLexer(r io.Reader) *klexer {
br, ok := r.(io.ByteReader)
if !ok {
br = bufio.NewReaderSize(r, 1024)
}
return &klexer{
br: br,
line: 1,
key: true,
}
}
func (kl *klexer) Err() error {
if kl.readErr == io.EOF {
return nil
}
return kl.readErr
}
// readByte returns the next byte from the input
func (kl *klexer) readByte() (byte, bool) {
if kl.readErr != nil {
return 0, false
}
c, err := kl.br.ReadByte()
if err != nil {
kl.readErr = err
return 0, false
}
// delay the newline handling until the next token is delivered,
// fixes off-by-one errors when reporting a parse error.
if kl.eol {
kl.line++
kl.column = 0
kl.eol = false
}
if c == '\n' {
kl.eol = true
} else {
kl.column++
}
return c, true
}
func (kl *klexer) Next() (lex, bool) {
var (
l lex
str strings.Builder
commt bool
)
for x, ok := kl.readByte(); ok; x, ok = kl.readByte() {
l.line, l.column = kl.line, kl.column
switch x {
case ':':
if commt {
if commt || !kl.key {
break
}
l.token = str
if key {
l.value = zKey
c <- l
// Next token is a space, eat it
s.tokenText()
key = false
str = ""
} else {
l.value = zValue
}
kl.key = false
// Next token is a space, eat it
kl.readByte()
l.value = zKey
l.token = str.String()
return l, true
case ';':
commt = true
case '\n':
@ -261,24 +321,32 @@ func klexer(s *scan, c chan lex) {
// Reset a comment
commt = false
}
kl.key = true
l.value = zValue
l.token = str
c <- l
str = ""
commt = false
key = true
l.token = str.String()
return l, true
default:
if commt {
break
}
str += string(x)
str.WriteByte(x)
}
x, err = s.tokenText()
}
if len(str) > 0 {
if kl.readErr != nil && kl.readErr != io.EOF {
// Don't return any tokens after a read error occurs.
return lex{value: zEOF}, false
}
if str.Len() > 0 {
// Send remainder
l.token = str
l.value = zValue
c <- l
l.token = str.String()
return l, true
}
return lex{value: zEOF}, false
}

View file

@ -2,8 +2,8 @@ package dns
import (
"bytes"
"errors"
"fmt"
"io"
"strconv"
"strings"
)
@ -18,152 +18,225 @@ import (
// * rhs (rdata)
// But we are lazy here, only the range is parsed *all* occurrences
// of $ after that are interpreted.
// Any error are returned as a string value, the empty string signals
// "no error".
func generate(l lex, c chan lex, t chan *Token, o string) string {
func (zp *ZoneParser) generate(l lex) (RR, bool) {
token := l.token
step := 1
if i := strings.IndexAny(l.token, "/"); i != -1 {
if i+1 == len(l.token) {
return "bad step in $GENERATE range"
if i := strings.IndexByte(token, '/'); i >= 0 {
if i+1 == len(token) {
return zp.setParseError("bad step in $GENERATE range", l)
}
if s, err := strconv.Atoi(l.token[i+1:]); err == nil {
if s < 0 {
return "bad step in $GENERATE range"
}
step = s
} else {
return "bad step in $GENERATE range"
s, err := strconv.Atoi(token[i+1:])
if err != nil || s <= 0 {
return zp.setParseError("bad step in $GENERATE range", l)
}
l.token = l.token[:i]
step = s
token = token[:i]
}
sx := strings.SplitN(l.token, "-", 2)
sx := strings.SplitN(token, "-", 2)
if len(sx) != 2 {
return "bad start-stop in $GENERATE range"
return zp.setParseError("bad start-stop in $GENERATE range", l)
}
start, err := strconv.Atoi(sx[0])
if err != nil {
return "bad start in $GENERATE range"
return zp.setParseError("bad start in $GENERATE range", l)
}
end, err := strconv.Atoi(sx[1])
if err != nil {
return "bad stop in $GENERATE range"
return zp.setParseError("bad stop in $GENERATE range", l)
}
if end < 0 || start < 0 || end < start {
return "bad range in $GENERATE range"
return zp.setParseError("bad range in $GENERATE range", l)
}
<-c // _BLANK
zp.c.Next() // _BLANK
// Create a complete new string, which we then parse again.
s := ""
BuildRR:
l = <-c
if l.value != zNewline && l.value != zEOF {
s += l.token
goto BuildRR
}
for i := start; i <= end; i += step {
var (
escape bool
dom bytes.Buffer
mod string
err error
offset int
)
var s string
for l, ok := zp.c.Next(); ok; l, ok = zp.c.Next() {
if l.err {
return zp.setParseError("bad data in $GENERATE directive", l)
}
if l.value == zNewline {
break
}
for j := 0; j < len(s); j++ { // No 'range' because we need to jump around
switch s[j] {
case '\\':
if escape {
dom.WriteByte('\\')
escape = false
continue
}
escape = true
case '$':
mod = "%d"
offset = 0
if escape {
dom.WriteByte('$')
escape = false
continue
}
escape = false
if j+1 >= len(s) { // End of the string
dom.WriteString(fmt.Sprintf(mod, i+offset))
continue
} else {
if s[j+1] == '$' {
dom.WriteByte('$')
j++
continue
}
}
// Search for { and }
if s[j+1] == '{' { // Modifier block
sep := strings.Index(s[j+2:], "}")
if sep == -1 {
return "bad modifier in $GENERATE"
}
mod, offset, err = modToPrintf(s[j+2 : j+2+sep])
if err != nil {
return err.Error()
}
j += 2 + sep // Jump to it
}
dom.WriteString(fmt.Sprintf(mod, i+offset))
default:
if escape { // Pretty useless here
escape = false
continue
}
dom.WriteByte(s[j])
}
}
// Re-parse the RR and send it on the current channel t
rx, err := NewRR("$ORIGIN " + o + "\n" + dom.String())
if err != nil {
return err.Error()
}
t <- &Token{RR: rx}
// Its more efficient to first built the rrlist and then parse it in
// one go! But is this a problem?
s += l.token
}
r := &generateReader{
s: s,
cur: start,
start: start,
end: end,
step: step,
file: zp.file,
lex: &l,
}
zp.sub = NewZoneParser(r, zp.origin, zp.file)
zp.sub.includeDepth, zp.sub.includeAllowed = zp.includeDepth, zp.includeAllowed
zp.sub.SetDefaultTTL(defaultTtl)
return zp.subNext()
}
type generateReader struct {
s string
si int
cur int
start int
end int
step int
mod bytes.Buffer
escape bool
eof bool
file string
lex *lex
}
func (r *generateReader) parseError(msg string, end int) *ParseError {
r.eof = true // Make errors sticky.
l := *r.lex
l.token = r.s[r.si-1 : end]
l.column += r.si // l.column starts one zBLANK before r.s
return &ParseError{r.file, msg, l}
}
func (r *generateReader) Read(p []byte) (int, error) {
// NewZLexer, through NewZoneParser, should use ReadByte and
// not end up here.
panic("not implemented")
}
func (r *generateReader) ReadByte() (byte, error) {
if r.eof {
return 0, io.EOF
}
if r.mod.Len() > 0 {
return r.mod.ReadByte()
}
if r.si >= len(r.s) {
r.si = 0
r.cur += r.step
r.eof = r.cur > r.end || r.cur < 0
return '\n', nil
}
si := r.si
r.si++
switch r.s[si] {
case '\\':
if r.escape {
r.escape = false
return '\\', nil
}
r.escape = true
return r.ReadByte()
case '$':
if r.escape {
r.escape = false
return '$', nil
}
mod := "%d"
if si >= len(r.s)-1 {
// End of the string
fmt.Fprintf(&r.mod, mod, r.cur)
return r.mod.ReadByte()
}
if r.s[si+1] == '$' {
r.si++
return '$', nil
}
var offset int
// Search for { and }
if r.s[si+1] == '{' {
// Modifier block
sep := strings.Index(r.s[si+2:], "}")
if sep < 0 {
return 0, r.parseError("bad modifier in $GENERATE", len(r.s))
}
var errMsg string
mod, offset, errMsg = modToPrintf(r.s[si+2 : si+2+sep])
if errMsg != "" {
return 0, r.parseError(errMsg, si+3+sep)
}
if r.start+offset < 0 || r.end+offset > 1<<31-1 {
return 0, r.parseError("bad offset in $GENERATE", si+3+sep)
}
r.si += 2 + sep // Jump to it
}
fmt.Fprintf(&r.mod, mod, r.cur+offset)
return r.mod.ReadByte()
default:
if r.escape { // Pretty useless here
r.escape = false
return r.ReadByte()
}
return r.s[si], nil
}
return ""
}
// Convert a $GENERATE modifier 0,0,d to something Printf can deal with.
func modToPrintf(s string) (string, int, error) {
xs := strings.Split(s, ",")
func modToPrintf(s string) (string, int, string) {
// Modifier is { offset [ ,width [ ,base ] ] } - provide default
// values for optional width and type, if necessary.
switch len(xs) {
var offStr, widthStr, base string
switch xs := strings.Split(s, ","); len(xs) {
case 1:
xs = append(xs, "0", "d")
offStr, widthStr, base = xs[0], "0", "d"
case 2:
xs = append(xs, "d")
offStr, widthStr, base = xs[0], xs[1], "d"
case 3:
offStr, widthStr, base = xs[0], xs[1], xs[2]
default:
return "", 0, errors.New("bad modifier in $GENERATE")
return "", 0, "bad modifier in $GENERATE"
}
// xs[0] is offset, xs[1] is width, xs[2] is base
if xs[2] != "o" && xs[2] != "d" && xs[2] != "x" && xs[2] != "X" {
return "", 0, errors.New("bad base in $GENERATE")
switch base {
case "o", "d", "x", "X":
default:
return "", 0, "bad base in $GENERATE"
}
offset, err := strconv.Atoi(xs[0])
if err != nil || offset > 255 {
return "", 0, errors.New("bad offset in $GENERATE")
offset, err := strconv.Atoi(offStr)
if err != nil {
return "", 0, "bad offset in $GENERATE"
}
width, err := strconv.Atoi(xs[1])
if err != nil || width > 255 {
return "", offset, errors.New("bad width in $GENERATE")
width, err := strconv.Atoi(widthStr)
if err != nil || width < 0 || width > 255 {
return "", 0, "bad width in $GENERATE"
}
switch {
case width < 0:
return "", offset, errors.New("bad width in $GENERATE")
case width == 0:
return "%" + xs[1] + xs[2], offset, nil
if width == 0 {
return "%" + base, offset, ""
}
return "%0" + xs[1] + xs[2], offset, nil
return "%0" + widthStr + base, offset, ""
}

10
vendor/github.com/miekg/dns/msg.go generated vendored
View file

@ -302,6 +302,12 @@ func packDomainName(s string, msg []byte, off int, compression map[string]int, c
}
// If we did compression and we find something add the pointer here
if pointer != -1 {
// Clear the msg buffer after the pointer location, otherwise
// packDataNsec writes the wrong data to msg.
tainted := msg[nameoffset:off]
for i := range tainted {
tainted[i] = 0
}
// We have two bytes (14 bits) to put the pointer in
// if msg == nil, we will never do compression
binary.BigEndian.PutUint16(msg[nameoffset:], uint16(pointer^0xC000))
@ -525,6 +531,10 @@ func dddToByte(s []byte) byte {
return byte((s[0]-'0')*100 + (s[1]-'0')*10 + (s[2] - '0'))
}
func dddStringToByte(s string) byte {
return byte((s[0]-'0')*100 + (s[1]-'0')*10 + (s[2] - '0'))
}
// Helper function for packing and unpacking
func intToBytes(i *big.Int, length int) []byte {
buf := i.Bytes()

View file

@ -6,7 +6,6 @@ import (
"encoding/binary"
"encoding/hex"
"net"
"strconv"
"strings"
)
@ -276,13 +275,7 @@ func unpackString(msg []byte, off int) (string, int, error) {
s.WriteByte('\\')
s.WriteByte(b)
case b < ' ' || b > '~': // unprintable
var buf [3]byte
bufs := strconv.AppendInt(buf[:0], int64(b), 10)
s.WriteByte('\\')
for i := len(bufs); i < 3; i++ {
s.WriteByte('0')
}
s.Write(bufs)
writeEscapedByte(&s, b)
default:
s.WriteByte(b)
}

View file

@ -105,7 +105,7 @@ func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata)
return rr, off, err
}
setPrivateRR := func(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
setPrivateRR := func(h RR_Header, c *zlexer, o, f string) (RR, *ParseError, string) {
rr := mkPrivateRR(h.Rrtype)
rr.Hdr = h
@ -115,7 +115,7 @@ func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata)
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; l.value {
switch l, _ = c.Next(); l.value {
case zNewline, zEOF:
break Fetch
case zString:

1019
vendor/github.com/miekg/dns/scan.go generated vendored

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,56 +0,0 @@
package dns
// Implement a simple scanner, return a byte stream from an io reader.
import (
"bufio"
"context"
"io"
"text/scanner"
)
type scan struct {
src *bufio.Reader
position scanner.Position
eof bool // Have we just seen a eof
ctx context.Context
}
func scanInit(r io.Reader) (*scan, context.CancelFunc) {
s := new(scan)
s.src = bufio.NewReader(r)
s.position.Line = 1
ctx, cancel := context.WithCancel(context.Background())
s.ctx = ctx
return s, cancel
}
// tokenText returns the next byte from the input
func (s *scan) tokenText() (byte, error) {
c, err := s.src.ReadByte()
if err != nil {
return c, err
}
select {
case <-s.ctx.Done():
return c, context.Canceled
default:
break
}
// delay the newline handling until the next token is delivered,
// fixes off-by-one errors when reporting a parse error.
if s.eof {
s.position.Line++
s.position.Column = 0
s.eof = false
}
if c == '\n' {
s.eof = true
return c, nil
}
s.position.Column++
return c, nil
}

View file

@ -82,6 +82,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
@ -416,14 +417,13 @@ func (srv *Server) Shutdown() error {
// to terminate.
func (srv *Server) ShutdownContext(ctx context.Context) error {
srv.lock.Lock()
started := srv.started
srv.started = false
srv.lock.Unlock()
if !started {
if !srv.started {
srv.lock.Unlock()
return &Error{err: "server not started"}
}
srv.started = false
if srv.PacketConn != nil {
srv.PacketConn.SetReadDeadline(aLongTimeAgo) // Unblock reads
}
@ -432,10 +432,10 @@ func (srv *Server) ShutdownContext(ctx context.Context) error {
srv.Listener.Close()
}
srv.lock.Lock()
for rw := range srv.conns {
rw.SetReadDeadline(aLongTimeAgo) // Unblock reads
}
srv.lock.Unlock()
if testShutdownNotify != nil {
@ -666,7 +666,16 @@ func (srv *Server) serveDNS(w *response) {
}
func (srv *Server) readTCP(conn net.Conn, timeout time.Duration) ([]byte, error) {
conn.SetReadDeadline(time.Now().Add(timeout))
// If we race with ShutdownContext, the read deadline may
// have been set in the distant past to unblock the read
// below. We must not override it, otherwise we may block
// ShutdownContext.
srv.lock.RLock()
if srv.started {
conn.SetReadDeadline(time.Now().Add(timeout))
}
srv.lock.RUnlock()
l := make([]byte, 2)
n, err := conn.Read(l)
if err != nil || n != 2 {
@ -701,7 +710,13 @@ func (srv *Server) readTCP(conn net.Conn, timeout time.Duration) ([]byte, error)
}
func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) {
conn.SetReadDeadline(time.Now().Add(timeout))
srv.lock.RLock()
if srv.started {
// See the comment in readTCP above.
conn.SetReadDeadline(time.Now().Add(timeout))
}
srv.lock.RUnlock()
m := srv.udpPool.Get().([]byte)
n, s, err := ReadFromSessionUDP(conn, m)
if err != nil {
@ -714,6 +729,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 {
@ -735,6 +754,10 @@ 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)
@ -753,24 +776,33 @@ func (w *response) Write(m []byte) (int, error) {
n, err := io.Copy(w.tcp, bytes.NewReader(m))
return int(n), err
default:
panic("dns: internal error: udp and tcp both nil")
}
panic("not reached")
}
// LocalAddr implements the ResponseWriter.LocalAddr method.
func (w *response) LocalAddr() net.Addr {
if w.tcp != nil {
switch {
case w.udp != nil:
return w.udp.LocalAddr()
case w.tcp != nil:
return w.tcp.LocalAddr()
default:
panic("dns: internal error: udp and tcp both nil")
}
return w.udp.LocalAddr()
}
// RemoteAddr implements the ResponseWriter.RemoteAddr method.
func (w *response) RemoteAddr() net.Addr {
if w.tcp != nil {
switch {
case w.udpSession != nil:
return w.udpSession.RemoteAddr()
case w.tcp != nil:
return w.tcp.RemoteAddr()
default:
panic("dns: internal error: udpSession and tcp both nil")
}
return w.udpSession.RemoteAddr()
}
// TsigStatus implements the ResponseWriter.TsigStatus method.
@ -784,13 +816,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.

150
vendor/github.com/miekg/dns/types.go generated vendored
View file

@ -419,128 +419,130 @@ type TXT struct {
func (rr *TXT) String() string { return rr.Hdr.String() + sprintTxt(rr.Txt) }
func sprintName(s string) string {
src := []byte(s)
dst := make([]byte, 0, len(src))
for i := 0; i < len(src); {
if i+1 < len(src) && src[i] == '\\' && src[i+1] == '.' {
dst = append(dst, src[i:i+2]...)
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])
i += 2
} else {
b, n := nextByte(src, i)
if n == 0 {
i++ // dangling back slash
} else if b == '.' {
dst = append(dst, b)
} else {
dst = appendDomainNameByte(dst, b)
}
i += n
continue
}
b, n := nextByte(s, i)
switch {
case n == 0:
i++ // dangling back slash
case b == '.':
dst.WriteByte('.')
default:
writeDomainNameByte(&dst, b)
}
i += n
}
return string(dst)
return dst.String()
}
func sprintTxtOctet(s string) string {
src := []byte(s)
dst := make([]byte, 0, len(src))
dst = append(dst, '"')
for i := 0; i < len(src); {
if i+1 < len(src) && src[i] == '\\' && src[i+1] == '.' {
dst = append(dst, src[i:i+2]...)
var dst strings.Builder
dst.Grow(2 + len(s))
dst.WriteByte('"')
for i := 0; i < len(s); {
if i+1 < len(s) && s[i] == '\\' && s[i+1] == '.' {
dst.WriteString(s[i : i+2])
i += 2
} else {
b, n := nextByte(src, i)
if n == 0 {
i++ // dangling back slash
} else if b == '.' {
dst = append(dst, b)
} else {
if b < ' ' || b > '~' {
dst = appendByte(dst, b)
} else {
dst = append(dst, b)
}
}
i += n
continue
}
b, n := nextByte(s, i)
switch {
case n == 0:
i++ // dangling back slash
case b == '.':
dst.WriteByte('.')
case b < ' ' || b > '~':
writeEscapedByte(&dst, b)
default:
dst.WriteByte(b)
}
i += n
}
dst = append(dst, '"')
return string(dst)
dst.WriteByte('"')
return dst.String()
}
func sprintTxt(txt []string) string {
var out []byte
var out strings.Builder
for i, s := range txt {
out.Grow(3 + len(s))
if i > 0 {
out = append(out, ` "`...)
out.WriteString(` "`)
} else {
out = append(out, '"')
out.WriteByte('"')
}
bs := []byte(s)
for j := 0; j < len(bs); {
b, n := nextByte(bs, j)
for j := 0; j < len(s); {
b, n := nextByte(s, j)
if n == 0 {
break
}
out = appendTXTStringByte(out, b)
writeTXTStringByte(&out, b)
j += n
}
out = append(out, '"')
out.WriteByte('"')
}
return string(out)
return out.String()
}
func appendDomainNameByte(s []byte, b byte) []byte {
func writeDomainNameByte(s *strings.Builder, b byte) {
switch b {
case '.', ' ', '\'', '@', ';', '(', ')': // additional chars to escape
return append(s, '\\', b)
s.WriteByte('\\')
s.WriteByte(b)
default:
writeTXTStringByte(s, b)
}
return appendTXTStringByte(s, b)
}
func appendTXTStringByte(s []byte, b byte) []byte {
switch b {
case '"', '\\':
return append(s, '\\', b)
func writeTXTStringByte(s *strings.Builder, b byte) {
switch {
case b == '"' || b == '\\':
s.WriteByte('\\')
s.WriteByte(b)
case b < ' ' || b > '~':
writeEscapedByte(s, b)
default:
s.WriteByte(b)
}
if b < ' ' || b > '~' {
return appendByte(s, b)
}
return append(s, b)
}
func appendByte(s []byte, b byte) []byte {
func writeEscapedByte(s *strings.Builder, b byte) {
var buf [3]byte
bufs := strconv.AppendInt(buf[:0], int64(b), 10)
s = append(s, '\\')
for i := 0; i < 3-len(bufs); i++ {
s = append(s, '0')
s.WriteByte('\\')
for i := len(bufs); i < 3; i++ {
s.WriteByte('0')
}
for _, r := range bufs {
s = append(s, r)
}
return s
s.Write(bufs)
}
func nextByte(b []byte, offset int) (byte, int) {
if offset >= len(b) {
func nextByte(s string, offset int) (byte, int) {
if offset >= len(s) {
return 0, 0
}
if b[offset] != '\\' {
if s[offset] != '\\' {
// not an escape sequence
return b[offset], 1
return s[offset], 1
}
switch len(b) - offset {
switch len(s) - offset {
case 1: // dangling escape
return 0, 0
case 2, 3: // too short to be \ddd
default: // maybe \ddd
if isDigit(b[offset+1]) && isDigit(b[offset+2]) && isDigit(b[offset+3]) {
return dddToByte(b[offset+1:]), 4
if isDigit(s[offset+1]) && isDigit(s[offset+2]) && isDigit(s[offset+3]) {
return dddStringToByte(s[offset+1:]), 4
}
}
// not \ddd, just an RFC 1035 "quoted" character
return b[offset+1], 2
return s[offset+1], 2
}
// SPF RR. See RFC 4408, Section 3.1.1.

View file

@ -3,7 +3,7 @@ package dns
import "fmt"
// Version is current version of this library.
var Version = V{1, 0, 12}
var Version = V{1, 0, 15}
// V holds the version of this library.
type V struct {