Updating dependencies.
Этот коммит содержится в:
12
vendor/github.com/corpix/uarand/uarand.go
сгенерированный
поставляемый
12
vendor/github.com/corpix/uarand/uarand.go
сгенерированный
поставляемый
@@ -23,11 +23,12 @@ type Randomizer interface {
|
||||
// UARand describes the user agent randomizer settings.
|
||||
type UARand struct {
|
||||
Randomizer
|
||||
UserAgents []string
|
||||
}
|
||||
|
||||
// GetRandom returns a random user agent from UserAgents slice.
|
||||
func (u *UARand) GetRandom() string {
|
||||
return UserAgents[u.Intn(len(UserAgents))]
|
||||
return u.UserAgents[u.Intn(len(u.UserAgents))]
|
||||
}
|
||||
|
||||
// GetRandom returns a random user agent from UserAgents slice.
|
||||
@@ -36,6 +37,13 @@ func GetRandom() string {
|
||||
return Default.GetRandom()
|
||||
}
|
||||
|
||||
// New return UserAgent randomizer settings with default user-agents list
|
||||
func New(r Randomizer) *UARand {
|
||||
return &UARand{r}
|
||||
return &UARand{r, UserAgents}
|
||||
}
|
||||
|
||||
// NewWithCustomList return UserAgent randomizer settings with custom user-agents list
|
||||
func NewWithCustomList(userAgents []string) *UARand {
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
return &UARand{r, userAgents}
|
||||
}
|
||||
|
||||
1
vendor/github.com/go-ini/ini/.travis.yml
сгенерированный
поставляемый
1
vendor/github.com/go-ini/ini/.travis.yml
сгенерированный
поставляемый
@@ -6,6 +6,7 @@ go:
|
||||
- 1.8.x
|
||||
- 1.9.x
|
||||
- 1.10.x
|
||||
- 1.11.x
|
||||
|
||||
script:
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
|
||||
2
vendor/github.com/go-ini/ini/README.md
сгенерированный
поставляемый
2
vendor/github.com/go-ini/ini/README.md
сгенерированный
поставляемый
@@ -20,6 +20,8 @@ Package ini provides INI file read and write functionality in Go.
|
||||
|
||||
## Installation
|
||||
|
||||
The minimum requirement of Go is **1.6**.
|
||||
|
||||
To use a tagged revision:
|
||||
|
||||
```sh
|
||||
|
||||
10
vendor/github.com/go-ini/ini/file.go
сгенерированный
поставляемый
10
vendor/github.com/go-ini/ini/file.go
сгенерированный
поставляемый
@@ -45,6 +45,9 @@ type File struct {
|
||||
|
||||
// newFile initializes File object with given data sources.
|
||||
func newFile(dataSources []dataSource, opts LoadOptions) *File {
|
||||
if len(opts.KeyValueDelimiters) == 0 {
|
||||
opts.KeyValueDelimiters = "=:"
|
||||
}
|
||||
return &File{
|
||||
BlockMode: true,
|
||||
dataSources: dataSources,
|
||||
@@ -227,7 +230,8 @@ func (f *File) Append(source interface{}, others ...interface{}) error {
|
||||
}
|
||||
|
||||
func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) {
|
||||
equalSign := "="
|
||||
equalSign := DefaultFormatLeft + "=" + DefaultFormatRight
|
||||
|
||||
if PrettyFormat || PrettyEqual {
|
||||
equalSign = " = "
|
||||
}
|
||||
@@ -285,7 +289,7 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) {
|
||||
for _, kname := range sec.keyList {
|
||||
keyLength := len(kname)
|
||||
// First case will surround key by ` and second by """
|
||||
if strings.ContainsAny(kname, "\"=:") {
|
||||
if strings.Contains(kname, "\"") || strings.ContainsAny(kname, f.options.KeyValueDelimiters) {
|
||||
keyLength += 2
|
||||
} else if strings.Contains(kname, "`") {
|
||||
keyLength += 6
|
||||
@@ -328,7 +332,7 @@ func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) {
|
||||
switch {
|
||||
case key.isAutoIncrement:
|
||||
kname = "-"
|
||||
case strings.ContainsAny(kname, "\"=:"):
|
||||
case strings.Contains(kname, "\"") || strings.ContainsAny(kname, f.options.KeyValueDelimiters):
|
||||
kname = "`" + kname + "`"
|
||||
case strings.Contains(kname, "`"):
|
||||
kname = `"""` + kname + `"""`
|
||||
|
||||
8
vendor/github.com/go-ini/ini/ini.go
сгенерированный
поставляемый
8
vendor/github.com/go-ini/ini/ini.go
сгенерированный
поставляемый
@@ -34,7 +34,7 @@ const (
|
||||
|
||||
// Maximum allowed depth when recursively substituing variable names.
|
||||
_DEPTH_VALUES = 99
|
||||
_VERSION = "1.38.2"
|
||||
_VERSION = "1.39.1"
|
||||
)
|
||||
|
||||
// Version returns current package version literal.
|
||||
@@ -48,6 +48,10 @@ var (
|
||||
// at package init time.
|
||||
LineBreak = "\n"
|
||||
|
||||
// Place custom spaces when PrettyFormat and PrettyEqual are both disabled
|
||||
DefaultFormatLeft = ""
|
||||
DefaultFormatRight = ""
|
||||
|
||||
// Variable regexp pattern: %(variable)s
|
||||
varPattern = regexp.MustCompile(`%\(([^\)]+)\)s`)
|
||||
|
||||
@@ -164,6 +168,8 @@ type LoadOptions struct {
|
||||
// UnparseableSections stores a list of blocks that are allowed with raw content which do not otherwise
|
||||
// conform to key/value pairs. Specify the names of those blocks here.
|
||||
UnparseableSections []string
|
||||
// KeyValueDelimiters is the sequence of delimiters that are used to separate key and value. By default, it is "=:".
|
||||
KeyValueDelimiters string
|
||||
}
|
||||
|
||||
func LoadSources(opts LoadOptions, source interface{}, others ...interface{}) (_ *File, err error) {
|
||||
|
||||
20
vendor/github.com/go-ini/ini/parser.go
сгенерированный
поставляемый
20
vendor/github.com/go-ini/ini/parser.go
сгенерированный
поставляемый
@@ -100,7 +100,7 @@ func cleanComment(in []byte) ([]byte, bool) {
|
||||
return in[i:], true
|
||||
}
|
||||
|
||||
func readKeyName(in []byte) (string, int, error) {
|
||||
func readKeyName(delimiters string, in []byte) (string, int, error) {
|
||||
line := string(in)
|
||||
|
||||
// Check if key name surrounded by quotes.
|
||||
@@ -127,7 +127,7 @@ func readKeyName(in []byte) (string, int, error) {
|
||||
pos += startIdx
|
||||
|
||||
// Find key-value delimiter
|
||||
i := strings.IndexAny(line[pos+startIdx:], "=:")
|
||||
i := strings.IndexAny(line[pos+startIdx:], delimiters)
|
||||
if i < 0 {
|
||||
return "", -1, ErrDelimiterNotFound{line}
|
||||
}
|
||||
@@ -135,7 +135,7 @@ func readKeyName(in []byte) (string, int, error) {
|
||||
return strings.TrimSpace(line[startIdx:pos]), endIdx + startIdx + 1, nil
|
||||
}
|
||||
|
||||
endIdx = strings.IndexAny(line, "=:")
|
||||
endIdx = strings.IndexAny(line, delimiters)
|
||||
if endIdx < 0 {
|
||||
return "", -1, ErrDelimiterNotFound{line}
|
||||
}
|
||||
@@ -273,7 +273,6 @@ func (p *parser) readValue(in []byte,
|
||||
parserBufferPeekResult, _ := p.buf.Peek(parserBufferSize)
|
||||
peekBuffer := bytes.NewBuffer(parserBufferPeekResult)
|
||||
|
||||
identSize := -1
|
||||
val := line
|
||||
|
||||
for {
|
||||
@@ -290,12 +289,11 @@ func (p *parser) readValue(in []byte,
|
||||
return val, nil
|
||||
}
|
||||
|
||||
currentIdentSize := len(peekMatches[1])
|
||||
// NOTE: Return if not a python-ini multi-line value.
|
||||
if currentIdentSize < 0 {
|
||||
currentIdentSize := len(peekMatches[1])
|
||||
if currentIdentSize <= 0 {
|
||||
return val, nil
|
||||
}
|
||||
identSize = currentIdentSize
|
||||
|
||||
// NOTE: Just advance the parser reader (buffer) in-sync with the peek buffer.
|
||||
_, err := p.readUntil('\n')
|
||||
@@ -305,12 +303,6 @@ func (p *parser) readValue(in []byte,
|
||||
|
||||
val += fmt.Sprintf("\n%s", peekMatches[2])
|
||||
}
|
||||
|
||||
// NOTE: If it was a Python multi-line value,
|
||||
// return the appended value.
|
||||
if identSize > 0 {
|
||||
return val, nil
|
||||
}
|
||||
}
|
||||
|
||||
return line, nil
|
||||
@@ -428,7 +420,7 @@ func (f *File) parse(reader io.Reader) (err error) {
|
||||
continue
|
||||
}
|
||||
|
||||
kname, offset, err := readKeyName(line)
|
||||
kname, offset, err := readKeyName(f.options.KeyValueDelimiters, line)
|
||||
if err != nil {
|
||||
// Treat as boolean key when desired, and whole line is key name.
|
||||
if IsErrDelimiterNotFound(err) {
|
||||
|
||||
34
vendor/github.com/go-ldap/ldap/.travis.yml
сгенерированный
поставляемый
34
vendor/github.com/go-ldap/ldap/.travis.yml
сгенерированный
поставляемый
@@ -1,31 +1,31 @@
|
||||
sudo: false
|
||||
language: go
|
||||
env:
|
||||
global:
|
||||
- VET_VERSIONS="1.6 1.7 1.8 1.9 tip"
|
||||
- LINT_VERSIONS="1.6 1.7 1.8 1.9 tip"
|
||||
go:
|
||||
- 1.2
|
||||
- 1.3
|
||||
- 1.4
|
||||
- 1.5
|
||||
- 1.6
|
||||
- 1.7
|
||||
- 1.8
|
||||
- 1.9
|
||||
- "1.4.x"
|
||||
- "1.5.x"
|
||||
- "1.6.x"
|
||||
- "1.7.x"
|
||||
- "1.8.x"
|
||||
- "1.9.x"
|
||||
- "1.10.x"
|
||||
- "1.11.x"
|
||||
- tip
|
||||
|
||||
git:
|
||||
depth: 1
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- go: tip
|
||||
go_import_path: gopkg.in/ldap.v2
|
||||
go_import_path: gopkg.in/ldap.v3
|
||||
install:
|
||||
- go get gopkg.in/asn1-ber.v1
|
||||
- go get gopkg.in/ldap.v2
|
||||
- go get code.google.com/p/go.tools/cmd/cover || go get golang.org/x/tools/cmd/cover
|
||||
- go get github.com/golang/lint/golint || true
|
||||
- go get github.com/golang/lint/golint || go get golang.org/x/lint/golint || true
|
||||
- go build -v ./...
|
||||
script:
|
||||
- make test
|
||||
- make fmt
|
||||
- if [[ "$VET_VERSIONS" == *"$TRAVIS_GO_VERSION"* ]]; then make vet; fi
|
||||
- if [[ "$LINT_VERSIONS" == *"$TRAVIS_GO_VERSION"* ]]; then make lint; fi
|
||||
- make vet
|
||||
- make lint
|
||||
|
||||
12
vendor/github.com/go-ldap/ldap/CONTRIBUTING.md
сгенерированный
поставляемый
Обычный файл
12
vendor/github.com/go-ldap/ldap/CONTRIBUTING.md
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,12 @@
|
||||
# Contribution Guidelines
|
||||
|
||||
We welcome contribution and improvements.
|
||||
|
||||
## Guiding Principles
|
||||
|
||||
To begin with here is a draft from an email exchange:
|
||||
|
||||
* take compatibility seriously (our semvers, compatibility with older go versions, etc)
|
||||
* don't tag untested code for release
|
||||
* beware of baking in implicit behavior based on other libraries/tools choices
|
||||
* be as high-fidelity as possible in plumbing through LDAP data (don't mask errors or reduce power of someone using the library)
|
||||
20
vendor/github.com/go-ldap/ldap/Makefile
сгенерированный
поставляемый
20
vendor/github.com/go-ldap/ldap/Makefile
сгенерированный
поставляемый
@@ -36,7 +36,23 @@ fmt:
|
||||
|
||||
# Only run on go1.5+
|
||||
vet:
|
||||
go tool vet -atomic -bool -copylocks -nilfunc -printf -shadow -rangeloops -unreachable -unsafeptr -unusedresult .
|
||||
@go tool -n vet >/dev/null 2>&1; \
|
||||
if [ $$? -eq 0 ]; then \
|
||||
echo "go vet" ; \
|
||||
go tool vet \
|
||||
-atomic \
|
||||
-bool \
|
||||
-copylocks \
|
||||
-nilfunc \
|
||||
-printf \
|
||||
-shadow \
|
||||
-rangeloops \
|
||||
-unreachable \
|
||||
-unsafeptr \
|
||||
-unusedresult \
|
||||
. ; \
|
||||
fi ;
|
||||
|
||||
|
||||
# https://github.com/golang/lint
|
||||
# go get github.com/golang/lint/golint
|
||||
@@ -44,7 +60,7 @@ vet:
|
||||
# Only run on go1.5+
|
||||
lint:
|
||||
@echo golint ./...
|
||||
@OUTPUT=`golint ./... 2>&1`; \
|
||||
@OUTPUT=`command -v golint >/dev/null 2>&1 && golint ./... 2>&1`; \
|
||||
if [ "$$OUTPUT" ]; then \
|
||||
echo "golint errors:"; \
|
||||
echo "$$OUTPUT"; \
|
||||
|
||||
7
vendor/github.com/go-ldap/ldap/README.md
сгенерированный
поставляемый
7
vendor/github.com/go-ldap/ldap/README.md
сгенерированный
поставляемый
@@ -1,4 +1,4 @@
|
||||
[](https://godoc.org/gopkg.in/ldap.v2)
|
||||
[](https://godoc.org/gopkg.in/ldap.v3)
|
||||
[](https://travis-ci.org/go-ldap/ldap)
|
||||
|
||||
# Basic LDAP v3 functionality for the GO programming language.
|
||||
@@ -7,11 +7,11 @@
|
||||
|
||||
For the latest version use:
|
||||
|
||||
go get gopkg.in/ldap.v2
|
||||
go get gopkg.in/ldap.v3
|
||||
|
||||
Import the latest version with:
|
||||
|
||||
import "gopkg.in/ldap.v2"
|
||||
import "gopkg.in/ldap.v3"
|
||||
|
||||
## Required Libraries:
|
||||
|
||||
@@ -27,6 +27,7 @@ Import the latest version with:
|
||||
- Modify Requests / Responses
|
||||
- Add Requests / Responses
|
||||
- Delete Requests / Responses
|
||||
- Modify DN Requests / Responses
|
||||
|
||||
## Examples:
|
||||
|
||||
|
||||
16
vendor/github.com/go-ldap/ldap/add.go
сгенерированный
поставляемый
16
vendor/github.com/go-ldap/ldap/add.go
сгенерированный
поставляемый
@@ -41,6 +41,8 @@ type AddRequest struct {
|
||||
DN string
|
||||
// Attributes list the attributes of the new entry
|
||||
Attributes []Attribute
|
||||
// Controls hold optional controls to send with the request
|
||||
Controls []Control
|
||||
}
|
||||
|
||||
func (a AddRequest) encode() *ber.Packet {
|
||||
@@ -60,9 +62,10 @@ func (a *AddRequest) Attribute(attrType string, attrVals []string) {
|
||||
}
|
||||
|
||||
// NewAddRequest returns an AddRequest for the given DN, with no attributes
|
||||
func NewAddRequest(dn string) *AddRequest {
|
||||
func NewAddRequest(dn string, controls []Control) *AddRequest {
|
||||
return &AddRequest{
|
||||
DN: dn,
|
||||
DN: dn,
|
||||
Controls: controls,
|
||||
}
|
||||
|
||||
}
|
||||
@@ -72,6 +75,9 @@ func (l *Conn) Add(addRequest *AddRequest) error {
|
||||
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
|
||||
packet.AppendChild(addRequest.encode())
|
||||
if len(addRequest.Controls) > 0 {
|
||||
packet.AppendChild(encodeControls(addRequest.Controls))
|
||||
}
|
||||
|
||||
l.Debug.PrintPacket(packet)
|
||||
|
||||
@@ -100,9 +106,9 @@ func (l *Conn) Add(addRequest *AddRequest) error {
|
||||
}
|
||||
|
||||
if packet.Children[1].Tag == ApplicationAddResponse {
|
||||
resultCode, resultDescription := getLDAPResultCode(packet)
|
||||
if resultCode != 0 {
|
||||
return NewError(resultCode, errors.New(resultDescription))
|
||||
err := GetLDAPError(packet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
|
||||
|
||||
13
vendor/github.com/go-ldap/ldap/atomic_value.go
сгенерированный
поставляемый
13
vendor/github.com/go-ldap/ldap/atomic_value.go
сгенерированный
поставляемый
@@ -1,13 +0,0 @@
|
||||
// +build go1.4
|
||||
|
||||
package ldap
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// For compilers that support it, we just use the underlying sync/atomic.Value
|
||||
// type.
|
||||
type atomicValue struct {
|
||||
atomic.Value
|
||||
}
|
||||
28
vendor/github.com/go-ldap/ldap/atomic_value_go13.go
сгенерированный
поставляемый
28
vendor/github.com/go-ldap/ldap/atomic_value_go13.go
сгенерированный
поставляемый
@@ -1,28 +0,0 @@
|
||||
// +build !go1.4
|
||||
|
||||
package ldap
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// This is a helper type that emulates the use of the "sync/atomic.Value"
|
||||
// struct that's available in Go 1.4 and up.
|
||||
type atomicValue struct {
|
||||
value interface{}
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
func (av *atomicValue) Store(val interface{}) {
|
||||
av.lock.Lock()
|
||||
av.value = val
|
||||
av.lock.Unlock()
|
||||
}
|
||||
|
||||
func (av *atomicValue) Load() interface{} {
|
||||
av.lock.RLock()
|
||||
ret := av.value
|
||||
av.lock.RUnlock()
|
||||
|
||||
return ret
|
||||
}
|
||||
108
vendor/github.com/go-ldap/ldap/bind.go
сгенерированный
поставляемый
108
vendor/github.com/go-ldap/ldap/bind.go
сгенерированный
поставляемый
@@ -1,11 +1,8 @@
|
||||
// Copyright 2011 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 ldap
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"gopkg.in/asn1-ber.v1"
|
||||
)
|
||||
@@ -18,6 +15,9 @@ type SimpleBindRequest struct {
|
||||
Password string
|
||||
// Controls are optional controls to send with the bind request
|
||||
Controls []Control
|
||||
// AllowEmptyPassword sets whether the client allows binding with an empty password
|
||||
// (normally used for unauthenticated bind).
|
||||
AllowEmptyPassword bool
|
||||
}
|
||||
|
||||
// SimpleBindResult contains the response from the server
|
||||
@@ -28,9 +28,10 @@ type SimpleBindResult struct {
|
||||
// NewSimpleBindRequest returns a bind request
|
||||
func NewSimpleBindRequest(username string, password string, controls []Control) *SimpleBindRequest {
|
||||
return &SimpleBindRequest{
|
||||
Username: username,
|
||||
Password: password,
|
||||
Controls: controls,
|
||||
Username: username,
|
||||
Password: password,
|
||||
Controls: controls,
|
||||
AllowEmptyPassword: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,17 +41,22 @@ func (bindRequest *SimpleBindRequest) encode() *ber.Packet {
|
||||
request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, bindRequest.Username, "User Name"))
|
||||
request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, bindRequest.Password, "Password"))
|
||||
|
||||
request.AppendChild(encodeControls(bindRequest.Controls))
|
||||
|
||||
return request
|
||||
}
|
||||
|
||||
// SimpleBind performs the simple bind operation defined in the given request
|
||||
func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResult, error) {
|
||||
if simpleBindRequest.Password == "" && !simpleBindRequest.AllowEmptyPassword {
|
||||
return nil, NewError(ErrorEmptyPassword, errors.New("ldap: empty password not allowed by the client"))
|
||||
}
|
||||
|
||||
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
|
||||
encodedBindRequest := simpleBindRequest.encode()
|
||||
packet.AppendChild(encodedBindRequest)
|
||||
if len(simpleBindRequest.Controls) > 0 {
|
||||
packet.AppendChild(encodeControls(simpleBindRequest.Controls))
|
||||
}
|
||||
|
||||
if l.Debug {
|
||||
ber.PrintPacket(packet)
|
||||
@@ -73,7 +79,7 @@ func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResu
|
||||
}
|
||||
|
||||
if l.Debug {
|
||||
if err := addLDAPDescriptions(packet); err != nil {
|
||||
if err = addLDAPDescriptions(packet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ber.PrintPacket(packet)
|
||||
@@ -85,59 +91,45 @@ func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResu
|
||||
|
||||
if len(packet.Children) == 3 {
|
||||
for _, child := range packet.Children[2].Children {
|
||||
result.Controls = append(result.Controls, DecodeControl(child))
|
||||
decodedChild, decodeErr := DecodeControl(child)
|
||||
if decodeErr != nil {
|
||||
return nil, fmt.Errorf("failed to decode child control: %s", decodeErr)
|
||||
}
|
||||
result.Controls = append(result.Controls, decodedChild)
|
||||
}
|
||||
}
|
||||
|
||||
resultCode, resultDescription := getLDAPResultCode(packet)
|
||||
if resultCode != 0 {
|
||||
return result, NewError(resultCode, errors.New(resultDescription))
|
||||
}
|
||||
|
||||
return result, nil
|
||||
err = GetLDAPError(packet)
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Bind performs a bind with the given username and password
|
||||
// Bind performs a bind with the given username and password.
|
||||
//
|
||||
// It does not allow unauthenticated bind (i.e. empty password). Use the UnauthenticatedBind method
|
||||
// for that.
|
||||
func (l *Conn) Bind(username, password string) error {
|
||||
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
|
||||
bindRequest := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request")
|
||||
bindRequest.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version"))
|
||||
bindRequest.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, username, "User Name"))
|
||||
bindRequest.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, password, "Password"))
|
||||
packet.AppendChild(bindRequest)
|
||||
|
||||
if l.Debug {
|
||||
ber.PrintPacket(packet)
|
||||
req := &SimpleBindRequest{
|
||||
Username: username,
|
||||
Password: password,
|
||||
AllowEmptyPassword: false,
|
||||
}
|
||||
|
||||
msgCtx, err := l.sendMessage(packet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer l.finishMessage(msgCtx)
|
||||
|
||||
packetResponse, ok := <-msgCtx.responses
|
||||
if !ok {
|
||||
return NewError(ErrorNetwork, errors.New("ldap: response channel closed"))
|
||||
}
|
||||
packet, err = packetResponse.ReadPacket()
|
||||
l.Debug.Printf("%d: got response %p", msgCtx.id, packet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if l.Debug {
|
||||
if err := addLDAPDescriptions(packet); err != nil {
|
||||
return err
|
||||
}
|
||||
ber.PrintPacket(packet)
|
||||
}
|
||||
|
||||
resultCode, resultDescription := getLDAPResultCode(packet)
|
||||
if resultCode != 0 {
|
||||
return NewError(resultCode, errors.New(resultDescription))
|
||||
}
|
||||
|
||||
return nil
|
||||
_, err := l.SimpleBind(req)
|
||||
return err
|
||||
}
|
||||
|
||||
// UnauthenticatedBind performs an unauthenticated bind.
|
||||
//
|
||||
// A username may be provided for trace (e.g. logging) purpose only, but it is normally not
|
||||
// authenticated or otherwise validated by the LDAP server.
|
||||
//
|
||||
// See https://tools.ietf.org/html/rfc4513#section-5.1.2 .
|
||||
// See https://tools.ietf.org/html/rfc4513#section-6.3.1 .
|
||||
func (l *Conn) UnauthenticatedBind(username string) error {
|
||||
req := &SimpleBindRequest{
|
||||
Username: username,
|
||||
Password: "",
|
||||
AllowEmptyPassword: true,
|
||||
}
|
||||
_, err := l.SimpleBind(req)
|
||||
return err
|
||||
}
|
||||
|
||||
1
vendor/github.com/go-ldap/ldap/client.go
сгенерированный
поставляемый
1
vendor/github.com/go-ldap/ldap/client.go
сгенерированный
поставляемый
@@ -18,6 +18,7 @@ type Client interface {
|
||||
Add(addRequest *AddRequest) error
|
||||
Del(delRequest *DelRequest) error
|
||||
Modify(modifyRequest *ModifyRequest) error
|
||||
ModifyDN(modifyDNRequest *ModifyDNRequest) error
|
||||
|
||||
Compare(dn, attribute, value string) (bool, error)
|
||||
PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error)
|
||||
|
||||
20
vendor/github.com/go-ldap/ldap/compare.go
сгенерированный
поставляемый
20
vendor/github.com/go-ldap/ldap/compare.go
сгенерированный
поставляемый
@@ -1,7 +1,3 @@
|
||||
// Copyright 2014 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.
|
||||
//
|
||||
// File contains Compare functionality
|
||||
//
|
||||
// https://tools.ietf.org/html/rfc4511
|
||||
@@ -41,7 +37,7 @@ func (l *Conn) Compare(dn, attribute, value string) (bool, error) {
|
||||
|
||||
ava := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "AttributeValueAssertion")
|
||||
ava.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, attribute, "AttributeDesc"))
|
||||
ava.AppendChild(ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagOctetString, value, "AssertionValue"))
|
||||
ava.AppendChild(ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, value, "AssertionValue"))
|
||||
request.AppendChild(ava)
|
||||
packet.AppendChild(request)
|
||||
|
||||
@@ -72,14 +68,16 @@ func (l *Conn) Compare(dn, attribute, value string) (bool, error) {
|
||||
}
|
||||
|
||||
if packet.Children[1].Tag == ApplicationCompareResponse {
|
||||
resultCode, resultDescription := getLDAPResultCode(packet)
|
||||
if resultCode == LDAPResultCompareTrue {
|
||||
err := GetLDAPError(packet)
|
||||
|
||||
switch {
|
||||
case IsErrorWithCode(err, LDAPResultCompareTrue):
|
||||
return true, nil
|
||||
} else if resultCode == LDAPResultCompareFalse {
|
||||
case IsErrorWithCode(err, LDAPResultCompareFalse):
|
||||
return false, nil
|
||||
} else {
|
||||
return false, NewError(resultCode, errors.New(resultDescription))
|
||||
default:
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
return false, fmt.Errorf("Unexpected Response: %d", packet.Children[1].Tag)
|
||||
return false, fmt.Errorf("unexpected Response: %d", packet.Children[1].Tag)
|
||||
}
|
||||
|
||||
67
vendor/github.com/go-ldap/ldap/conn.go
сгенерированный
поставляемый
67
vendor/github.com/go-ldap/ldap/conn.go
сгенерированный
поставляемый
@@ -1,7 +1,3 @@
|
||||
// Copyright 2011 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 ldap
|
||||
|
||||
import (
|
||||
@@ -10,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/url"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
@@ -30,6 +27,13 @@ const (
|
||||
MessageTimeout = 4
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultLdapPort default ldap port for pure TCP connection
|
||||
DefaultLdapPort = "389"
|
||||
// DefaultLdapsPort default ldap port for SSL connection
|
||||
DefaultLdapsPort = "636"
|
||||
)
|
||||
|
||||
// PacketResponse contains the packet or error encountered reading a response
|
||||
type PacketResponse struct {
|
||||
// Packet is the packet read from the server
|
||||
@@ -84,7 +88,7 @@ type Conn struct {
|
||||
conn net.Conn
|
||||
isTLS bool
|
||||
closing uint32
|
||||
closeErr atomicValue
|
||||
closeErr atomic.Value
|
||||
isStartingTLS bool
|
||||
Debug debugging
|
||||
chanConfirm chan struct{}
|
||||
@@ -121,22 +125,51 @@ func Dial(network, addr string) (*Conn, error) {
|
||||
// DialTLS connects to the given address on the given network using tls.Dial
|
||||
// and then returns a new Conn for the connection.
|
||||
func DialTLS(network, addr string, config *tls.Config) (*Conn, error) {
|
||||
dc, err := net.DialTimeout(network, addr, DefaultTimeout)
|
||||
c, err := tls.DialWithDialer(&net.Dialer{Timeout: DefaultTimeout}, network, addr, config)
|
||||
if err != nil {
|
||||
return nil, NewError(ErrorNetwork, err)
|
||||
}
|
||||
c := tls.Client(dc, config)
|
||||
err = c.Handshake()
|
||||
if err != nil {
|
||||
// Handshake error, close the established connection before we return an error
|
||||
dc.Close()
|
||||
return nil, NewError(ErrorNetwork, err)
|
||||
}
|
||||
conn := NewConn(c, true)
|
||||
conn.Start()
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// DialURL connects to the given ldap URL vie TCP using tls.Dial or net.Dial if ldaps://
|
||||
// or ldap:// specified as protocol. On success a new Conn for the connection
|
||||
// is returned.
|
||||
func DialURL(addr string) (*Conn, error) {
|
||||
|
||||
lurl, err := url.Parse(addr)
|
||||
if err != nil {
|
||||
return nil, NewError(ErrorNetwork, err)
|
||||
}
|
||||
|
||||
host, port, err := net.SplitHostPort(lurl.Host)
|
||||
if err != nil {
|
||||
// we asume that error is due to missing port
|
||||
host = lurl.Host
|
||||
port = ""
|
||||
}
|
||||
|
||||
switch lurl.Scheme {
|
||||
case "ldap":
|
||||
if port == "" {
|
||||
port = DefaultLdapPort
|
||||
}
|
||||
return Dial("tcp", net.JoinHostPort(host, port))
|
||||
case "ldaps":
|
||||
if port == "" {
|
||||
port = DefaultLdapsPort
|
||||
}
|
||||
tlsConf := &tls.Config{
|
||||
ServerName: host,
|
||||
}
|
||||
return DialTLS("tcp", net.JoinHostPort(host, port), tlsConf)
|
||||
}
|
||||
|
||||
return nil, NewError(ErrorNetwork, fmt.Errorf("Unknown scheme '%s'", lurl.Scheme))
|
||||
}
|
||||
|
||||
// NewConn returns a new Conn using conn for network I/O.
|
||||
func NewConn(conn net.Conn, isTLS bool) *Conn {
|
||||
return &Conn{
|
||||
@@ -242,18 +275,18 @@ func (l *Conn) StartTLS(config *tls.Config) error {
|
||||
ber.PrintPacket(packet)
|
||||
}
|
||||
|
||||
if resultCode, message := getLDAPResultCode(packet); resultCode == LDAPResultSuccess {
|
||||
if err := GetLDAPError(packet); err == nil {
|
||||
conn := tls.Client(l.conn, config)
|
||||
|
||||
if err := conn.Handshake(); err != nil {
|
||||
if connErr := conn.Handshake(); connErr != nil {
|
||||
l.Close()
|
||||
return NewError(ErrorNetwork, fmt.Errorf("TLS handshake failed (%v)", err))
|
||||
return NewError(ErrorNetwork, fmt.Errorf("TLS handshake failed (%v)", connErr))
|
||||
}
|
||||
|
||||
l.isTLS = true
|
||||
l.conn = conn
|
||||
} else {
|
||||
return NewError(resultCode, fmt.Errorf("ldap: cannot StartTLS (%s)", message))
|
||||
return err
|
||||
}
|
||||
go l.reader()
|
||||
|
||||
|
||||
119
vendor/github.com/go-ldap/ldap/control.go
сгенерированный
поставляемый
119
vendor/github.com/go-ldap/ldap/control.go
сгенерированный
поставляемый
@@ -1,7 +1,3 @@
|
||||
// Copyright 2011 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 ldap
|
||||
|
||||
import (
|
||||
@@ -22,13 +18,20 @@ const (
|
||||
ControlTypeVChuPasswordWarning = "2.16.840.1.113730.3.4.5"
|
||||
// ControlTypeManageDsaIT - https://tools.ietf.org/html/rfc3296
|
||||
ControlTypeManageDsaIT = "2.16.840.1.113730.3.4.2"
|
||||
|
||||
// ControlTypeMicrosoftNotification - https://msdn.microsoft.com/en-us/library/aa366983(v=vs.85).aspx
|
||||
ControlTypeMicrosoftNotification = "1.2.840.113556.1.4.528"
|
||||
// ControlTypeMicrosoftShowDeleted - https://msdn.microsoft.com/en-us/library/aa366989(v=vs.85).aspx
|
||||
ControlTypeMicrosoftShowDeleted = "1.2.840.113556.1.4.417"
|
||||
)
|
||||
|
||||
// ControlTypeMap maps controls to text descriptions
|
||||
var ControlTypeMap = map[string]string{
|
||||
ControlTypePaging: "Paging",
|
||||
ControlTypeBeheraPasswordPolicy: "Password Policy - Behera Draft",
|
||||
ControlTypeManageDsaIT: "Manage DSA IT",
|
||||
ControlTypePaging: "Paging",
|
||||
ControlTypeBeheraPasswordPolicy: "Password Policy - Behera Draft",
|
||||
ControlTypeManageDsaIT: "Manage DSA IT",
|
||||
ControlTypeMicrosoftNotification: "Change Notification - Microsoft",
|
||||
ControlTypeMicrosoftShowDeleted: "Show Deleted Objects - Microsoft",
|
||||
}
|
||||
|
||||
// Control defines an interface controls provide to encode and describe themselves
|
||||
@@ -242,6 +245,64 @@ func NewControlManageDsaIT(Criticality bool) *ControlManageDsaIT {
|
||||
return &ControlManageDsaIT{Criticality: Criticality}
|
||||
}
|
||||
|
||||
// ControlMicrosoftNotification implements the control described in https://msdn.microsoft.com/en-us/library/aa366983(v=vs.85).aspx
|
||||
type ControlMicrosoftNotification struct{}
|
||||
|
||||
// GetControlType returns the OID
|
||||
func (c *ControlMicrosoftNotification) GetControlType() string {
|
||||
return ControlTypeMicrosoftNotification
|
||||
}
|
||||
|
||||
// Encode returns the ber packet representation
|
||||
func (c *ControlMicrosoftNotification) Encode() *ber.Packet {
|
||||
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
|
||||
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeMicrosoftNotification, "Control Type ("+ControlTypeMap[ControlTypeMicrosoftNotification]+")"))
|
||||
|
||||
return packet
|
||||
}
|
||||
|
||||
// String returns a human-readable description
|
||||
func (c *ControlMicrosoftNotification) String() string {
|
||||
return fmt.Sprintf(
|
||||
"Control Type: %s (%q)",
|
||||
ControlTypeMap[ControlTypeMicrosoftNotification],
|
||||
ControlTypeMicrosoftNotification)
|
||||
}
|
||||
|
||||
// NewControlMicrosoftNotification returns a ControlMicrosoftNotification control
|
||||
func NewControlMicrosoftNotification() *ControlMicrosoftNotification {
|
||||
return &ControlMicrosoftNotification{}
|
||||
}
|
||||
|
||||
// ControlMicrosoftShowDeleted implements the control described in https://msdn.microsoft.com/en-us/library/aa366989(v=vs.85).aspx
|
||||
type ControlMicrosoftShowDeleted struct{}
|
||||
|
||||
// GetControlType returns the OID
|
||||
func (c *ControlMicrosoftShowDeleted) GetControlType() string {
|
||||
return ControlTypeMicrosoftShowDeleted
|
||||
}
|
||||
|
||||
// Encode returns the ber packet representation
|
||||
func (c *ControlMicrosoftShowDeleted) Encode() *ber.Packet {
|
||||
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control")
|
||||
packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeMicrosoftShowDeleted, "Control Type ("+ControlTypeMap[ControlTypeMicrosoftShowDeleted]+")"))
|
||||
|
||||
return packet
|
||||
}
|
||||
|
||||
// String returns a human-readable description
|
||||
func (c *ControlMicrosoftShowDeleted) String() string {
|
||||
return fmt.Sprintf(
|
||||
"Control Type: %s (%q)",
|
||||
ControlTypeMap[ControlTypeMicrosoftShowDeleted],
|
||||
ControlTypeMicrosoftShowDeleted)
|
||||
}
|
||||
|
||||
// NewControlMicrosoftShowDeleted returns a ControlMicrosoftShowDeleted control
|
||||
func NewControlMicrosoftShowDeleted() *ControlMicrosoftShowDeleted {
|
||||
return &ControlMicrosoftShowDeleted{}
|
||||
}
|
||||
|
||||
// FindControl returns the first control of the given type in the list, or nil
|
||||
func FindControl(controls []Control, controlType string) Control {
|
||||
for _, c := range controls {
|
||||
@@ -253,7 +314,7 @@ func FindControl(controls []Control, controlType string) Control {
|
||||
}
|
||||
|
||||
// DecodeControl returns a control read from the given packet, or nil if no recognized control can be made
|
||||
func DecodeControl(packet *ber.Packet) Control {
|
||||
func DecodeControl(packet *ber.Packet) (Control, error) {
|
||||
var (
|
||||
ControlType = ""
|
||||
Criticality = false
|
||||
@@ -263,7 +324,7 @@ func DecodeControl(packet *ber.Packet) Control {
|
||||
switch len(packet.Children) {
|
||||
case 0:
|
||||
// at least one child is required for control type
|
||||
return nil
|
||||
return nil, fmt.Errorf("at least one child is required for control type")
|
||||
|
||||
case 1:
|
||||
// just type, no criticality or value
|
||||
@@ -296,17 +357,20 @@ func DecodeControl(packet *ber.Packet) Control {
|
||||
|
||||
default:
|
||||
// more than 3 children is invalid
|
||||
return nil
|
||||
return nil, fmt.Errorf("more than 3 children is invalid for controls")
|
||||
}
|
||||
|
||||
switch ControlType {
|
||||
case ControlTypeManageDsaIT:
|
||||
return NewControlManageDsaIT(Criticality)
|
||||
return NewControlManageDsaIT(Criticality), nil
|
||||
case ControlTypePaging:
|
||||
value.Description += " (Paging)"
|
||||
c := new(ControlPaging)
|
||||
if value.Value != nil {
|
||||
valueChildren := ber.DecodePacket(value.Data.Bytes())
|
||||
valueChildren, err := ber.DecodePacketErr(value.Data.Bytes())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode data bytes: %s", err)
|
||||
}
|
||||
value.Data.Truncate(0)
|
||||
value.Value = nil
|
||||
value.AppendChild(valueChildren)
|
||||
@@ -318,12 +382,15 @@ func DecodeControl(packet *ber.Packet) Control {
|
||||
c.PagingSize = uint32(value.Children[0].Value.(int64))
|
||||
c.Cookie = value.Children[1].Data.Bytes()
|
||||
value.Children[1].Value = c.Cookie
|
||||
return c
|
||||
return c, nil
|
||||
case ControlTypeBeheraPasswordPolicy:
|
||||
value.Description += " (Password Policy - Behera)"
|
||||
c := NewControlBeheraPasswordPolicy()
|
||||
if value.Value != nil {
|
||||
valueChildren := ber.DecodePacket(value.Data.Bytes())
|
||||
valueChildren, err := ber.DecodePacketErr(value.Data.Bytes())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode data bytes: %s", err)
|
||||
}
|
||||
value.Data.Truncate(0)
|
||||
value.Value = nil
|
||||
value.AppendChild(valueChildren)
|
||||
@@ -335,7 +402,10 @@ func DecodeControl(packet *ber.Packet) Control {
|
||||
if child.Tag == 0 {
|
||||
//Warning
|
||||
warningPacket := child.Children[0]
|
||||
packet := ber.DecodePacket(warningPacket.Data.Bytes())
|
||||
packet, err := ber.DecodePacketErr(warningPacket.Data.Bytes())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode data bytes: %s", err)
|
||||
}
|
||||
val, ok := packet.Value.(int64)
|
||||
if ok {
|
||||
if warningPacket.Tag == 0 {
|
||||
@@ -350,7 +420,10 @@ func DecodeControl(packet *ber.Packet) Control {
|
||||
}
|
||||
} else if child.Tag == 1 {
|
||||
// Error
|
||||
packet := ber.DecodePacket(child.Data.Bytes())
|
||||
packet, err := ber.DecodePacketErr(child.Data.Bytes())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode data bytes: %s", err)
|
||||
}
|
||||
val, ok := packet.Value.(int8)
|
||||
if !ok {
|
||||
// what to do?
|
||||
@@ -361,22 +434,26 @@ func DecodeControl(packet *ber.Packet) Control {
|
||||
c.ErrorString = BeheraPasswordPolicyErrorMap[c.Error]
|
||||
}
|
||||
}
|
||||
return c
|
||||
return c, nil
|
||||
case ControlTypeVChuPasswordMustChange:
|
||||
c := &ControlVChuPasswordMustChange{MustChange: true}
|
||||
return c
|
||||
return c, nil
|
||||
case ControlTypeVChuPasswordWarning:
|
||||
c := &ControlVChuPasswordWarning{Expire: -1}
|
||||
expireStr := ber.DecodeString(value.Data.Bytes())
|
||||
|
||||
expire, err := strconv.ParseInt(expireStr, 10, 64)
|
||||
if err != nil {
|
||||
return nil
|
||||
return nil, fmt.Errorf("failed to parse value as int: %s", err)
|
||||
}
|
||||
c.Expire = expire
|
||||
value.Value = c.Expire
|
||||
|
||||
return c
|
||||
return c, nil
|
||||
case ControlTypeMicrosoftNotification:
|
||||
return NewControlMicrosoftNotification(), nil
|
||||
case ControlTypeMicrosoftShowDeleted:
|
||||
return NewControlMicrosoftShowDeleted(), nil
|
||||
default:
|
||||
c := new(ControlString)
|
||||
c.ControlType = ControlType
|
||||
@@ -384,7 +461,7 @@ func DecodeControl(packet *ber.Packet) Control {
|
||||
if value != nil {
|
||||
c.ControlValue = value.Value.(string)
|
||||
}
|
||||
return c
|
||||
return c, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
8
vendor/github.com/go-ldap/ldap/del.go
сгенерированный
поставляемый
8
vendor/github.com/go-ldap/ldap/del.go
сгенерированный
поставляемый
@@ -40,7 +40,7 @@ func (l *Conn) Del(delRequest *DelRequest) error {
|
||||
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
|
||||
packet.AppendChild(delRequest.encode())
|
||||
if delRequest.Controls != nil {
|
||||
if len(delRequest.Controls) > 0 {
|
||||
packet.AppendChild(encodeControls(delRequest.Controls))
|
||||
}
|
||||
|
||||
@@ -71,9 +71,9 @@ func (l *Conn) Del(delRequest *DelRequest) error {
|
||||
}
|
||||
|
||||
if packet.Children[1].Tag == ApplicationDelResponse {
|
||||
resultCode, resultDescription := getLDAPResultCode(packet)
|
||||
if resultCode != 0 {
|
||||
return NewError(resultCode, errors.New(resultDescription))
|
||||
err := GetLDAPError(packet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
|
||||
|
||||
30
vendor/github.com/go-ldap/ldap/dn.go
сгенерированный
поставляемый
30
vendor/github.com/go-ldap/ldap/dn.go
сгенерированный
поставляемый
@@ -1,7 +1,3 @@
|
||||
// Copyright 2015 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.
|
||||
//
|
||||
// File contains DN parsing functionality
|
||||
//
|
||||
// https://tools.ietf.org/html/rfc4514
|
||||
@@ -94,7 +90,8 @@ func ParseDN(str string) (*DN, error) {
|
||||
|
||||
for i := 0; i < len(str); i++ {
|
||||
char := str[i]
|
||||
if escaping {
|
||||
switch {
|
||||
case escaping:
|
||||
unescapedTrailingSpaces = 0
|
||||
escaping = false
|
||||
switch char {
|
||||
@@ -104,22 +101,22 @@ func ParseDN(str string) (*DN, error) {
|
||||
}
|
||||
// Not a special character, assume hex encoded octet
|
||||
if len(str) == i+1 {
|
||||
return nil, errors.New("Got corrupted escaped character")
|
||||
return nil, errors.New("got corrupted escaped character")
|
||||
}
|
||||
|
||||
dst := []byte{0}
|
||||
n, err := enchex.Decode([]byte(dst), []byte(str[i:i+2]))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to decode escaped character: %s", err)
|
||||
return nil, fmt.Errorf("failed to decode escaped character: %s", err)
|
||||
} else if n != 1 {
|
||||
return nil, fmt.Errorf("Expected 1 byte when un-escaping, got %d", n)
|
||||
return nil, fmt.Errorf("expected 1 byte when un-escaping, got %d", n)
|
||||
}
|
||||
buffer.WriteByte(dst[0])
|
||||
i++
|
||||
} else if char == '\\' {
|
||||
case char == '\\':
|
||||
unescapedTrailingSpaces = 0
|
||||
escaping = true
|
||||
} else if char == '=' {
|
||||
case char == '=':
|
||||
attribute.Type = stringFromBuffer()
|
||||
// Special case: If the first character in the value is # the
|
||||
// following data is BER encoded so we can just fast forward
|
||||
@@ -135,13 +132,16 @@ func ParseDN(str string) (*DN, error) {
|
||||
}
|
||||
rawBER, err := enchex.DecodeString(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to decode BER encoding: %s", err)
|
||||
return nil, fmt.Errorf("failed to decode BER encoding: %s", err)
|
||||
}
|
||||
packet, err := ber.DecodePacketErr(rawBER)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode BER packet: %s", err)
|
||||
}
|
||||
packet := ber.DecodePacket(rawBER)
|
||||
buffer.WriteString(packet.Data.String())
|
||||
i += len(data) - 1
|
||||
}
|
||||
} else if char == ',' || char == '+' {
|
||||
case char == ',' || char == '+':
|
||||
// We're done with this RDN or value, push it
|
||||
if len(attribute.Type) == 0 {
|
||||
return nil, errors.New("incomplete type, value pair")
|
||||
@@ -154,10 +154,10 @@ func ParseDN(str string) (*DN, error) {
|
||||
rdn = new(RelativeDN)
|
||||
rdn.Attributes = make([]*AttributeTypeAndValue, 0)
|
||||
}
|
||||
} else if char == ' ' && buffer.Len() == 0 {
|
||||
case char == ' ' && buffer.Len() == 0:
|
||||
// ignore unescaped leading spaces
|
||||
continue
|
||||
} else {
|
||||
default:
|
||||
if char == ' ' {
|
||||
// Track unescaped spaces in case they are trailing and we need to remove them
|
||||
unescapedTrailingSpaces++
|
||||
|
||||
277
vendor/github.com/go-ldap/ldap/error.go
сгенерированный
поставляемый
277
vendor/github.com/go-ldap/ldap/error.go
сгенерированный
поставляемый
@@ -8,45 +8,79 @@ import (
|
||||
|
||||
// LDAP Result Codes
|
||||
const (
|
||||
LDAPResultSuccess = 0
|
||||
LDAPResultOperationsError = 1
|
||||
LDAPResultProtocolError = 2
|
||||
LDAPResultTimeLimitExceeded = 3
|
||||
LDAPResultSizeLimitExceeded = 4
|
||||
LDAPResultCompareFalse = 5
|
||||
LDAPResultCompareTrue = 6
|
||||
LDAPResultAuthMethodNotSupported = 7
|
||||
LDAPResultStrongAuthRequired = 8
|
||||
LDAPResultReferral = 10
|
||||
LDAPResultAdminLimitExceeded = 11
|
||||
LDAPResultUnavailableCriticalExtension = 12
|
||||
LDAPResultConfidentialityRequired = 13
|
||||
LDAPResultSaslBindInProgress = 14
|
||||
LDAPResultNoSuchAttribute = 16
|
||||
LDAPResultUndefinedAttributeType = 17
|
||||
LDAPResultInappropriateMatching = 18
|
||||
LDAPResultConstraintViolation = 19
|
||||
LDAPResultAttributeOrValueExists = 20
|
||||
LDAPResultInvalidAttributeSyntax = 21
|
||||
LDAPResultNoSuchObject = 32
|
||||
LDAPResultAliasProblem = 33
|
||||
LDAPResultInvalidDNSyntax = 34
|
||||
LDAPResultAliasDereferencingProblem = 36
|
||||
LDAPResultInappropriateAuthentication = 48
|
||||
LDAPResultInvalidCredentials = 49
|
||||
LDAPResultInsufficientAccessRights = 50
|
||||
LDAPResultBusy = 51
|
||||
LDAPResultUnavailable = 52
|
||||
LDAPResultUnwillingToPerform = 53
|
||||
LDAPResultLoopDetect = 54
|
||||
LDAPResultNamingViolation = 64
|
||||
LDAPResultObjectClassViolation = 65
|
||||
LDAPResultNotAllowedOnNonLeaf = 66
|
||||
LDAPResultNotAllowedOnRDN = 67
|
||||
LDAPResultEntryAlreadyExists = 68
|
||||
LDAPResultObjectClassModsProhibited = 69
|
||||
LDAPResultAffectsMultipleDSAs = 71
|
||||
LDAPResultOther = 80
|
||||
LDAPResultSuccess = 0
|
||||
LDAPResultOperationsError = 1
|
||||
LDAPResultProtocolError = 2
|
||||
LDAPResultTimeLimitExceeded = 3
|
||||
LDAPResultSizeLimitExceeded = 4
|
||||
LDAPResultCompareFalse = 5
|
||||
LDAPResultCompareTrue = 6
|
||||
LDAPResultAuthMethodNotSupported = 7
|
||||
LDAPResultStrongAuthRequired = 8
|
||||
LDAPResultReferral = 10
|
||||
LDAPResultAdminLimitExceeded = 11
|
||||
LDAPResultUnavailableCriticalExtension = 12
|
||||
LDAPResultConfidentialityRequired = 13
|
||||
LDAPResultSaslBindInProgress = 14
|
||||
LDAPResultNoSuchAttribute = 16
|
||||
LDAPResultUndefinedAttributeType = 17
|
||||
LDAPResultInappropriateMatching = 18
|
||||
LDAPResultConstraintViolation = 19
|
||||
LDAPResultAttributeOrValueExists = 20
|
||||
LDAPResultInvalidAttributeSyntax = 21
|
||||
LDAPResultNoSuchObject = 32
|
||||
LDAPResultAliasProblem = 33
|
||||
LDAPResultInvalidDNSyntax = 34
|
||||
LDAPResultIsLeaf = 35
|
||||
LDAPResultAliasDereferencingProblem = 36
|
||||
LDAPResultInappropriateAuthentication = 48
|
||||
LDAPResultInvalidCredentials = 49
|
||||
LDAPResultInsufficientAccessRights = 50
|
||||
LDAPResultBusy = 51
|
||||
LDAPResultUnavailable = 52
|
||||
LDAPResultUnwillingToPerform = 53
|
||||
LDAPResultLoopDetect = 54
|
||||
LDAPResultSortControlMissing = 60
|
||||
LDAPResultOffsetRangeError = 61
|
||||
LDAPResultNamingViolation = 64
|
||||
LDAPResultObjectClassViolation = 65
|
||||
LDAPResultNotAllowedOnNonLeaf = 66
|
||||
LDAPResultNotAllowedOnRDN = 67
|
||||
LDAPResultEntryAlreadyExists = 68
|
||||
LDAPResultObjectClassModsProhibited = 69
|
||||
LDAPResultResultsTooLarge = 70
|
||||
LDAPResultAffectsMultipleDSAs = 71
|
||||
LDAPResultVirtualListViewErrorOrControlError = 76
|
||||
LDAPResultOther = 80
|
||||
LDAPResultServerDown = 81
|
||||
LDAPResultLocalError = 82
|
||||
LDAPResultEncodingError = 83
|
||||
LDAPResultDecodingError = 84
|
||||
LDAPResultTimeout = 85
|
||||
LDAPResultAuthUnknown = 86
|
||||
LDAPResultFilterError = 87
|
||||
LDAPResultUserCanceled = 88
|
||||
LDAPResultParamError = 89
|
||||
LDAPResultNoMemory = 90
|
||||
LDAPResultConnectError = 91
|
||||
LDAPResultNotSupported = 92
|
||||
LDAPResultControlNotFound = 93
|
||||
LDAPResultNoResultsReturned = 94
|
||||
LDAPResultMoreResultsToReturn = 95
|
||||
LDAPResultClientLoop = 96
|
||||
LDAPResultReferralLimitExceeded = 97
|
||||
LDAPResultInvalidResponse = 100
|
||||
LDAPResultAmbiguousResponse = 101
|
||||
LDAPResultTLSNotSupported = 112
|
||||
LDAPResultIntermediateResponse = 113
|
||||
LDAPResultUnknownType = 114
|
||||
LDAPResultCanceled = 118
|
||||
LDAPResultNoSuchOperation = 119
|
||||
LDAPResultTooLate = 120
|
||||
LDAPResultCannotCancel = 121
|
||||
LDAPResultAssertionFailed = 122
|
||||
LDAPResultAuthorizationDenied = 123
|
||||
LDAPResultSyncRefreshRequired = 4096
|
||||
|
||||
ErrorNetwork = 200
|
||||
ErrorFilterCompile = 201
|
||||
@@ -54,49 +88,84 @@ const (
|
||||
ErrorDebugging = 203
|
||||
ErrorUnexpectedMessage = 204
|
||||
ErrorUnexpectedResponse = 205
|
||||
ErrorEmptyPassword = 206
|
||||
)
|
||||
|
||||
// LDAPResultCodeMap contains string descriptions for LDAP error codes
|
||||
var LDAPResultCodeMap = map[uint8]string{
|
||||
LDAPResultSuccess: "Success",
|
||||
LDAPResultOperationsError: "Operations Error",
|
||||
LDAPResultProtocolError: "Protocol Error",
|
||||
LDAPResultTimeLimitExceeded: "Time Limit Exceeded",
|
||||
LDAPResultSizeLimitExceeded: "Size Limit Exceeded",
|
||||
LDAPResultCompareFalse: "Compare False",
|
||||
LDAPResultCompareTrue: "Compare True",
|
||||
LDAPResultAuthMethodNotSupported: "Auth Method Not Supported",
|
||||
LDAPResultStrongAuthRequired: "Strong Auth Required",
|
||||
LDAPResultReferral: "Referral",
|
||||
LDAPResultAdminLimitExceeded: "Admin Limit Exceeded",
|
||||
LDAPResultUnavailableCriticalExtension: "Unavailable Critical Extension",
|
||||
LDAPResultConfidentialityRequired: "Confidentiality Required",
|
||||
LDAPResultSaslBindInProgress: "Sasl Bind In Progress",
|
||||
LDAPResultNoSuchAttribute: "No Such Attribute",
|
||||
LDAPResultUndefinedAttributeType: "Undefined Attribute Type",
|
||||
LDAPResultInappropriateMatching: "Inappropriate Matching",
|
||||
LDAPResultConstraintViolation: "Constraint Violation",
|
||||
LDAPResultAttributeOrValueExists: "Attribute Or Value Exists",
|
||||
LDAPResultInvalidAttributeSyntax: "Invalid Attribute Syntax",
|
||||
LDAPResultNoSuchObject: "No Such Object",
|
||||
LDAPResultAliasProblem: "Alias Problem",
|
||||
LDAPResultInvalidDNSyntax: "Invalid DN Syntax",
|
||||
LDAPResultAliasDereferencingProblem: "Alias Dereferencing Problem",
|
||||
LDAPResultInappropriateAuthentication: "Inappropriate Authentication",
|
||||
LDAPResultInvalidCredentials: "Invalid Credentials",
|
||||
LDAPResultInsufficientAccessRights: "Insufficient Access Rights",
|
||||
LDAPResultBusy: "Busy",
|
||||
LDAPResultUnavailable: "Unavailable",
|
||||
LDAPResultUnwillingToPerform: "Unwilling To Perform",
|
||||
LDAPResultLoopDetect: "Loop Detect",
|
||||
LDAPResultNamingViolation: "Naming Violation",
|
||||
LDAPResultObjectClassViolation: "Object Class Violation",
|
||||
LDAPResultNotAllowedOnNonLeaf: "Not Allowed On Non Leaf",
|
||||
LDAPResultNotAllowedOnRDN: "Not Allowed On RDN",
|
||||
LDAPResultEntryAlreadyExists: "Entry Already Exists",
|
||||
LDAPResultObjectClassModsProhibited: "Object Class Mods Prohibited",
|
||||
LDAPResultAffectsMultipleDSAs: "Affects Multiple DSAs",
|
||||
LDAPResultOther: "Other",
|
||||
var LDAPResultCodeMap = map[uint16]string{
|
||||
LDAPResultSuccess: "Success",
|
||||
LDAPResultOperationsError: "Operations Error",
|
||||
LDAPResultProtocolError: "Protocol Error",
|
||||
LDAPResultTimeLimitExceeded: "Time Limit Exceeded",
|
||||
LDAPResultSizeLimitExceeded: "Size Limit Exceeded",
|
||||
LDAPResultCompareFalse: "Compare False",
|
||||
LDAPResultCompareTrue: "Compare True",
|
||||
LDAPResultAuthMethodNotSupported: "Auth Method Not Supported",
|
||||
LDAPResultStrongAuthRequired: "Strong Auth Required",
|
||||
LDAPResultReferral: "Referral",
|
||||
LDAPResultAdminLimitExceeded: "Admin Limit Exceeded",
|
||||
LDAPResultUnavailableCriticalExtension: "Unavailable Critical Extension",
|
||||
LDAPResultConfidentialityRequired: "Confidentiality Required",
|
||||
LDAPResultSaslBindInProgress: "Sasl Bind In Progress",
|
||||
LDAPResultNoSuchAttribute: "No Such Attribute",
|
||||
LDAPResultUndefinedAttributeType: "Undefined Attribute Type",
|
||||
LDAPResultInappropriateMatching: "Inappropriate Matching",
|
||||
LDAPResultConstraintViolation: "Constraint Violation",
|
||||
LDAPResultAttributeOrValueExists: "Attribute Or Value Exists",
|
||||
LDAPResultInvalidAttributeSyntax: "Invalid Attribute Syntax",
|
||||
LDAPResultNoSuchObject: "No Such Object",
|
||||
LDAPResultAliasProblem: "Alias Problem",
|
||||
LDAPResultInvalidDNSyntax: "Invalid DN Syntax",
|
||||
LDAPResultIsLeaf: "Is Leaf",
|
||||
LDAPResultAliasDereferencingProblem: "Alias Dereferencing Problem",
|
||||
LDAPResultInappropriateAuthentication: "Inappropriate Authentication",
|
||||
LDAPResultInvalidCredentials: "Invalid Credentials",
|
||||
LDAPResultInsufficientAccessRights: "Insufficient Access Rights",
|
||||
LDAPResultBusy: "Busy",
|
||||
LDAPResultUnavailable: "Unavailable",
|
||||
LDAPResultUnwillingToPerform: "Unwilling To Perform",
|
||||
LDAPResultLoopDetect: "Loop Detect",
|
||||
LDAPResultSortControlMissing: "Sort Control Missing",
|
||||
LDAPResultOffsetRangeError: "Result Offset Range Error",
|
||||
LDAPResultNamingViolation: "Naming Violation",
|
||||
LDAPResultObjectClassViolation: "Object Class Violation",
|
||||
LDAPResultResultsTooLarge: "Results Too Large",
|
||||
LDAPResultNotAllowedOnNonLeaf: "Not Allowed On Non Leaf",
|
||||
LDAPResultNotAllowedOnRDN: "Not Allowed On RDN",
|
||||
LDAPResultEntryAlreadyExists: "Entry Already Exists",
|
||||
LDAPResultObjectClassModsProhibited: "Object Class Mods Prohibited",
|
||||
LDAPResultAffectsMultipleDSAs: "Affects Multiple DSAs",
|
||||
LDAPResultVirtualListViewErrorOrControlError: "Failed because of a problem related to the virtual list view",
|
||||
LDAPResultOther: "Other",
|
||||
LDAPResultServerDown: "Cannot establish a connection",
|
||||
LDAPResultLocalError: "An error occurred",
|
||||
LDAPResultEncodingError: "LDAP encountered an error while encoding",
|
||||
LDAPResultDecodingError: "LDAP encountered an error while decoding",
|
||||
LDAPResultTimeout: "LDAP timeout while waiting for a response from the server",
|
||||
LDAPResultAuthUnknown: "The auth method requested in a bind request is unknown",
|
||||
LDAPResultFilterError: "An error occurred while encoding the given search filter",
|
||||
LDAPResultUserCanceled: "The user canceled the operation",
|
||||
LDAPResultParamError: "An invalid parameter was specified",
|
||||
LDAPResultNoMemory: "Out of memory error",
|
||||
LDAPResultConnectError: "A connection to the server could not be established",
|
||||
LDAPResultNotSupported: "An attempt has been made to use a feature not supported LDAP",
|
||||
LDAPResultControlNotFound: "The controls required to perform the requested operation were not found",
|
||||
LDAPResultNoResultsReturned: "No results were returned from the server",
|
||||
LDAPResultMoreResultsToReturn: "There are more results in the chain of results",
|
||||
LDAPResultClientLoop: "A loop has been detected. For example when following referrals",
|
||||
LDAPResultReferralLimitExceeded: "The referral hop limit has been exceeded",
|
||||
LDAPResultCanceled: "Operation was canceled",
|
||||
LDAPResultNoSuchOperation: "Server has no knowledge of the operation requested for cancellation",
|
||||
LDAPResultTooLate: "Too late to cancel the outstanding operation",
|
||||
LDAPResultCannotCancel: "The identified operation does not support cancellation or the cancel operation cannot be performed",
|
||||
LDAPResultAssertionFailed: "An assertion control given in the LDAP operation evaluated to false causing the operation to not be performed",
|
||||
LDAPResultSyncRefreshRequired: "Refresh Required",
|
||||
LDAPResultInvalidResponse: "Invalid Response",
|
||||
LDAPResultAmbiguousResponse: "Ambiguous Response",
|
||||
LDAPResultTLSNotSupported: "Tls Not Supported",
|
||||
LDAPResultIntermediateResponse: "Intermediate Response",
|
||||
LDAPResultUnknownType: "Unknown Type",
|
||||
LDAPResultAuthorizationDenied: "Authorization Denied",
|
||||
|
||||
ErrorNetwork: "Network Error",
|
||||
ErrorFilterCompile: "Filter Compile Error",
|
||||
@@ -104,23 +173,7 @@ var LDAPResultCodeMap = map[uint8]string{
|
||||
ErrorDebugging: "Debugging Error",
|
||||
ErrorUnexpectedMessage: "Unexpected Message",
|
||||
ErrorUnexpectedResponse: "Unexpected Response",
|
||||
}
|
||||
|
||||
func getLDAPResultCode(packet *ber.Packet) (code uint8, description string) {
|
||||
if packet == nil {
|
||||
return ErrorUnexpectedResponse, "Empty packet"
|
||||
} else if len(packet.Children) >= 2 {
|
||||
response := packet.Children[1]
|
||||
if response == nil {
|
||||
return ErrorUnexpectedResponse, "Empty response in packet"
|
||||
}
|
||||
if response.ClassType == ber.ClassApplication && response.TagType == ber.TypeConstructed && len(response.Children) >= 3 {
|
||||
// Children[1].Children[2] is the diagnosticMessage which is guaranteed to exist as seen here: https://tools.ietf.org/html/rfc4511#section-4.1.9
|
||||
return uint8(response.Children[0].Value.(int64)), response.Children[2].Value.(string)
|
||||
}
|
||||
}
|
||||
|
||||
return ErrorNetwork, "Invalid packet format"
|
||||
ErrorEmptyPassword: "Empty password not allowed by the client",
|
||||
}
|
||||
|
||||
// Error holds LDAP error information
|
||||
@@ -128,20 +181,46 @@ type Error struct {
|
||||
// Err is the underlying error
|
||||
Err error
|
||||
// ResultCode is the LDAP error code
|
||||
ResultCode uint8
|
||||
ResultCode uint16
|
||||
// MatchedDN is the matchedDN returned if any
|
||||
MatchedDN string
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
return fmt.Sprintf("LDAP Result Code %d %q: %s", e.ResultCode, LDAPResultCodeMap[e.ResultCode], e.Err.Error())
|
||||
}
|
||||
|
||||
// GetLDAPError creates an Error out of a BER packet representing a LDAPResult
|
||||
// The return is an error object. It can be casted to a Error structure.
|
||||
// This function returns nil if resultCode in the LDAPResult sequence is success(0).
|
||||
func GetLDAPError(packet *ber.Packet) error {
|
||||
if packet == nil {
|
||||
return &Error{ResultCode: ErrorUnexpectedResponse, Err: fmt.Errorf("Empty packet")}
|
||||
} else if len(packet.Children) >= 2 {
|
||||
response := packet.Children[1]
|
||||
if response == nil {
|
||||
return &Error{ResultCode: ErrorUnexpectedResponse, Err: fmt.Errorf("Empty response in packet")}
|
||||
}
|
||||
if response.ClassType == ber.ClassApplication && response.TagType == ber.TypeConstructed && len(response.Children) >= 3 {
|
||||
resultCode := uint16(response.Children[0].Value.(int64))
|
||||
if resultCode == 0 { // No error
|
||||
return nil
|
||||
}
|
||||
return &Error{ResultCode: resultCode, MatchedDN: response.Children[1].Value.(string),
|
||||
Err: fmt.Errorf(response.Children[2].Value.(string))}
|
||||
}
|
||||
}
|
||||
|
||||
return &Error{ResultCode: ErrorNetwork, Err: fmt.Errorf("Invalid packet format")}
|
||||
}
|
||||
|
||||
// NewError creates an LDAP error with the given code and underlying error
|
||||
func NewError(resultCode uint8, err error) error {
|
||||
func NewError(resultCode uint16, err error) error {
|
||||
return &Error{ResultCode: resultCode, Err: err}
|
||||
}
|
||||
|
||||
// IsErrorWithCode returns true if the given error is an LDAP error with the given result code
|
||||
func IsErrorWithCode(err error, desiredResultCode uint8) bool {
|
||||
func IsErrorWithCode(err error, desiredResultCode uint16) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
4
vendor/github.com/go-ldap/ldap/filter.go
сгенерированный
поставляемый
4
vendor/github.com/go-ldap/ldap/filter.go
сгенерированный
поставляемый
@@ -1,7 +1,3 @@
|
||||
// Copyright 2011 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 ldap
|
||||
|
||||
import (
|
||||
|
||||
86
vendor/github.com/go-ldap/ldap/ldap.go
сгенерированный
поставляемый
86
vendor/github.com/go-ldap/ldap/ldap.go
сгенерированный
поставляемый
@@ -1,11 +1,8 @@
|
||||
// Copyright 2011 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 ldap
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
@@ -101,13 +98,13 @@ func addLDAPDescriptions(packet *ber.Packet) (err error) {
|
||||
|
||||
switch application {
|
||||
case ApplicationBindRequest:
|
||||
addRequestDescriptions(packet)
|
||||
err = addRequestDescriptions(packet)
|
||||
case ApplicationBindResponse:
|
||||
addDefaultLDAPResponseDescriptions(packet)
|
||||
err = addDefaultLDAPResponseDescriptions(packet)
|
||||
case ApplicationUnbindRequest:
|
||||
addRequestDescriptions(packet)
|
||||
err = addRequestDescriptions(packet)
|
||||
case ApplicationSearchRequest:
|
||||
addRequestDescriptions(packet)
|
||||
err = addRequestDescriptions(packet)
|
||||
case ApplicationSearchResultEntry:
|
||||
packet.Children[1].Children[0].Description = "Object Name"
|
||||
packet.Children[1].Children[1].Description = "Attributes"
|
||||
@@ -120,37 +117,37 @@ func addLDAPDescriptions(packet *ber.Packet) (err error) {
|
||||
}
|
||||
}
|
||||
if len(packet.Children) == 3 {
|
||||
addControlDescriptions(packet.Children[2])
|
||||
err = addControlDescriptions(packet.Children[2])
|
||||
}
|
||||
case ApplicationSearchResultDone:
|
||||
addDefaultLDAPResponseDescriptions(packet)
|
||||
err = addDefaultLDAPResponseDescriptions(packet)
|
||||
case ApplicationModifyRequest:
|
||||
addRequestDescriptions(packet)
|
||||
err = addRequestDescriptions(packet)
|
||||
case ApplicationModifyResponse:
|
||||
case ApplicationAddRequest:
|
||||
addRequestDescriptions(packet)
|
||||
err = addRequestDescriptions(packet)
|
||||
case ApplicationAddResponse:
|
||||
case ApplicationDelRequest:
|
||||
addRequestDescriptions(packet)
|
||||
err = addRequestDescriptions(packet)
|
||||
case ApplicationDelResponse:
|
||||
case ApplicationModifyDNRequest:
|
||||
addRequestDescriptions(packet)
|
||||
err = addRequestDescriptions(packet)
|
||||
case ApplicationModifyDNResponse:
|
||||
case ApplicationCompareRequest:
|
||||
addRequestDescriptions(packet)
|
||||
err = addRequestDescriptions(packet)
|
||||
case ApplicationCompareResponse:
|
||||
case ApplicationAbandonRequest:
|
||||
addRequestDescriptions(packet)
|
||||
err = addRequestDescriptions(packet)
|
||||
case ApplicationSearchResultReference:
|
||||
case ApplicationExtendedRequest:
|
||||
addRequestDescriptions(packet)
|
||||
err = addRequestDescriptions(packet)
|
||||
case ApplicationExtendedResponse:
|
||||
}
|
||||
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
func addControlDescriptions(packet *ber.Packet) {
|
||||
func addControlDescriptions(packet *ber.Packet) error {
|
||||
packet.Description = "Controls"
|
||||
for _, child := range packet.Children {
|
||||
var value *ber.Packet
|
||||
@@ -159,7 +156,7 @@ func addControlDescriptions(packet *ber.Packet) {
|
||||
switch len(child.Children) {
|
||||
case 0:
|
||||
// at least one child is required for control type
|
||||
continue
|
||||
return fmt.Errorf("at least one child is required for control type")
|
||||
|
||||
case 1:
|
||||
// just type, no criticality or value
|
||||
@@ -188,8 +185,9 @@ func addControlDescriptions(packet *ber.Packet) {
|
||||
|
||||
default:
|
||||
// more than 3 children is invalid
|
||||
continue
|
||||
return fmt.Errorf("more than 3 children for control packet found")
|
||||
}
|
||||
|
||||
if value == nil {
|
||||
continue
|
||||
}
|
||||
@@ -197,7 +195,10 @@ func addControlDescriptions(packet *ber.Packet) {
|
||||
case ControlTypePaging:
|
||||
value.Description += " (Paging)"
|
||||
if value.Value != nil {
|
||||
valueChildren := ber.DecodePacket(value.Data.Bytes())
|
||||
valueChildren, err := ber.DecodePacketErr(value.Data.Bytes())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode data bytes: %s", err)
|
||||
}
|
||||
value.Data.Truncate(0)
|
||||
value.Value = nil
|
||||
valueChildren.Children[1].Value = valueChildren.Children[1].Data.Bytes()
|
||||
@@ -210,7 +211,10 @@ func addControlDescriptions(packet *ber.Packet) {
|
||||
case ControlTypeBeheraPasswordPolicy:
|
||||
value.Description += " (Password Policy - Behera Draft)"
|
||||
if value.Value != nil {
|
||||
valueChildren := ber.DecodePacket(value.Data.Bytes())
|
||||
valueChildren, err := ber.DecodePacketErr(value.Data.Bytes())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode data bytes: %s", err)
|
||||
}
|
||||
value.Data.Truncate(0)
|
||||
value.Value = nil
|
||||
value.AppendChild(valueChildren)
|
||||
@@ -220,7 +224,10 @@ func addControlDescriptions(packet *ber.Packet) {
|
||||
if child.Tag == 0 {
|
||||
//Warning
|
||||
warningPacket := child.Children[0]
|
||||
packet := ber.DecodePacket(warningPacket.Data.Bytes())
|
||||
packet, err := ber.DecodePacketErr(warningPacket.Data.Bytes())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode data bytes: %s", err)
|
||||
}
|
||||
val, ok := packet.Value.(int64)
|
||||
if ok {
|
||||
if warningPacket.Tag == 0 {
|
||||
@@ -235,7 +242,10 @@ func addControlDescriptions(packet *ber.Packet) {
|
||||
}
|
||||
} else if child.Tag == 1 {
|
||||
// Error
|
||||
packet := ber.DecodePacket(child.Data.Bytes())
|
||||
packet, err := ber.DecodePacketErr(child.Data.Bytes())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode data bytes: %s", err)
|
||||
}
|
||||
val, ok := packet.Value.(int8)
|
||||
if !ok {
|
||||
val = -1
|
||||
@@ -246,28 +256,31 @@ func addControlDescriptions(packet *ber.Packet) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func addRequestDescriptions(packet *ber.Packet) {
|
||||
func addRequestDescriptions(packet *ber.Packet) error {
|
||||
packet.Description = "LDAP Request"
|
||||
packet.Children[0].Description = "Message ID"
|
||||
packet.Children[1].Description = ApplicationMap[uint8(packet.Children[1].Tag)]
|
||||
if len(packet.Children) == 3 {
|
||||
addControlDescriptions(packet.Children[2])
|
||||
return addControlDescriptions(packet.Children[2])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func addDefaultLDAPResponseDescriptions(packet *ber.Packet) {
|
||||
resultCode, _ := getLDAPResultCode(packet)
|
||||
packet.Children[1].Children[0].Description = "Result Code (" + LDAPResultCodeMap[resultCode] + ")"
|
||||
packet.Children[1].Children[1].Description = "Matched DN"
|
||||
func addDefaultLDAPResponseDescriptions(packet *ber.Packet) error {
|
||||
err := GetLDAPError(packet)
|
||||
packet.Children[1].Children[0].Description = "Result Code (" + LDAPResultCodeMap[err.(*Error).ResultCode] + ")"
|
||||
packet.Children[1].Children[1].Description = "Matched DN (" + err.(*Error).MatchedDN + ")"
|
||||
packet.Children[1].Children[2].Description = "Error Message"
|
||||
if len(packet.Children[1].Children) > 3 {
|
||||
packet.Children[1].Children[3].Description = "Referral"
|
||||
}
|
||||
if len(packet.Children) == 3 {
|
||||
addControlDescriptions(packet.Children[2])
|
||||
return addControlDescriptions(packet.Children[2])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DebugBinaryFile reads and prints packets from the given filename
|
||||
@@ -277,8 +290,13 @@ func DebugBinaryFile(fileName string) error {
|
||||
return NewError(ErrorDebugging, err)
|
||||
}
|
||||
ber.PrintBytes(os.Stdout, file, "")
|
||||
packet := ber.DecodePacket(file)
|
||||
addLDAPDescriptions(packet)
|
||||
packet, err := ber.DecodePacketErr(file)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to decode packet: %s", err)
|
||||
}
|
||||
if err := addLDAPDescriptions(packet); err != nil {
|
||||
return err
|
||||
}
|
||||
ber.PrintPacket(packet)
|
||||
|
||||
return nil
|
||||
|
||||
104
vendor/github.com/go-ldap/ldap/moddn.go
сгенерированный
поставляемый
Обычный файл
104
vendor/github.com/go-ldap/ldap/moddn.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,104 @@
|
||||
// Package ldap - moddn.go contains ModifyDN functionality
|
||||
//
|
||||
// https://tools.ietf.org/html/rfc4511
|
||||
// ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
|
||||
// entry LDAPDN,
|
||||
// newrdn RelativeLDAPDN,
|
||||
// deleteoldrdn BOOLEAN,
|
||||
// newSuperior [0] LDAPDN OPTIONAL }
|
||||
//
|
||||
//
|
||||
package ldap
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
|
||||
"gopkg.in/asn1-ber.v1"
|
||||
)
|
||||
|
||||
// ModifyDNRequest holds the request to modify a DN
|
||||
type ModifyDNRequest struct {
|
||||
DN string
|
||||
NewRDN string
|
||||
DeleteOldRDN bool
|
||||
NewSuperior string
|
||||
}
|
||||
|
||||
// NewModifyDNRequest creates a new request which can be passed to ModifyDN().
|
||||
//
|
||||
// To move an object in the tree, set the "newSup" to the new parent entry DN. Use an
|
||||
// empty string for just changing the object's RDN.
|
||||
//
|
||||
// For moving the object without renaming, the "rdn" must be the first
|
||||
// RDN of the given DN.
|
||||
//
|
||||
// A call like
|
||||
// mdnReq := NewModifyDNRequest("uid=someone,dc=example,dc=org", "uid=newname", true, "")
|
||||
// will setup the request to just rename uid=someone,dc=example,dc=org to
|
||||
// uid=newname,dc=example,dc=org.
|
||||
func NewModifyDNRequest(dn string, rdn string, delOld bool, newSup string) *ModifyDNRequest {
|
||||
return &ModifyDNRequest{
|
||||
DN: dn,
|
||||
NewRDN: rdn,
|
||||
DeleteOldRDN: delOld,
|
||||
NewSuperior: newSup,
|
||||
}
|
||||
}
|
||||
|
||||
func (m ModifyDNRequest) encode() *ber.Packet {
|
||||
request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyDNRequest, nil, "Modify DN Request")
|
||||
request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.DN, "DN"))
|
||||
request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.NewRDN, "New RDN"))
|
||||
request.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, m.DeleteOldRDN, "Delete old RDN"))
|
||||
if m.NewSuperior != "" {
|
||||
request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, m.NewSuperior, "New Superior"))
|
||||
}
|
||||
return request
|
||||
}
|
||||
|
||||
// ModifyDN renames the given DN and optionally move to another base (when the "newSup" argument
|
||||
// to NewModifyDNRequest() is not "").
|
||||
func (l *Conn) ModifyDN(m *ModifyDNRequest) error {
|
||||
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
|
||||
packet.AppendChild(m.encode())
|
||||
|
||||
l.Debug.PrintPacket(packet)
|
||||
|
||||
msgCtx, err := l.sendMessage(packet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer l.finishMessage(msgCtx)
|
||||
|
||||
l.Debug.Printf("%d: waiting for response", msgCtx.id)
|
||||
packetResponse, ok := <-msgCtx.responses
|
||||
if !ok {
|
||||
return NewError(ErrorNetwork, errors.New("ldap: channel closed"))
|
||||
}
|
||||
packet, err = packetResponse.ReadPacket()
|
||||
l.Debug.Printf("%d: got response %p", msgCtx.id, packet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if l.Debug {
|
||||
if err := addLDAPDescriptions(packet); err != nil {
|
||||
return err
|
||||
}
|
||||
ber.PrintPacket(packet)
|
||||
}
|
||||
|
||||
if packet.Children[1].Tag == ApplicationModifyDNResponse {
|
||||
err := GetLDAPError(packet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
|
||||
}
|
||||
|
||||
l.Debug.Printf("%d: returning", msgCtx.id)
|
||||
return nil
|
||||
}
|
||||
77
vendor/github.com/go-ldap/ldap/modify.go
сгенерированный
поставляемый
77
vendor/github.com/go-ldap/ldap/modify.go
сгенерированный
поставляемый
@@ -1,7 +1,3 @@
|
||||
// Copyright 2014 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.
|
||||
//
|
||||
// File contains Modify functionality
|
||||
//
|
||||
// https://tools.ietf.org/html/rfc4511
|
||||
@@ -62,54 +58,56 @@ func (p *PartialAttribute) encode() *ber.Packet {
|
||||
return seq
|
||||
}
|
||||
|
||||
// Change for a ModifyRequest as defined in https://tools.ietf.org/html/rfc4511
|
||||
type Change struct {
|
||||
// Operation is the type of change to be made
|
||||
Operation uint
|
||||
// Modification is the attribute to be modified
|
||||
Modification PartialAttribute
|
||||
}
|
||||
|
||||
func (c *Change) encode() *ber.Packet {
|
||||
change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
|
||||
change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(c.Operation), "Operation"))
|
||||
change.AppendChild(c.Modification.encode())
|
||||
return change
|
||||
}
|
||||
|
||||
// ModifyRequest as defined in https://tools.ietf.org/html/rfc4511
|
||||
type ModifyRequest struct {
|
||||
// DN is the distinguishedName of the directory entry to modify
|
||||
DN string
|
||||
// AddAttributes contain the attributes to add
|
||||
AddAttributes []PartialAttribute
|
||||
// DeleteAttributes contain the attributes to delete
|
||||
DeleteAttributes []PartialAttribute
|
||||
// ReplaceAttributes contain the attributes to replace
|
||||
ReplaceAttributes []PartialAttribute
|
||||
// Changes contain the attributes to modify
|
||||
Changes []Change
|
||||
// Controls hold optional controls to send with the request
|
||||
Controls []Control
|
||||
}
|
||||
|
||||
// Add inserts the given attribute to the list of attributes to add
|
||||
// Add appends the given attribute to the list of changes to be made
|
||||
func (m *ModifyRequest) Add(attrType string, attrVals []string) {
|
||||
m.AddAttributes = append(m.AddAttributes, PartialAttribute{Type: attrType, Vals: attrVals})
|
||||
m.appendChange(AddAttribute, attrType, attrVals)
|
||||
}
|
||||
|
||||
// Delete inserts the given attribute to the list of attributes to delete
|
||||
// Delete appends the given attribute to the list of changes to be made
|
||||
func (m *ModifyRequest) Delete(attrType string, attrVals []string) {
|
||||
m.DeleteAttributes = append(m.DeleteAttributes, PartialAttribute{Type: attrType, Vals: attrVals})
|
||||
m.appendChange(DeleteAttribute, attrType, attrVals)
|
||||
}
|
||||
|
||||
// Replace inserts the given attribute to the list of attributes to replace
|
||||
// Replace appends the given attribute to the list of changes to be made
|
||||
func (m *ModifyRequest) Replace(attrType string, attrVals []string) {
|
||||
m.ReplaceAttributes = append(m.ReplaceAttributes, PartialAttribute{Type: attrType, Vals: attrVals})
|
||||
m.appendChange(ReplaceAttribute, attrType, attrVals)
|
||||
}
|
||||
|
||||
func (m *ModifyRequest) appendChange(operation uint, attrType string, attrVals []string) {
|
||||
m.Changes = append(m.Changes, Change{operation, PartialAttribute{Type: attrType, Vals: attrVals}})
|
||||
}
|
||||
|
||||
func (m ModifyRequest) encode() *ber.Packet {
|
||||
request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyRequest, nil, "Modify Request")
|
||||
request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.DN, "DN"))
|
||||
changes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Changes")
|
||||
for _, attribute := range m.AddAttributes {
|
||||
change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
|
||||
change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(AddAttribute), "Operation"))
|
||||
change.AppendChild(attribute.encode())
|
||||
changes.AppendChild(change)
|
||||
}
|
||||
for _, attribute := range m.DeleteAttributes {
|
||||
change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
|
||||
change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(DeleteAttribute), "Operation"))
|
||||
change.AppendChild(attribute.encode())
|
||||
changes.AppendChild(change)
|
||||
}
|
||||
for _, attribute := range m.ReplaceAttributes {
|
||||
change := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Change")
|
||||
change.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, uint64(ReplaceAttribute), "Operation"))
|
||||
change.AppendChild(attribute.encode())
|
||||
changes.AppendChild(change)
|
||||
for _, change := range m.Changes {
|
||||
changes.AppendChild(change.encode())
|
||||
}
|
||||
request.AppendChild(changes)
|
||||
return request
|
||||
@@ -118,9 +116,11 @@ func (m ModifyRequest) encode() *ber.Packet {
|
||||
// NewModifyRequest creates a modify request for the given DN
|
||||
func NewModifyRequest(
|
||||
dn string,
|
||||
controls []Control,
|
||||
) *ModifyRequest {
|
||||
return &ModifyRequest{
|
||||
DN: dn,
|
||||
DN: dn,
|
||||
Controls: controls,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +129,9 @@ func (l *Conn) Modify(modifyRequest *ModifyRequest) error {
|
||||
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
|
||||
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
|
||||
packet.AppendChild(modifyRequest.encode())
|
||||
if len(modifyRequest.Controls) > 0 {
|
||||
packet.AppendChild(encodeControls(modifyRequest.Controls))
|
||||
}
|
||||
|
||||
l.Debug.PrintPacket(packet)
|
||||
|
||||
@@ -157,9 +160,9 @@ func (l *Conn) Modify(modifyRequest *ModifyRequest) error {
|
||||
}
|
||||
|
||||
if packet.Children[1].Tag == ApplicationModifyResponse {
|
||||
resultCode, resultDescription := getLDAPResultCode(packet)
|
||||
if resultCode != 0 {
|
||||
return NewError(resultCode, errors.New(resultDescription))
|
||||
err := GetLDAPError(packet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
|
||||
|
||||
17
vendor/github.com/go-ldap/ldap/passwdmodify.go
сгенерированный
поставляемый
17
vendor/github.com/go-ldap/ldap/passwdmodify.go
сгенерированный
поставляемый
@@ -32,6 +32,8 @@ type PasswordModifyRequest struct {
|
||||
type PasswordModifyResult struct {
|
||||
// GeneratedPassword holds a password generated by the server, if present
|
||||
GeneratedPassword string
|
||||
// Referral are the returned referral
|
||||
Referral string
|
||||
}
|
||||
|
||||
func (r *PasswordModifyRequest) encode() (*ber.Packet, error) {
|
||||
@@ -124,12 +126,19 @@ func (l *Conn) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*Pa
|
||||
}
|
||||
|
||||
if packet.Children[1].Tag == ApplicationExtendedResponse {
|
||||
resultCode, resultDescription := getLDAPResultCode(packet)
|
||||
if resultCode != 0 {
|
||||
return nil, NewError(resultCode, errors.New(resultDescription))
|
||||
err := GetLDAPError(packet)
|
||||
if err != nil {
|
||||
if IsErrorWithCode(err, LDAPResultReferral) {
|
||||
for _, child := range packet.Children[1].Children {
|
||||
if child.Tag == 3 {
|
||||
result.Referral = child.Children[0].Value.(string)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result, err
|
||||
}
|
||||
} else {
|
||||
return nil, NewError(ErrorUnexpectedResponse, fmt.Errorf("Unexpected Response: %d", packet.Children[1].Tag))
|
||||
return nil, NewError(ErrorUnexpectedResponse, fmt.Errorf("unexpected Response: %d", packet.Children[1].Tag))
|
||||
}
|
||||
|
||||
extendedResponse := packet.Children[1]
|
||||
|
||||
22
vendor/github.com/go-ldap/ldap/search.go
сгенерированный
поставляемый
22
vendor/github.com/go-ldap/ldap/search.go
сгенерированный
поставляемый
@@ -1,7 +1,3 @@
|
||||
// Copyright 2011 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.
|
||||
//
|
||||
// File contains Search functionality
|
||||
//
|
||||
// https://tools.ietf.org/html/rfc4511
|
||||
@@ -313,10 +309,10 @@ func (l *Conn) SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32)
|
||||
} else {
|
||||
castControl, ok := control.(*ControlPaging)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Expected paging control to be of type *ControlPaging, got %v", control)
|
||||
return nil, fmt.Errorf("expected paging control to be of type *ControlPaging, got %v", control)
|
||||
}
|
||||
if castControl.PagingSize != pagingSize {
|
||||
return nil, fmt.Errorf("Paging size given in search request (%d) conflicts with size given in search call (%d)", castControl.PagingSize, pagingSize)
|
||||
return nil, fmt.Errorf("paging size given in search request (%d) conflicts with size given in search call (%d)", castControl.PagingSize, pagingSize)
|
||||
}
|
||||
pagingControl = castControl
|
||||
}
|
||||
@@ -379,7 +375,7 @@ func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
|
||||
}
|
||||
packet.AppendChild(encodedSearchRequest)
|
||||
// encode search controls
|
||||
if searchRequest.Controls != nil {
|
||||
if len(searchRequest.Controls) > 0 {
|
||||
packet.AppendChild(encodeControls(searchRequest.Controls))
|
||||
}
|
||||
|
||||
@@ -431,13 +427,17 @@ func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
|
||||
}
|
||||
result.Entries = append(result.Entries, entry)
|
||||
case 5:
|
||||
resultCode, resultDescription := getLDAPResultCode(packet)
|
||||
if resultCode != 0 {
|
||||
return result, NewError(resultCode, errors.New(resultDescription))
|
||||
err := GetLDAPError(packet)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(packet.Children) == 3 {
|
||||
for _, child := range packet.Children[2].Children {
|
||||
result.Controls = append(result.Controls, DecodeControl(child))
|
||||
decodedChild, err := DecodeControl(child)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode child control: %s", err)
|
||||
}
|
||||
result.Controls = append(result.Controls, decodedChild)
|
||||
}
|
||||
}
|
||||
foundSearchResultDone = true
|
||||
|
||||
1
vendor/github.com/go-redis/redis/.travis.yml
сгенерированный
поставляемый
1
vendor/github.com/go-redis/redis/.travis.yml
сгенерированный
поставляемый
@@ -9,6 +9,7 @@ go:
|
||||
- 1.8.x
|
||||
- 1.9.x
|
||||
- 1.10.x
|
||||
- 1.11.x
|
||||
- tip
|
||||
|
||||
matrix:
|
||||
|
||||
4
vendor/github.com/go-redis/redis/CHANGELOG.md
сгенерированный
поставляемый
4
vendor/github.com/go-redis/redis/CHANGELOG.md
сгенерированный
поставляемый
@@ -1,5 +1,9 @@
|
||||
# Changelog
|
||||
|
||||
## Unreleased
|
||||
|
||||
- Cluster and Ring pipelines process commands for each node in its own goroutine.
|
||||
|
||||
## 6.14
|
||||
|
||||
- Added Options.MinIdleConns.
|
||||
|
||||
145
vendor/github.com/go-redis/redis/cluster.go
сгенерированный
поставляемый
145
vendor/github.com/go-redis/redis/cluster.go
сгенерированный
поставляемый
@@ -82,7 +82,7 @@ func (opt *ClusterOptions) init() {
|
||||
opt.MaxRedirects = 8
|
||||
}
|
||||
|
||||
if opt.RouteByLatency || opt.RouteRandomly {
|
||||
if (opt.RouteByLatency || opt.RouteRandomly) && opt.ClusterSlots == nil {
|
||||
opt.ReadOnly = true
|
||||
}
|
||||
|
||||
@@ -831,7 +831,7 @@ func (c *ClusterClient) cmdSlotAndNode(cmd Cmder) (int, *clusterNode, error) {
|
||||
cmdInfo := c.cmdInfo(cmd.Name())
|
||||
slot := cmdSlot(cmd, cmdFirstKeyPos(cmd, cmdInfo))
|
||||
|
||||
if cmdInfo != nil && cmdInfo.ReadOnly && c.opt.ReadOnly {
|
||||
if c.opt.ReadOnly && cmdInfo != nil && cmdInfo.ReadOnly {
|
||||
if c.opt.RouteByLatency {
|
||||
node, err := state.slotClosestNode(slot)
|
||||
return slot, node, err
|
||||
@@ -1241,7 +1241,8 @@ func (c *ClusterClient) WrapProcessPipeline(
|
||||
}
|
||||
|
||||
func (c *ClusterClient) defaultProcessPipeline(cmds []Cmder) error {
|
||||
cmdsMap, err := c.mapCmdsByNode(cmds)
|
||||
cmdsMap := newCmdsMap()
|
||||
err := c.mapCmdsByNode(cmds, cmdsMap)
|
||||
if err != nil {
|
||||
setCmdsErr(cmds, err)
|
||||
return err
|
||||
@@ -1252,28 +1253,31 @@ func (c *ClusterClient) defaultProcessPipeline(cmds []Cmder) error {
|
||||
time.Sleep(c.retryBackoff(attempt))
|
||||
}
|
||||
|
||||
failedCmds := make(map[*clusterNode][]Cmder)
|
||||
failedCmds := newCmdsMap()
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for node, cmds := range cmdsMap {
|
||||
cn, err := node.Client.getConn()
|
||||
if err != nil {
|
||||
if err == pool.ErrClosed {
|
||||
c.remapCmds(cmds, failedCmds)
|
||||
} else {
|
||||
setCmdsErr(cmds, err)
|
||||
for node, cmds := range cmdsMap.m {
|
||||
wg.Add(1)
|
||||
go func(node *clusterNode, cmds []Cmder) {
|
||||
defer wg.Done()
|
||||
|
||||
cn, err := node.Client.getConn()
|
||||
if err != nil {
|
||||
if err == pool.ErrClosed {
|
||||
c.mapCmdsByNode(cmds, failedCmds)
|
||||
} else {
|
||||
setCmdsErr(cmds, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
err = c.pipelineProcessCmds(node, cn, cmds, failedCmds)
|
||||
if err == nil || internal.IsRedisError(err) {
|
||||
node.Client.connPool.Put(cn)
|
||||
} else {
|
||||
node.Client.connPool.Remove(cn)
|
||||
}
|
||||
err = c.pipelineProcessCmds(node, cn, cmds, failedCmds)
|
||||
node.Client.releaseConnStrict(cn, err)
|
||||
}(node, cmds)
|
||||
}
|
||||
|
||||
if len(failedCmds) == 0 {
|
||||
wg.Wait()
|
||||
if len(failedCmds.m) == 0 {
|
||||
break
|
||||
}
|
||||
cmdsMap = failedCmds
|
||||
@@ -1282,14 +1286,24 @@ func (c *ClusterClient) defaultProcessPipeline(cmds []Cmder) error {
|
||||
return cmdsFirstErr(cmds)
|
||||
}
|
||||
|
||||
func (c *ClusterClient) mapCmdsByNode(cmds []Cmder) (map[*clusterNode][]Cmder, error) {
|
||||
type cmdsMap struct {
|
||||
mu sync.Mutex
|
||||
m map[*clusterNode][]Cmder
|
||||
}
|
||||
|
||||
func newCmdsMap() *cmdsMap {
|
||||
return &cmdsMap{
|
||||
m: make(map[*clusterNode][]Cmder),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ClusterClient) mapCmdsByNode(cmds []Cmder, cmdsMap *cmdsMap) error {
|
||||
state, err := c.state.Get()
|
||||
if err != nil {
|
||||
setCmdsErr(cmds, err)
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
cmdsMap := make(map[*clusterNode][]Cmder)
|
||||
cmdsAreReadOnly := c.cmdsAreReadOnly(cmds)
|
||||
for _, cmd := range cmds {
|
||||
var node *clusterNode
|
||||
@@ -1301,11 +1315,13 @@ func (c *ClusterClient) mapCmdsByNode(cmds []Cmder) (map[*clusterNode][]Cmder, e
|
||||
node, err = state.slotMasterNode(slot)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
cmdsMap[node] = append(cmdsMap[node], cmd)
|
||||
cmdsMap.mu.Lock()
|
||||
cmdsMap.m[node] = append(cmdsMap.m[node], cmd)
|
||||
cmdsMap.mu.Unlock()
|
||||
}
|
||||
return cmdsMap, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClusterClient) cmdsAreReadOnly(cmds []Cmder) bool {
|
||||
@@ -1318,27 +1334,17 @@ func (c *ClusterClient) cmdsAreReadOnly(cmds []Cmder) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *ClusterClient) remapCmds(cmds []Cmder, failedCmds map[*clusterNode][]Cmder) {
|
||||
remappedCmds, err := c.mapCmdsByNode(cmds)
|
||||
if err != nil {
|
||||
setCmdsErr(cmds, err)
|
||||
return
|
||||
}
|
||||
|
||||
for node, cmds := range remappedCmds {
|
||||
failedCmds[node] = cmds
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ClusterClient) pipelineProcessCmds(
|
||||
node *clusterNode, cn *pool.Conn, cmds []Cmder, failedCmds map[*clusterNode][]Cmder,
|
||||
node *clusterNode, cn *pool.Conn, cmds []Cmder, failedCmds *cmdsMap,
|
||||
) error {
|
||||
err := cn.WithWriter(c.opt.WriteTimeout, func(wr *proto.Writer) error {
|
||||
return writeCmd(wr, cmds...)
|
||||
})
|
||||
if err != nil {
|
||||
setCmdsErr(cmds, err)
|
||||
failedCmds[node] = cmds
|
||||
failedCmds.mu.Lock()
|
||||
failedCmds.m[node] = cmds
|
||||
failedCmds.mu.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1349,7 +1355,7 @@ func (c *ClusterClient) pipelineProcessCmds(
|
||||
}
|
||||
|
||||
func (c *ClusterClient) pipelineReadCmds(
|
||||
rd *proto.Reader, cmds []Cmder, failedCmds map[*clusterNode][]Cmder,
|
||||
rd *proto.Reader, cmds []Cmder, failedCmds *cmdsMap,
|
||||
) error {
|
||||
for _, cmd := range cmds {
|
||||
err := cmd.readReply(rd)
|
||||
@@ -1371,7 +1377,7 @@ func (c *ClusterClient) pipelineReadCmds(
|
||||
}
|
||||
|
||||
func (c *ClusterClient) checkMovedErr(
|
||||
cmd Cmder, err error, failedCmds map[*clusterNode][]Cmder,
|
||||
cmd Cmder, err error, failedCmds *cmdsMap,
|
||||
) bool {
|
||||
moved, ask, addr := internal.IsMovedError(err)
|
||||
|
||||
@@ -1383,7 +1389,9 @@ func (c *ClusterClient) checkMovedErr(
|
||||
return false
|
||||
}
|
||||
|
||||
failedCmds[node] = append(failedCmds[node], cmd)
|
||||
failedCmds.mu.Lock()
|
||||
failedCmds.m[node] = append(failedCmds.m[node], cmd)
|
||||
failedCmds.mu.Unlock()
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -1393,7 +1401,9 @@ func (c *ClusterClient) checkMovedErr(
|
||||
return false
|
||||
}
|
||||
|
||||
failedCmds[node] = append(failedCmds[node], NewCmd("ASKING"), cmd)
|
||||
failedCmds.mu.Lock()
|
||||
failedCmds.m[node] = append(failedCmds.m[node], NewCmd("ASKING"), cmd)
|
||||
failedCmds.mu.Unlock()
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -1433,31 +1443,34 @@ func (c *ClusterClient) defaultProcessTxPipeline(cmds []Cmder) error {
|
||||
time.Sleep(c.retryBackoff(attempt))
|
||||
}
|
||||
|
||||
failedCmds := make(map[*clusterNode][]Cmder)
|
||||
failedCmds := newCmdsMap()
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for node, cmds := range cmdsMap {
|
||||
cn, err := node.Client.getConn()
|
||||
if err != nil {
|
||||
if err == pool.ErrClosed {
|
||||
c.remapCmds(cmds, failedCmds)
|
||||
} else {
|
||||
setCmdsErr(cmds, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
wg.Add(1)
|
||||
go func(node *clusterNode, cmds []Cmder) {
|
||||
defer wg.Done()
|
||||
|
||||
err = c.txPipelineProcessCmds(node, cn, cmds, failedCmds)
|
||||
if err == nil || internal.IsRedisError(err) {
|
||||
node.Client.connPool.Put(cn)
|
||||
} else {
|
||||
node.Client.connPool.Remove(cn)
|
||||
}
|
||||
cn, err := node.Client.getConn()
|
||||
if err != nil {
|
||||
if err == pool.ErrClosed {
|
||||
c.mapCmdsByNode(cmds, failedCmds)
|
||||
} else {
|
||||
setCmdsErr(cmds, err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
err = c.txPipelineProcessCmds(node, cn, cmds, failedCmds)
|
||||
node.Client.releaseConnStrict(cn, err)
|
||||
}(node, cmds)
|
||||
}
|
||||
|
||||
if len(failedCmds) == 0 {
|
||||
wg.Wait()
|
||||
if len(failedCmds.m) == 0 {
|
||||
break
|
||||
}
|
||||
cmdsMap = failedCmds
|
||||
cmdsMap = failedCmds.m
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1474,14 +1487,16 @@ func (c *ClusterClient) mapCmdsBySlot(cmds []Cmder) map[int][]Cmder {
|
||||
}
|
||||
|
||||
func (c *ClusterClient) txPipelineProcessCmds(
|
||||
node *clusterNode, cn *pool.Conn, cmds []Cmder, failedCmds map[*clusterNode][]Cmder,
|
||||
node *clusterNode, cn *pool.Conn, cmds []Cmder, failedCmds *cmdsMap,
|
||||
) error {
|
||||
err := cn.WithWriter(c.opt.WriteTimeout, func(wr *proto.Writer) error {
|
||||
return txPipelineWriteMulti(wr, cmds)
|
||||
})
|
||||
if err != nil {
|
||||
setCmdsErr(cmds, err)
|
||||
failedCmds[node] = cmds
|
||||
failedCmds.mu.Lock()
|
||||
failedCmds.m[node] = cmds
|
||||
failedCmds.mu.Unlock()
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1497,7 +1512,7 @@ func (c *ClusterClient) txPipelineProcessCmds(
|
||||
}
|
||||
|
||||
func (c *ClusterClient) txPipelineReadQueued(
|
||||
rd *proto.Reader, cmds []Cmder, failedCmds map[*clusterNode][]Cmder,
|
||||
rd *proto.Reader, cmds []Cmder, failedCmds *cmdsMap,
|
||||
) error {
|
||||
// Parse queued replies.
|
||||
var statusCmd StatusCmd
|
||||
|
||||
13
vendor/github.com/go-redis/redis/commands.go
сгенерированный
поставляемый
13
vendor/github.com/go-redis/redis/commands.go
сгенерированный
поставляемый
@@ -8,13 +8,6 @@ import (
|
||||
"github.com/go-redis/redis/internal"
|
||||
)
|
||||
|
||||
func readTimeout(timeout time.Duration) time.Duration {
|
||||
if timeout == 0 {
|
||||
return 0
|
||||
}
|
||||
return timeout + 10*time.Second
|
||||
}
|
||||
|
||||
func usePrecise(dur time.Duration) bool {
|
||||
return dur < time.Second || dur%time.Second != 0
|
||||
}
|
||||
@@ -1397,6 +1390,9 @@ func (c *cmdable) XRead(a *XReadArgs) *XStreamSliceCmd {
|
||||
}
|
||||
|
||||
cmd := NewXStreamSliceCmd(args...)
|
||||
if a.Block >= 0 {
|
||||
cmd.setReadTimeout(a.Block)
|
||||
}
|
||||
c.process(cmd)
|
||||
return cmd
|
||||
}
|
||||
@@ -1455,6 +1451,9 @@ func (c *cmdable) XReadGroup(a *XReadGroupArgs) *XStreamSliceCmd {
|
||||
}
|
||||
|
||||
cmd := NewXStreamSliceCmd(args...)
|
||||
if a.Block >= 0 {
|
||||
cmd.setReadTimeout(a.Block)
|
||||
}
|
||||
c.process(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
3
vendor/github.com/go-redis/redis/internal/error.go
сгенерированный
поставляемый
3
vendor/github.com/go-redis/redis/internal/error.go
сгенерированный
поставляемый
@@ -9,6 +9,9 @@ import (
|
||||
)
|
||||
|
||||
func IsRetryableError(err error, retryTimeout bool) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
if err == io.EOF {
|
||||
return true
|
||||
}
|
||||
|
||||
2
vendor/github.com/go-redis/redis/options.go
сгенерированный
поставляемый
2
vendor/github.com/go-redis/redis/options.go
сгенерированный
поставляемый
@@ -48,7 +48,7 @@ type Options struct {
|
||||
// Default is 5 seconds.
|
||||
DialTimeout time.Duration
|
||||
// Timeout for socket reads. If reached, commands will fail
|
||||
// with a timeout instead of blocking.
|
||||
// with a timeout instead of blocking. Use value -1 for no timeout and 0 for default.
|
||||
// Default is 3 seconds.
|
||||
ReadTimeout time.Duration
|
||||
// Timeout for socket writes. If reached, commands will fail
|
||||
|
||||
10
vendor/github.com/go-redis/redis/pubsub.go
сгенерированный
поставляемый
10
vendor/github.com/go-redis/redis/pubsub.go
сгенерированный
поставляемый
@@ -1,6 +1,7 @@
|
||||
package redis
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -10,6 +11,8 @@ import (
|
||||
"github.com/go-redis/redis/internal/proto"
|
||||
)
|
||||
|
||||
var errPingTimeout = errors.New("redis: ping timeout")
|
||||
|
||||
// PubSub implements Pub/Sub commands bas described in
|
||||
// http://redis.io/topics/pubsub. Message receiving is NOT safe
|
||||
// for concurrent use by multiple goroutines.
|
||||
@@ -51,7 +54,6 @@ func (c *PubSub) _conn(newChannels []string) (*pool.Conn, error) {
|
||||
if c.closed {
|
||||
return nil, pool.ErrClosed
|
||||
}
|
||||
|
||||
if c.cn != nil {
|
||||
return c.cn, nil
|
||||
}
|
||||
@@ -439,7 +441,6 @@ func (c *PubSub) initChannel() {
|
||||
timer.Stop()
|
||||
|
||||
healthy := true
|
||||
var pingErr error
|
||||
for {
|
||||
timer.Reset(timeout)
|
||||
select {
|
||||
@@ -449,10 +450,13 @@ func (c *PubSub) initChannel() {
|
||||
<-timer.C
|
||||
}
|
||||
case <-timer.C:
|
||||
pingErr = c.Ping()
|
||||
pingErr := c.Ping()
|
||||
if healthy {
|
||||
healthy = false
|
||||
} else {
|
||||
if pingErr == nil {
|
||||
pingErr = errPingTimeout
|
||||
}
|
||||
c.mu.Lock()
|
||||
c._reconnect(pingErr)
|
||||
c.mu.Unlock()
|
||||
|
||||
29
vendor/github.com/go-redis/redis/redis.go
сгенерированный
поставляемый
29
vendor/github.com/go-redis/redis/redis.go
сгенерированный
поставляемый
@@ -77,14 +77,20 @@ func (c *baseClient) getConn() (*pool.Conn, error) {
|
||||
return cn, nil
|
||||
}
|
||||
|
||||
func (c *baseClient) releaseConn(cn *pool.Conn, err error) bool {
|
||||
func (c *baseClient) releaseConn(cn *pool.Conn, err error) {
|
||||
if internal.IsBadConn(err, false) {
|
||||
c.connPool.Remove(cn)
|
||||
return false
|
||||
} else {
|
||||
c.connPool.Put(cn)
|
||||
}
|
||||
}
|
||||
|
||||
c.connPool.Put(cn)
|
||||
return true
|
||||
func (c *baseClient) releaseConnStrict(cn *pool.Conn, err error) {
|
||||
if err == nil || internal.IsRedisError(err) {
|
||||
c.connPool.Put(cn)
|
||||
} else {
|
||||
c.connPool.Remove(cn)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *baseClient) initConn(cn *pool.Conn) error {
|
||||
@@ -188,7 +194,11 @@ func (c *baseClient) retryBackoff(attempt int) time.Duration {
|
||||
|
||||
func (c *baseClient) cmdTimeout(cmd Cmder) time.Duration {
|
||||
if timeout := cmd.readTimeout(); timeout != nil {
|
||||
return readTimeout(*timeout)
|
||||
t := *timeout
|
||||
if t == 0 {
|
||||
return 0
|
||||
}
|
||||
return t + 10*time.Second
|
||||
}
|
||||
return c.opt.ReadTimeout
|
||||
}
|
||||
@@ -244,12 +254,7 @@ func (c *baseClient) generalProcessPipeline(cmds []Cmder, p pipelineProcessor) e
|
||||
}
|
||||
|
||||
canRetry, err := p(cn, cmds)
|
||||
|
||||
if err == nil || internal.IsRedisError(err) {
|
||||
c.connPool.Put(cn)
|
||||
break
|
||||
}
|
||||
c.connPool.Remove(cn)
|
||||
c.releaseConnStrict(cn, err)
|
||||
|
||||
if !canRetry || !internal.IsRetryableError(err, true) {
|
||||
break
|
||||
@@ -319,7 +324,7 @@ func txPipelineReadQueued(rd *proto.Reader, cmds []Cmder) error {
|
||||
return err
|
||||
}
|
||||
|
||||
for _ = range cmds {
|
||||
for range cmds {
|
||||
err = statusCmd.readReply(rd)
|
||||
if err != nil && !internal.IsRedisError(err) {
|
||||
return err
|
||||
|
||||
87
vendor/github.com/go-redis/redis/ring.go
сгенерированный
поставляемый
87
vendor/github.com/go-redis/redis/ring.go
сгенерированный
поставляемый
@@ -342,6 +342,7 @@ type Ring struct {
|
||||
shards *ringShards
|
||||
cmdsInfoCache *cmdsInfoCache
|
||||
|
||||
process func(Cmder) error
|
||||
processPipeline func([]Cmder) error
|
||||
}
|
||||
|
||||
@@ -354,6 +355,7 @@ func NewRing(opt *RingOptions) *Ring {
|
||||
}
|
||||
ring.cmdsInfoCache = newCmdsInfoCache(ring.cmdsInfo)
|
||||
|
||||
ring.process = ring.defaultProcess
|
||||
ring.processPipeline = ring.defaultProcessPipeline
|
||||
ring.cmdable.setProcessor(ring.Process)
|
||||
|
||||
@@ -526,19 +528,34 @@ func (c *Ring) Do(args ...interface{}) *Cmd {
|
||||
func (c *Ring) WrapProcess(
|
||||
fn func(oldProcess func(cmd Cmder) error) func(cmd Cmder) error,
|
||||
) {
|
||||
c.ForEachShard(func(c *Client) error {
|
||||
c.WrapProcess(fn)
|
||||
return nil
|
||||
})
|
||||
c.process = fn(c.process)
|
||||
}
|
||||
|
||||
func (c *Ring) Process(cmd Cmder) error {
|
||||
shard, err := c.cmdShard(cmd)
|
||||
if err != nil {
|
||||
cmd.setErr(err)
|
||||
return err
|
||||
return c.process(cmd)
|
||||
}
|
||||
|
||||
func (c *Ring) defaultProcess(cmd Cmder) error {
|
||||
for attempt := 0; attempt <= c.opt.MaxRetries; attempt++ {
|
||||
if attempt > 0 {
|
||||
time.Sleep(c.retryBackoff(attempt))
|
||||
}
|
||||
|
||||
shard, err := c.cmdShard(cmd)
|
||||
if err != nil {
|
||||
cmd.setErr(err)
|
||||
return err
|
||||
}
|
||||
|
||||
err = shard.Client.Process(cmd)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if !internal.IsRetryableError(err, cmd.readTimeout() == nil) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return shard.Client.Process(cmd)
|
||||
return cmd.Err()
|
||||
}
|
||||
|
||||
func (c *Ring) Pipeline() Pipeliner {
|
||||
@@ -575,36 +592,42 @@ func (c *Ring) defaultProcessPipeline(cmds []Cmder) error {
|
||||
time.Sleep(c.retryBackoff(attempt))
|
||||
}
|
||||
|
||||
var mu sync.Mutex
|
||||
var failedCmdsMap map[string][]Cmder
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for hash, cmds := range cmdsMap {
|
||||
shard, err := c.shards.GetByHash(hash)
|
||||
if err != nil {
|
||||
setCmdsErr(cmds, err)
|
||||
continue
|
||||
}
|
||||
wg.Add(1)
|
||||
go func(hash string, cmds []Cmder) {
|
||||
defer wg.Done()
|
||||
|
||||
cn, err := shard.Client.getConn()
|
||||
if err != nil {
|
||||
setCmdsErr(cmds, err)
|
||||
continue
|
||||
}
|
||||
|
||||
canRetry, err := shard.Client.pipelineProcessCmds(cn, cmds)
|
||||
if err == nil || internal.IsRedisError(err) {
|
||||
shard.Client.connPool.Put(cn)
|
||||
continue
|
||||
}
|
||||
shard.Client.connPool.Remove(cn)
|
||||
|
||||
if canRetry && internal.IsRetryableError(err, true) {
|
||||
if failedCmdsMap == nil {
|
||||
failedCmdsMap = make(map[string][]Cmder)
|
||||
shard, err := c.shards.GetByHash(hash)
|
||||
if err != nil {
|
||||
setCmdsErr(cmds, err)
|
||||
return
|
||||
}
|
||||
failedCmdsMap[hash] = cmds
|
||||
}
|
||||
|
||||
cn, err := shard.Client.getConn()
|
||||
if err != nil {
|
||||
setCmdsErr(cmds, err)
|
||||
return
|
||||
}
|
||||
|
||||
canRetry, err := shard.Client.pipelineProcessCmds(cn, cmds)
|
||||
shard.Client.releaseConnStrict(cn, err)
|
||||
|
||||
if canRetry && internal.IsRetryableError(err, true) {
|
||||
mu.Lock()
|
||||
if failedCmdsMap == nil {
|
||||
failedCmdsMap = make(map[string][]Cmder)
|
||||
}
|
||||
failedCmdsMap[hash] = cmds
|
||||
mu.Unlock()
|
||||
}
|
||||
}(hash, cmds)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
if len(failedCmdsMap) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
212
vendor/github.com/go-redis/redis/sentinel.go
сгенерированный
поставляемый
212
vendor/github.com/go-redis/redis/sentinel.go
сгенерированный
поставляемый
@@ -119,7 +119,7 @@ func NewSentinelClient(opt *Options) *SentinelClient {
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *SentinelClient) PubSub() *PubSub {
|
||||
func (c *SentinelClient) pubSub() *PubSub {
|
||||
pubsub := &PubSub{
|
||||
opt: c.opt,
|
||||
|
||||
@@ -132,14 +132,34 @@ func (c *SentinelClient) PubSub() *PubSub {
|
||||
return pubsub
|
||||
}
|
||||
|
||||
// Subscribe subscribes the client to the specified channels.
|
||||
// Channels can be omitted to create empty subscription.
|
||||
func (c *SentinelClient) Subscribe(channels ...string) *PubSub {
|
||||
pubsub := c.pubSub()
|
||||
if len(channels) > 0 {
|
||||
_ = pubsub.Subscribe(channels...)
|
||||
}
|
||||
return pubsub
|
||||
}
|
||||
|
||||
// PSubscribe subscribes the client to the given patterns.
|
||||
// Patterns can be omitted to create empty subscription.
|
||||
func (c *SentinelClient) PSubscribe(channels ...string) *PubSub {
|
||||
pubsub := c.pubSub()
|
||||
if len(channels) > 0 {
|
||||
_ = pubsub.PSubscribe(channels...)
|
||||
}
|
||||
return pubsub
|
||||
}
|
||||
|
||||
func (c *SentinelClient) GetMasterAddrByName(name string) *StringSliceCmd {
|
||||
cmd := NewStringSliceCmd("SENTINEL", "get-master-addr-by-name", name)
|
||||
cmd := NewStringSliceCmd("sentinel", "get-master-addr-by-name", name)
|
||||
c.Process(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c *SentinelClient) Sentinels(name string) *SliceCmd {
|
||||
cmd := NewSliceCmd("SENTINEL", "sentinels", name)
|
||||
cmd := NewSliceCmd("sentinel", "sentinels", name)
|
||||
c.Process(cmd)
|
||||
return cmd
|
||||
}
|
||||
@@ -158,77 +178,78 @@ type sentinelFailover struct {
|
||||
sentinel *SentinelClient
|
||||
}
|
||||
|
||||
func (d *sentinelFailover) Close() error {
|
||||
return d.resetSentinel()
|
||||
func (c *sentinelFailover) Close() error {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if c.sentinel != nil {
|
||||
return c.closeSentinel()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *sentinelFailover) Pool() *pool.ConnPool {
|
||||
d.poolOnce.Do(func() {
|
||||
d.opt.Dialer = d.dial
|
||||
d.pool = newConnPool(d.opt)
|
||||
func (c *sentinelFailover) Pool() *pool.ConnPool {
|
||||
c.poolOnce.Do(func() {
|
||||
c.opt.Dialer = c.dial
|
||||
c.pool = newConnPool(c.opt)
|
||||
})
|
||||
return d.pool
|
||||
return c.pool
|
||||
}
|
||||
|
||||
func (d *sentinelFailover) dial() (net.Conn, error) {
|
||||
addr, err := d.MasterAddr()
|
||||
func (c *sentinelFailover) dial() (net.Conn, error) {
|
||||
addr, err := c.MasterAddr()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return net.DialTimeout("tcp", addr, d.opt.DialTimeout)
|
||||
return net.DialTimeout("tcp", addr, c.opt.DialTimeout)
|
||||
}
|
||||
|
||||
func (d *sentinelFailover) MasterAddr() (string, error) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
addr, err := d.masterAddr()
|
||||
func (c *sentinelFailover) MasterAddr() (string, error) {
|
||||
addr, err := c.masterAddr()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
d._switchMaster(addr)
|
||||
|
||||
c.switchMaster(addr)
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
func (d *sentinelFailover) masterAddr() (string, error) {
|
||||
// Try last working sentinel.
|
||||
if d.sentinel != nil {
|
||||
addr, err := d.sentinel.GetMasterAddrByName(d.masterName).Result()
|
||||
if err == nil {
|
||||
addr := net.JoinHostPort(addr[0], addr[1])
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
internal.Logf("sentinel: GetMasterAddrByName name=%q failed: %s",
|
||||
d.masterName, err)
|
||||
d._resetSentinel()
|
||||
func (c *sentinelFailover) masterAddr() (string, error) {
|
||||
addr := c.getMasterAddr()
|
||||
if addr != "" {
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
for i, sentinelAddr := range d.sentinelAddrs {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
for i, sentinelAddr := range c.sentinelAddrs {
|
||||
sentinel := NewSentinelClient(&Options{
|
||||
Addr: sentinelAddr,
|
||||
|
||||
DialTimeout: d.opt.DialTimeout,
|
||||
ReadTimeout: d.opt.ReadTimeout,
|
||||
WriteTimeout: d.opt.WriteTimeout,
|
||||
MaxRetries: c.opt.MaxRetries,
|
||||
|
||||
PoolSize: d.opt.PoolSize,
|
||||
PoolTimeout: d.opt.PoolTimeout,
|
||||
IdleTimeout: d.opt.IdleTimeout,
|
||||
DialTimeout: c.opt.DialTimeout,
|
||||
ReadTimeout: c.opt.ReadTimeout,
|
||||
WriteTimeout: c.opt.WriteTimeout,
|
||||
|
||||
PoolSize: c.opt.PoolSize,
|
||||
PoolTimeout: c.opt.PoolTimeout,
|
||||
IdleTimeout: c.opt.IdleTimeout,
|
||||
IdleCheckFrequency: c.opt.IdleCheckFrequency,
|
||||
|
||||
TLSConfig: c.opt.TLSConfig,
|
||||
})
|
||||
|
||||
masterAddr, err := sentinel.GetMasterAddrByName(d.masterName).Result()
|
||||
masterAddr, err := sentinel.GetMasterAddrByName(c.masterName).Result()
|
||||
if err != nil {
|
||||
internal.Logf("sentinel: GetMasterAddrByName master=%q failed: %s",
|
||||
d.masterName, err)
|
||||
sentinel.Close()
|
||||
c.masterName, err)
|
||||
_ = sentinel.Close()
|
||||
continue
|
||||
}
|
||||
|
||||
// Push working sentinel to the top.
|
||||
d.sentinelAddrs[0], d.sentinelAddrs[i] = d.sentinelAddrs[i], d.sentinelAddrs[0]
|
||||
d.setSentinel(sentinel)
|
||||
c.sentinelAddrs[0], c.sentinelAddrs[i] = c.sentinelAddrs[i], c.sentinelAddrs[0]
|
||||
c.setSentinel(sentinel)
|
||||
|
||||
addr := net.JoinHostPort(masterAddr[0], masterAddr[1])
|
||||
return addr, nil
|
||||
@@ -237,17 +258,41 @@ func (d *sentinelFailover) masterAddr() (string, error) {
|
||||
return "", errors.New("redis: all sentinels are unreachable")
|
||||
}
|
||||
|
||||
func (c *sentinelFailover) switchMaster(addr string) {
|
||||
c.mu.Lock()
|
||||
c._switchMaster(addr)
|
||||
c.mu.Unlock()
|
||||
func (c *sentinelFailover) getMasterAddr() string {
|
||||
c.mu.RLock()
|
||||
sentinel := c.sentinel
|
||||
c.mu.RUnlock()
|
||||
|
||||
if sentinel == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
addr, err := sentinel.GetMasterAddrByName(c.masterName).Result()
|
||||
if err != nil {
|
||||
internal.Logf("sentinel: GetMasterAddrByName name=%q failed: %s",
|
||||
c.masterName, err)
|
||||
c.mu.Lock()
|
||||
if c.sentinel == sentinel {
|
||||
c.closeSentinel()
|
||||
}
|
||||
c.mu.Unlock()
|
||||
return ""
|
||||
}
|
||||
|
||||
return net.JoinHostPort(addr[0], addr[1])
|
||||
}
|
||||
|
||||
func (c *sentinelFailover) _switchMaster(addr string) {
|
||||
if c._masterAddr == addr {
|
||||
func (c *sentinelFailover) switchMaster(addr string) {
|
||||
c.mu.RLock()
|
||||
masterAddr := c._masterAddr
|
||||
c.mu.RUnlock()
|
||||
if masterAddr == addr {
|
||||
return
|
||||
}
|
||||
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
internal.Logf("sentinel: new master=%q addr=%q",
|
||||
c.masterName, addr)
|
||||
_ = c.Pool().Filter(func(cn *pool.Conn) bool {
|
||||
@@ -256,32 +301,22 @@ func (c *sentinelFailover) _switchMaster(addr string) {
|
||||
c._masterAddr = addr
|
||||
}
|
||||
|
||||
func (d *sentinelFailover) setSentinel(sentinel *SentinelClient) {
|
||||
d.discoverSentinels(sentinel)
|
||||
d.sentinel = sentinel
|
||||
go d.listen(sentinel)
|
||||
func (c *sentinelFailover) setSentinel(sentinel *SentinelClient) {
|
||||
c.discoverSentinels(sentinel)
|
||||
c.sentinel = sentinel
|
||||
go c.listen(sentinel)
|
||||
}
|
||||
|
||||
func (d *sentinelFailover) resetSentinel() error {
|
||||
var err error
|
||||
d.mu.Lock()
|
||||
if d.sentinel != nil {
|
||||
err = d._resetSentinel()
|
||||
}
|
||||
d.mu.Unlock()
|
||||
func (c *sentinelFailover) closeSentinel() error {
|
||||
err := c.sentinel.Close()
|
||||
c.sentinel = nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *sentinelFailover) _resetSentinel() error {
|
||||
err := d.sentinel.Close()
|
||||
d.sentinel = nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *sentinelFailover) discoverSentinels(sentinel *SentinelClient) {
|
||||
sentinels, err := sentinel.Sentinels(d.masterName).Result()
|
||||
func (c *sentinelFailover) discoverSentinels(sentinel *SentinelClient) {
|
||||
sentinels, err := sentinel.Sentinels(c.masterName).Result()
|
||||
if err != nil {
|
||||
internal.Logf("sentinel: Sentinels master=%q failed: %s", d.masterName, err)
|
||||
internal.Logf("sentinel: Sentinels master=%q failed: %s", c.masterName, err)
|
||||
return
|
||||
}
|
||||
for _, sentinel := range sentinels {
|
||||
@@ -290,49 +325,36 @@ func (d *sentinelFailover) discoverSentinels(sentinel *SentinelClient) {
|
||||
key := vals[i].(string)
|
||||
if key == "name" {
|
||||
sentinelAddr := vals[i+1].(string)
|
||||
if !contains(d.sentinelAddrs, sentinelAddr) {
|
||||
internal.Logf(
|
||||
"sentinel: discovered new sentinel=%q for master=%q",
|
||||
sentinelAddr, d.masterName,
|
||||
)
|
||||
d.sentinelAddrs = append(d.sentinelAddrs, sentinelAddr)
|
||||
if !contains(c.sentinelAddrs, sentinelAddr) {
|
||||
internal.Logf("sentinel: discovered new sentinel=%q for master=%q",
|
||||
sentinelAddr, c.masterName)
|
||||
c.sentinelAddrs = append(c.sentinelAddrs, sentinelAddr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (d *sentinelFailover) listen(sentinel *SentinelClient) {
|
||||
pubsub := sentinel.PubSub()
|
||||
func (c *sentinelFailover) listen(sentinel *SentinelClient) {
|
||||
pubsub := sentinel.Subscribe("+switch-master")
|
||||
defer pubsub.Close()
|
||||
|
||||
err := pubsub.Subscribe("+switch-master")
|
||||
if err != nil {
|
||||
internal.Logf("sentinel: Subscribe failed: %s", err)
|
||||
d.resetSentinel()
|
||||
return
|
||||
}
|
||||
|
||||
ch := pubsub.Channel()
|
||||
for {
|
||||
msg, err := pubsub.ReceiveMessage()
|
||||
if err != nil {
|
||||
if err == pool.ErrClosed {
|
||||
d.resetSentinel()
|
||||
return
|
||||
}
|
||||
internal.Logf("sentinel: ReceiveMessage failed: %s", err)
|
||||
continue
|
||||
msg, ok := <-ch
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
|
||||
switch msg.Channel {
|
||||
case "+switch-master":
|
||||
parts := strings.Split(msg.Payload, " ")
|
||||
if parts[0] != d.masterName {
|
||||
if parts[0] != c.masterName {
|
||||
internal.Logf("sentinel: ignore addr for master=%q", parts[0])
|
||||
continue
|
||||
}
|
||||
addr := net.JoinHostPort(parts[3], parts[4])
|
||||
d.switchMaster(addr)
|
||||
c.switchMaster(addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
11
vendor/github.com/go-sql-driver/mysql/CHANGELOG.md
сгенерированный
поставляемый
11
vendor/github.com/go-sql-driver/mysql/CHANGELOG.md
сгенерированный
поставляемый
@@ -1,3 +1,14 @@
|
||||
## Version 1.4.1 (2018-11-14)
|
||||
|
||||
Bugfixes:
|
||||
|
||||
- Fix TIME format for binary columns (#818)
|
||||
- Fix handling of empty auth plugin names (#835)
|
||||
- Fix caching_sha2_password with empty password (#826)
|
||||
- Fix canceled context broke mysqlConn (#862)
|
||||
- Fix OldAuthSwitchRequest support (#870)
|
||||
- Fix Auth Response packet for cleartext password (#887)
|
||||
|
||||
## Version 1.4 (2018-06-03)
|
||||
|
||||
Changes:
|
||||
|
||||
36
vendor/github.com/go-sql-driver/mysql/auth.go
сгенерированный
поставляемый
36
vendor/github.com/go-sql-driver/mysql/auth.go
сгенерированный
поставляемый
@@ -234,64 +234,64 @@ func (mc *mysqlConn) sendEncryptedPassword(seed []byte, pub *rsa.PublicKey) erro
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return mc.writeAuthSwitchPacket(enc, false)
|
||||
return mc.writeAuthSwitchPacket(enc)
|
||||
}
|
||||
|
||||
func (mc *mysqlConn) auth(authData []byte, plugin string) ([]byte, bool, error) {
|
||||
func (mc *mysqlConn) auth(authData []byte, plugin string) ([]byte, error) {
|
||||
switch plugin {
|
||||
case "caching_sha2_password":
|
||||
authResp := scrambleSHA256Password(authData, mc.cfg.Passwd)
|
||||
return authResp, (authResp == nil), nil
|
||||
return authResp, nil
|
||||
|
||||
case "mysql_old_password":
|
||||
if !mc.cfg.AllowOldPasswords {
|
||||
return nil, false, ErrOldPassword
|
||||
return nil, ErrOldPassword
|
||||
}
|
||||
// Note: there are edge cases where this should work but doesn't;
|
||||
// this is currently "wontfix":
|
||||
// https://github.com/go-sql-driver/mysql/issues/184
|
||||
authResp := scrambleOldPassword(authData[:8], mc.cfg.Passwd)
|
||||
return authResp, true, nil
|
||||
authResp := append(scrambleOldPassword(authData[:8], mc.cfg.Passwd), 0)
|
||||
return authResp, nil
|
||||
|
||||
case "mysql_clear_password":
|
||||
if !mc.cfg.AllowCleartextPasswords {
|
||||
return nil, false, ErrCleartextPassword
|
||||
return nil, ErrCleartextPassword
|
||||
}
|
||||
// http://dev.mysql.com/doc/refman/5.7/en/cleartext-authentication-plugin.html
|
||||
// http://dev.mysql.com/doc/refman/5.7/en/pam-authentication-plugin.html
|
||||
return []byte(mc.cfg.Passwd), true, nil
|
||||
return append([]byte(mc.cfg.Passwd), 0), nil
|
||||
|
||||
case "mysql_native_password":
|
||||
if !mc.cfg.AllowNativePasswords {
|
||||
return nil, false, ErrNativePassword
|
||||
return nil, ErrNativePassword
|
||||
}
|
||||
// https://dev.mysql.com/doc/internals/en/secure-password-authentication.html
|
||||
// Native password authentication only need and will need 20-byte challenge.
|
||||
authResp := scramblePassword(authData[:20], mc.cfg.Passwd)
|
||||
return authResp, false, nil
|
||||
return authResp, nil
|
||||
|
||||
case "sha256_password":
|
||||
if len(mc.cfg.Passwd) == 0 {
|
||||
return nil, true, nil
|
||||
return []byte{0}, nil
|
||||
}
|
||||
if mc.cfg.tls != nil || mc.cfg.Net == "unix" {
|
||||
// write cleartext auth packet
|
||||
return []byte(mc.cfg.Passwd), true, nil
|
||||
return append([]byte(mc.cfg.Passwd), 0), nil
|
||||
}
|
||||
|
||||
pubKey := mc.cfg.pubKey
|
||||
if pubKey == nil {
|
||||
// request public key from server
|
||||
return []byte{1}, false, nil
|
||||
return []byte{1}, nil
|
||||
}
|
||||
|
||||
// encrypted password
|
||||
enc, err := encryptPassword(mc.cfg.Passwd, authData, pubKey)
|
||||
return enc, false, err
|
||||
return enc, err
|
||||
|
||||
default:
|
||||
errLog.Print("unknown auth plugin:", plugin)
|
||||
return nil, false, ErrUnknownPlugin
|
||||
return nil, ErrUnknownPlugin
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,11 +315,11 @@ func (mc *mysqlConn) handleAuthResult(oldAuthData []byte, plugin string) error {
|
||||
|
||||
plugin = newPlugin
|
||||
|
||||
authResp, addNUL, err := mc.auth(authData, plugin)
|
||||
authResp, err := mc.auth(authData, plugin)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = mc.writeAuthSwitchPacket(authResp, addNUL); err != nil {
|
||||
if err = mc.writeAuthSwitchPacket(authResp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -352,7 +352,7 @@ func (mc *mysqlConn) handleAuthResult(oldAuthData []byte, plugin string) error {
|
||||
case cachingSha2PasswordPerformFullAuthentication:
|
||||
if mc.cfg.tls != nil || mc.cfg.Net == "unix" {
|
||||
// write cleartext auth packet
|
||||
err = mc.writeAuthSwitchPacket([]byte(mc.cfg.Passwd), true)
|
||||
err = mc.writeAuthSwitchPacket(append([]byte(mc.cfg.Passwd), 0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
15
vendor/github.com/go-sql-driver/mysql/connection_go18.go
сгенерированный
поставляемый
15
vendor/github.com/go-sql-driver/mysql/connection_go18.go
сгенерированный
поставляемый
@@ -149,22 +149,21 @@ func (mc *mysqlConn) watchCancel(ctx context.Context) error {
|
||||
mc.cleanup()
|
||||
return nil
|
||||
}
|
||||
// When ctx is already cancelled, don't watch it.
|
||||
if err := ctx.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
// When ctx is not cancellable, don't watch it.
|
||||
if ctx.Done() == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
mc.watching = true
|
||||
select {
|
||||
default:
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
// When watcher is not alive, can't watch it.
|
||||
if mc.watcher == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
mc.watching = true
|
||||
mc.watcher <- ctx
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
9
vendor/github.com/go-sql-driver/mysql/driver.go
сгенерированный
поставляемый
9
vendor/github.com/go-sql-driver/mysql/driver.go
сгенерированный
поставляемый
@@ -112,20 +112,23 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
|
||||
mc.cleanup()
|
||||
return nil, err
|
||||
}
|
||||
if plugin == "" {
|
||||
plugin = defaultAuthPlugin
|
||||
}
|
||||
|
||||
// Send Client Authentication Packet
|
||||
authResp, addNUL, err := mc.auth(authData, plugin)
|
||||
authResp, err := mc.auth(authData, plugin)
|
||||
if err != nil {
|
||||
// try the default auth plugin, if using the requested plugin failed
|
||||
errLog.Print("could not use requested auth plugin '"+plugin+"': ", err.Error())
|
||||
plugin = defaultAuthPlugin
|
||||
authResp, addNUL, err = mc.auth(authData, plugin)
|
||||
authResp, err = mc.auth(authData, plugin)
|
||||
if err != nil {
|
||||
mc.cleanup()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err = mc.writeHandshakeResponsePacket(authResp, addNUL, plugin); err != nil {
|
||||
if err = mc.writeHandshakeResponsePacket(authResp, plugin); err != nil {
|
||||
mc.cleanup()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
39
vendor/github.com/go-sql-driver/mysql/packets.go
сгенерированный
поставляемый
39
vendor/github.com/go-sql-driver/mysql/packets.go
сгенерированный
поставляемый
@@ -154,15 +154,15 @@ func (mc *mysqlConn) writePacket(data []byte) error {
|
||||
|
||||
// Handshake Initialization Packet
|
||||
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake
|
||||
func (mc *mysqlConn) readHandshakePacket() ([]byte, string, error) {
|
||||
data, err := mc.readPacket()
|
||||
func (mc *mysqlConn) readHandshakePacket() (data []byte, plugin string, err error) {
|
||||
data, err = mc.readPacket()
|
||||
if err != nil {
|
||||
// for init we can rewrite this to ErrBadConn for sql.Driver to retry, since
|
||||
// in connection initialization we don't risk retrying non-idempotent actions.
|
||||
if err == ErrInvalidConn {
|
||||
return nil, "", driver.ErrBadConn
|
||||
}
|
||||
return nil, "", err
|
||||
return
|
||||
}
|
||||
|
||||
if data[0] == iERR {
|
||||
@@ -198,7 +198,6 @@ func (mc *mysqlConn) readHandshakePacket() ([]byte, string, error) {
|
||||
}
|
||||
pos += 2
|
||||
|
||||
plugin := ""
|
||||
if len(data) > pos {
|
||||
// character set [1 byte]
|
||||
// status flags [2 bytes]
|
||||
@@ -236,8 +235,6 @@ func (mc *mysqlConn) readHandshakePacket() ([]byte, string, error) {
|
||||
return b[:], plugin, nil
|
||||
}
|
||||
|
||||
plugin = defaultAuthPlugin
|
||||
|
||||
// make a memory safe copy of the cipher slice
|
||||
var b [8]byte
|
||||
copy(b[:], authData)
|
||||
@@ -246,7 +243,7 @@ func (mc *mysqlConn) readHandshakePacket() ([]byte, string, error) {
|
||||
|
||||
// Client Authentication Packet
|
||||
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::HandshakeResponse
|
||||
func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, addNUL bool, plugin string) error {
|
||||
func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, plugin string) error {
|
||||
// Adjust client flags based on server support
|
||||
clientFlags := clientProtocol41 |
|
||||
clientSecureConn |
|
||||
@@ -272,7 +269,8 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, addNUL bool,
|
||||
|
||||
// encode length of the auth plugin data
|
||||
var authRespLEIBuf [9]byte
|
||||
authRespLEI := appendLengthEncodedInteger(authRespLEIBuf[:0], uint64(len(authResp)))
|
||||
authRespLen := len(authResp)
|
||||
authRespLEI := appendLengthEncodedInteger(authRespLEIBuf[:0], uint64(authRespLen))
|
||||
if len(authRespLEI) > 1 {
|
||||
// if the length can not be written in 1 byte, it must be written as a
|
||||
// length encoded integer
|
||||
@@ -280,9 +278,6 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, addNUL bool,
|
||||
}
|
||||
|
||||
pktLen := 4 + 4 + 1 + 23 + len(mc.cfg.User) + 1 + len(authRespLEI) + len(authResp) + 21 + 1
|
||||
if addNUL {
|
||||
pktLen++
|
||||
}
|
||||
|
||||
// To specify a db name
|
||||
if n := len(mc.cfg.DBName); n > 0 {
|
||||
@@ -353,10 +348,6 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, addNUL bool,
|
||||
// Auth Data [length encoded integer]
|
||||
pos += copy(data[pos:], authRespLEI)
|
||||
pos += copy(data[pos:], authResp)
|
||||
if addNUL {
|
||||
data[pos] = 0x00
|
||||
pos++
|
||||
}
|
||||
|
||||
// Databasename [null terminated string]
|
||||
if len(mc.cfg.DBName) > 0 {
|
||||
@@ -367,17 +358,15 @@ func (mc *mysqlConn) writeHandshakeResponsePacket(authResp []byte, addNUL bool,
|
||||
|
||||
pos += copy(data[pos:], plugin)
|
||||
data[pos] = 0x00
|
||||
pos++
|
||||
|
||||
// Send Auth packet
|
||||
return mc.writePacket(data)
|
||||
return mc.writePacket(data[:pos])
|
||||
}
|
||||
|
||||
// http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse
|
||||
func (mc *mysqlConn) writeAuthSwitchPacket(authData []byte, addNUL bool) error {
|
||||
func (mc *mysqlConn) writeAuthSwitchPacket(authData []byte) error {
|
||||
pktLen := 4 + len(authData)
|
||||
if addNUL {
|
||||
pktLen++
|
||||
}
|
||||
data := mc.buf.takeSmallBuffer(pktLen)
|
||||
if data == nil {
|
||||
// cannot take the buffer. Something must be wrong with the connection
|
||||
@@ -387,10 +376,6 @@ func (mc *mysqlConn) writeAuthSwitchPacket(authData []byte, addNUL bool) error {
|
||||
|
||||
// Add the auth data [EOF]
|
||||
copy(data[4:], authData)
|
||||
if addNUL {
|
||||
data[pktLen-1] = 0x00
|
||||
}
|
||||
|
||||
return mc.writePacket(data)
|
||||
}
|
||||
|
||||
@@ -482,7 +467,7 @@ func (mc *mysqlConn) readAuthResult() ([]byte, string, error) {
|
||||
return data[1:], "", err
|
||||
|
||||
case iEOF:
|
||||
if len(data) < 1 {
|
||||
if len(data) == 1 {
|
||||
// https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::OldAuthSwitchRequest
|
||||
return nil, "mysql_old_password", nil
|
||||
}
|
||||
@@ -1261,7 +1246,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
||||
rows.rs.columns[i].decimals,
|
||||
)
|
||||
}
|
||||
dest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], dstlen, true)
|
||||
dest[i], err = formatBinaryTime(data[pos:pos+int(num)], dstlen)
|
||||
case rows.mc.parseTime:
|
||||
dest[i], err = parseBinaryDateTime(num, data[pos:], rows.mc.cfg.Loc)
|
||||
default:
|
||||
@@ -1281,7 +1266,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
|
||||
)
|
||||
}
|
||||
}
|
||||
dest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], dstlen, false)
|
||||
dest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], dstlen)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
|
||||
246
vendor/github.com/go-sql-driver/mysql/utils.go
сгенерированный
поставляемый
246
vendor/github.com/go-sql-driver/mysql/utils.go
сгенерированный
поставляемый
@@ -14,6 +14,7 @@ import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
@@ -227,87 +228,104 @@ var zeroDateTime = []byte("0000-00-00 00:00:00.000000")
|
||||
const digits01 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
|
||||
const digits10 = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
|
||||
|
||||
func formatBinaryDateTime(src []byte, length uint8, justTime bool) (driver.Value, error) {
|
||||
func appendMicrosecs(dst, src []byte, decimals int) []byte {
|
||||
if decimals <= 0 {
|
||||
return dst
|
||||
}
|
||||
if len(src) == 0 {
|
||||
return append(dst, ".000000"[:decimals+1]...)
|
||||
}
|
||||
|
||||
microsecs := binary.LittleEndian.Uint32(src[:4])
|
||||
p1 := byte(microsecs / 10000)
|
||||
microsecs -= 10000 * uint32(p1)
|
||||
p2 := byte(microsecs / 100)
|
||||
microsecs -= 100 * uint32(p2)
|
||||
p3 := byte(microsecs)
|
||||
|
||||
switch decimals {
|
||||
default:
|
||||
return append(dst, '.',
|
||||
digits10[p1], digits01[p1],
|
||||
digits10[p2], digits01[p2],
|
||||
digits10[p3], digits01[p3],
|
||||
)
|
||||
case 1:
|
||||
return append(dst, '.',
|
||||
digits10[p1],
|
||||
)
|
||||
case 2:
|
||||
return append(dst, '.',
|
||||
digits10[p1], digits01[p1],
|
||||
)
|
||||
case 3:
|
||||
return append(dst, '.',
|
||||
digits10[p1], digits01[p1],
|
||||
digits10[p2],
|
||||
)
|
||||
case 4:
|
||||
return append(dst, '.',
|
||||
digits10[p1], digits01[p1],
|
||||
digits10[p2], digits01[p2],
|
||||
)
|
||||
case 5:
|
||||
return append(dst, '.',
|
||||
digits10[p1], digits01[p1],
|
||||
digits10[p2], digits01[p2],
|
||||
digits10[p3],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func formatBinaryDateTime(src []byte, length uint8) (driver.Value, error) {
|
||||
// length expects the deterministic length of the zero value,
|
||||
// negative time and 100+ hours are automatically added if needed
|
||||
if len(src) == 0 {
|
||||
if justTime {
|
||||
return zeroDateTime[11 : 11+length], nil
|
||||
}
|
||||
return zeroDateTime[:length], nil
|
||||
}
|
||||
var dst []byte // return value
|
||||
var pt, p1, p2, p3 byte // current digit pair
|
||||
var zOffs byte // offset of value in zeroDateTime
|
||||
if justTime {
|
||||
switch length {
|
||||
case
|
||||
8, // time (can be up to 10 when negative and 100+ hours)
|
||||
10, 11, 12, 13, 14, 15: // time with fractional seconds
|
||||
default:
|
||||
return nil, fmt.Errorf("illegal TIME length %d", length)
|
||||
var dst []byte // return value
|
||||
var p1, p2, p3 byte // current digit pair
|
||||
|
||||
switch length {
|
||||
case 10, 19, 21, 22, 23, 24, 25, 26:
|
||||
default:
|
||||
t := "DATE"
|
||||
if length > 10 {
|
||||
t += "TIME"
|
||||
}
|
||||
switch len(src) {
|
||||
case 8, 12:
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid TIME packet length %d", len(src))
|
||||
}
|
||||
// +2 to enable negative time and 100+ hours
|
||||
dst = make([]byte, 0, length+2)
|
||||
if src[0] == 1 {
|
||||
dst = append(dst, '-')
|
||||
}
|
||||
if src[1] != 0 {
|
||||
hour := uint16(src[1])*24 + uint16(src[5])
|
||||
pt = byte(hour / 100)
|
||||
p1 = byte(hour - 100*uint16(pt))
|
||||
dst = append(dst, digits01[pt])
|
||||
} else {
|
||||
p1 = src[5]
|
||||
}
|
||||
zOffs = 11
|
||||
src = src[6:]
|
||||
} else {
|
||||
switch length {
|
||||
case 10, 19, 21, 22, 23, 24, 25, 26:
|
||||
default:
|
||||
t := "DATE"
|
||||
if length > 10 {
|
||||
t += "TIME"
|
||||
}
|
||||
return nil, fmt.Errorf("illegal %s length %d", t, length)
|
||||
}
|
||||
switch len(src) {
|
||||
case 4, 7, 11:
|
||||
default:
|
||||
t := "DATE"
|
||||
if length > 10 {
|
||||
t += "TIME"
|
||||
}
|
||||
return nil, fmt.Errorf("illegal %s packet length %d", t, len(src))
|
||||
}
|
||||
dst = make([]byte, 0, length)
|
||||
// start with the date
|
||||
year := binary.LittleEndian.Uint16(src[:2])
|
||||
pt = byte(year / 100)
|
||||
p1 = byte(year - 100*uint16(pt))
|
||||
p2, p3 = src[2], src[3]
|
||||
dst = append(dst,
|
||||
digits10[pt], digits01[pt],
|
||||
digits10[p1], digits01[p1], '-',
|
||||
digits10[p2], digits01[p2], '-',
|
||||
digits10[p3], digits01[p3],
|
||||
)
|
||||
if length == 10 {
|
||||
return dst, nil
|
||||
}
|
||||
if len(src) == 4 {
|
||||
return append(dst, zeroDateTime[10:length]...), nil
|
||||
}
|
||||
dst = append(dst, ' ')
|
||||
p1 = src[4] // hour
|
||||
src = src[5:]
|
||||
return nil, fmt.Errorf("illegal %s length %d", t, length)
|
||||
}
|
||||
switch len(src) {
|
||||
case 4, 7, 11:
|
||||
default:
|
||||
t := "DATE"
|
||||
if length > 10 {
|
||||
t += "TIME"
|
||||
}
|
||||
return nil, fmt.Errorf("illegal %s packet length %d", t, len(src))
|
||||
}
|
||||
dst = make([]byte, 0, length)
|
||||
// start with the date
|
||||
year := binary.LittleEndian.Uint16(src[:2])
|
||||
pt := year / 100
|
||||
p1 = byte(year - 100*uint16(pt))
|
||||
p2, p3 = src[2], src[3]
|
||||
dst = append(dst,
|
||||
digits10[pt], digits01[pt],
|
||||
digits10[p1], digits01[p1], '-',
|
||||
digits10[p2], digits01[p2], '-',
|
||||
digits10[p3], digits01[p3],
|
||||
)
|
||||
if length == 10 {
|
||||
return dst, nil
|
||||
}
|
||||
if len(src) == 4 {
|
||||
return append(dst, zeroDateTime[10:length]...), nil
|
||||
}
|
||||
dst = append(dst, ' ')
|
||||
p1 = src[4] // hour
|
||||
src = src[5:]
|
||||
|
||||
// p1 is 2-digit hour, src is after hour
|
||||
p2, p3 = src[0], src[1]
|
||||
dst = append(dst,
|
||||
@@ -315,51 +333,49 @@ func formatBinaryDateTime(src []byte, length uint8, justTime bool) (driver.Value
|
||||
digits10[p2], digits01[p2], ':',
|
||||
digits10[p3], digits01[p3],
|
||||
)
|
||||
if length <= byte(len(dst)) {
|
||||
return dst, nil
|
||||
}
|
||||
src = src[2:]
|
||||
return appendMicrosecs(dst, src[2:], int(length)-20), nil
|
||||
}
|
||||
|
||||
func formatBinaryTime(src []byte, length uint8) (driver.Value, error) {
|
||||
// length expects the deterministic length of the zero value,
|
||||
// negative time and 100+ hours are automatically added if needed
|
||||
if len(src) == 0 {
|
||||
return append(dst, zeroDateTime[19:zOffs+length]...), nil
|
||||
return zeroDateTime[11 : 11+length], nil
|
||||
}
|
||||
microsecs := binary.LittleEndian.Uint32(src[:4])
|
||||
p1 = byte(microsecs / 10000)
|
||||
microsecs -= 10000 * uint32(p1)
|
||||
p2 = byte(microsecs / 100)
|
||||
microsecs -= 100 * uint32(p2)
|
||||
p3 = byte(microsecs)
|
||||
switch decimals := zOffs + length - 20; decimals {
|
||||
var dst []byte // return value
|
||||
|
||||
switch length {
|
||||
case
|
||||
8, // time (can be up to 10 when negative and 100+ hours)
|
||||
10, 11, 12, 13, 14, 15: // time with fractional seconds
|
||||
default:
|
||||
return append(dst, '.',
|
||||
digits10[p1], digits01[p1],
|
||||
digits10[p2], digits01[p2],
|
||||
digits10[p3], digits01[p3],
|
||||
), nil
|
||||
case 1:
|
||||
return append(dst, '.',
|
||||
digits10[p1],
|
||||
), nil
|
||||
case 2:
|
||||
return append(dst, '.',
|
||||
digits10[p1], digits01[p1],
|
||||
), nil
|
||||
case 3:
|
||||
return append(dst, '.',
|
||||
digits10[p1], digits01[p1],
|
||||
digits10[p2],
|
||||
), nil
|
||||
case 4:
|
||||
return append(dst, '.',
|
||||
digits10[p1], digits01[p1],
|
||||
digits10[p2], digits01[p2],
|
||||
), nil
|
||||
case 5:
|
||||
return append(dst, '.',
|
||||
digits10[p1], digits01[p1],
|
||||
digits10[p2], digits01[p2],
|
||||
digits10[p3],
|
||||
), nil
|
||||
return nil, fmt.Errorf("illegal TIME length %d", length)
|
||||
}
|
||||
switch len(src) {
|
||||
case 8, 12:
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid TIME packet length %d", len(src))
|
||||
}
|
||||
// +2 to enable negative time and 100+ hours
|
||||
dst = make([]byte, 0, length+2)
|
||||
if src[0] == 1 {
|
||||
dst = append(dst, '-')
|
||||
}
|
||||
days := binary.LittleEndian.Uint32(src[1:5])
|
||||
hours := int64(days)*24 + int64(src[5])
|
||||
|
||||
if hours >= 100 {
|
||||
dst = strconv.AppendInt(dst, hours, 10)
|
||||
} else {
|
||||
dst = append(dst, digits10[hours], digits01[hours])
|
||||
}
|
||||
|
||||
min, sec := src[6], src[7]
|
||||
dst = append(dst, ':',
|
||||
digits10[min], digits01[min], ':',
|
||||
digits10[sec], digits01[sec],
|
||||
)
|
||||
return appendMicrosecs(dst, src[8:], int(length)-9), nil
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
1
vendor/github.com/google/uuid/go.mod
сгенерированный
поставляемый
Обычный файл
1
vendor/github.com/google/uuid/go.mod
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
||||
module github.com/google/uuid
|
||||
73
vendor/github.com/google/uuid/uuid.go
сгенерированный
поставляемый
73
vendor/github.com/google/uuid/uuid.go
сгенерированный
поставляемый
@@ -1,4 +1,4 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
// Copyright 2018 Google Inc. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
@@ -35,20 +35,43 @@ const (
|
||||
|
||||
var rander = rand.Reader // random function
|
||||
|
||||
// Parse decodes s into a UUID or returns an error. Both the UUID form of
|
||||
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded.
|
||||
// Parse decodes s into a UUID or returns an error. Both the standard UUID
|
||||
// forms of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx and
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx are decoded as well as the
|
||||
// Microsoft encoding {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} and the raw hex
|
||||
// encoding: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
|
||||
func Parse(s string) (UUID, error) {
|
||||
var uuid UUID
|
||||
if len(s) != 36 {
|
||||
if len(s) != 36+9 {
|
||||
return uuid, fmt.Errorf("invalid UUID length: %d", len(s))
|
||||
}
|
||||
switch len(s) {
|
||||
// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
case 36:
|
||||
|
||||
// urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
case 36 + 9:
|
||||
if strings.ToLower(s[:9]) != "urn:uuid:" {
|
||||
return uuid, fmt.Errorf("invalid urn prefix: %q", s[:9])
|
||||
}
|
||||
s = s[9:]
|
||||
|
||||
// {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||
case 36 + 2:
|
||||
s = s[1:]
|
||||
|
||||
// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
case 32:
|
||||
var ok bool
|
||||
for i := range uuid {
|
||||
uuid[i], ok = xtob(s[i*2], s[i*2+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
}
|
||||
return uuid, nil
|
||||
default:
|
||||
return uuid, fmt.Errorf("invalid UUID length: %d", len(s))
|
||||
}
|
||||
// s is now at least 36 bytes long
|
||||
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
if s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
@@ -70,15 +93,29 @@ func Parse(s string) (UUID, error) {
|
||||
// ParseBytes is like Parse, except it parses a byte slice instead of a string.
|
||||
func ParseBytes(b []byte) (UUID, error) {
|
||||
var uuid UUID
|
||||
if len(b) != 36 {
|
||||
if len(b) != 36+9 {
|
||||
return uuid, fmt.Errorf("invalid UUID length: %d", len(b))
|
||||
}
|
||||
switch len(b) {
|
||||
case 36: // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
case 36 + 9: // urn:uuid:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
if !bytes.Equal(bytes.ToLower(b[:9]), []byte("urn:uuid:")) {
|
||||
return uuid, fmt.Errorf("invalid urn prefix: %q", b[:9])
|
||||
}
|
||||
b = b[9:]
|
||||
case 36 + 2: // {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
||||
b = b[1:]
|
||||
case 32: // xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
var ok bool
|
||||
for i := 0; i < 32; i += 2 {
|
||||
uuid[i/2], ok = xtob(b[i], b[i+1])
|
||||
if !ok {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
}
|
||||
return uuid, nil
|
||||
default:
|
||||
return uuid, fmt.Errorf("invalid UUID length: %d", len(b))
|
||||
}
|
||||
// s is now at least 36 bytes long
|
||||
// it must be of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
|
||||
if b[8] != '-' || b[13] != '-' || b[18] != '-' || b[23] != '-' {
|
||||
return uuid, errors.New("invalid UUID format")
|
||||
}
|
||||
@@ -97,6 +134,16 @@ func ParseBytes(b []byte) (UUID, error) {
|
||||
return uuid, nil
|
||||
}
|
||||
|
||||
// MustParse is like Parse but panics if the string cannot be parsed.
|
||||
// It simplifies safe initialization of global variables holding compiled UUIDs.
|
||||
func MustParse(s string) UUID {
|
||||
uuid, err := Parse(s)
|
||||
if err != nil {
|
||||
panic(`uuid: Parse(` + s + `): ` + err.Error())
|
||||
}
|
||||
return uuid
|
||||
}
|
||||
|
||||
// FromBytes creates a new UUID from a byte slice. Returns an error if the slice
|
||||
// does not have a length of 16. The bytes are copied from the slice.
|
||||
func FromBytes(b []byte) (uuid UUID, err error) {
|
||||
@@ -130,7 +177,7 @@ func (uuid UUID) URN() string {
|
||||
}
|
||||
|
||||
func encodeHex(dst []byte, uuid UUID) {
|
||||
hex.Encode(dst[:], uuid[:4])
|
||||
hex.Encode(dst, uuid[:4])
|
||||
dst[8] = '-'
|
||||
hex.Encode(dst[9:13], uuid[4:6])
|
||||
dst[13] = '-'
|
||||
|
||||
18
vendor/github.com/hashicorp/go-plugin/README.md
сгенерированный
поставляемый
18
vendor/github.com/hashicorp/go-plugin/README.md
сгенерированный
поставляемый
@@ -109,7 +109,7 @@ high-level steps that must be done. Examples are available in the
|
||||
1. Choose the interface(s) you want to expose for plugins.
|
||||
|
||||
2. For each interface, implement an implementation of that interface
|
||||
that communicates over a `net/rpc` connection or other a
|
||||
that communicates over a `net/rpc` connection or over a
|
||||
[gRPC](http://www.grpc.io) connection or both. You'll have to implement
|
||||
both a client and server implementation.
|
||||
|
||||
@@ -150,19 +150,19 @@ user experience.
|
||||
|
||||
When we started using plugins (late 2012, early 2013), plugins over RPC
|
||||
were the only option since Go didn't support dynamic library loading. Today,
|
||||
Go still doesn't support dynamic library loading, but they do intend to.
|
||||
Since 2012, our plugin system has stabilized from millions of users using it,
|
||||
and has many benefits we've come to value greatly.
|
||||
Go supports the [plugin](https://golang.org/pkg/plugin/) standard library with
|
||||
a number of limitations. Since 2012, our plugin system has stabilized
|
||||
from tens of millions of users using it, and has many benefits we've come to
|
||||
value greatly.
|
||||
|
||||
For example, we intend to use this plugin system in
|
||||
[Vault](https://www.vaultproject.io), and dynamic library loading will
|
||||
simply never be acceptable in Vault for security reasons. That is an extreme
|
||||
For example, we use this plugin system in
|
||||
[Vault](https://www.vaultproject.io) where dynamic library loading is
|
||||
not acceptable for security reasons. That is an extreme
|
||||
example, but we believe our library system has more upsides than downsides
|
||||
over dynamic library loading and since we've had it built and tested for years,
|
||||
we'll likely continue to use it.
|
||||
we'll continue to use it.
|
||||
|
||||
Shared libraries have one major advantage over our system which is much
|
||||
higher performance. In real world scenarios across our various tools,
|
||||
we've never required any more performance out of our plugin system and it
|
||||
has seen very high throughput, so this isn't a concern for us at the moment.
|
||||
|
||||
|
||||
39
vendor/github.com/hashicorp/go-plugin/client.go
сгенерированный
поставляемый
39
vendor/github.com/hashicorp/go-plugin/client.go
сгенерированный
поставляемый
@@ -358,11 +358,19 @@ func (c *Client) Kill() {
|
||||
doneCh := c.doneLogging
|
||||
c.l.Unlock()
|
||||
|
||||
// If there is no process, we never started anything. Nothing to kill.
|
||||
// If there is no process, there is nothing to kill.
|
||||
if process == nil {
|
||||
return
|
||||
}
|
||||
|
||||
defer func() {
|
||||
// Make sure there is no reference to the old process after it has been
|
||||
// killed.
|
||||
c.l.Lock()
|
||||
defer c.l.Unlock()
|
||||
c.process = nil
|
||||
}()
|
||||
|
||||
// We need to check for address here. It is possible that the plugin
|
||||
// started (process != nil) but has no address (addr == nil) if the
|
||||
// plugin failed at startup. If we do have an address, we need to close
|
||||
@@ -392,8 +400,12 @@ func (c *Client) Kill() {
|
||||
if graceful {
|
||||
select {
|
||||
case <-doneCh:
|
||||
// FIXME: this is never reached under normal circumstances, because
|
||||
// the plugin process is never signaled to exit. We can reach this
|
||||
// if the child process exited abnormally before the Kill call.
|
||||
return
|
||||
case <-time.After(250 * time.Millisecond):
|
||||
c.logger.Warn("plugin failed to exit gracefully")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -460,6 +472,8 @@ func (c *Client) Start() (addr net.Addr, err error) {
|
||||
|
||||
// Goroutine to mark exit status
|
||||
go func(pid int) {
|
||||
// ensure the context is cancelled when we're done
|
||||
defer ctxCancel()
|
||||
// Wait for the process to die
|
||||
pidWait(pid)
|
||||
|
||||
@@ -473,9 +487,6 @@ func (c *Client) Start() (addr net.Addr, err error) {
|
||||
|
||||
// Close the logging channel since that doesn't work on reattach
|
||||
close(c.doneLogging)
|
||||
|
||||
// Cancel the context
|
||||
ctxCancel()
|
||||
}(p.Pid)
|
||||
|
||||
// Set the address and process
|
||||
@@ -542,6 +553,7 @@ func (c *Client) Start() (addr net.Addr, err error) {
|
||||
|
||||
// Set the process
|
||||
c.process = cmd.Process
|
||||
c.logger.Debug("plugin started", "path", cmd.Path, "pid", c.process.Pid)
|
||||
|
||||
// Make sure the command is properly cleaned up if there is an error
|
||||
defer func() {
|
||||
@@ -564,19 +576,28 @@ func (c *Client) Start() (addr net.Addr, err error) {
|
||||
defer stderr_w.Close()
|
||||
defer stdout_w.Close()
|
||||
|
||||
// ensure the context is cancelled when we're done
|
||||
defer ctxCancel()
|
||||
|
||||
// Wait for the command to end.
|
||||
cmd.Wait()
|
||||
err := cmd.Wait()
|
||||
|
||||
debugMsgArgs := []interface{}{
|
||||
"path", cmd.Path,
|
||||
"pid", c.process.Pid,
|
||||
}
|
||||
if err != nil {
|
||||
debugMsgArgs = append(debugMsgArgs,
|
||||
[]interface{}{"error", err.Error()}...)
|
||||
}
|
||||
|
||||
// Log and make sure to flush the logs write away
|
||||
c.logger.Debug("plugin process exited", "path", cmd.Path)
|
||||
c.logger.Debug("plugin process exited", debugMsgArgs...)
|
||||
os.Stderr.Sync()
|
||||
|
||||
// Mark that we exited
|
||||
close(exitCh)
|
||||
|
||||
// Cancel the context, marking that we exited
|
||||
ctxCancel()
|
||||
|
||||
// Set that we exited, which takes a lock
|
||||
c.l.Lock()
|
||||
defer c.l.Unlock()
|
||||
|
||||
13
vendor/github.com/hashicorp/go-plugin/go.mod
сгенерированный
поставляемый
Обычный файл
13
vendor/github.com/hashicorp/go-plugin/go.mod
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,13 @@
|
||||
module github.com/hashicorp/go-plugin
|
||||
|
||||
require (
|
||||
github.com/golang/protobuf v1.2.0
|
||||
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd
|
||||
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb
|
||||
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77
|
||||
github.com/oklog/run v1.0.0
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d
|
||||
golang.org/x/text v0.3.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 // indirect
|
||||
google.golang.org/grpc v1.14.0
|
||||
)
|
||||
18
vendor/github.com/hashicorp/go-plugin/go.sum
сгенерированный
поставляемый
Обычный файл
18
vendor/github.com/hashicorp/go-plugin/go.sum
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,18 @@
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd h1:rNuUHR+CvK1IS89MMtcF0EpcVMZtjKfPRp4MEmt/aTs=
|
||||
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
|
||||
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=
|
||||
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 h1:7GoSOOW2jpsfkntVKaS2rAr1TJqfcxotyaUcuxoZSzg=
|
||||
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
|
||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d h1:g9qWBGx4puODJTMVyoPrpoxPFgVGd+z1DZwjfRu4d0I=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/grpc v1.14.0 h1:ArxJuB1NWfPY6r9Gp9gqwplT0Ge7nqv9msgu03lHLmo=
|
||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
31
vendor/github.com/hashicorp/go-plugin/server.go
сгенерированный
поставляемый
31
vendor/github.com/hashicorp/go-plugin/server.go
сгенерированный
поставляемый
@@ -93,7 +93,7 @@ func protocolVersion(opts *ServeConfig) (int, Protocol, PluginSet) {
|
||||
protoVersion := int(opts.ProtocolVersion)
|
||||
pluginSet := opts.Plugins
|
||||
protoType := ProtocolNetRPC
|
||||
// check if the client sent a list of acceptable versions
|
||||
// Check if the client sent a list of acceptable versions
|
||||
var clientVersions []int
|
||||
if vs := os.Getenv("PLUGIN_PROTOCOL_VERSIONS"); vs != "" {
|
||||
for _, s := range strings.Split(vs, ",") {
|
||||
@@ -106,7 +106,7 @@ func protocolVersion(opts *ServeConfig) (int, Protocol, PluginSet) {
|
||||
}
|
||||
}
|
||||
|
||||
// we want to iterate in reverse order, to ensure we match the newest
|
||||
// We want to iterate in reverse order, to ensure we match the newest
|
||||
// compatible plugin version.
|
||||
sort.Sort(sort.Reverse(sort.IntSlice(clientVersions)))
|
||||
|
||||
@@ -119,7 +119,7 @@ func protocolVersion(opts *ServeConfig) (int, Protocol, PluginSet) {
|
||||
opts.VersionedPlugins[protoVersion] = pluginSet
|
||||
}
|
||||
|
||||
// sort the version to make sure we match the latest first
|
||||
// Sort the version to make sure we match the latest first
|
||||
var versions []int
|
||||
for v := range opts.VersionedPlugins {
|
||||
versions = append(versions, v)
|
||||
@@ -127,23 +127,26 @@ func protocolVersion(opts *ServeConfig) (int, Protocol, PluginSet) {
|
||||
|
||||
sort.Sort(sort.Reverse(sort.IntSlice(versions)))
|
||||
|
||||
// see if we have multiple versions of Plugins to choose from
|
||||
// See if we have multiple versions of Plugins to choose from
|
||||
for _, version := range versions {
|
||||
// record each version, since we guarantee that this returns valid
|
||||
// Record each version, since we guarantee that this returns valid
|
||||
// values even if they are not a protocol match.
|
||||
protoVersion = version
|
||||
pluginSet = opts.VersionedPlugins[version]
|
||||
|
||||
// all plugins in a set must use the same transport, so check the first
|
||||
// for the protocol type
|
||||
for _, p := range pluginSet {
|
||||
switch p.(type) {
|
||||
case GRPCPlugin:
|
||||
protoType = ProtocolGRPC
|
||||
default:
|
||||
protoType = ProtocolNetRPC
|
||||
// If we have a configured gRPC server we should select a protocol
|
||||
if opts.GRPCServer != nil {
|
||||
// All plugins in a set must use the same transport, so check the first
|
||||
// for the protocol type
|
||||
for _, p := range pluginSet {
|
||||
switch p.(type) {
|
||||
case GRPCPlugin:
|
||||
protoType = ProtocolGRPC
|
||||
default:
|
||||
protoType = ProtocolNetRPC
|
||||
}
|
||||
break
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
for _, clientVersion := range clientVersions {
|
||||
|
||||
13
vendor/github.com/hashicorp/memberlist/.travis.yml
сгенерированный
поставляемый
Обычный файл
13
vendor/github.com/hashicorp/memberlist/.travis.yml
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,13 @@
|
||||
language: go
|
||||
|
||||
sudo: true
|
||||
|
||||
go:
|
||||
- "1.x"
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
install:
|
||||
- make deps
|
||||
5
vendor/github.com/hashicorp/memberlist/Makefile
сгенерированный
поставляемый
5
vendor/github.com/hashicorp/memberlist/Makefile
сгенерированный
поставляемый
@@ -1,4 +1,5 @@
|
||||
DEPS = $(go list -f '{{range .Imports}}{{.}} {{end}}' ./...)
|
||||
DEPS := $(shell go list -f '{{range .Imports}}{{.}} {{end}}' ./...)
|
||||
|
||||
test: subnet
|
||||
go test ./...
|
||||
|
||||
@@ -13,7 +14,7 @@ cov:
|
||||
open /tmp/coverage.html
|
||||
|
||||
deps:
|
||||
go get -d -v ./...
|
||||
go get -t -d -v ./...
|
||||
echo $(DEPS) | xargs -n1 go get -d
|
||||
|
||||
.PHONY: test cov integ
|
||||
|
||||
2
vendor/github.com/hashicorp/memberlist/README.md
сгенерированный
поставляемый
2
vendor/github.com/hashicorp/memberlist/README.md
сгенерированный
поставляемый
@@ -1,4 +1,4 @@
|
||||
# memberlist [](https://godoc.org/github.com/hashicorp/memberlist)
|
||||
# memberlist [](https://godoc.org/github.com/hashicorp/memberlist) [](https://travis-ci.org/hashicorp/memberlist)
|
||||
|
||||
memberlist is a [Go](http://www.golang.org) library that manages cluster
|
||||
membership and member failure detection using a gossip based protocol.
|
||||
|
||||
24
vendor/github.com/hashicorp/memberlist/memberlist.go
сгенерированный
поставляемый
24
vendor/github.com/hashicorp/memberlist/memberlist.go
сгенерированный
поставляемый
@@ -665,3 +665,27 @@ func (m *Memberlist) hasShutdown() bool {
|
||||
func (m *Memberlist) hasLeft() bool {
|
||||
return atomic.LoadInt32(&m.leave) == 1
|
||||
}
|
||||
|
||||
func (m *Memberlist) getNodeState(addr string) nodeStateType {
|
||||
m.nodeLock.RLock()
|
||||
defer m.nodeLock.RUnlock()
|
||||
|
||||
n := m.nodeMap[addr]
|
||||
return n.State
|
||||
}
|
||||
|
||||
func (m *Memberlist) getNodeStateChange(addr string) time.Time {
|
||||
m.nodeLock.RLock()
|
||||
defer m.nodeLock.RUnlock()
|
||||
|
||||
n := m.nodeMap[addr]
|
||||
return n.StateChange
|
||||
}
|
||||
|
||||
func (m *Memberlist) changeNode(addr string, f func(*nodeState)) {
|
||||
m.nodeLock.Lock()
|
||||
defer m.nodeLock.Unlock()
|
||||
|
||||
n := m.nodeMap[addr]
|
||||
f(n)
|
||||
}
|
||||
|
||||
20
vendor/github.com/hashicorp/memberlist/queue.go
сгенерированный
поставляемый
20
vendor/github.com/hashicorp/memberlist/queue.go
сгенерированный
поставляемый
@@ -27,6 +27,26 @@ type limitedBroadcast struct {
|
||||
transmits int // Number of transmissions attempted.
|
||||
b Broadcast
|
||||
}
|
||||
|
||||
// for testing; emits in transmit order if reverse=false
|
||||
func (q *TransmitLimitedQueue) orderedView(reverse bool) []*limitedBroadcast {
|
||||
q.Lock()
|
||||
defer q.Unlock()
|
||||
|
||||
out := make([]*limitedBroadcast, 0, len(q.bcQueue))
|
||||
if reverse {
|
||||
for i := 0; i < len(q.bcQueue); i++ {
|
||||
out = append(out, q.bcQueue[i])
|
||||
}
|
||||
} else {
|
||||
for i := len(q.bcQueue) - 1; i >= 0; i-- {
|
||||
out = append(out, q.bcQueue[i])
|
||||
}
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
type limitedBroadcasts []*limitedBroadcast
|
||||
|
||||
// Broadcast is something that can be broadcasted via gossip to
|
||||
|
||||
9
vendor/github.com/hashicorp/memberlist/state.go
сгенерированный
поставляемый
9
vendor/github.com/hashicorp/memberlist/state.go
сгенерированный
поставляемый
@@ -233,6 +233,15 @@ START:
|
||||
m.probeNode(&node)
|
||||
}
|
||||
|
||||
// probeNodeByAddr just safely calls probeNode given only the address of the node (for tests)
|
||||
func (m *Memberlist) probeNodeByAddr(addr string) {
|
||||
m.nodeLock.RLock()
|
||||
n := m.nodeMap[addr]
|
||||
m.nodeLock.RUnlock()
|
||||
|
||||
m.probeNode(n)
|
||||
}
|
||||
|
||||
// probeNode handles a single round of failure checking on a node.
|
||||
func (m *Memberlist) probeNode(node *nodeState) {
|
||||
defer metrics.MeasureSince([]string{"memberlist", "probeNode"}, time.Now())
|
||||
|
||||
5
vendor/github.com/hashicorp/memberlist/util.go
сгенерированный
поставляемый
5
vendor/github.com/hashicorp/memberlist/util.go
сгенерированный
поставляемый
@@ -78,10 +78,9 @@ func retransmitLimit(retransmitMult, n int) int {
|
||||
// shuffleNodes randomly shuffles the input nodes using the Fisher-Yates shuffle
|
||||
func shuffleNodes(nodes []*nodeState) {
|
||||
n := len(nodes)
|
||||
for i := n - 1; i > 0; i-- {
|
||||
j := rand.Intn(i + 1)
|
||||
rand.Shuffle(n, func(i, j int) {
|
||||
nodes[i], nodes[j] = nodes[j], nodes[i]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// pushPushScale is used to scale the time interval at which push/pull
|
||||
|
||||
1
vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod
сгенерированный
поставляемый
Обычный файл
1
vendor/github.com/konsorten/go-windows-terminal-sequences/go.mod
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1 @@
|
||||
module github.com/konsorten/go-windows-terminal-sequences
|
||||
2
vendor/github.com/mattermost/viper/go.mod
сгенерированный
поставляемый
2
vendor/github.com/mattermost/viper/go.mod
сгенерированный
поставляемый
@@ -1,4 +1,4 @@
|
||||
module github.com/spf13/viper
|
||||
module github.com/mattermost/viper
|
||||
|
||||
require (
|
||||
github.com/fsnotify/fsnotify v1.4.7
|
||||
|
||||
4
vendor/github.com/mattn/go-sqlite3/.travis.yml
сгенерированный
поставляемый
4
vendor/github.com/mattn/go-sqlite3/.travis.yml
сгенерированный
поставляемый
@@ -12,18 +12,18 @@ env:
|
||||
matrix:
|
||||
- GOTAGS=
|
||||
- GOTAGS=libsqlite3
|
||||
- GOTAGS="sqlite_allow_uri_authority sqlite_app_armor sqlite_foreign_keys sqlite_fts5 sqlite_icu sqlite_introspect sqlite_json sqlite_secure_delete sqlite_see sqlite_stat4 sqlite_trace sqlite_userauth sqlite_vacuum_incr sqlite_vtable"
|
||||
- GOTAGS="sqlite_allow_uri_authority sqlite_app_armor sqlite_foreign_keys sqlite_fts5 sqlite_icu sqlite_introspect sqlite_json sqlite_secure_delete sqlite_see sqlite_stat4 sqlite_trace sqlite_userauth sqlite_vacuum_incr sqlite_vtable sqlite_unlock_notify"
|
||||
- GOTAGS=sqlite_vacuum_full
|
||||
|
||||
go:
|
||||
- 1.9.x
|
||||
- 1.10.x
|
||||
- 1.11.x
|
||||
|
||||
before_install:
|
||||
- |
|
||||
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
|
||||
brew update
|
||||
brew upgrade icu4c
|
||||
fi
|
||||
- |
|
||||
go get github.com/smartystreets/goconvey
|
||||
|
||||
7
vendor/github.com/mattn/go-sqlite3/README.md
сгенерированный
поставляемый
7
vendor/github.com/mattn/go-sqlite3/README.md
сгенерированный
поставляемый
@@ -67,6 +67,7 @@ This is also known as a DSN string. (Data Source Name).
|
||||
|
||||
Options are append after the filename of the SQLite database.
|
||||
The database filename and options are seperated by an `?` (Question Mark).
|
||||
Options should be URL-encoded (see [url.QueryEscape](https://golang.org/pkg/net/url/#QueryEscape)).
|
||||
|
||||
This also applies when using an in-memory database instead of a file.
|
||||
|
||||
@@ -198,7 +199,7 @@ Additional information:
|
||||
|
||||
# Google Cloud Platform
|
||||
|
||||
Building on GCP is not possible because `Google Cloud Platform does not allow `gcc` to be executed.
|
||||
Building on GCP is not possible because Google Cloud Platform does not allow `gcc` to be executed.
|
||||
|
||||
Please work only with compiled final binaries.
|
||||
|
||||
@@ -290,7 +291,7 @@ For example the TDM-GCC Toolchain can be found [here](ttps://sourceforge.net/pro
|
||||
When receiving a compile time error referencing recompile with `-FPIC` then you
|
||||
are probably using a hardend system.
|
||||
|
||||
You can copile the library on a hardend system with the following command.
|
||||
You can compile the library on a hardend system with the following command.
|
||||
|
||||
```bash
|
||||
go build -ldflags '-extldflags=-fno-PIC'
|
||||
@@ -473,7 +474,7 @@ For an example see [shaxbee/go-spatialite](https://github.com/shaxbee/go-spatial
|
||||
|
||||
For more information see [#289](https://github.com/mattn/go-sqlite3/issues/289)
|
||||
|
||||
- Trying to execure a `.` (dot) command throws an error.
|
||||
- Trying to execute a `.` (dot) command throws an error.
|
||||
|
||||
Error: `Error: near ".": syntax error`
|
||||
Dot command are part of SQLite3 CLI not of this library.
|
||||
|
||||
6
vendor/github.com/mattn/go-sqlite3/callback.go
сгенерированный
поставляемый
6
vendor/github.com/mattn/go-sqlite3/callback.go
сгенерированный
поставляемый
@@ -77,6 +77,12 @@ func updateHookTrampoline(handle uintptr, op int, db *C.char, table *C.char, row
|
||||
callback(op, C.GoString(db), C.GoString(table), rowid)
|
||||
}
|
||||
|
||||
//export authorizerTrampoline
|
||||
func authorizerTrampoline(handle uintptr, op int, arg1 *C.char, arg2 *C.char, arg3 *C.char) int {
|
||||
callback := lookupHandle(handle).(func(int, string, string, string) int)
|
||||
return callback(op, C.GoString(arg1), C.GoString(arg2), C.GoString(arg3))
|
||||
}
|
||||
|
||||
// Use handles to avoid passing Go pointers to C.
|
||||
|
||||
type handleVal struct {
|
||||
|
||||
21393
vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c
сгенерированный
поставляемый
21393
vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c
сгенерированный
поставляемый
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
293
vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h
сгенерированный
поставляемый
293
vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h
сгенерированный
поставляемый
@@ -124,9 +124,9 @@ extern "C" {
|
||||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||
** [sqlite_version()] and [sqlite_source_id()].
|
||||
*/
|
||||
#define SQLITE_VERSION "3.24.0"
|
||||
#define SQLITE_VERSION_NUMBER 3024000
|
||||
#define SQLITE_SOURCE_ID "2018-06-04 19:24:41 c7ee0833225bfd8c5ec2f9bf62b97c4e04d03bd9566366d5221ac8fb199a87ca"
|
||||
#define SQLITE_VERSION "3.25.2"
|
||||
#define SQLITE_VERSION_NUMBER 3025002
|
||||
#define SQLITE_SOURCE_ID "2018-09-25 19:08:10 fb90e7189ae6d62e77ba3a308ca5d683f90bbe633cf681865365b8e92792d1c7"
|
||||
|
||||
/*
|
||||
** CAPI3REF: Run-Time Library Version Numbers
|
||||
@@ -473,6 +473,7 @@ SQLITE_API int sqlite3_exec(
|
||||
*/
|
||||
#define SQLITE_ERROR_MISSING_COLLSEQ (SQLITE_ERROR | (1<<8))
|
||||
#define SQLITE_ERROR_RETRY (SQLITE_ERROR | (2<<8))
|
||||
#define SQLITE_ERROR_SNAPSHOT (SQLITE_ERROR | (3<<8))
|
||||
#define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8))
|
||||
#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8))
|
||||
#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8))
|
||||
@@ -512,6 +513,7 @@ SQLITE_API int sqlite3_exec(
|
||||
#define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8))
|
||||
#define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8))
|
||||
#define SQLITE_CANTOPEN_CONVPATH (SQLITE_CANTOPEN | (4<<8))
|
||||
#define SQLITE_CANTOPEN_DIRTYWAL (SQLITE_CANTOPEN | (5<<8)) /* Not Used */
|
||||
#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8))
|
||||
#define SQLITE_CORRUPT_SEQUENCE (SQLITE_CORRUPT | (2<<8))
|
||||
#define SQLITE_READONLY_RECOVERY (SQLITE_READONLY | (1<<8))
|
||||
@@ -887,7 +889,8 @@ struct sqlite3_io_methods {
|
||||
** <li>[[SQLITE_FCNTL_PERSIST_WAL]]
|
||||
** ^The [SQLITE_FCNTL_PERSIST_WAL] opcode is used to set or query the
|
||||
** persistent [WAL | Write Ahead Log] setting. By default, the auxiliary
|
||||
** write ahead log and shared memory files used for transaction control
|
||||
** write ahead log ([WAL file]) and shared memory
|
||||
** files used for transaction control
|
||||
** are automatically deleted when the latest connection to the database
|
||||
** closes. Setting persistent WAL mode causes those files to persist after
|
||||
** close. Persisting the files is useful when other processes that do not
|
||||
@@ -1073,6 +1076,26 @@ struct sqlite3_io_methods {
|
||||
** a file lock using the xLock or xShmLock methods of the VFS to wait
|
||||
** for up to M milliseconds before failing, where M is the single
|
||||
** unsigned integer parameter.
|
||||
**
|
||||
** <li>[[SQLITE_FCNTL_DATA_VERSION]]
|
||||
** The [SQLITE_FCNTL_DATA_VERSION] opcode is used to detect changes to
|
||||
** a database file. The argument is a pointer to a 32-bit unsigned integer.
|
||||
** The "data version" for the pager is written into the pointer. The
|
||||
** "data version" changes whenever any change occurs to the corresponding
|
||||
** database file, either through SQL statements on the same database
|
||||
** connection or through transactions committed by separate database
|
||||
** connections possibly in other processes. The [sqlite3_total_changes()]
|
||||
** interface can be used to find if any database on the connection has changed,
|
||||
** but that interface responds to changes on TEMP as well as MAIN and does
|
||||
** not provide a mechanism to detect changes to MAIN only. Also, the
|
||||
** [sqlite3_total_changes()] interface responds to internal changes only and
|
||||
** omits changes made by other database connections. The
|
||||
** [PRAGMA data_version] command provide a mechanism to detect changes to
|
||||
** a single attached database that occur due to other database connections,
|
||||
** but omits changes implemented by the database connection on which it is
|
||||
** called. This file control is the only mechanism to detect changes that
|
||||
** happen either internally or externally and that are associated with
|
||||
** a particular attached database.
|
||||
** </ul>
|
||||
*/
|
||||
#define SQLITE_FCNTL_LOCKSTATE 1
|
||||
@@ -1108,6 +1131,7 @@ struct sqlite3_io_methods {
|
||||
#define SQLITE_FCNTL_COMMIT_ATOMIC_WRITE 32
|
||||
#define SQLITE_FCNTL_ROLLBACK_ATOMIC_WRITE 33
|
||||
#define SQLITE_FCNTL_LOCK_TIMEOUT 34
|
||||
#define SQLITE_FCNTL_DATA_VERSION 35
|
||||
|
||||
/* deprecated names */
|
||||
#define SQLITE_GET_LOCKPROXYFILE SQLITE_FCNTL_GET_LOCKPROXYFILE
|
||||
@@ -2122,6 +2146,12 @@ struct sqlite3_mem_methods {
|
||||
** with no schema and no content. The following process works even for
|
||||
** a badly corrupted database file:
|
||||
** <ol>
|
||||
** <li> If the database connection is newly opened, make sure it has read the
|
||||
** database schema by preparing then discarding some query against the
|
||||
** database, or calling sqlite3_table_column_metadata(), ignoring any
|
||||
** errors. This step is only necessary if the application desires to keep
|
||||
** the database in WAL mode after the reset if it was in WAL mode before
|
||||
** the reset.
|
||||
** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 1, 0);
|
||||
** <li> [sqlite3_exec](db, "[VACUUM]", 0, 0, 0);
|
||||
** <li> sqlite3_db_config(db, SQLITE_DBCONFIG_RESET_DATABASE, 0, 0);
|
||||
@@ -2270,12 +2300,17 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64);
|
||||
** program, the value returned reflects the number of rows modified by the
|
||||
** previous INSERT, UPDATE or DELETE statement within the same trigger.
|
||||
**
|
||||
** See also the [sqlite3_total_changes()] interface, the
|
||||
** [count_changes pragma], and the [changes() SQL function].
|
||||
**
|
||||
** If a separate thread makes changes on the same database connection
|
||||
** while [sqlite3_changes()] is running then the value returned
|
||||
** is unpredictable and not meaningful.
|
||||
**
|
||||
** See also:
|
||||
** <ul>
|
||||
** <li> the [sqlite3_total_changes()] interface
|
||||
** <li> the [count_changes pragma]
|
||||
** <li> the [changes() SQL function]
|
||||
** <li> the [data_version pragma]
|
||||
** </ul>
|
||||
*/
|
||||
SQLITE_API int sqlite3_changes(sqlite3*);
|
||||
|
||||
@@ -2293,13 +2328,26 @@ SQLITE_API int sqlite3_changes(sqlite3*);
|
||||
** count, but those made as part of REPLACE constraint resolution are
|
||||
** not. ^Changes to a view that are intercepted by INSTEAD OF triggers
|
||||
** are not counted.
|
||||
**
|
||||
** See also the [sqlite3_changes()] interface, the
|
||||
** [count_changes pragma], and the [total_changes() SQL function].
|
||||
**
|
||||
** This the [sqlite3_total_changes(D)] interface only reports the number
|
||||
** of rows that changed due to SQL statement run against database
|
||||
** connection D. Any changes by other database connections are ignored.
|
||||
** To detect changes against a database file from other database
|
||||
** connections use the [PRAGMA data_version] command or the
|
||||
** [SQLITE_FCNTL_DATA_VERSION] [file control].
|
||||
**
|
||||
** If a separate thread makes changes on the same database connection
|
||||
** while [sqlite3_total_changes()] is running then the value
|
||||
** returned is unpredictable and not meaningful.
|
||||
**
|
||||
** See also:
|
||||
** <ul>
|
||||
** <li> the [sqlite3_changes()] interface
|
||||
** <li> the [count_changes pragma]
|
||||
** <li> the [changes() SQL function]
|
||||
** <li> the [data_version pragma]
|
||||
** <li> the [SQLITE_FCNTL_DATA_VERSION] [file control]
|
||||
** </ul>
|
||||
*/
|
||||
SQLITE_API int sqlite3_total_changes(sqlite3*);
|
||||
|
||||
@@ -3355,13 +3403,24 @@ SQLITE_API sqlite3_int64 sqlite3_uri_int64(const char*, const char*, sqlite3_int
|
||||
** [database connection] D failed, then the sqlite3_errcode(D) interface
|
||||
** returns the numeric [result code] or [extended result code] for that
|
||||
** API call.
|
||||
** If the most recent API call was successful,
|
||||
** then the return value from sqlite3_errcode() is undefined.
|
||||
** ^The sqlite3_extended_errcode()
|
||||
** interface is the same except that it always returns the
|
||||
** [extended result code] even when extended result codes are
|
||||
** disabled.
|
||||
**
|
||||
** The values returned by sqlite3_errcode() and/or
|
||||
** sqlite3_extended_errcode() might change with each API call.
|
||||
** Except, there are some interfaces that are guaranteed to never
|
||||
** change the value of the error code. The error-code preserving
|
||||
** interfaces are:
|
||||
**
|
||||
** <ul>
|
||||
** <li> sqlite3_errcode()
|
||||
** <li> sqlite3_extended_errcode()
|
||||
** <li> sqlite3_errmsg()
|
||||
** <li> sqlite3_errmsg16()
|
||||
** </ul>
|
||||
**
|
||||
** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language
|
||||
** text that describes the error, as either UTF-8 or UTF-16 respectively.
|
||||
** ^(Memory to hold the error message string is managed internally.
|
||||
@@ -4515,11 +4574,25 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
|
||||
** from [sqlite3_column_blob()], [sqlite3_column_text()], etc. into
|
||||
** [sqlite3_free()].
|
||||
**
|
||||
** ^(If a memory allocation error occurs during the evaluation of any
|
||||
** of these routines, a default value is returned. The default value
|
||||
** is either the integer 0, the floating point number 0.0, or a NULL
|
||||
** pointer. Subsequent calls to [sqlite3_errcode()] will return
|
||||
** [SQLITE_NOMEM].)^
|
||||
** As long as the input parameters are correct, these routines will only
|
||||
** fail if an out-of-memory error occurs during a format conversion.
|
||||
** Only the following subset of interfaces are subject to out-of-memory
|
||||
** errors:
|
||||
**
|
||||
** <ul>
|
||||
** <li> sqlite3_column_blob()
|
||||
** <li> sqlite3_column_text()
|
||||
** <li> sqlite3_column_text16()
|
||||
** <li> sqlite3_column_bytes()
|
||||
** <li> sqlite3_column_bytes16()
|
||||
** </ul>
|
||||
**
|
||||
** If an out-of-memory error occurs, then the return value from these
|
||||
** routines is the same as if the column had contained an SQL NULL value.
|
||||
** Valid SQL NULL returns can be distinguished from out-of-memory errors
|
||||
** by invoking the [sqlite3_errcode()] immediately after the suspect
|
||||
** return value is obtained and before any
|
||||
** other SQLite interface is called on the same [database connection].
|
||||
*/
|
||||
SQLITE_API const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
|
||||
SQLITE_API double sqlite3_column_double(sqlite3_stmt*, int iCol);
|
||||
@@ -4596,11 +4669,13 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
|
||||
**
|
||||
** ^These functions (collectively known as "function creation routines")
|
||||
** are used to add SQL functions or aggregates or to redefine the behavior
|
||||
** of existing SQL functions or aggregates. The only differences between
|
||||
** these routines are the text encoding expected for
|
||||
** the second parameter (the name of the function being created)
|
||||
** and the presence or absence of a destructor callback for
|
||||
** the application data pointer.
|
||||
** of existing SQL functions or aggregates. The only differences between
|
||||
** the three "sqlite3_create_function*" routines are the text encoding
|
||||
** expected for the second parameter (the name of the function being
|
||||
** created) and the presence or absence of a destructor callback for
|
||||
** the application data pointer. Function sqlite3_create_window_function()
|
||||
** is similar, but allows the user to supply the extra callback functions
|
||||
** needed by [aggregate window functions].
|
||||
**
|
||||
** ^The first parameter is the [database connection] to which the SQL
|
||||
** function is to be added. ^If an application uses more than one database
|
||||
@@ -4646,7 +4721,8 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
|
||||
** ^(The fifth parameter is an arbitrary pointer. The implementation of the
|
||||
** function can gain access to this pointer using [sqlite3_user_data()].)^
|
||||
**
|
||||
** ^The sixth, seventh and eighth parameters, xFunc, xStep and xFinal, are
|
||||
** ^The sixth, seventh and eighth parameters passed to the three
|
||||
** "sqlite3_create_function*" functions, xFunc, xStep and xFinal, are
|
||||
** pointers to C-language functions that implement the SQL function or
|
||||
** aggregate. ^A scalar SQL function requires an implementation of the xFunc
|
||||
** callback only; NULL pointers must be passed as the xStep and xFinal
|
||||
@@ -4655,15 +4731,24 @@ SQLITE_API int sqlite3_reset(sqlite3_stmt *pStmt);
|
||||
** SQL function or aggregate, pass NULL pointers for all three function
|
||||
** callbacks.
|
||||
**
|
||||
** ^(If the ninth parameter to sqlite3_create_function_v2() is not NULL,
|
||||
** then it is destructor for the application data pointer.
|
||||
** The destructor is invoked when the function is deleted, either by being
|
||||
** overloaded or when the database connection closes.)^
|
||||
** ^The destructor is also invoked if the call to
|
||||
** sqlite3_create_function_v2() fails.
|
||||
** ^When the destructor callback of the tenth parameter is invoked, it
|
||||
** is passed a single argument which is a copy of the application data
|
||||
** pointer which was the fifth parameter to sqlite3_create_function_v2().
|
||||
** ^The sixth, seventh, eighth and ninth parameters (xStep, xFinal, xValue
|
||||
** and xInverse) passed to sqlite3_create_window_function are pointers to
|
||||
** C-language callbacks that implement the new function. xStep and xFinal
|
||||
** must both be non-NULL. xValue and xInverse may either both be NULL, in
|
||||
** which case a regular aggregate function is created, or must both be
|
||||
** non-NULL, in which case the new function may be used as either an aggregate
|
||||
** or aggregate window function. More details regarding the implementation
|
||||
** of aggregate window functions are
|
||||
** [user-defined window functions|available here].
|
||||
**
|
||||
** ^(If the final parameter to sqlite3_create_function_v2() or
|
||||
** sqlite3_create_window_function() is not NULL, then it is destructor for
|
||||
** the application data pointer. The destructor is invoked when the function
|
||||
** is deleted, either by being overloaded or when the database connection
|
||||
** closes.)^ ^The destructor is also invoked if the call to
|
||||
** sqlite3_create_function_v2() fails. ^When the destructor callback is
|
||||
** invoked, it is passed a single argument which is a copy of the application
|
||||
** data pointer which was the fifth parameter to sqlite3_create_function_v2().
|
||||
**
|
||||
** ^It is permitted to register multiple implementations of the same
|
||||
** functions with the same name but with either differing numbers of
|
||||
@@ -4716,6 +4801,18 @@ SQLITE_API int sqlite3_create_function_v2(
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
void(*xDestroy)(void*)
|
||||
);
|
||||
SQLITE_API int sqlite3_create_window_function(
|
||||
sqlite3 *db,
|
||||
const char *zFunctionName,
|
||||
int nArg,
|
||||
int eTextRep,
|
||||
void *pApp,
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
void (*xValue)(sqlite3_context*),
|
||||
void (*xInverse)(sqlite3_context*,int,sqlite3_value**),
|
||||
void(*xDestroy)(void*)
|
||||
);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Text Encodings
|
||||
@@ -4858,6 +4955,28 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int6
|
||||
**
|
||||
** These routines must be called from the same thread as
|
||||
** the SQL function that supplied the [sqlite3_value*] parameters.
|
||||
**
|
||||
** As long as the input parameter is correct, these routines can only
|
||||
** fail if an out-of-memory error occurs during a format conversion.
|
||||
** Only the following subset of interfaces are subject to out-of-memory
|
||||
** errors:
|
||||
**
|
||||
** <ul>
|
||||
** <li> sqlite3_value_blob()
|
||||
** <li> sqlite3_value_text()
|
||||
** <li> sqlite3_value_text16()
|
||||
** <li> sqlite3_value_text16le()
|
||||
** <li> sqlite3_value_text16be()
|
||||
** <li> sqlite3_value_bytes()
|
||||
** <li> sqlite3_value_bytes16()
|
||||
** </ul>
|
||||
**
|
||||
** If an out-of-memory error occurs, then the return value from these
|
||||
** routines is the same as if the column had contained an SQL NULL value.
|
||||
** Valid SQL NULL returns can be distinguished from out-of-memory errors
|
||||
** by invoking the [sqlite3_errcode()] immediately after the suspect
|
||||
** return value is obtained and before any
|
||||
** other SQLite interface is called on the same [database connection].
|
||||
*/
|
||||
SQLITE_API const void *sqlite3_value_blob(sqlite3_value*);
|
||||
SQLITE_API double sqlite3_value_double(sqlite3_value*);
|
||||
@@ -6324,6 +6443,7 @@ struct sqlite3_index_info {
|
||||
#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
|
||||
#define SQLITE_INDEX_CONSTRAINT_ISNULL 71
|
||||
#define SQLITE_INDEX_CONSTRAINT_IS 72
|
||||
#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150
|
||||
|
||||
/*
|
||||
** CAPI3REF: Register A Virtual Table Implementation
|
||||
@@ -7000,6 +7120,7 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
|
||||
/*
|
||||
** CAPI3REF: Low-Level Control Of Database Files
|
||||
** METHOD: sqlite3
|
||||
** KEYWORDS: {file control}
|
||||
**
|
||||
** ^The [sqlite3_file_control()] interface makes a direct call to the
|
||||
** xFileControl method for the [sqlite3_io_methods] object associated
|
||||
@@ -7014,11 +7135,18 @@ SQLITE_API sqlite3_mutex *sqlite3_db_mutex(sqlite3*);
|
||||
** the xFileControl method. ^The return value of the xFileControl
|
||||
** method becomes the return value of this routine.
|
||||
**
|
||||
** A few opcodes for [sqlite3_file_control()] are handled directly
|
||||
** by the SQLite core and never invoke the
|
||||
** sqlite3_io_methods.xFileControl method.
|
||||
** ^The [SQLITE_FCNTL_FILE_POINTER] value for the op parameter causes
|
||||
** a pointer to the underlying [sqlite3_file] object to be written into
|
||||
** the space pointed to by the 4th parameter. ^The [SQLITE_FCNTL_FILE_POINTER]
|
||||
** case is a short-circuit path which does not actually invoke the
|
||||
** underlying sqlite3_io_methods.xFileControl method.
|
||||
** the space pointed to by the 4th parameter. The
|
||||
** [SQLITE_FCNTL_JOURNAL_POINTER] works similarly except that it returns
|
||||
** the [sqlite3_file] object associated with the journal file instead of
|
||||
** the main database. The [SQLITE_FCNTL_VFS_POINTER] opcode returns
|
||||
** a pointer to the underlying [sqlite3_vfs] object for the file.
|
||||
** The [SQLITE_FCNTL_DATA_VERSION] returns the data version counter
|
||||
** from the pager.
|
||||
**
|
||||
** ^If the second parameter (zDbName) does not match the name of any
|
||||
** open database file, then SQLITE_ERROR is returned. ^This error
|
||||
@@ -8837,7 +8965,6 @@ SQLITE_API int sqlite3_system_errno(sqlite3*);
|
||||
/*
|
||||
** CAPI3REF: Database Snapshot
|
||||
** KEYWORDS: {snapshot} {sqlite3_snapshot}
|
||||
** EXPERIMENTAL
|
||||
**
|
||||
** An instance of the snapshot object records the state of a [WAL mode]
|
||||
** database for some specific point in history.
|
||||
@@ -8854,11 +8981,6 @@ SQLITE_API int sqlite3_system_errno(sqlite3*);
|
||||
** version of the database file so that it is possible to later open a new read
|
||||
** transaction that sees that historical version of the database rather than
|
||||
** the most recent version.
|
||||
**
|
||||
** The constructor for this object is [sqlite3_snapshot_get()]. The
|
||||
** [sqlite3_snapshot_open()] method causes a fresh read transaction to refer
|
||||
** to an historical snapshot (if possible). The destructor for
|
||||
** sqlite3_snapshot objects is [sqlite3_snapshot_free()].
|
||||
*/
|
||||
typedef struct sqlite3_snapshot {
|
||||
unsigned char hidden[48];
|
||||
@@ -8866,7 +8988,7 @@ typedef struct sqlite3_snapshot {
|
||||
|
||||
/*
|
||||
** CAPI3REF: Record A Database Snapshot
|
||||
** EXPERIMENTAL
|
||||
** CONSTRUCTOR: sqlite3_snapshot
|
||||
**
|
||||
** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a
|
||||
** new [sqlite3_snapshot] object that records the current state of
|
||||
@@ -8882,7 +9004,7 @@ typedef struct sqlite3_snapshot {
|
||||
** in this case.
|
||||
**
|
||||
** <ul>
|
||||
** <li> The database handle must be in [autocommit mode].
|
||||
** <li> The database handle must not be in [autocommit mode].
|
||||
**
|
||||
** <li> Schema S of [database connection] D must be a [WAL mode] database.
|
||||
**
|
||||
@@ -8905,7 +9027,7 @@ typedef struct sqlite3_snapshot {
|
||||
** to avoid a memory leak.
|
||||
**
|
||||
** The [sqlite3_snapshot_get()] interface is only available when the
|
||||
** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
|
||||
** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used.
|
||||
*/
|
||||
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
|
||||
sqlite3 *db,
|
||||
@@ -8915,24 +9037,35 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
|
||||
|
||||
/*
|
||||
** CAPI3REF: Start a read transaction on an historical snapshot
|
||||
** EXPERIMENTAL
|
||||
** METHOD: sqlite3_snapshot
|
||||
**
|
||||
** ^The [sqlite3_snapshot_open(D,S,P)] interface starts a
|
||||
** read transaction for schema S of
|
||||
** [database connection] D such that the read transaction
|
||||
** refers to historical [snapshot] P, rather than the most
|
||||
** recent change to the database.
|
||||
** ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK on success
|
||||
** or an appropriate [error code] if it fails.
|
||||
** ^The [sqlite3_snapshot_open(D,S,P)] interface either starts a new read
|
||||
** transaction or upgrades an existing one for schema S of
|
||||
** [database connection] D such that the read transaction refers to
|
||||
** historical [snapshot] P, rather than the most recent change to the
|
||||
** database. ^The [sqlite3_snapshot_open()] interface returns SQLITE_OK
|
||||
** on success or an appropriate [error code] if it fails.
|
||||
**
|
||||
** ^In order to succeed, the database connection must not be in
|
||||
** [autocommit mode] when [sqlite3_snapshot_open(D,S,P)] is called. If there
|
||||
** is already a read transaction open on schema S, then the database handle
|
||||
** must have no active statements (SELECT statements that have been passed
|
||||
** to sqlite3_step() but not sqlite3_reset() or sqlite3_finalize()).
|
||||
** SQLITE_ERROR is returned if either of these conditions is violated, or
|
||||
** if schema S does not exist, or if the snapshot object is invalid.
|
||||
**
|
||||
** ^A call to sqlite3_snapshot_open() will fail to open if the specified
|
||||
** snapshot has been overwritten by a [checkpoint]. In this case
|
||||
** SQLITE_ERROR_SNAPSHOT is returned.
|
||||
**
|
||||
** If there is already a read transaction open when this function is
|
||||
** invoked, then the same read transaction remains open (on the same
|
||||
** database snapshot) if SQLITE_ERROR, SQLITE_BUSY or SQLITE_ERROR_SNAPSHOT
|
||||
** is returned. If another error code - for example SQLITE_PROTOCOL or an
|
||||
** SQLITE_IOERR error code - is returned, then the final state of the
|
||||
** read transaction is undefined. If SQLITE_OK is returned, then the
|
||||
** read transaction is now open on database snapshot P.
|
||||
**
|
||||
** ^In order to succeed, a call to [sqlite3_snapshot_open(D,S,P)] must be
|
||||
** the first operation following the [BEGIN] that takes the schema S
|
||||
** out of [autocommit mode].
|
||||
** ^In other words, schema S must not currently be in
|
||||
** a transaction for [sqlite3_snapshot_open(D,S,P)] to work, but the
|
||||
** database connection D must be out of [autocommit mode].
|
||||
** ^A [snapshot] will fail to open if it has been overwritten by a
|
||||
** [checkpoint].
|
||||
** ^(A call to [sqlite3_snapshot_open(D,S,P)] will fail if the
|
||||
** database connection D does not know that the database file for
|
||||
** schema S is in [WAL mode]. A database connection might not know
|
||||
@@ -8943,7 +9076,7 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_get(
|
||||
** database connection in order to make it ready to use snapshots.)
|
||||
**
|
||||
** The [sqlite3_snapshot_open()] interface is only available when the
|
||||
** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
|
||||
** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used.
|
||||
*/
|
||||
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open(
|
||||
sqlite3 *db,
|
||||
@@ -8953,20 +9086,20 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_open(
|
||||
|
||||
/*
|
||||
** CAPI3REF: Destroy a snapshot
|
||||
** EXPERIMENTAL
|
||||
** DESTRUCTOR: sqlite3_snapshot
|
||||
**
|
||||
** ^The [sqlite3_snapshot_free(P)] interface destroys [sqlite3_snapshot] P.
|
||||
** The application must eventually free every [sqlite3_snapshot] object
|
||||
** using this routine to avoid a memory leak.
|
||||
**
|
||||
** The [sqlite3_snapshot_free()] interface is only available when the
|
||||
** SQLITE_ENABLE_SNAPSHOT compile-time option is used.
|
||||
** [SQLITE_ENABLE_SNAPSHOT] compile-time option is used.
|
||||
*/
|
||||
SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*);
|
||||
|
||||
/*
|
||||
** CAPI3REF: Compare the ages of two snapshot handles.
|
||||
** EXPERIMENTAL
|
||||
** METHOD: sqlite3_snapshot
|
||||
**
|
||||
** The sqlite3_snapshot_cmp(P1, P2) interface is used to compare the ages
|
||||
** of two valid snapshot handles.
|
||||
@@ -8985,6 +9118,9 @@ SQLITE_API SQLITE_EXPERIMENTAL void sqlite3_snapshot_free(sqlite3_snapshot*);
|
||||
** Otherwise, this API returns a negative value if P1 refers to an older
|
||||
** snapshot than P2, zero if the two handles refer to the same database
|
||||
** snapshot, and a positive value if P1 is a newer snapshot than P2.
|
||||
**
|
||||
** This interface is only available if SQLite is compiled with the
|
||||
** [SQLITE_ENABLE_SNAPSHOT] option.
|
||||
*/
|
||||
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
|
||||
sqlite3_snapshot *p1,
|
||||
@@ -8993,23 +9129,26 @@ SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_cmp(
|
||||
|
||||
/*
|
||||
** CAPI3REF: Recover snapshots from a wal file
|
||||
** EXPERIMENTAL
|
||||
** METHOD: sqlite3_snapshot
|
||||
**
|
||||
** If all connections disconnect from a database file but do not perform
|
||||
** a checkpoint, the existing wal file is opened along with the database
|
||||
** file the next time the database is opened. At this point it is only
|
||||
** possible to successfully call sqlite3_snapshot_open() to open the most
|
||||
** recent snapshot of the database (the one at the head of the wal file),
|
||||
** even though the wal file may contain other valid snapshots for which
|
||||
** clients have sqlite3_snapshot handles.
|
||||
** If a [WAL file] remains on disk after all database connections close
|
||||
** (either through the use of the [SQLITE_FCNTL_PERSIST_WAL] [file control]
|
||||
** or because the last process to have the database opened exited without
|
||||
** calling [sqlite3_close()]) and a new connection is subsequently opened
|
||||
** on that database and [WAL file], the [sqlite3_snapshot_open()] interface
|
||||
** will only be able to open the last transaction added to the WAL file
|
||||
** even though the WAL file contains other valid transactions.
|
||||
**
|
||||
** This function attempts to scan the wal file associated with database zDb
|
||||
** This function attempts to scan the WAL file associated with database zDb
|
||||
** of database handle db and make all valid snapshots available to
|
||||
** sqlite3_snapshot_open(). It is an error if there is already a read
|
||||
** transaction open on the database, or if the database is not a wal mode
|
||||
** transaction open on the database, or if the database is not a WAL mode
|
||||
** database.
|
||||
**
|
||||
** SQLITE_OK is returned if successful, or an SQLite error code otherwise.
|
||||
**
|
||||
** This interface is only available if SQLite is compiled with the
|
||||
** [SQLITE_ENABLE_SNAPSHOT] option.
|
||||
*/
|
||||
SQLITE_API SQLITE_EXPERIMENTAL int sqlite3_snapshot_recover(sqlite3 *db, const char *zDb);
|
||||
|
||||
@@ -9120,7 +9259,7 @@ SQLITE_API int sqlite3_deserialize(
|
||||
** in the P argument is held in memory obtained from [sqlite3_malloc64()]
|
||||
** and that SQLite should take ownership of this memory and automatically
|
||||
** free it when it has finished using it. Without this flag, the caller
|
||||
** is resposible for freeing any dynamically allocated memory.
|
||||
** is responsible for freeing any dynamically allocated memory.
|
||||
**
|
||||
** The SQLITE_DESERIALIZE_RESIZEABLE flag means that SQLite is allowed to
|
||||
** grow the size of the database using calls to [sqlite3_realloc64()]. This
|
||||
@@ -11298,7 +11437,7 @@ struct Fts5ExtensionApi {
|
||||
** This way, even if the tokenizer does not provide synonyms
|
||||
** when tokenizing query text (it should not - to do would be
|
||||
** inefficient), it doesn't matter if the user queries for
|
||||
** 'first + place' or '1st + place', as there are entires in the
|
||||
** 'first + place' or '1st + place', as there are entries in the
|
||||
** FTS index corresponding to both forms of the first token.
|
||||
** </ol>
|
||||
**
|
||||
@@ -11326,7 +11465,7 @@ struct Fts5ExtensionApi {
|
||||
** extra data to the FTS index or require FTS5 to query for multiple terms,
|
||||
** so it is efficient in terms of disk space and query speed. However, it
|
||||
** does not support prefix queries very well. If, as suggested above, the
|
||||
** token "first" is subsituted for "1st" by the tokenizer, then the query:
|
||||
** token "first" is substituted for "1st" by the tokenizer, then the query:
|
||||
**
|
||||
** <codeblock>
|
||||
** ... MATCH '1s*'</codeblock>
|
||||
|
||||
116
vendor/github.com/mattn/go-sqlite3/sqlite3.go
сгенерированный
поставляемый
116
vendor/github.com/mattn/go-sqlite3/sqlite3.go
сгенерированный
поставляемый
@@ -78,8 +78,38 @@ _sqlite3_exec(sqlite3* db, const char* pcmd, long long* rowid, long long* change
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
|
||||
extern int _sqlite3_step_blocking(sqlite3_stmt *stmt);
|
||||
extern int _sqlite3_step_row_blocking(sqlite3_stmt* stmt, long long* rowid, long long* changes);
|
||||
extern int _sqlite3_prepare_v2_blocking(sqlite3 *db, const char *zSql, int nBytes, sqlite3_stmt **ppStmt, const char **pzTail);
|
||||
|
||||
static int
|
||||
_sqlite3_step(sqlite3_stmt* stmt, long long* rowid, long long* changes)
|
||||
_sqlite3_step_internal(sqlite3_stmt *stmt)
|
||||
{
|
||||
return _sqlite3_step_blocking(stmt);
|
||||
}
|
||||
|
||||
static int
|
||||
_sqlite3_step_row_internal(sqlite3_stmt* stmt, long long* rowid, long long* changes)
|
||||
{
|
||||
return _sqlite3_step_row_blocking(stmt, rowid, changes);
|
||||
}
|
||||
|
||||
static int
|
||||
_sqlite3_prepare_v2_internal(sqlite3 *db, const char *zSql, int nBytes, sqlite3_stmt **ppStmt, const char **pzTail)
|
||||
{
|
||||
return _sqlite3_prepare_v2_blocking(db, zSql, nBytes, ppStmt, pzTail);
|
||||
}
|
||||
|
||||
#else
|
||||
static int
|
||||
_sqlite3_step_internal(sqlite3_stmt *stmt)
|
||||
{
|
||||
return sqlite3_step(stmt);
|
||||
}
|
||||
|
||||
static int
|
||||
_sqlite3_step_row_internal(sqlite3_stmt* stmt, long long* rowid, long long* changes)
|
||||
{
|
||||
int rv = sqlite3_step(stmt);
|
||||
sqlite3* db = sqlite3_db_handle(stmt);
|
||||
@@ -88,6 +118,13 @@ _sqlite3_step(sqlite3_stmt* stmt, long long* rowid, long long* changes)
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int
|
||||
_sqlite3_prepare_v2_internal(sqlite3 *db, const char *zSql, int nBytes, sqlite3_stmt **ppStmt, const char **pzTail)
|
||||
{
|
||||
return sqlite3_prepare_v2(db, zSql, nBytes, ppStmt, pzTail);
|
||||
}
|
||||
#endif
|
||||
|
||||
void _sqlite3_result_text(sqlite3_context* ctx, const char* s) {
|
||||
sqlite3_result_text(ctx, s, -1, &free);
|
||||
}
|
||||
@@ -119,6 +156,8 @@ int commitHookTrampoline(void*);
|
||||
void rollbackHookTrampoline(void*);
|
||||
void updateHookTrampoline(void*, int, char*, char*, sqlite3_int64);
|
||||
|
||||
int authorizerTrampoline(void*, int, char*, char*, char*, char*);
|
||||
|
||||
#ifdef SQLITE_LIMIT_WORKER_THREADS
|
||||
# define _SQLITE_HAS_LIMIT
|
||||
# define SQLITE_LIMIT_LENGTH 0
|
||||
@@ -200,18 +239,57 @@ func Version() (libVersion string, libVersionNumber int, sourceID string) {
|
||||
}
|
||||
|
||||
const (
|
||||
// used by authorizer and pre_update_hook
|
||||
SQLITE_DELETE = C.SQLITE_DELETE
|
||||
SQLITE_INSERT = C.SQLITE_INSERT
|
||||
SQLITE_UPDATE = C.SQLITE_UPDATE
|
||||
|
||||
// used by authorzier - as return value
|
||||
SQLITE_OK = C.SQLITE_OK
|
||||
SQLITE_IGNORE = C.SQLITE_IGNORE
|
||||
SQLITE_DENY = C.SQLITE_DENY
|
||||
|
||||
// different actions query tries to do - passed as argument to authorizer
|
||||
SQLITE_CREATE_INDEX = C.SQLITE_CREATE_INDEX
|
||||
SQLITE_CREATE_TABLE = C.SQLITE_CREATE_TABLE
|
||||
SQLITE_CREATE_TEMP_INDEX = C.SQLITE_CREATE_TEMP_INDEX
|
||||
SQLITE_CREATE_TEMP_TABLE = C.SQLITE_CREATE_TEMP_TABLE
|
||||
SQLITE_CREATE_TEMP_TRIGGER = C.SQLITE_CREATE_TEMP_TRIGGER
|
||||
SQLITE_CREATE_TEMP_VIEW = C.SQLITE_CREATE_TEMP_VIEW
|
||||
SQLITE_CREATE_TRIGGER = C.SQLITE_CREATE_TRIGGER
|
||||
SQLITE_CREATE_VIEW = C.SQLITE_CREATE_VIEW
|
||||
SQLITE_CREATE_VTABLE = C.SQLITE_CREATE_VTABLE
|
||||
SQLITE_DROP_INDEX = C.SQLITE_DROP_INDEX
|
||||
SQLITE_DROP_TABLE = C.SQLITE_DROP_TABLE
|
||||
SQLITE_DROP_TEMP_INDEX = C.SQLITE_DROP_TEMP_INDEX
|
||||
SQLITE_DROP_TEMP_TABLE = C.SQLITE_DROP_TEMP_TABLE
|
||||
SQLITE_DROP_TEMP_TRIGGER = C.SQLITE_DROP_TEMP_TRIGGER
|
||||
SQLITE_DROP_TEMP_VIEW = C.SQLITE_DROP_TEMP_VIEW
|
||||
SQLITE_DROP_TRIGGER = C.SQLITE_DROP_TRIGGER
|
||||
SQLITE_DROP_VIEW = C.SQLITE_DROP_VIEW
|
||||
SQLITE_DROP_VTABLE = C.SQLITE_DROP_VTABLE
|
||||
SQLITE_PRAGMA = C.SQLITE_PRAGMA
|
||||
SQLITE_READ = C.SQLITE_READ
|
||||
SQLITE_SELECT = C.SQLITE_SELECT
|
||||
SQLITE_TRANSACTION = C.SQLITE_TRANSACTION
|
||||
SQLITE_ATTACH = C.SQLITE_ATTACH
|
||||
SQLITE_DETACH = C.SQLITE_DETACH
|
||||
SQLITE_ALTER_TABLE = C.SQLITE_ALTER_TABLE
|
||||
SQLITE_REINDEX = C.SQLITE_REINDEX
|
||||
SQLITE_ANALYZE = C.SQLITE_ANALYZE
|
||||
SQLITE_FUNCTION = C.SQLITE_FUNCTION
|
||||
SQLITE_SAVEPOINT = C.SQLITE_SAVEPOINT
|
||||
SQLITE_COPY = C.SQLITE_COPY
|
||||
/*SQLITE_RECURSIVE = C.SQLITE_RECURSIVE*/
|
||||
)
|
||||
|
||||
// SQLiteDriver implement sql.Driver.
|
||||
// SQLiteDriver implements driver.Driver.
|
||||
type SQLiteDriver struct {
|
||||
Extensions []string
|
||||
ConnectHook func(*SQLiteConn) error
|
||||
}
|
||||
|
||||
// SQLiteConn implement sql.Conn.
|
||||
// SQLiteConn implements driver.Conn.
|
||||
type SQLiteConn struct {
|
||||
mu sync.Mutex
|
||||
db *C.sqlite3
|
||||
@@ -221,12 +299,12 @@ type SQLiteConn struct {
|
||||
aggregators []*aggInfo
|
||||
}
|
||||
|
||||
// SQLiteTx implemen sql.Tx.
|
||||
// SQLiteTx implements driver.Tx.
|
||||
type SQLiteTx struct {
|
||||
c *SQLiteConn
|
||||
}
|
||||
|
||||
// SQLiteStmt implement sql.Stmt.
|
||||
// SQLiteStmt implements driver.Stmt.
|
||||
type SQLiteStmt struct {
|
||||
mu sync.Mutex
|
||||
c *SQLiteConn
|
||||
@@ -236,13 +314,13 @@ type SQLiteStmt struct {
|
||||
cls bool
|
||||
}
|
||||
|
||||
// SQLiteResult implement sql.Result.
|
||||
// SQLiteResult implements sql.Result.
|
||||
type SQLiteResult struct {
|
||||
id int64
|
||||
changes int64
|
||||
}
|
||||
|
||||
// SQLiteRows implement sql.Rows.
|
||||
// SQLiteRows implements driver.Rows.
|
||||
type SQLiteRows struct {
|
||||
s *SQLiteStmt
|
||||
nc int
|
||||
@@ -440,6 +518,20 @@ func (c *SQLiteConn) RegisterUpdateHook(callback func(int, string, string, int64
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterAuthorizer sets the authorizer for connection.
|
||||
//
|
||||
// The parameters to the callback are the operation (one of the constants
|
||||
// SQLITE_INSERT, SQLITE_DELETE, or SQLITE_UPDATE), and 1 to 3 arguments,
|
||||
// depending on operation. More details see:
|
||||
// https://www.sqlite.org/c3ref/c_alter_table.html
|
||||
func (c *SQLiteConn) RegisterAuthorizer(callback func(int, string, string, string) int) {
|
||||
if callback == nil {
|
||||
C.sqlite3_set_authorizer(c.db, nil, nil)
|
||||
} else {
|
||||
C.sqlite3_set_authorizer(c.db, (*[0]byte)(C.authorizerTrampoline), unsafe.Pointer(newHandle(c, callback)))
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterFunc makes a Go function available as a SQLite function.
|
||||
//
|
||||
// The Go function can have arguments of the following types: any
|
||||
@@ -1582,7 +1674,7 @@ func (c *SQLiteConn) prepare(ctx context.Context, query string) (driver.Stmt, er
|
||||
defer C.free(unsafe.Pointer(pquery))
|
||||
var s *C.sqlite3_stmt
|
||||
var tail *C.char
|
||||
rv := C.sqlite3_prepare_v2(c.db, pquery, -1, &s, &tail)
|
||||
rv := C._sqlite3_prepare_v2_internal(c.db, pquery, -1, &s, &tail)
|
||||
if rv != C.SQLITE_OK {
|
||||
return nil, c.lastError()
|
||||
}
|
||||
@@ -1816,7 +1908,7 @@ func (s *SQLiteStmt) exec(ctx context.Context, args []namedValue) (driver.Result
|
||||
}
|
||||
|
||||
var rowid, changes C.longlong
|
||||
rv := C._sqlite3_step(s.s, &rowid, &changes)
|
||||
rv := C._sqlite3_step_row_internal(s.s, &rowid, &changes)
|
||||
if rv != C.SQLITE_ROW && rv != C.SQLITE_OK && rv != C.SQLITE_DONE {
|
||||
err := s.c.lastError()
|
||||
C.sqlite3_reset(s.s)
|
||||
@@ -1883,12 +1975,12 @@ func (rc *SQLiteRows) DeclTypes() []string {
|
||||
|
||||
// Next move cursor to next.
|
||||
func (rc *SQLiteRows) Next(dest []driver.Value) error {
|
||||
rc.s.mu.Lock()
|
||||
defer rc.s.mu.Unlock()
|
||||
if rc.s.closed {
|
||||
return io.EOF
|
||||
}
|
||||
rc.s.mu.Lock()
|
||||
defer rc.s.mu.Unlock()
|
||||
rv := C.sqlite3_step(rc.s.s)
|
||||
rv := C._sqlite3_step_internal(rc.s.s)
|
||||
if rv == C.SQLITE_DONE {
|
||||
return io.EOF
|
||||
}
|
||||
|
||||
8
vendor/github.com/mattn/go-sqlite3/sqlite3_func_crypt.go
сгенерированный
поставляемый
8
vendor/github.com/mattn/go-sqlite3/sqlite3_func_crypt.go
сгенерированный
поставляемый
@@ -83,13 +83,13 @@ func CryptEncoderSSHA256(salt string) func(pass []byte, hash interface{}) []byte
|
||||
}
|
||||
}
|
||||
|
||||
// CryptEncoderSHA384 encodes a password with SHA256
|
||||
// CryptEncoderSHA384 encodes a password with SHA384
|
||||
func CryptEncoderSHA384(pass []byte, hash interface{}) []byte {
|
||||
h := sha512.Sum384(pass)
|
||||
return h[:]
|
||||
}
|
||||
|
||||
// CryptEncoderSSHA384 encodes a password with SHA256
|
||||
// CryptEncoderSSHA384 encodes a password with SHA384
|
||||
// with the configured salt
|
||||
func CryptEncoderSSHA384(salt string) func(pass []byte, hash interface{}) []byte {
|
||||
return func(pass []byte, hash interface{}) []byte {
|
||||
@@ -100,13 +100,13 @@ func CryptEncoderSSHA384(salt string) func(pass []byte, hash interface{}) []byte
|
||||
}
|
||||
}
|
||||
|
||||
// CryptEncoderSHA512 encodes a password with SHA256
|
||||
// CryptEncoderSHA512 encodes a password with SHA512
|
||||
func CryptEncoderSHA512(pass []byte, hash interface{}) []byte {
|
||||
h := sha512.Sum512(pass)
|
||||
return h[:]
|
||||
}
|
||||
|
||||
// CryptEncoderSSHA512 encodes a password with SHA256
|
||||
// CryptEncoderSSHA512 encodes a password with SHA512
|
||||
// with the configured salt
|
||||
func CryptEncoderSSHA512(salt string) func(pass []byte, hash interface{}) []byte {
|
||||
return func(pass []byte, hash interface{}) []byte {
|
||||
|
||||
85
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_unlock_notify.c
сгенерированный
поставляемый
Обычный файл
85
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_unlock_notify.c
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,85 @@
|
||||
// Copyright (C) 2018 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#ifdef SQLITE_ENABLE_UNLOCK_NOTIFY
|
||||
#include <stdio.h>
|
||||
#include <sqlite3-binding.h>
|
||||
|
||||
extern int unlock_notify_wait(sqlite3 *db);
|
||||
|
||||
int
|
||||
_sqlite3_step_blocking(sqlite3_stmt *stmt)
|
||||
{
|
||||
int rv;
|
||||
sqlite3* db;
|
||||
|
||||
db = sqlite3_db_handle(stmt);
|
||||
for (;;) {
|
||||
rv = sqlite3_step(stmt);
|
||||
if (rv != SQLITE_LOCKED) {
|
||||
break;
|
||||
}
|
||||
if (sqlite3_extended_errcode(db) != SQLITE_LOCKED_SHAREDCACHE) {
|
||||
break;
|
||||
}
|
||||
rv = unlock_notify_wait(db);
|
||||
if (rv != SQLITE_OK) {
|
||||
break;
|
||||
}
|
||||
sqlite3_reset(stmt);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
_sqlite3_step_row_blocking(sqlite3_stmt* stmt, long long* rowid, long long* changes)
|
||||
{
|
||||
int rv;
|
||||
sqlite3* db;
|
||||
|
||||
db = sqlite3_db_handle(stmt);
|
||||
for (;;) {
|
||||
rv = sqlite3_step(stmt);
|
||||
if (rv!=SQLITE_LOCKED) {
|
||||
break;
|
||||
}
|
||||
if (sqlite3_extended_errcode(db) != SQLITE_LOCKED_SHAREDCACHE) {
|
||||
break;
|
||||
}
|
||||
rv = unlock_notify_wait(db);
|
||||
if (rv != SQLITE_OK) {
|
||||
break;
|
||||
}
|
||||
sqlite3_reset(stmt);
|
||||
}
|
||||
|
||||
*rowid = (long long) sqlite3_last_insert_rowid(db);
|
||||
*changes = (long long) sqlite3_changes(db);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int
|
||||
_sqlite3_prepare_v2_blocking(sqlite3 *db, const char *zSql, int nBytes, sqlite3_stmt **ppStmt, const char **pzTail)
|
||||
{
|
||||
int rv;
|
||||
|
||||
for (;;) {
|
||||
rv = sqlite3_prepare_v2(db, zSql, nBytes, ppStmt, pzTail);
|
||||
if (rv!=SQLITE_LOCKED) {
|
||||
break;
|
||||
}
|
||||
if (sqlite3_extended_errcode(db) != SQLITE_LOCKED_SHAREDCACHE) {
|
||||
break;
|
||||
}
|
||||
rv = unlock_notify_wait(db);
|
||||
if (rv != SQLITE_OK) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
93
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_unlock_notify.go
сгенерированный
поставляемый
Обычный файл
93
vendor/github.com/mattn/go-sqlite3/sqlite3_opt_unlock_notify.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,93 @@
|
||||
// Copyright (C) 2018 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build cgo
|
||||
// +build sqlite_unlock_notify
|
||||
|
||||
package sqlite3
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -DSQLITE_ENABLE_UNLOCK_NOTIFY
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sqlite3-binding.h>
|
||||
|
||||
extern void unlock_notify_callback(void *arg, int argc);
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type unlock_notify_table struct {
|
||||
sync.Mutex
|
||||
seqnum uint
|
||||
table map[uint]chan struct{}
|
||||
}
|
||||
|
||||
var unt unlock_notify_table = unlock_notify_table{table: make(map[uint]chan struct{})}
|
||||
|
||||
func (t *unlock_notify_table) add(c chan struct{}) uint {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
h := t.seqnum
|
||||
t.table[h] = c
|
||||
t.seqnum++
|
||||
return h
|
||||
}
|
||||
|
||||
func (t *unlock_notify_table) remove(h uint) {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
delete(t.table, h)
|
||||
}
|
||||
|
||||
func (t *unlock_notify_table) get(h uint) chan struct{} {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
c, ok := t.table[h]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("Non-existent key for unlcok-notify channel: %d", h))
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
//export unlock_notify_callback
|
||||
func unlock_notify_callback(argv unsafe.Pointer, argc C.int) {
|
||||
for i := 0; i < int(argc); i++ {
|
||||
parg := ((*(*[(math.MaxInt32 - 1) / unsafe.Sizeof((*C.uint)(nil))]*[1]uint)(argv))[i])
|
||||
arg := *parg
|
||||
h := arg[0]
|
||||
c := unt.get(h)
|
||||
c <- struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
//export unlock_notify_wait
|
||||
func unlock_notify_wait(db *C.sqlite3) C.int {
|
||||
// It has to be a bufferred channel to not block in sqlite_unlock_notify
|
||||
// as sqlite_unlock_notify could invoke the callback before it returns.
|
||||
c := make(chan struct{}, 1)
|
||||
defer close(c)
|
||||
|
||||
h := unt.add(c)
|
||||
defer unt.remove(h)
|
||||
|
||||
pargv := C.malloc(C.sizeof_uint)
|
||||
defer C.free(pargv)
|
||||
|
||||
argv := (*[1]uint)(pargv)
|
||||
argv[0] = h
|
||||
if rv := C.sqlite3_unlock_notify(db, (*[0]byte)(C.unlock_notify_callback), unsafe.Pointer(pargv)); rv != C.SQLITE_OK {
|
||||
return rv
|
||||
}
|
||||
|
||||
<-c
|
||||
|
||||
return C.SQLITE_OK
|
||||
}
|
||||
3
vendor/github.com/mattn/go-sqlite3/sqlite3_other.go
сгенерированный
поставляемый
3
vendor/github.com/mattn/go-sqlite3/sqlite3_other.go
сгенерированный
поставляемый
@@ -10,5 +10,8 @@ package sqlite3
|
||||
/*
|
||||
#cgo CFLAGS: -I.
|
||||
#cgo linux LDFLAGS: -ldl
|
||||
#cgo linux,ppc LDFLAGS: -lpthread
|
||||
#cgo linux,ppc64 LDFLAGS: -lpthread
|
||||
#cgo linux,ppc64le LDFLAGS: -lpthread
|
||||
*/
|
||||
import "C"
|
||||
|
||||
8
vendor/github.com/mattn/go-sqlite3/sqlite3ext.h
сгенерированный
поставляемый
8
vendor/github.com/mattn/go-sqlite3/sqlite3ext.h
сгенерированный
поставляемый
@@ -311,6 +311,12 @@ struct sqlite3_api_routines {
|
||||
int (*str_errcode)(sqlite3_str*);
|
||||
int (*str_length)(sqlite3_str*);
|
||||
char *(*str_value)(sqlite3_str*);
|
||||
int (*create_window_function)(sqlite3*,const char*,int,int,void*,
|
||||
void (*xStep)(sqlite3_context*,int,sqlite3_value**),
|
||||
void (*xFinal)(sqlite3_context*),
|
||||
void (*xValue)(sqlite3_context*),
|
||||
void (*xInv)(sqlite3_context*,int,sqlite3_value**),
|
||||
void(*xDestroy)(void*));
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -596,6 +602,8 @@ typedef int (*sqlite3_loadext_entry)(
|
||||
#define sqlite3_str_errcode sqlite3_api->str_errcode
|
||||
#define sqlite3_str_length sqlite3_api->str_length
|
||||
#define sqlite3_str_value sqlite3_api->str_value
|
||||
/* Version 3.25.0 and later */
|
||||
#define sqlite3_create_window_function sqlite3_api->create_window_function
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
|
||||
7
vendor/github.com/miekg/dns/.travis.yml
сгенерированный
поставляемый
7
vendor/github.com/miekg/dns/.travis.yml
сгенерированный
поставляемый
@@ -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)
|
||||
|
||||
46
vendor/github.com/miekg/dns/Gopkg.lock
сгенерированный
поставляемый
46
vendor/github.com/miekg/dns/Gopkg.lock
сгенерированный
поставляемый
@@ -3,19 +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","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 = "c4abc38abaeeeeb9be92455c9c02cae32841122b8982aaa067ef25bb8e86ff9d"
|
||||
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
|
||||
|
||||
12
vendor/github.com/miekg/dns/Gopkg.toml
сгенерированный
поставляемый
12
vendor/github.com/miekg/dns/Gopkg.toml
сгенерированный
поставляемый
@@ -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"
|
||||
|
||||
50
vendor/github.com/miekg/dns/README.md
сгенерированный
поставляемый
50
vendor/github.com/miekg/dns/README.md
сгенерированный
поставляемый
@@ -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/
|
||||
@@ -67,29 +66,28 @@ 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.
|
||||
|
||||
# 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
|
||||
|
||||
@@ -163,9 +161,9 @@ Example programs can be found in the `github.com/miekg/exdns` repository.
|
||||
* 7873 - Domain Name System (DNS) Cookies (draft-ietf-dnsop-cookies)
|
||||
* 8080 - EdDSA for DNSSEC
|
||||
|
||||
## 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>
|
||||
|
||||
54
vendor/github.com/miekg/dns/acceptfunc.go
сгенерированный
поставляемый
Обычный файл
54
vendor/github.com/miekg/dns/acceptfunc.go
сгенерированный
поставляемый
Обычный файл
@@ -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 0 RRs 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.
|
||||
)
|
||||
|
||||
var defaultMsgAcceptFunc = func(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 MsgReject
|
||||
}
|
||||
|
||||
if isZero := dh.Bits&_Z != 0; isZero {
|
||||
return MsgReject
|
||||
}
|
||||
if dh.Qdcount != 1 {
|
||||
return MsgReject
|
||||
}
|
||||
if dh.Ancount != 0 {
|
||||
return MsgReject
|
||||
}
|
||||
if dh.Nscount != 0 {
|
||||
return MsgReject
|
||||
}
|
||||
if dh.Arcount > 2 {
|
||||
return MsgReject
|
||||
}
|
||||
return MsgAccept
|
||||
}
|
||||
85
vendor/github.com/miekg/dns/client.go
сгенерированный
поставляемый
85
vendor/github.com/miekg/dns/client.go
сгенерированный
поставляемый
@@ -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,19 +482,15 @@ 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
|
||||
} else {
|
||||
timeout = deadline.Sub(time.Now())
|
||||
timeout = time.Until(deadline)
|
||||
}
|
||||
// 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)
|
||||
}
|
||||
|
||||
198
vendor/github.com/miekg/dns/compress_generate.go
сгенерированный
поставляемый
198
vendor/github.com/miekg/dns/compress_generate.go
сгенерированный
поставляемый
@@ -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)
|
||||
}
|
||||
}
|
||||
2
vendor/github.com/miekg/dns/defaults.go
сгенерированный
поставляемый
2
vendor/github.com/miekg/dns/defaults.go
сгенерированный
поставляемый
@@ -166,7 +166,7 @@ func (dns *Msg) IsEdns0() *OPT {
|
||||
// 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.
|
||||
func IsDomainName(s string) (labels int, ok bool) {
|
||||
_, labels, err := packDomainName(s, nil, 0, nil, false)
|
||||
_, labels, err := packDomainName(s, nil, 0, compressionMap{}, false)
|
||||
return labels, err == nil
|
||||
}
|
||||
|
||||
|
||||
28
vendor/github.com/miekg/dns/dns.go
сгенерированный
поставляемый
28
vendor/github.com/miekg/dns/dns.go
сгенерированный
поставляемый
@@ -34,10 +34,15 @@ 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
|
||||
|
||||
// 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 an RR into wire format.
|
||||
pack([]byte, int, map[string]int, bool) (int, error)
|
||||
pack(msg []byte, off int, compression compressionMap, compress bool) (headerEnd int, off1 int, err error)
|
||||
}
|
||||
|
||||
// RR_Header is the header all DNS resource records share.
|
||||
@@ -70,28 +75,29 @@ 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
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
rfc3597, _, err := unpackRFC3597(*r.Header(), buf, off-int(r.Header().Rdlength))
|
||||
hdr := *r.Header()
|
||||
hdr.Rdlength = uint16(off - headerEnd)
|
||||
|
||||
rfc3597, _, err := unpackRFC3597(hdr, buf, headerEnd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*rr = *rfc3597.(*RFC3597)
|
||||
return nil
|
||||
}
|
||||
|
||||
4
vendor/github.com/miekg/dns/dnssec.go
сгенерированный
поставляемый
4
vendor/github.com/miekg/dns/dnssec.go
сгенерированный
поставляемый
@@ -401,7 +401,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 {
|
||||
@@ -724,7 +724,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
|
||||
|
||||
168
vendor/github.com/miekg/dns/dnssec_keyscan.go
сгенерированный
поставляемый
168
vendor/github.com/miekg/dns/dnssec_keyscan.go
сгенерированный
поставляемый
@@ -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
|
||||
}
|
||||
|
||||
107
vendor/github.com/miekg/dns/doc.go
сгенерированный
поставляемый
107
vendor/github.com/miekg/dns/doc.go
сгенерированный
поставляемый
@@ -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.
|
||||
*/
|
||||
|
||||
33
vendor/github.com/miekg/dns/edns.go
сгенерированный
поставляемый
33
vendor/github.com/miekg/dns/edns.go
сгенерированный
поставляемый
@@ -78,8 +78,8 @@ func (rr *OPT) String() string {
|
||||
return s
|
||||
}
|
||||
|
||||
func (rr *OPT) len() int {
|
||||
l := rr.Hdr.len()
|
||||
func (rr *OPT) len(off int, compression map[string]struct{}) int {
|
||||
l := rr.Hdr.len(off, compression)
|
||||
for i := 0; i < len(rr.Option); i++ {
|
||||
l += 4 // Account for 2-byte option code and 2-byte option length.
|
||||
lo, _ := rr.Option[i].pack()
|
||||
@@ -102,15 +102,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.
|
||||
@@ -274,22 +273,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")
|
||||
}
|
||||
|
||||
305
vendor/github.com/miekg/dns/generate.go
сгенерированный
поставляемый
305
vendor/github.com/miekg/dns/generate.go
сгенерированный
поставляемый
@@ -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, ""
|
||||
}
|
||||
|
||||
3
vendor/github.com/miekg/dns/listen_go111.go
сгенерированный
поставляемый
3
vendor/github.com/miekg/dns/listen_go111.go
сгенерированный
поставляемый
@@ -1,4 +1,5 @@
|
||||
// +build go1.11,!windows
|
||||
// +build go1.11
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd
|
||||
|
||||
package dns
|
||||
|
||||
|
||||
2
vendor/github.com/miekg/dns/listen_go_not111.go
сгенерированный
поставляемый
2
vendor/github.com/miekg/dns/listen_go_not111.go
сгенерированный
поставляемый
@@ -1,4 +1,4 @@
|
||||
// +build !go1.11 windows
|
||||
// +build !go1.11 !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd
|
||||
|
||||
package dns
|
||||
|
||||
|
||||
647
vendor/github.com/miekg/dns/msg.go
сгенерированный
поставляемый
647
vendor/github.com/miekg/dns/msg.go
сгенерированный
поставляемый
@@ -9,7 +9,6 @@
|
||||
package dns
|
||||
|
||||
//go:generate go run msg_generate.go
|
||||
//go:generate go run compress_generate.go
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
@@ -18,12 +17,35 @@ import (
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
maxCompressionOffset = 2 << 13 // We have 14 bits for the compression pointer
|
||||
maxDomainNameWireOctets = 255 // See RFC 1035 section 2.3.4
|
||||
|
||||
// This is the maximum number of compression pointers that should occur in a
|
||||
// semantically valid message. Each label in a domain name must be at least one
|
||||
// octet and is separated by a period. The root label won't be represented by a
|
||||
// compression pointer to a compression pointer, hence the -2 to exclude the
|
||||
// smallest valid root label.
|
||||
//
|
||||
// It is possible to construct a valid message that has more compression pointers
|
||||
// than this, and still doesn't loop, by pointing to a previous pointer. This is
|
||||
// not something a well written implementation should ever do, so we leave them
|
||||
// to trip the maximum compression pointer check.
|
||||
maxCompressionPointers = (maxDomainNameWireOctets+1)/2 - 2
|
||||
|
||||
// This is the maximum length of a domain name in presentation format. The
|
||||
// maximum wire length of a domain name is 255 octets (see above), with the
|
||||
// maximum label length being 63. The wire format requires one extra byte over
|
||||
// the presentation format, reducing the number of octets by 1. Each label in
|
||||
// the name will be separated by a single period, with each octet in the label
|
||||
// expanding to at most 4 bytes (\DDD). If all other labels are of the maximum
|
||||
// length, then the final label can only be 61 octets long to not exceed the
|
||||
// maximum allowed wire length.
|
||||
maxDomainNamePresentationLength = 61*4 + 1 + 63*4 + 1 + 63*4 + 1 + 63*4 + 1
|
||||
)
|
||||
|
||||
// Errors defined in this package.
|
||||
@@ -46,10 +68,9 @@ var (
|
||||
ErrRRset error = &Error{err: "bad rrset"}
|
||||
ErrSecret error = &Error{err: "no secrets defined"}
|
||||
ErrShortRead error = &Error{err: "short read"}
|
||||
ErrSig error = &Error{err: "bad signature"} // ErrSig indicates that a signature can not be cryptographically validated.
|
||||
ErrSoa error = &Error{err: "no SOA"} // ErrSOA indicates that no SOA RR was seen when doing zone transfers.
|
||||
ErrTime error = &Error{err: "bad time"} // ErrTime indicates a timing error in TSIG authentication.
|
||||
ErrTruncated error = &Error{err: "failed to unpack truncated message"} // ErrTruncated indicates that we failed to unpack a truncated message. We unpacked as much as we had so Msg can still be used, if desired.
|
||||
ErrSig error = &Error{err: "bad signature"} // ErrSig indicates that a signature can not be cryptographically validated.
|
||||
ErrSoa error = &Error{err: "no SOA"} // ErrSOA indicates that no SOA RR was seen when doing zone transfers.
|
||||
ErrTime error = &Error{err: "bad time"} // ErrTime indicates a timing error in TSIG authentication.
|
||||
)
|
||||
|
||||
// Id by default, returns a 16 bits random number to be used as a
|
||||
@@ -151,7 +172,7 @@ var RcodeToString = map[int]string{
|
||||
RcodeFormatError: "FORMERR",
|
||||
RcodeServerFailure: "SERVFAIL",
|
||||
RcodeNameError: "NXDOMAIN",
|
||||
RcodeNotImplemented: "NOTIMPL",
|
||||
RcodeNotImplemented: "NOTIMP",
|
||||
RcodeRefused: "REFUSED",
|
||||
RcodeYXDomain: "YXDOMAIN", // See RFC 2136
|
||||
RcodeYXRrset: "YXRRSET",
|
||||
@@ -169,6 +190,39 @@ var RcodeToString = map[int]string{
|
||||
RcodeBadCookie: "BADCOOKIE",
|
||||
}
|
||||
|
||||
// compressionMap is used to allow a more efficient compression map
|
||||
// to be used for internal packDomainName calls without changing the
|
||||
// signature or functionality of public API.
|
||||
//
|
||||
// In particular, map[string]uint16 uses 25% less per-entry memory
|
||||
// than does map[string]int.
|
||||
type compressionMap struct {
|
||||
ext map[string]int // external callers
|
||||
int map[string]uint16 // internal callers
|
||||
}
|
||||
|
||||
func (m compressionMap) valid() bool {
|
||||
return m.int != nil || m.ext != nil
|
||||
}
|
||||
|
||||
func (m compressionMap) insert(s string, pos int) {
|
||||
if m.ext != nil {
|
||||
m.ext[s] = pos
|
||||
} else {
|
||||
m.int[s] = uint16(pos)
|
||||
}
|
||||
}
|
||||
|
||||
func (m compressionMap) find(s string) (int, bool) {
|
||||
if m.ext != nil {
|
||||
pos, ok := m.ext[s]
|
||||
return pos, ok
|
||||
}
|
||||
|
||||
pos, ok := m.int[s]
|
||||
return int(pos), ok
|
||||
}
|
||||
|
||||
// Domain names are a sequence of counted strings
|
||||
// split at the dots. They end with a zero-length string.
|
||||
|
||||
@@ -177,143 +231,168 @@ var RcodeToString = map[int]string{
|
||||
// map needs to hold a mapping between domain names and offsets
|
||||
// pointing into msg.
|
||||
func PackDomainName(s string, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
|
||||
off1, _, err = packDomainName(s, msg, off, compression, compress)
|
||||
off1, _, err = packDomainName(s, msg, off, compressionMap{ext: compression}, compress)
|
||||
return
|
||||
}
|
||||
|
||||
func packDomainName(s string, msg []byte, off int, compression map[string]int, compress bool) (off1 int, labels int, err error) {
|
||||
func packDomainName(s string, msg []byte, off int, compression compressionMap, compress bool) (off1 int, labels int, err error) {
|
||||
// special case if msg == nil
|
||||
lenmsg := 256
|
||||
if msg != nil {
|
||||
lenmsg = len(msg)
|
||||
}
|
||||
|
||||
ls := len(s)
|
||||
if ls == 0 { // Ok, for instance when dealing with update RR without any rdata.
|
||||
return off, 0, nil
|
||||
}
|
||||
// If not fully qualified, error out, but only if msg == nil #ugly
|
||||
switch {
|
||||
case msg == nil:
|
||||
if s[ls-1] != '.' {
|
||||
s += "."
|
||||
ls++
|
||||
}
|
||||
case msg != nil:
|
||||
if s[ls-1] != '.' {
|
||||
|
||||
// If not fully qualified, error out, but only if msg != nil #ugly
|
||||
if s[ls-1] != '.' {
|
||||
if msg != nil {
|
||||
return lenmsg, 0, ErrFqdn
|
||||
}
|
||||
s += "."
|
||||
ls++
|
||||
}
|
||||
|
||||
// Each dot ends a segment of the name.
|
||||
// We trade each dot byte for a length byte.
|
||||
// Except for escaped dots (\.), which are normal dots.
|
||||
// There is also a trailing zero.
|
||||
|
||||
// Compression
|
||||
nameoffset := -1
|
||||
pointer := -1
|
||||
|
||||
// Emit sequence of counted strings, chopping at dots.
|
||||
begin := 0
|
||||
bs := []byte(s)
|
||||
roBs, bsFresh, escapedDot := s, true, false
|
||||
var (
|
||||
begin int
|
||||
compBegin int
|
||||
compOff int
|
||||
bs []byte
|
||||
wasDot bool
|
||||
)
|
||||
loop:
|
||||
for i := 0; i < ls; i++ {
|
||||
if bs[i] == '\\' {
|
||||
for j := i; j < ls-1; j++ {
|
||||
bs[j] = bs[j+1]
|
||||
}
|
||||
ls--
|
||||
var c byte
|
||||
if bs == nil {
|
||||
c = s[i]
|
||||
} else {
|
||||
c = bs[i]
|
||||
}
|
||||
|
||||
switch c {
|
||||
case '\\':
|
||||
if off+1 > lenmsg {
|
||||
return lenmsg, labels, ErrBuf
|
||||
}
|
||||
// check for \DDD
|
||||
if i+2 < ls && isDigit(bs[i]) && isDigit(bs[i+1]) && isDigit(bs[i+2]) {
|
||||
bs[i] = dddToByte(bs[i:])
|
||||
for j := i + 1; j < ls-2; j++ {
|
||||
bs[j] = bs[j+2]
|
||||
}
|
||||
ls -= 2
|
||||
}
|
||||
escapedDot = bs[i] == '.'
|
||||
bsFresh = false
|
||||
continue
|
||||
}
|
||||
|
||||
if bs[i] == '.' {
|
||||
if i > 0 && bs[i-1] == '.' && !escapedDot {
|
||||
if bs == nil {
|
||||
bs = []byte(s)
|
||||
}
|
||||
|
||||
// check for \DDD
|
||||
if i+3 < ls && isDigit(bs[i+1]) && isDigit(bs[i+2]) && isDigit(bs[i+3]) {
|
||||
bs[i] = dddToByte(bs[i+1:])
|
||||
copy(bs[i+1:ls-3], bs[i+4:])
|
||||
ls -= 3
|
||||
compOff += 3
|
||||
} else {
|
||||
copy(bs[i:ls-1], bs[i+1:])
|
||||
ls--
|
||||
compOff++
|
||||
}
|
||||
|
||||
wasDot = false
|
||||
case '.':
|
||||
if wasDot {
|
||||
// two dots back to back is not legal
|
||||
return lenmsg, labels, ErrRdata
|
||||
}
|
||||
if i-begin >= 1<<6 { // top two bits of length must be clear
|
||||
wasDot = true
|
||||
|
||||
labelLen := i - begin
|
||||
if labelLen >= 1<<6 { // top two bits of length must be clear
|
||||
return lenmsg, labels, ErrRdata
|
||||
}
|
||||
|
||||
// off can already (we're in a loop) be bigger than len(msg)
|
||||
// this happens when a name isn't fully qualified
|
||||
if off+1 > lenmsg {
|
||||
if off+1+labelLen > lenmsg {
|
||||
return lenmsg, labels, ErrBuf
|
||||
}
|
||||
if msg != nil {
|
||||
msg[off] = byte(i - begin)
|
||||
}
|
||||
offset := off
|
||||
off++
|
||||
for j := begin; j < i; j++ {
|
||||
if off+1 > lenmsg {
|
||||
return lenmsg, labels, ErrBuf
|
||||
}
|
||||
if msg != nil {
|
||||
msg[off] = bs[j]
|
||||
}
|
||||
off++
|
||||
}
|
||||
if compress && !bsFresh {
|
||||
roBs = string(bs)
|
||||
bsFresh = true
|
||||
}
|
||||
|
||||
// Don't try to compress '.'
|
||||
// We should only compress when compress it true, but we should also still pick
|
||||
// We should only compress when compress is true, but we should also still pick
|
||||
// up names that can be used for *future* compression(s).
|
||||
if compression != nil && roBs[begin:] != "." {
|
||||
if p, ok := compression[roBs[begin:]]; !ok {
|
||||
// Only offsets smaller than this can be used.
|
||||
if offset < maxCompressionOffset {
|
||||
compression[roBs[begin:]] = offset
|
||||
}
|
||||
} else {
|
||||
if compression.valid() && !isRootLabel(s, bs, begin, ls) {
|
||||
if p, ok := compression.find(s[compBegin:]); ok {
|
||||
// The first hit is the longest matching dname
|
||||
// keep the pointer offset we get back and store
|
||||
// the offset of the current name, because that's
|
||||
// where we need to insert the pointer later
|
||||
|
||||
// If compress is true, we're allowed to compress this dname
|
||||
if pointer == -1 && compress {
|
||||
pointer = p // Where to point to
|
||||
nameoffset = offset // Where to point from
|
||||
break
|
||||
if compress {
|
||||
pointer = p // Where to point to
|
||||
break loop
|
||||
}
|
||||
} else if off < maxCompressionOffset {
|
||||
// Only offsets smaller than maxCompressionOffset can be used.
|
||||
compression.insert(s[compBegin:], off)
|
||||
}
|
||||
}
|
||||
|
||||
// The following is covered by the length check above.
|
||||
if msg != nil {
|
||||
msg[off] = byte(labelLen)
|
||||
|
||||
if bs == nil {
|
||||
copy(msg[off+1:], s[begin:i])
|
||||
} else {
|
||||
copy(msg[off+1:], bs[begin:i])
|
||||
}
|
||||
}
|
||||
off += 1 + labelLen
|
||||
|
||||
labels++
|
||||
begin = i + 1
|
||||
compBegin = begin + compOff
|
||||
default:
|
||||
wasDot = false
|
||||
}
|
||||
escapedDot = false
|
||||
}
|
||||
|
||||
// Root label is special
|
||||
if len(bs) == 1 && bs[0] == '.' {
|
||||
if isRootLabel(s, bs, 0, ls) {
|
||||
return off, labels, nil
|
||||
}
|
||||
|
||||
// If we did compression and we find something add the pointer here
|
||||
if pointer != -1 {
|
||||
// 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))
|
||||
off = nameoffset + 1
|
||||
goto End
|
||||
binary.BigEndian.PutUint16(msg[off:], uint16(pointer^0xC000))
|
||||
return off + 2, labels, nil
|
||||
}
|
||||
if msg != nil && off < len(msg) {
|
||||
|
||||
if msg != nil && off < lenmsg {
|
||||
msg[off] = 0
|
||||
}
|
||||
End:
|
||||
off++
|
||||
return off, labels, nil
|
||||
|
||||
return off + 1, labels, nil
|
||||
}
|
||||
|
||||
// isRootLabel returns whether s or bs, from off to end, is the root
|
||||
// label ".".
|
||||
//
|
||||
// If bs is nil, s will be checked, otherwise bs will be checked.
|
||||
func isRootLabel(s string, bs []byte, off, end int) bool {
|
||||
if bs == nil {
|
||||
return s[off:end] == "."
|
||||
}
|
||||
|
||||
return end-off == 1 && bs[off] == '.'
|
||||
}
|
||||
|
||||
// Unpack a domain name.
|
||||
@@ -330,12 +409,16 @@ End:
|
||||
// In theory, the pointers are only allowed to jump backward.
|
||||
// We let them jump anywhere and stop jumping after a while.
|
||||
|
||||
// UnpackDomainName unpacks a domain name into a string.
|
||||
// UnpackDomainName unpacks a domain name into a string. It returns
|
||||
// the name, the new offset into msg and any error that occurred.
|
||||
//
|
||||
// When an error is encountered, the unpacked name will be discarded
|
||||
// and len(msg) will be returned as the offset.
|
||||
func UnpackDomainName(msg []byte, off int) (string, int, error) {
|
||||
s := make([]byte, 0, 64)
|
||||
s := make([]byte, 0, maxDomainNamePresentationLength)
|
||||
off1 := 0
|
||||
lenmsg := len(msg)
|
||||
maxLen := maxDomainNameWireOctets
|
||||
budget := maxDomainNameWireOctets
|
||||
ptr := 0 // number of pointers followed
|
||||
Loop:
|
||||
for {
|
||||
@@ -354,27 +437,19 @@ Loop:
|
||||
if off+c > lenmsg {
|
||||
return "", lenmsg, ErrBuf
|
||||
}
|
||||
budget -= c + 1 // +1 for the label separator
|
||||
if budget <= 0 {
|
||||
return "", lenmsg, ErrLongDomain
|
||||
}
|
||||
for j := off; j < off+c; j++ {
|
||||
switch b := msg[j]; b {
|
||||
case '.', '(', ')', ';', ' ', '@':
|
||||
fallthrough
|
||||
case '"', '\\':
|
||||
s = append(s, '\\', b)
|
||||
// presentation-format \X escapes add an extra byte
|
||||
maxLen++
|
||||
default:
|
||||
if b < 32 || b >= 127 { // unprintable, use \DDD
|
||||
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')
|
||||
}
|
||||
for _, r := range bufs {
|
||||
s = append(s, r)
|
||||
}
|
||||
// presentation-format \DDD escapes add 3 extra bytes
|
||||
maxLen += 3
|
||||
if b < ' ' || b > '~' { // unprintable, use \DDD
|
||||
s = append(s, escapeByte(b)...)
|
||||
} else {
|
||||
s = append(s, b)
|
||||
}
|
||||
@@ -396,7 +471,7 @@ Loop:
|
||||
if ptr == 0 {
|
||||
off1 = off
|
||||
}
|
||||
if ptr++; ptr > 10 {
|
||||
if ptr++; ptr > maxCompressionPointers {
|
||||
return "", lenmsg, &Error{err: "too many compression pointers"}
|
||||
}
|
||||
// pointer should guarantee that it advances and points forwards at least
|
||||
@@ -412,10 +487,7 @@ Loop:
|
||||
off1 = off
|
||||
}
|
||||
if len(s) == 0 {
|
||||
s = []byte(".")
|
||||
} else if len(s) >= maxLen {
|
||||
// error if the name is too long, but don't throw it away
|
||||
return string(s), lenmsg, ErrLongDomain
|
||||
return ".", off1, nil
|
||||
}
|
||||
return string(s), off1, nil
|
||||
}
|
||||
@@ -512,7 +584,7 @@ func unpackTxt(msg []byte, off0 int) (ss []string, off int, err error) {
|
||||
off = off0
|
||||
var s string
|
||||
for off < len(msg) && err == nil {
|
||||
s, off, err = unpackTxtString(msg, off)
|
||||
s, off, err = unpackString(msg, off)
|
||||
if err == nil {
|
||||
ss = append(ss, s)
|
||||
}
|
||||
@@ -520,43 +592,16 @@ func unpackTxt(msg []byte, off0 int) (ss []string, off int, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func unpackTxtString(msg []byte, offset int) (string, int, error) {
|
||||
if offset+1 > len(msg) {
|
||||
return "", offset, &Error{err: "overflow unpacking txt"}
|
||||
}
|
||||
l := int(msg[offset])
|
||||
if offset+l+1 > len(msg) {
|
||||
return "", offset, &Error{err: "overflow unpacking txt"}
|
||||
}
|
||||
s := make([]byte, 0, l)
|
||||
for _, b := range msg[offset+1 : offset+1+l] {
|
||||
switch b {
|
||||
case '"', '\\':
|
||||
s = append(s, '\\', b)
|
||||
default:
|
||||
if b < 32 || b > 127 { // unprintable
|
||||
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')
|
||||
}
|
||||
for _, r := range bufs {
|
||||
s = append(s, r)
|
||||
}
|
||||
} else {
|
||||
s = append(s, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
offset += 1 + l
|
||||
return string(s), offset, nil
|
||||
}
|
||||
|
||||
// Helpers for dealing with escaped bytes
|
||||
func isDigit(b byte) bool { return b >= '0' && b <= '9' }
|
||||
|
||||
func dddToByte(s []byte) byte {
|
||||
_ = s[2] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return byte((s[0]-'0')*100 + (s[1]-'0')*10 + (s[2] - '0'))
|
||||
}
|
||||
|
||||
func dddStringToByte(s string) byte {
|
||||
_ = s[2] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return byte((s[0]-'0')*100 + (s[1]-'0')*10 + (s[2] - '0'))
|
||||
}
|
||||
|
||||
@@ -574,19 +619,33 @@ func intToBytes(i *big.Int, length int) []byte {
|
||||
// PackRR packs a resource record rr into msg[off:].
|
||||
// See PackDomainName for documentation about the compression.
|
||||
func PackRR(rr RR, msg []byte, off int, compression map[string]int, compress bool) (off1 int, err error) {
|
||||
headerEnd, off1, err := packRR(rr, msg, off, compressionMap{ext: compression}, compress)
|
||||
if err == nil {
|
||||
// packRR no longer sets the Rdlength field on the rr, but
|
||||
// callers might be expecting it so we set it here.
|
||||
rr.Header().Rdlength = uint16(off1 - headerEnd)
|
||||
}
|
||||
return off1, err
|
||||
}
|
||||
|
||||
func packRR(rr RR, msg []byte, off int, compression compressionMap, compress bool) (headerEnd int, off1 int, err error) {
|
||||
if rr == nil {
|
||||
return len(msg), &Error{err: "nil rr"}
|
||||
return len(msg), len(msg), &Error{err: "nil rr"}
|
||||
}
|
||||
|
||||
off1, err = rr.pack(msg, off, compression, compress)
|
||||
headerEnd, off1, err = rr.pack(msg, off, compression, compress)
|
||||
if err != nil {
|
||||
return len(msg), err
|
||||
return headerEnd, len(msg), err
|
||||
}
|
||||
// TODO(miek): Not sure if this is needed? If removed we can remove rawmsg.go as well.
|
||||
if rawSetRdlength(msg, off, off1) {
|
||||
return off1, nil
|
||||
|
||||
rdlength := off1 - headerEnd
|
||||
if int(uint16(rdlength)) != rdlength { // overflow
|
||||
return headerEnd, len(msg), ErrRdata
|
||||
}
|
||||
return off, ErrRdata
|
||||
|
||||
// The RDLENGTH field is the last field in the header and we set it here.
|
||||
binary.BigEndian.PutUint16(msg[headerEnd-2:], uint16(rdlength))
|
||||
return headerEnd, off1, nil
|
||||
}
|
||||
|
||||
// UnpackRR unpacks msg[off:] into an RR.
|
||||
@@ -693,32 +752,33 @@ func (dns *Msg) Pack() (msg []byte, err error) {
|
||||
|
||||
// PackBuffer packs a Msg, using the given buffer buf. If buf is too small a new buffer is allocated.
|
||||
func (dns *Msg) PackBuffer(buf []byte) (msg []byte, err error) {
|
||||
var compression map[string]int
|
||||
if dns.Compress {
|
||||
compression = make(map[string]int) // Compression pointer mappings.
|
||||
// If this message can't be compressed, avoid filling the
|
||||
// compression map and creating garbage.
|
||||
if dns.Compress && dns.isCompressible() {
|
||||
compression := make(map[string]uint16) // Compression pointer mappings.
|
||||
return dns.packBufferWithCompressionMap(buf, compressionMap{int: compression}, true)
|
||||
}
|
||||
return dns.packBufferWithCompressionMap(buf, compression)
|
||||
|
||||
return dns.packBufferWithCompressionMap(buf, compressionMap{}, false)
|
||||
}
|
||||
|
||||
// packBufferWithCompressionMap packs a Msg, using the given buffer buf.
|
||||
func (dns *Msg) packBufferWithCompressionMap(buf []byte, compression map[string]int) (msg []byte, err error) {
|
||||
// We use a similar function in tsig.go's stripTsig.
|
||||
|
||||
var dh Header
|
||||
|
||||
func (dns *Msg) packBufferWithCompressionMap(buf []byte, compression compressionMap, compress bool) (msg []byte, err error) {
|
||||
if dns.Rcode < 0 || dns.Rcode > 0xFFF {
|
||||
return nil, ErrRcode
|
||||
}
|
||||
if dns.Rcode > 0xF {
|
||||
// Regular RCODE field is 4 bits
|
||||
opt := dns.IsEdns0()
|
||||
if opt == nil {
|
||||
return nil, ErrExtendedRcode
|
||||
}
|
||||
opt.SetExtendedRcode(uint8(dns.Rcode >> 4))
|
||||
|
||||
// Set extended rcode unconditionally if we have an opt, this will allow
|
||||
// reseting the extended rcode bits if they need to.
|
||||
if opt := dns.IsEdns0(); opt != nil {
|
||||
opt.SetExtendedRcode(uint16(dns.Rcode))
|
||||
} else if dns.Rcode > 0xF {
|
||||
// If Rcode is an extended one and opt is nil, error out.
|
||||
return nil, ErrExtendedRcode
|
||||
}
|
||||
|
||||
// Convert convenient Msg into wire-like Header.
|
||||
var dh Header
|
||||
dh.Id = dns.Id
|
||||
dh.Bits = uint16(dns.Opcode)<<11 | uint16(dns.Rcode&0xF)
|
||||
if dns.Response {
|
||||
@@ -746,50 +806,44 @@ func (dns *Msg) packBufferWithCompressionMap(buf []byte, compression map[string]
|
||||
dh.Bits |= _CD
|
||||
}
|
||||
|
||||
// Prepare variable sized arrays.
|
||||
question := dns.Question
|
||||
answer := dns.Answer
|
||||
ns := dns.Ns
|
||||
extra := dns.Extra
|
||||
|
||||
dh.Qdcount = uint16(len(question))
|
||||
dh.Ancount = uint16(len(answer))
|
||||
dh.Nscount = uint16(len(ns))
|
||||
dh.Arcount = uint16(len(extra))
|
||||
dh.Qdcount = uint16(len(dns.Question))
|
||||
dh.Ancount = uint16(len(dns.Answer))
|
||||
dh.Nscount = uint16(len(dns.Ns))
|
||||
dh.Arcount = uint16(len(dns.Extra))
|
||||
|
||||
// We need the uncompressed length here, because we first pack it and then compress it.
|
||||
msg = buf
|
||||
uncompressedLen := compressedLen(dns, false)
|
||||
uncompressedLen := msgLenWithCompressionMap(dns, nil)
|
||||
if packLen := uncompressedLen + 1; len(msg) < packLen {
|
||||
msg = make([]byte, packLen)
|
||||
}
|
||||
|
||||
// Pack it in: header and then the pieces.
|
||||
off := 0
|
||||
off, err = dh.pack(msg, off, compression, dns.Compress)
|
||||
off, err = dh.pack(msg, off, compression, compress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for i := 0; i < len(question); i++ {
|
||||
off, err = question[i].pack(msg, off, compression, dns.Compress)
|
||||
for _, r := range dns.Question {
|
||||
off, err = r.pack(msg, off, compression, compress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(answer); i++ {
|
||||
off, err = PackRR(answer[i], msg, off, compression, dns.Compress)
|
||||
for _, r := range dns.Answer {
|
||||
_, off, err = packRR(r, msg, off, compression, compress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(ns); i++ {
|
||||
off, err = PackRR(ns[i], msg, off, compression, dns.Compress)
|
||||
for _, r := range dns.Ns {
|
||||
_, off, err = packRR(r, msg, off, compression, compress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(extra); i++ {
|
||||
off, err = PackRR(extra[i], msg, off, compression, dns.Compress)
|
||||
for _, r := range dns.Extra {
|
||||
_, off, err = packRR(r, msg, off, compression, compress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -797,28 +851,7 @@ func (dns *Msg) packBufferWithCompressionMap(buf []byte, compression map[string]
|
||||
return msg[:off], nil
|
||||
}
|
||||
|
||||
// Unpack unpacks a binary message to a Msg structure.
|
||||
func (dns *Msg) Unpack(msg []byte) (err error) {
|
||||
var (
|
||||
dh Header
|
||||
off int
|
||||
)
|
||||
if dh, off, err = unpackMsgHdr(msg, off); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dns.Id = dh.Id
|
||||
dns.Response = dh.Bits&_QR != 0
|
||||
dns.Opcode = int(dh.Bits>>11) & 0xF
|
||||
dns.Authoritative = dh.Bits&_AA != 0
|
||||
dns.Truncated = dh.Bits&_TC != 0
|
||||
dns.RecursionDesired = dh.Bits&_RD != 0
|
||||
dns.RecursionAvailable = dh.Bits&_RA != 0
|
||||
dns.Zero = dh.Bits&_Z != 0
|
||||
dns.AuthenticatedData = dh.Bits&_AD != 0
|
||||
dns.CheckingDisabled = dh.Bits&_CD != 0
|
||||
dns.Rcode = int(dh.Bits & 0xF)
|
||||
|
||||
func (dns *Msg) unpack(dh Header, msg []byte, off int) (err error) {
|
||||
// If we are at the end of the message we should return *just* the
|
||||
// header. This can still be useful to the caller. 9.9.9.9 sends these
|
||||
// when responding with REFUSED for instance.
|
||||
@@ -837,8 +870,6 @@ func (dns *Msg) Unpack(msg []byte) (err error) {
|
||||
var q Question
|
||||
q, off, err = unpackQuestion(msg, off)
|
||||
if err != nil {
|
||||
// Even if Truncated is set, we only will set ErrTruncated if we
|
||||
// actually got the questions
|
||||
return err
|
||||
}
|
||||
if off1 == off { // Offset does not increase anymore, dh.Qdcount is a lie!
|
||||
@@ -862,16 +893,29 @@ func (dns *Msg) Unpack(msg []byte) (err error) {
|
||||
// The header counts might have been wrong so we need to update it
|
||||
dh.Arcount = uint16(len(dns.Extra))
|
||||
|
||||
// Set extended Rcode
|
||||
if opt := dns.IsEdns0(); opt != nil {
|
||||
dns.Rcode |= opt.ExtendedRcode()
|
||||
}
|
||||
|
||||
if off != len(msg) {
|
||||
// TODO(miek) make this an error?
|
||||
// use PackOpt to let people tell how detailed the error reporting should be?
|
||||
// println("dns: extra bytes in dns packet", off, "<", len(msg))
|
||||
} else if dns.Truncated {
|
||||
// Whether we ran into a an error or not, we want to return that it
|
||||
// was truncated
|
||||
err = ErrTruncated
|
||||
}
|
||||
return err
|
||||
|
||||
}
|
||||
|
||||
// Unpack unpacks a binary message to a Msg structure.
|
||||
func (dns *Msg) Unpack(msg []byte) (err error) {
|
||||
dh, off, err := unpackMsgHdr(msg, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dns.setHdr(dh)
|
||||
return dns.unpack(dh, msg, off)
|
||||
}
|
||||
|
||||
// Convert a complete message to a string with dig-like output.
|
||||
@@ -917,151 +961,117 @@ func (dns *Msg) String() string {
|
||||
return s
|
||||
}
|
||||
|
||||
// isCompressible returns whether the msg may be compressible.
|
||||
func (dns *Msg) isCompressible() bool {
|
||||
// If we only have one question, there is nothing we can ever compress.
|
||||
return len(dns.Question) > 1 || len(dns.Answer) > 0 ||
|
||||
len(dns.Ns) > 0 || len(dns.Extra) > 0
|
||||
}
|
||||
|
||||
// Len returns the message length when in (un)compressed wire format.
|
||||
// If dns.Compress is true compression it is taken into account. Len()
|
||||
// is provided to be a faster way to get the size of the resulting packet,
|
||||
// than packing it, measuring the size and discarding the buffer.
|
||||
func (dns *Msg) Len() int { return compressedLen(dns, dns.Compress) }
|
||||
|
||||
func compressedLenWithCompressionMap(dns *Msg, compression map[string]int) int {
|
||||
l := 12 // Message header is always 12 bytes
|
||||
for _, r := range dns.Question {
|
||||
compressionLenHelper(compression, r.Name, l)
|
||||
l += r.len()
|
||||
func (dns *Msg) Len() int {
|
||||
// If this message can't be compressed, avoid filling the
|
||||
// compression map and creating garbage.
|
||||
if dns.Compress && dns.isCompressible() {
|
||||
compression := make(map[string]struct{})
|
||||
return msgLenWithCompressionMap(dns, compression)
|
||||
}
|
||||
l += compressionLenSlice(l, compression, dns.Answer)
|
||||
l += compressionLenSlice(l, compression, dns.Ns)
|
||||
l += compressionLenSlice(l, compression, dns.Extra)
|
||||
return l
|
||||
|
||||
return msgLenWithCompressionMap(dns, nil)
|
||||
}
|
||||
|
||||
// compressedLen returns the message length when in compressed wire format
|
||||
// when compress is true, otherwise the uncompressed length is returned.
|
||||
func compressedLen(dns *Msg, compress bool) int {
|
||||
// We always return one more than needed.
|
||||
if compress {
|
||||
compression := map[string]int{}
|
||||
return compressedLenWithCompressionMap(dns, compression)
|
||||
}
|
||||
func msgLenWithCompressionMap(dns *Msg, compression map[string]struct{}) int {
|
||||
l := 12 // Message header is always 12 bytes
|
||||
|
||||
for _, r := range dns.Question {
|
||||
l += r.len()
|
||||
l += r.len(l, compression)
|
||||
}
|
||||
for _, r := range dns.Answer {
|
||||
if r != nil {
|
||||
l += r.len()
|
||||
l += r.len(l, compression)
|
||||
}
|
||||
}
|
||||
for _, r := range dns.Ns {
|
||||
if r != nil {
|
||||
l += r.len()
|
||||
l += r.len(l, compression)
|
||||
}
|
||||
}
|
||||
for _, r := range dns.Extra {
|
||||
if r != nil {
|
||||
l += r.len()
|
||||
l += r.len(l, compression)
|
||||
}
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
||||
|
||||
func compressionLenSlice(lenp int, c map[string]int, rs []RR) int {
|
||||
initLen := lenp
|
||||
for _, r := range rs {
|
||||
if r == nil {
|
||||
func domainNameLen(s string, off int, compression map[string]struct{}, compress bool) int {
|
||||
if s == "" || s == "." {
|
||||
return 1
|
||||
}
|
||||
|
||||
escaped := strings.Contains(s, "\\")
|
||||
|
||||
if compression != nil && (compress || off < maxCompressionOffset) {
|
||||
// compressionLenSearch will insert the entry into the compression
|
||||
// map if it doesn't contain it.
|
||||
if l, ok := compressionLenSearch(compression, s, off); ok && compress {
|
||||
if escaped {
|
||||
return escapedNameLen(s[:l]) + 2
|
||||
}
|
||||
|
||||
return l + 2
|
||||
}
|
||||
}
|
||||
|
||||
if escaped {
|
||||
return escapedNameLen(s) + 1
|
||||
}
|
||||
|
||||
return len(s) + 1
|
||||
}
|
||||
|
||||
func escapedNameLen(s string) int {
|
||||
nameLen := len(s)
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] != '\\' {
|
||||
continue
|
||||
}
|
||||
// TmpLen is to track len of record at 14bits boudaries
|
||||
tmpLen := lenp
|
||||
|
||||
x := r.len()
|
||||
// track this length, and the global length in len, while taking compression into account for both.
|
||||
k, ok, _ := compressionLenSearch(c, r.Header().Name)
|
||||
if ok {
|
||||
// Size of x is reduced by k, but we add 1 since k includes the '.' and label descriptor take 2 bytes
|
||||
// so, basically x:= x - k - 1 + 2
|
||||
x += 1 - k
|
||||
}
|
||||
|
||||
tmpLen += compressionLenHelper(c, r.Header().Name, tmpLen)
|
||||
k, ok, _ = compressionLenSearchType(c, r)
|
||||
if ok {
|
||||
x += 1 - k
|
||||
}
|
||||
lenp += x
|
||||
tmpLen = lenp
|
||||
tmpLen += compressionLenHelperType(c, r, tmpLen)
|
||||
|
||||
}
|
||||
return lenp - initLen
|
||||
}
|
||||
|
||||
// Put the parts of the name in the compression map, return the size in bytes added in payload
|
||||
func compressionLenHelper(c map[string]int, s string, currentLen int) int {
|
||||
if currentLen > maxCompressionOffset {
|
||||
// We won't be able to add any label that could be re-used later anyway
|
||||
return 0
|
||||
}
|
||||
if _, ok := c[s]; ok {
|
||||
return 0
|
||||
}
|
||||
initLen := currentLen
|
||||
pref := ""
|
||||
prev := s
|
||||
lbs := Split(s)
|
||||
for j := 0; j < len(lbs); j++ {
|
||||
pref = s[lbs[j]:]
|
||||
currentLen += len(prev) - len(pref)
|
||||
prev = pref
|
||||
if _, ok := c[pref]; !ok {
|
||||
// If first byte label is within the first 14bits, it might be re-used later
|
||||
if currentLen < maxCompressionOffset {
|
||||
c[pref] = currentLen
|
||||
}
|
||||
if i+3 < len(s) && isDigit(s[i+1]) && isDigit(s[i+2]) && isDigit(s[i+3]) {
|
||||
nameLen -= 3
|
||||
i += 3
|
||||
} else {
|
||||
added := currentLen - initLen
|
||||
if j > 0 {
|
||||
// We added a new PTR
|
||||
added += 2
|
||||
}
|
||||
return added
|
||||
nameLen--
|
||||
i++
|
||||
}
|
||||
}
|
||||
return currentLen - initLen
|
||||
|
||||
return nameLen
|
||||
}
|
||||
|
||||
// Look for each part in the compression map and returns its length,
|
||||
// keep on searching so we get the longest match.
|
||||
// Will return the size of compression found, whether a match has been
|
||||
// found and the size of record if added in payload
|
||||
func compressionLenSearch(c map[string]int, s string) (int, bool, int) {
|
||||
off := 0
|
||||
end := false
|
||||
if s == "" { // don't bork on bogus data
|
||||
return 0, false, 0
|
||||
}
|
||||
fullSize := 0
|
||||
for {
|
||||
func compressionLenSearch(c map[string]struct{}, s string, msgOff int) (int, bool) {
|
||||
for off, end := 0, false; !end; off, end = NextLabel(s, off) {
|
||||
if _, ok := c[s[off:]]; ok {
|
||||
return len(s[off:]), true, fullSize + off
|
||||
return off, true
|
||||
}
|
||||
if end {
|
||||
break
|
||||
|
||||
if msgOff+off < maxCompressionOffset {
|
||||
c[s[off:]] = struct{}{}
|
||||
}
|
||||
// Each label descriptor takes 2 bytes, add it
|
||||
fullSize += 2
|
||||
off, end = NextLabel(s, off)
|
||||
}
|
||||
return 0, false, fullSize + len(s)
|
||||
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// Copy returns a new RR which is a deep-copy of r.
|
||||
func Copy(r RR) RR { r1 := r.copy(); return r1 }
|
||||
|
||||
// Len returns the length (in octets) of the uncompressed RR in wire format.
|
||||
func Len(r RR) int { return r.len() }
|
||||
func Len(r RR) int { return r.len(0, nil) }
|
||||
|
||||
// Copy returns a new *Msg which is a deep-copy of dns.
|
||||
func (dns *Msg) Copy() *Msg { return dns.CopyTo(new(Msg)) }
|
||||
@@ -1109,8 +1119,8 @@ func (dns *Msg) CopyTo(r1 *Msg) *Msg {
|
||||
return r1
|
||||
}
|
||||
|
||||
func (q *Question) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
|
||||
off, err := PackDomainName(q.Name, msg, off, compression, compress)
|
||||
func (q *Question) pack(msg []byte, off int, compression compressionMap, compress bool) (int, error) {
|
||||
off, _, err := packDomainName(q.Name, msg, off, compression, compress)
|
||||
if err != nil {
|
||||
return off, err
|
||||
}
|
||||
@@ -1151,7 +1161,7 @@ func unpackQuestion(msg []byte, off int) (Question, int, error) {
|
||||
return q, off, err
|
||||
}
|
||||
|
||||
func (dh *Header) pack(msg []byte, off int, compression map[string]int, compress bool) (int, error) {
|
||||
func (dh *Header) pack(msg []byte, off int, compression compressionMap, compress bool) (int, error) {
|
||||
off, err := packUint16(dh.Id, msg, off)
|
||||
if err != nil {
|
||||
return off, err
|
||||
@@ -1204,3 +1214,18 @@ func unpackMsgHdr(msg []byte, off int) (Header, int, error) {
|
||||
dh.Arcount, off, err = unpackUint16(msg, off)
|
||||
return dh, off, err
|
||||
}
|
||||
|
||||
// setHdr set the header in the dns using the binary data in dh.
|
||||
func (dns *Msg) setHdr(dh Header) {
|
||||
dns.Id = dh.Id
|
||||
dns.Response = dh.Bits&_QR != 0
|
||||
dns.Opcode = int(dh.Bits>>11) & 0xF
|
||||
dns.Authoritative = dh.Bits&_AA != 0
|
||||
dns.Truncated = dh.Bits&_TC != 0
|
||||
dns.RecursionDesired = dh.Bits&_RD != 0
|
||||
dns.RecursionAvailable = dh.Bits&_RA != 0
|
||||
dns.Zero = dh.Bits&_Z != 0 // _Z covers the zero bit, which should be zero; not sure why we set it to the opposite.
|
||||
dns.AuthenticatedData = dh.Bits&_AD != 0
|
||||
dns.CheckingDisabled = dh.Bits&_CD != 0
|
||||
dns.Rcode = int(dh.Bits & 0xF)
|
||||
}
|
||||
|
||||
21
vendor/github.com/miekg/dns/msg_generate.go
сгенерированный
поставляемый
21
vendor/github.com/miekg/dns/msg_generate.go
сгенерированный
поставляемый
@@ -80,18 +80,17 @@ 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)
|
||||
fmt.Fprintf(b, "func (rr *%s) pack(msg []byte, off int, compression compressionMap, compress bool) (int, int, error) {\n", name)
|
||||
fmt.Fprint(b, `headerEnd, off, err := rr.Hdr.pack(msg, off, compression, compress)
|
||||
if err != nil {
|
||||
return off, err
|
||||
return headerEnd, off, err
|
||||
}
|
||||
headerEnd := off
|
||||
`)
|
||||
for i := 1; i < st.NumFields(); i++ {
|
||||
o := func(s string) {
|
||||
fmt.Fprintf(b, s, st.Field(i).Name())
|
||||
fmt.Fprint(b, `if err != nil {
|
||||
return off, err
|
||||
return headerEnd, off, err
|
||||
}
|
||||
`)
|
||||
}
|
||||
@@ -106,7 +105,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 +115,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"`:
|
||||
@@ -145,7 +144,7 @@ return off, err
|
||||
if rr.%s != "-" {
|
||||
off, err = packStringHex(rr.%s, msg, off)
|
||||
if err != nil {
|
||||
return off, err
|
||||
return headerEnd, off, err
|
||||
}
|
||||
}
|
||||
`, field, field)
|
||||
@@ -176,9 +175,7 @@ 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")
|
||||
fmt.Fprintln(b, "return headerEnd, off, nil }\n")
|
||||
}
|
||||
|
||||
fmt.Fprint(b, "// unpack*() functions\n\n")
|
||||
|
||||
58
vendor/github.com/miekg/dns/msg_helpers.go
сгенерированный
поставляемый
58
vendor/github.com/miekg/dns/msg_helpers.go
сгенерированный
поставляемый
@@ -6,7 +6,7 @@ import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// helper functions called from the generated zmsg.go
|
||||
@@ -101,32 +101,32 @@ func unpackHeader(msg []byte, off int) (rr RR_Header, off1 int, truncmsg []byte,
|
||||
|
||||
// pack 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) pack(msg []byte, off int, compression compressionMap, compress bool) (int, int, error) {
|
||||
if off == len(msg) {
|
||||
return off, nil
|
||||
return off, 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
|
||||
return off, len(msg), err
|
||||
}
|
||||
off, err = packUint16(hdr.Rrtype, msg, off)
|
||||
if err != nil {
|
||||
return len(msg), err
|
||||
return off, len(msg), err
|
||||
}
|
||||
off, err = packUint16(hdr.Class, msg, off)
|
||||
if err != nil {
|
||||
return len(msg), err
|
||||
return off, len(msg), err
|
||||
}
|
||||
off, err = packUint32(hdr.Ttl, msg, off)
|
||||
if err != nil {
|
||||
return len(msg), err
|
||||
return off, 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
|
||||
return off, len(msg), err
|
||||
}
|
||||
return off, nil
|
||||
return off, off, nil
|
||||
}
|
||||
|
||||
// helper helper functions.
|
||||
@@ -223,8 +223,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
|
||||
}
|
||||
@@ -267,29 +267,21 @@ func unpackString(msg []byte, off int) (string, int, error) {
|
||||
if off+l+1 > len(msg) {
|
||||
return "", off, &Error{err: "overflow unpacking txt"}
|
||||
}
|
||||
s := make([]byte, 0, l)
|
||||
var s strings.Builder
|
||||
s.Grow(l)
|
||||
for _, b := range msg[off+1 : off+1+l] {
|
||||
switch b {
|
||||
case '"', '\\':
|
||||
s = append(s, '\\', b)
|
||||
switch {
|
||||
case b == '"' || b == '\\':
|
||||
s.WriteByte('\\')
|
||||
s.WriteByte(b)
|
||||
case b < ' ' || b > '~': // unprintable
|
||||
s.WriteString(escapeByte(b))
|
||||
default:
|
||||
if b < 32 || b > 127 { // unprintable
|
||||
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')
|
||||
}
|
||||
for _, r := range bufs {
|
||||
s = append(s, r)
|
||||
}
|
||||
} else {
|
||||
s = append(s, b)
|
||||
}
|
||||
s.WriteByte(b)
|
||||
}
|
||||
}
|
||||
off += 1 + l
|
||||
return string(s), off, nil
|
||||
return s.String(), off, nil
|
||||
}
|
||||
|
||||
func packString(s string, msg []byte, off int) (int, error) {
|
||||
@@ -629,10 +621,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)
|
||||
off, _, err = packDomainName(names[j], msg, off, compression, compress)
|
||||
if err != nil {
|
||||
return len(msg), err
|
||||
}
|
||||
|
||||
47
vendor/github.com/miekg/dns/nsecx.go
сгенерированный
поставляемый
47
vendor/github.com/miekg/dns/nsecx.go
сгенерированный
поставляемый
@@ -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
|
||||
}
|
||||
|
||||
27
vendor/github.com/miekg/dns/privaterr.go
сгенерированный
поставляемый
27
vendor/github.com/miekg/dns/privaterr.go
сгенерированный
поставляемый
@@ -52,7 +52,12 @@ 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)
|
||||
@@ -64,19 +69,18 @@ func (r *PrivateRR) copy() RR {
|
||||
}
|
||||
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)
|
||||
|
||||
func (r *PrivateRR) pack(msg []byte, off int, compression compressionMap, compress bool) (int, int, error) {
|
||||
headerEnd, off, err := r.Hdr.pack(msg, off, compression, compress)
|
||||
if err != nil {
|
||||
return off, err
|
||||
return off, off, err
|
||||
}
|
||||
headerEnd := off
|
||||
n, err := r.Data.Pack(msg[off:])
|
||||
if err != nil {
|
||||
return len(msg), err
|
||||
return headerEnd, len(msg), err
|
||||
}
|
||||
off += n
|
||||
r.Header().Rdlength = uint16(off - headerEnd)
|
||||
return off, nil
|
||||
return headerEnd, off, nil
|
||||
}
|
||||
|
||||
// PrivateHandle registers a private resource record type. It requires
|
||||
@@ -105,7 +109,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 +119,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:
|
||||
@@ -134,7 +138,7 @@ func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata)
|
||||
typeToparserFunc[rtype] = parserFunc{setPrivateRR, true}
|
||||
}
|
||||
|
||||
// PrivateHandleRemove removes defenitions required to support private RR type.
|
||||
// PrivateHandleRemove removes definitions required to support private RR type.
|
||||
func PrivateHandleRemove(rtype uint16) {
|
||||
rtypestr, ok := TypeToString[rtype]
|
||||
if ok {
|
||||
@@ -144,5 +148,4 @@ func PrivateHandleRemove(rtype uint16) {
|
||||
delete(StringToType, rtypestr)
|
||||
delete(typeToUnpack, rtype)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
49
vendor/github.com/miekg/dns/rawmsg.go
сгенерированный
поставляемый
49
vendor/github.com/miekg/dns/rawmsg.go
сгенерированный
поставляемый
@@ -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
|
||||
}
|
||||
5
vendor/github.com/miekg/dns/reverse.go
сгенерированный
поставляемый
5
vendor/github.com/miekg/dns/reverse.go
сгенерированный
поставляемый
@@ -12,6 +12,11 @@ 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
|
||||
}
|
||||
|
||||
// Reverse a map
|
||||
func reverseInt8(m map[uint8]string) map[string]uint8 {
|
||||
n := make(map[string]uint8, len(m))
|
||||
|
||||
1020
vendor/github.com/miekg/dns/scan.go
сгенерированный
поставляемый
1020
vendor/github.com/miekg/dns/scan.go
сгенерированный
поставляемый
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
730
vendor/github.com/miekg/dns/scan_rr.go
сгенерированный
поставляемый
730
vendor/github.com/miekg/dns/scan_rr.go
сгенерированный
поставляемый
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
56
vendor/github.com/miekg/dns/scanner.go
сгенерированный
поставляемый
56
vendor/github.com/miekg/dns/scanner.go
сгенерированный
поставляемый
@@ -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 == true {
|
||||
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
|
||||
}
|
||||
147
vendor/github.com/miekg/dns/serve_mux.go
сгенерированный
поставляемый
Обычный файл
147
vendor/github.com/miekg/dns/serve_mux.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,147 @@
|
||||
package dns
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// ServeMux is an DNS request multiplexer. It matches the zone name of
|
||||
// each incoming request against a list of registered patterns add calls
|
||||
// the handler for the pattern that most closely matches the zone name.
|
||||
//
|
||||
// ServeMux is DNSSEC aware, meaning that queries for the DS record are
|
||||
// redirected to the parent zone (if that is also registered), otherwise
|
||||
// the child gets the query.
|
||||
//
|
||||
// ServeMux is also safe for concurrent access from multiple goroutines.
|
||||
//
|
||||
// The zero ServeMux is empty and ready for use.
|
||||
type ServeMux struct {
|
||||
z map[string]Handler
|
||||
m sync.RWMutex
|
||||
}
|
||||
|
||||
// NewServeMux allocates and returns a new ServeMux.
|
||||
func NewServeMux() *ServeMux {
|
||||
return new(ServeMux)
|
||||
}
|
||||
|
||||
// DefaultServeMux is the default ServeMux used by Serve.
|
||||
var DefaultServeMux = NewServeMux()
|
||||
|
||||
func (mux *ServeMux) match(q string, t uint16) Handler {
|
||||
mux.m.RLock()
|
||||
defer mux.m.RUnlock()
|
||||
if mux.z == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
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 {
|
||||
return h
|
||||
}
|
||||
// Continue for DS to see if we have a parent too, if so delegate to the parent
|
||||
handler = h
|
||||
}
|
||||
}
|
||||
|
||||
// Wildcard match, if we have found nothing try the root zone as a last resort.
|
||||
if h, ok := mux.z["."]; ok {
|
||||
return h
|
||||
}
|
||||
|
||||
return handler
|
||||
}
|
||||
|
||||
// Handle adds a handler to the ServeMux for pattern.
|
||||
func (mux *ServeMux) Handle(pattern string, handler Handler) {
|
||||
if pattern == "" {
|
||||
panic("dns: invalid pattern " + pattern)
|
||||
}
|
||||
mux.m.Lock()
|
||||
if mux.z == nil {
|
||||
mux.z = make(map[string]Handler)
|
||||
}
|
||||
mux.z[Fqdn(pattern)] = handler
|
||||
mux.m.Unlock()
|
||||
}
|
||||
|
||||
// HandleFunc adds a handler function to the ServeMux for pattern.
|
||||
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
|
||||
mux.Handle(pattern, HandlerFunc(handler))
|
||||
}
|
||||
|
||||
// HandleRemove deregisters the handler specific for pattern from the ServeMux.
|
||||
func (mux *ServeMux) HandleRemove(pattern string) {
|
||||
if pattern == "" {
|
||||
panic("dns: invalid pattern " + pattern)
|
||||
}
|
||||
mux.m.Lock()
|
||||
delete(mux.z, Fqdn(pattern))
|
||||
mux.m.Unlock()
|
||||
}
|
||||
|
||||
// ServeDNS dispatches the request to the handler whose pattern most
|
||||
// closely matches the request message.
|
||||
//
|
||||
// ServeDNS is DNSSEC aware, meaning that queries for the DS record
|
||||
// are redirected to the parent zone (if that is also registered),
|
||||
// otherwise the child gets the query.
|
||||
//
|
||||
// If no handler is found, or there is no question, a standard SERVFAIL
|
||||
// message is returned
|
||||
func (mux *ServeMux) ServeDNS(w ResponseWriter, req *Msg) {
|
||||
var h Handler
|
||||
if len(req.Question) >= 1 { // allow more than one question
|
||||
h = mux.match(req.Question[0].Name, req.Question[0].Qtype)
|
||||
}
|
||||
|
||||
if h != nil {
|
||||
h.ServeDNS(w, req)
|
||||
} else {
|
||||
HandleFailed(w, req)
|
||||
}
|
||||
}
|
||||
|
||||
// Handle registers the handler with the given pattern
|
||||
// in the DefaultServeMux. The documentation for
|
||||
// ServeMux explains how patterns are matched.
|
||||
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
|
||||
|
||||
// HandleRemove deregisters the handle with the given pattern
|
||||
// in the DefaultServeMux.
|
||||
func HandleRemove(pattern string) { DefaultServeMux.HandleRemove(pattern) }
|
||||
|
||||
// HandleFunc registers the handler function with the given pattern
|
||||
// in the DefaultServeMux.
|
||||
func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
|
||||
DefaultServeMux.HandleFunc(pattern, handler)
|
||||
}
|
||||
264
vendor/github.com/miekg/dns/server.go
сгенерированный
поставляемый
264
vendor/github.com/miekg/dns/server.go
сгенерированный
поставляемый
@@ -41,6 +41,17 @@ type Handler interface {
|
||||
ServeDNS(w ResponseWriter, r *Msg)
|
||||
}
|
||||
|
||||
// The HandlerFunc type is an adapter to allow the use of
|
||||
// ordinary functions as DNS handlers. If f is a function
|
||||
// with the appropriate signature, HandlerFunc(f) is a
|
||||
// Handler object that calls f.
|
||||
type HandlerFunc func(ResponseWriter, *Msg)
|
||||
|
||||
// ServeDNS calls f(w, r).
|
||||
func (f HandlerFunc) ServeDNS(w ResponseWriter, r *Msg) {
|
||||
f(w, r)
|
||||
}
|
||||
|
||||
// A ResponseWriter interface is used by an DNS handler to
|
||||
// construct an DNS response.
|
||||
type ResponseWriter interface {
|
||||
@@ -71,9 +82,10 @@ type ConnectionStater interface {
|
||||
|
||||
type response struct {
|
||||
msg []byte
|
||||
closed bool // connection has been closed
|
||||
hijacked bool // connection has been hijacked by handler
|
||||
tsigStatus error
|
||||
tsigTimersOnly bool
|
||||
tsigStatus error
|
||||
tsigRequestMAC string
|
||||
tsigSecret map[string]string // the tsig secrets
|
||||
udp *net.UDPConn // i/o connection if UDP was used
|
||||
@@ -83,35 +95,6 @@ type response struct {
|
||||
wg *sync.WaitGroup // for gracefull shutdown
|
||||
}
|
||||
|
||||
// ServeMux is an DNS request multiplexer. It matches the
|
||||
// zone name of each incoming request against a list of
|
||||
// registered patterns add calls the handler for the pattern
|
||||
// that most closely matches the zone name. ServeMux is DNSSEC aware, meaning
|
||||
// that queries for the DS record are redirected to the parent zone (if that
|
||||
// is also registered), otherwise the child gets the query.
|
||||
// ServeMux is also safe for concurrent access from multiple goroutines.
|
||||
type ServeMux struct {
|
||||
z map[string]Handler
|
||||
m *sync.RWMutex
|
||||
}
|
||||
|
||||
// NewServeMux allocates and returns a new ServeMux.
|
||||
func NewServeMux() *ServeMux { return &ServeMux{z: make(map[string]Handler), m: new(sync.RWMutex)} }
|
||||
|
||||
// DefaultServeMux is the default ServeMux used by Serve.
|
||||
var DefaultServeMux = NewServeMux()
|
||||
|
||||
// The HandlerFunc type is an adapter to allow the use of
|
||||
// ordinary functions as DNS handlers. If f is a function
|
||||
// with the appropriate signature, HandlerFunc(f) is a
|
||||
// Handler object that calls f.
|
||||
type HandlerFunc func(ResponseWriter, *Msg)
|
||||
|
||||
// ServeDNS calls f(w, r).
|
||||
func (f HandlerFunc) ServeDNS(w ResponseWriter, r *Msg) {
|
||||
f(w, r)
|
||||
}
|
||||
|
||||
// HandleFailed returns a HandlerFunc that returns SERVFAIL for every request it gets.
|
||||
func HandleFailed(w ResponseWriter, r *Msg) {
|
||||
m := new(Msg)
|
||||
@@ -120,8 +103,6 @@ func HandleFailed(w ResponseWriter, r *Msg) {
|
||||
w.WriteMsg(m)
|
||||
}
|
||||
|
||||
func failedHandler() Handler { return HandlerFunc(HandleFailed) }
|
||||
|
||||
// ListenAndServe Starts a server on address and network specified Invoke handler
|
||||
// for incoming queries.
|
||||
func ListenAndServe(addr string, network string, handler Handler) error {
|
||||
@@ -160,99 +141,6 @@ func ActivateAndServe(l net.Listener, p net.PacketConn, handler Handler) error {
|
||||
return server.ActivateAndServe()
|
||||
}
|
||||
|
||||
func (mux *ServeMux) match(q string, t uint16) Handler {
|
||||
mux.m.RLock()
|
||||
defer mux.m.RUnlock()
|
||||
var handler Handler
|
||||
b := make([]byte, len(q)) // worst case, one label of length q
|
||||
off := 0
|
||||
end := false
|
||||
for {
|
||||
l := len(q[off:])
|
||||
for i := 0; i < l; i++ {
|
||||
b[i] = q[off+i]
|
||||
if b[i] >= 'A' && b[i] <= 'Z' {
|
||||
b[i] |= 'a' - 'A'
|
||||
}
|
||||
}
|
||||
if h, ok := mux.z[string(b[:l])]; ok { // causes garbage, might want to change the map key
|
||||
if t != TypeDS {
|
||||
return h
|
||||
}
|
||||
// Continue for DS to see if we have a parent too, if so delegeate to the parent
|
||||
handler = h
|
||||
}
|
||||
off, end = NextLabel(q, off)
|
||||
if end {
|
||||
break
|
||||
}
|
||||
}
|
||||
// Wildcard match, if we have found nothing try the root zone as a last resort.
|
||||
if h, ok := mux.z["."]; ok {
|
||||
return h
|
||||
}
|
||||
return handler
|
||||
}
|
||||
|
||||
// Handle adds a handler to the ServeMux for pattern.
|
||||
func (mux *ServeMux) Handle(pattern string, handler Handler) {
|
||||
if pattern == "" {
|
||||
panic("dns: invalid pattern " + pattern)
|
||||
}
|
||||
mux.m.Lock()
|
||||
mux.z[Fqdn(pattern)] = handler
|
||||
mux.m.Unlock()
|
||||
}
|
||||
|
||||
// HandleFunc adds a handler function to the ServeMux for pattern.
|
||||
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
|
||||
mux.Handle(pattern, HandlerFunc(handler))
|
||||
}
|
||||
|
||||
// HandleRemove deregistrars the handler specific for pattern from the ServeMux.
|
||||
func (mux *ServeMux) HandleRemove(pattern string) {
|
||||
if pattern == "" {
|
||||
panic("dns: invalid pattern " + pattern)
|
||||
}
|
||||
mux.m.Lock()
|
||||
delete(mux.z, Fqdn(pattern))
|
||||
mux.m.Unlock()
|
||||
}
|
||||
|
||||
// ServeDNS dispatches the request to the handler whose
|
||||
// pattern most closely matches the request message. If DefaultServeMux
|
||||
// is used the correct thing for DS queries is done: a possible parent
|
||||
// is sought.
|
||||
// If no handler is found a standard SERVFAIL message is returned
|
||||
// If the request message does not have exactly one question in the
|
||||
// question section a SERVFAIL is returned, unlesss Unsafe is true.
|
||||
func (mux *ServeMux) ServeDNS(w ResponseWriter, request *Msg) {
|
||||
var h Handler
|
||||
if len(request.Question) < 1 { // allow more than one question
|
||||
h = failedHandler()
|
||||
} else {
|
||||
if h = mux.match(request.Question[0].Name, request.Question[0].Qtype); h == nil {
|
||||
h = failedHandler()
|
||||
}
|
||||
}
|
||||
h.ServeDNS(w, request)
|
||||
}
|
||||
|
||||
// Handle registers the handler with the given pattern
|
||||
// in the DefaultServeMux. The documentation for
|
||||
// ServeMux explains how patterns are matched.
|
||||
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
|
||||
|
||||
// HandleRemove deregisters the handle with the given pattern
|
||||
// in the DefaultServeMux.
|
||||
func HandleRemove(pattern string) { DefaultServeMux.HandleRemove(pattern) }
|
||||
|
||||
// HandleFunc registers the handler function with the given pattern
|
||||
// in the DefaultServeMux.
|
||||
func HandleFunc(pattern string, handler func(ResponseWriter, *Msg)) {
|
||||
DefaultServeMux.HandleFunc(pattern, handler)
|
||||
}
|
||||
|
||||
// Writer writes raw DNS messages; each call to Write should send an entire message.
|
||||
type Writer interface {
|
||||
io.Writer
|
||||
@@ -315,9 +203,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.
|
||||
@@ -329,6 +214,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
|
||||
// AcceptMsgFunc will check the incoming message and will reject it early in the process.
|
||||
// By default DefaultMsgAcceptFunc will be used.
|
||||
MsgAcceptFunc MsgAcceptFunc
|
||||
|
||||
// UDP packet or TCP connection queue
|
||||
queue chan *response
|
||||
@@ -412,6 +300,9 @@ func (srv *Server) init() {
|
||||
if srv.UDPSize == 0 {
|
||||
srv.UDPSize = MinMsgSize
|
||||
}
|
||||
if srv.MsgAcceptFunc == nil {
|
||||
srv.MsgAcceptFunc = defaultMsgAcceptFunc
|
||||
}
|
||||
|
||||
srv.udpPool.New = makeUDPBuffer(srv.UDPSize)
|
||||
}
|
||||
@@ -529,14 +420,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
|
||||
}
|
||||
@@ -545,10 +435,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 {
|
||||
@@ -735,20 +625,43 @@ func (srv *Server) serve(w *response) {
|
||||
}
|
||||
}
|
||||
|
||||
func (srv *Server) serveDNS(w *response) {
|
||||
req := new(Msg)
|
||||
err := req.Unpack(w.msg)
|
||||
func (srv *Server) disposeBuffer(w *response) {
|
||||
if w.udp != nil && cap(w.msg) == srv.UDPSize {
|
||||
srv.udpPool.Put(w.msg[:srv.UDPSize])
|
||||
}
|
||||
w.msg = nil
|
||||
if err != nil { // Send a FormatError back
|
||||
x := new(Msg)
|
||||
x.SetRcodeFormatError(req)
|
||||
w.WriteMsg(x)
|
||||
}
|
||||
|
||||
func (srv *Server) serveDNS(w *response) {
|
||||
dh, off, err := unpackMsgHdr(w.msg, 0)
|
||||
if err != nil {
|
||||
// Let client hang, they are sending crap; any reply can be used to amplify.
|
||||
return
|
||||
}
|
||||
if !srv.Unsafe && req.Response {
|
||||
|
||||
req := new(Msg)
|
||||
req.setHdr(dh)
|
||||
|
||||
switch srv.MsgAcceptFunc(dh) {
|
||||
case MsgAccept:
|
||||
case MsgIgnore:
|
||||
return
|
||||
case MsgReject:
|
||||
req.SetRcodeFormatError(req)
|
||||
// Are we allowed to delete any OPT records here?
|
||||
req.Ns, req.Answer, req.Extra = nil, nil, nil
|
||||
|
||||
w.WriteMsg(req)
|
||||
srv.disposeBuffer(w)
|
||||
return
|
||||
}
|
||||
|
||||
if err := req.unpack(dh, w.msg, off); err != nil {
|
||||
req.SetRcodeFormatError(req)
|
||||
req.Ns, req.Answer, req.Extra = nil, nil, nil
|
||||
|
||||
w.WriteMsg(req)
|
||||
srv.disposeBuffer(w)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -765,6 +678,8 @@ func (srv *Server) serveDNS(w *response) {
|
||||
}
|
||||
}
|
||||
|
||||
srv.disposeBuffer(w)
|
||||
|
||||
handler := srv.Handler
|
||||
if handler == nil {
|
||||
handler = DefaultServeMux
|
||||
@@ -774,7 +689,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 {
|
||||
@@ -809,7 +733,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 {
|
||||
@@ -822,6 +752,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 {
|
||||
@@ -843,6 +777,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)
|
||||
@@ -861,24 +799,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.
|
||||
@@ -892,13 +839,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.
|
||||
|
||||
7
vendor/github.com/miekg/dns/sig0.go
сгенерированный
поставляемый
7
vendor/github.com/miekg/dns/sig0.go
сгенерированный
поставляемый
@@ -29,7 +29,7 @@ func (rr *SIG) Sign(k crypto.Signer, m *Msg) ([]byte, error) {
|
||||
rr.TypeCovered = 0
|
||||
rr.Labels = 0
|
||||
|
||||
buf := make([]byte, m.Len()+rr.len())
|
||||
buf := make([]byte, m.Len()+Len(rr))
|
||||
mbuf, err := m.PackBuffer(buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -127,8 +127,7 @@ func (rr *SIG) Verify(k *KEY, buf []byte) error {
|
||||
if offset+1 >= buflen {
|
||||
continue
|
||||
}
|
||||
var rdlen uint16
|
||||
rdlen = binary.BigEndian.Uint16(buf[offset:])
|
||||
rdlen := binary.BigEndian.Uint16(buf[offset:])
|
||||
offset += 2
|
||||
offset += int(rdlen)
|
||||
}
|
||||
@@ -168,7 +167,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
|
||||
|
||||
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Ссылка в новой задаче
Block a user