Merge pull request #851 from sanimej/godep
Godep fixup to import miekg/dns library
This commit is contained in:
commit
c5d59968b0
77 changed files with 20452 additions and 0 deletions
17
libnetwork/Godeps/Godeps.json
generated
17
libnetwork/Godeps/Godeps.json
generated
|
@ -5,6 +5,10 @@
|
|||
"./..."
|
||||
],
|
||||
"Deps": [
|
||||
{
|
||||
"ImportPath": "github.com/Azure/go-ansiterm",
|
||||
"Rev": "70b2c90b260171e829f1ebd7c17f600c11858dbe"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/BurntSushi/toml",
|
||||
"Comment": "v0.1.0-16-gf706d00",
|
||||
|
@ -84,6 +88,11 @@
|
|||
"Comment": "v1.4.1-8734-g577cf61",
|
||||
"Rev": "577cf61afad695f0ba226cdf8a995a8c78883e51"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/longpath",
|
||||
"Comment": "v1.4.1-8734-g577cf61",
|
||||
"Rev": "577cf61afad695f0ba226cdf8a995a8c78883e51"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/docker/docker/pkg/mflag",
|
||||
"Comment": "v1.4.1-8734-g577cf61",
|
||||
|
@ -203,6 +212,10 @@
|
|||
"Comment": "v0.6.4",
|
||||
"Rev": "7151adcef72687bf95f451a2e0ba15cb19412bf2"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/miekg/dns",
|
||||
"Rev": "d27455715200c7d3e321a1e5cadb27c9ee0b0f02"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/opencontainers/runc/libcontainer",
|
||||
"Comment": "v0.0.6-6-gba1568d",
|
||||
|
@ -212,6 +225,10 @@
|
|||
"ImportPath": "github.com/samuel/go-zookeeper/zk",
|
||||
"Rev": "d0e0d8e11f318e000a8cc434616d69e329edc374"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/seccomp/libseccomp-golang",
|
||||
"Rev": "1b506fc7c24eec5a3693cdcbed40d9c226cfc6a1"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/stretchr/testify/assert",
|
||||
"Rev": "dab07ac62d4905d3e48d17dc549c684ac3b7c15a"
|
||||
|
|
21
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/LICENSE
generated
vendored
Normal file
21
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Microsoft Corporation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
9
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/README.md
generated
vendored
Normal file
9
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/README.md
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
# go-ansiterm
|
||||
|
||||
This is a cross platform Ansi Terminal Emulation library. It reads a stream of Ansi characters and produces the appropriate function calls. The results of the function calls are platform dependent.
|
||||
|
||||
For example the parser might receive "ESC, [, A" as a stream of three characters. This is the code for Cursor Up (http://www.vt100.net/docs/vt510-rm/CUU). The parser then calls the cursor up function (CUU()) on an event handler. The event handler determines what platform specific work must be done to cause the cursor to move up one position.
|
||||
|
||||
The parser (parser.go) is a partial implementation of this state machine (http://vt100.net/emu/vt500_parser.png). There are also two event handler implementations, one for tests (test_event_handler.go) to validate that the expected events are being produced and called, the other is a Windows implementation (winterm/win_event_handler.go).
|
||||
|
||||
See parser_test.go for examples exercising the state machine and generating appropriate function calls.
|
188
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/constants.go
generated
vendored
Normal file
188
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/constants.go
generated
vendored
Normal file
|
@ -0,0 +1,188 @@
|
|||
package ansiterm
|
||||
|
||||
const LogEnv = "DEBUG_TERMINAL"
|
||||
|
||||
// ANSI constants
|
||||
// References:
|
||||
// -- http://www.ecma-international.org/publications/standards/Ecma-048.htm
|
||||
// -- http://man7.org/linux/man-pages/man4/console_codes.4.html
|
||||
// -- http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html
|
||||
// -- http://en.wikipedia.org/wiki/ANSI_escape_code
|
||||
// -- http://vt100.net/emu/dec_ansi_parser
|
||||
// -- http://vt100.net/emu/vt500_parser.svg
|
||||
// -- http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
|
||||
// -- http://www.inwap.com/pdp10/ansicode.txt
|
||||
const (
|
||||
// ECMA-48 Set Graphics Rendition
|
||||
// Note:
|
||||
// -- Constants leading with an underscore (e.g., _ANSI_xxx) are unsupported or reserved
|
||||
// -- Fonts could possibly be supported via SetCurrentConsoleFontEx
|
||||
// -- Windows does not expose the per-window cursor (i.e., caret) blink times
|
||||
ANSI_SGR_RESET = 0
|
||||
ANSI_SGR_BOLD = 1
|
||||
ANSI_SGR_DIM = 2
|
||||
_ANSI_SGR_ITALIC = 3
|
||||
ANSI_SGR_UNDERLINE = 4
|
||||
_ANSI_SGR_BLINKSLOW = 5
|
||||
_ANSI_SGR_BLINKFAST = 6
|
||||
ANSI_SGR_REVERSE = 7
|
||||
_ANSI_SGR_INVISIBLE = 8
|
||||
_ANSI_SGR_LINETHROUGH = 9
|
||||
_ANSI_SGR_FONT_00 = 10
|
||||
_ANSI_SGR_FONT_01 = 11
|
||||
_ANSI_SGR_FONT_02 = 12
|
||||
_ANSI_SGR_FONT_03 = 13
|
||||
_ANSI_SGR_FONT_04 = 14
|
||||
_ANSI_SGR_FONT_05 = 15
|
||||
_ANSI_SGR_FONT_06 = 16
|
||||
_ANSI_SGR_FONT_07 = 17
|
||||
_ANSI_SGR_FONT_08 = 18
|
||||
_ANSI_SGR_FONT_09 = 19
|
||||
_ANSI_SGR_FONT_10 = 20
|
||||
_ANSI_SGR_DOUBLEUNDERLINE = 21
|
||||
ANSI_SGR_BOLD_DIM_OFF = 22
|
||||
_ANSI_SGR_ITALIC_OFF = 23
|
||||
ANSI_SGR_UNDERLINE_OFF = 24
|
||||
_ANSI_SGR_BLINK_OFF = 25
|
||||
_ANSI_SGR_RESERVED_00 = 26
|
||||
ANSI_SGR_REVERSE_OFF = 27
|
||||
_ANSI_SGR_INVISIBLE_OFF = 28
|
||||
_ANSI_SGR_LINETHROUGH_OFF = 29
|
||||
ANSI_SGR_FOREGROUND_BLACK = 30
|
||||
ANSI_SGR_FOREGROUND_RED = 31
|
||||
ANSI_SGR_FOREGROUND_GREEN = 32
|
||||
ANSI_SGR_FOREGROUND_YELLOW = 33
|
||||
ANSI_SGR_FOREGROUND_BLUE = 34
|
||||
ANSI_SGR_FOREGROUND_MAGENTA = 35
|
||||
ANSI_SGR_FOREGROUND_CYAN = 36
|
||||
ANSI_SGR_FOREGROUND_WHITE = 37
|
||||
_ANSI_SGR_RESERVED_01 = 38
|
||||
ANSI_SGR_FOREGROUND_DEFAULT = 39
|
||||
ANSI_SGR_BACKGROUND_BLACK = 40
|
||||
ANSI_SGR_BACKGROUND_RED = 41
|
||||
ANSI_SGR_BACKGROUND_GREEN = 42
|
||||
ANSI_SGR_BACKGROUND_YELLOW = 43
|
||||
ANSI_SGR_BACKGROUND_BLUE = 44
|
||||
ANSI_SGR_BACKGROUND_MAGENTA = 45
|
||||
ANSI_SGR_BACKGROUND_CYAN = 46
|
||||
ANSI_SGR_BACKGROUND_WHITE = 47
|
||||
_ANSI_SGR_RESERVED_02 = 48
|
||||
ANSI_SGR_BACKGROUND_DEFAULT = 49
|
||||
// 50 - 65: Unsupported
|
||||
|
||||
ANSI_MAX_CMD_LENGTH = 4096
|
||||
|
||||
MAX_INPUT_EVENTS = 128
|
||||
DEFAULT_WIDTH = 80
|
||||
DEFAULT_HEIGHT = 24
|
||||
|
||||
ANSI_BEL = 0x07
|
||||
ANSI_BACKSPACE = 0x08
|
||||
ANSI_TAB = 0x09
|
||||
ANSI_LINE_FEED = 0x0A
|
||||
ANSI_VERTICAL_TAB = 0x0B
|
||||
ANSI_FORM_FEED = 0x0C
|
||||
ANSI_CARRIAGE_RETURN = 0x0D
|
||||
ANSI_ESCAPE_PRIMARY = 0x1B
|
||||
ANSI_ESCAPE_SECONDARY = 0x5B
|
||||
ANSI_OSC_STRING_ENTRY = 0x5D
|
||||
ANSI_COMMAND_FIRST = 0x40
|
||||
ANSI_COMMAND_LAST = 0x7E
|
||||
DCS_ENTRY = 0x90
|
||||
CSI_ENTRY = 0x9B
|
||||
OSC_STRING = 0x9D
|
||||
ANSI_PARAMETER_SEP = ";"
|
||||
ANSI_CMD_G0 = '('
|
||||
ANSI_CMD_G1 = ')'
|
||||
ANSI_CMD_G2 = '*'
|
||||
ANSI_CMD_G3 = '+'
|
||||
ANSI_CMD_DECPNM = '>'
|
||||
ANSI_CMD_DECPAM = '='
|
||||
ANSI_CMD_OSC = ']'
|
||||
ANSI_CMD_STR_TERM = '\\'
|
||||
|
||||
KEY_CONTROL_PARAM_2 = ";2"
|
||||
KEY_CONTROL_PARAM_3 = ";3"
|
||||
KEY_CONTROL_PARAM_4 = ";4"
|
||||
KEY_CONTROL_PARAM_5 = ";5"
|
||||
KEY_CONTROL_PARAM_6 = ";6"
|
||||
KEY_CONTROL_PARAM_7 = ";7"
|
||||
KEY_CONTROL_PARAM_8 = ";8"
|
||||
KEY_ESC_CSI = "\x1B["
|
||||
KEY_ESC_N = "\x1BN"
|
||||
KEY_ESC_O = "\x1BO"
|
||||
|
||||
FILL_CHARACTER = ' '
|
||||
)
|
||||
|
||||
func getByteRange(start byte, end byte) []byte {
|
||||
bytes := make([]byte, 0, 32)
|
||||
for i := start; i <= end; i++ {
|
||||
bytes = append(bytes, byte(i))
|
||||
}
|
||||
|
||||
return bytes
|
||||
}
|
||||
|
||||
var ToGroundBytes = getToGroundBytes()
|
||||
var Executors = getExecuteBytes()
|
||||
|
||||
// SPACE 20+A0 hex Always and everywhere a blank space
|
||||
// Intermediate 20-2F hex !"#$%&'()*+,-./
|
||||
var Intermeds = getByteRange(0x20, 0x2F)
|
||||
|
||||
// Parameters 30-3F hex 0123456789:;<=>?
|
||||
// CSI Parameters 30-39, 3B hex 0123456789;
|
||||
var CsiParams = getByteRange(0x30, 0x3F)
|
||||
|
||||
var CsiCollectables = append(getByteRange(0x30, 0x39), getByteRange(0x3B, 0x3F)...)
|
||||
|
||||
// Uppercase 40-5F hex @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_
|
||||
var UpperCase = getByteRange(0x40, 0x5F)
|
||||
|
||||
// Lowercase 60-7E hex `abcdefghijlkmnopqrstuvwxyz{|}~
|
||||
var LowerCase = getByteRange(0x60, 0x7E)
|
||||
|
||||
// Alphabetics 40-7E hex (all of upper and lower case)
|
||||
var Alphabetics = append(UpperCase, LowerCase...)
|
||||
|
||||
var Printables = getByteRange(0x20, 0x7F)
|
||||
|
||||
var EscapeIntermediateToGroundBytes = getByteRange(0x30, 0x7E)
|
||||
var EscapeToGroundBytes = getEscapeToGroundBytes()
|
||||
|
||||
// See http://www.vt100.net/emu/vt500_parser.png for description of the complex
|
||||
// byte ranges below
|
||||
|
||||
func getEscapeToGroundBytes() []byte {
|
||||
escapeToGroundBytes := getByteRange(0x30, 0x4F)
|
||||
escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x51, 0x57)...)
|
||||
escapeToGroundBytes = append(escapeToGroundBytes, 0x59)
|
||||
escapeToGroundBytes = append(escapeToGroundBytes, 0x5A)
|
||||
escapeToGroundBytes = append(escapeToGroundBytes, 0x5C)
|
||||
escapeToGroundBytes = append(escapeToGroundBytes, getByteRange(0x60, 0x7E)...)
|
||||
return escapeToGroundBytes
|
||||
}
|
||||
|
||||
func getExecuteBytes() []byte {
|
||||
executeBytes := getByteRange(0x00, 0x17)
|
||||
executeBytes = append(executeBytes, 0x19)
|
||||
executeBytes = append(executeBytes, getByteRange(0x1C, 0x1F)...)
|
||||
return executeBytes
|
||||
}
|
||||
|
||||
func getToGroundBytes() []byte {
|
||||
groundBytes := []byte{0x18}
|
||||
groundBytes = append(groundBytes, 0x1A)
|
||||
groundBytes = append(groundBytes, getByteRange(0x80, 0x8F)...)
|
||||
groundBytes = append(groundBytes, getByteRange(0x91, 0x97)...)
|
||||
groundBytes = append(groundBytes, 0x99)
|
||||
groundBytes = append(groundBytes, 0x9A)
|
||||
groundBytes = append(groundBytes, 0x9C)
|
||||
return groundBytes
|
||||
}
|
||||
|
||||
// Delete 7F hex Always and everywhere ignored
|
||||
// C1 Control 80-9F hex 32 additional control characters
|
||||
// G1 Displayable A1-FE hex 94 additional displayable characters
|
||||
// Special A0+FF hex Same as SPACE and DELETE
|
7
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/context.go
generated
vendored
Normal file
7
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/context.go
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
package ansiterm
|
||||
|
||||
type AnsiContext struct {
|
||||
currentChar byte
|
||||
paramBuffer []byte
|
||||
interBuffer []byte
|
||||
}
|
49
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/csi_entry_state.go
generated
vendored
Normal file
49
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/csi_entry_state.go
generated
vendored
Normal file
|
@ -0,0 +1,49 @@
|
|||
package ansiterm
|
||||
|
||||
type CsiEntryState struct {
|
||||
BaseState
|
||||
}
|
||||
|
||||
func (csiState CsiEntryState) Handle(b byte) (s State, e error) {
|
||||
logger.Infof("CsiEntry::Handle %#x", b)
|
||||
|
||||
nextState, err := csiState.BaseState.Handle(b)
|
||||
if nextState != nil || err != nil {
|
||||
return nextState, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case sliceContains(Alphabetics, b):
|
||||
return csiState.parser.Ground, nil
|
||||
case sliceContains(CsiCollectables, b):
|
||||
return csiState.parser.CsiParam, nil
|
||||
case sliceContains(Executors, b):
|
||||
return csiState, csiState.parser.execute()
|
||||
}
|
||||
|
||||
return csiState, nil
|
||||
}
|
||||
|
||||
func (csiState CsiEntryState) Transition(s State) error {
|
||||
logger.Infof("CsiEntry::Transition %s --> %s", csiState.Name(), s.Name())
|
||||
csiState.BaseState.Transition(s)
|
||||
|
||||
switch s {
|
||||
case csiState.parser.Ground:
|
||||
return csiState.parser.csiDispatch()
|
||||
case csiState.parser.CsiParam:
|
||||
switch {
|
||||
case sliceContains(CsiParams, csiState.parser.context.currentChar):
|
||||
csiState.parser.collectParam()
|
||||
case sliceContains(Intermeds, csiState.parser.context.currentChar):
|
||||
csiState.parser.collectInter()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (csiState CsiEntryState) Enter() error {
|
||||
csiState.parser.clear()
|
||||
return nil
|
||||
}
|
38
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/csi_param_state.go
generated
vendored
Normal file
38
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/csi_param_state.go
generated
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
package ansiterm
|
||||
|
||||
type CsiParamState struct {
|
||||
BaseState
|
||||
}
|
||||
|
||||
func (csiState CsiParamState) Handle(b byte) (s State, e error) {
|
||||
logger.Infof("CsiParam::Handle %#x", b)
|
||||
|
||||
nextState, err := csiState.BaseState.Handle(b)
|
||||
if nextState != nil || err != nil {
|
||||
return nextState, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case sliceContains(Alphabetics, b):
|
||||
return csiState.parser.Ground, nil
|
||||
case sliceContains(CsiCollectables, b):
|
||||
csiState.parser.collectParam()
|
||||
return csiState, nil
|
||||
case sliceContains(Executors, b):
|
||||
return csiState, csiState.parser.execute()
|
||||
}
|
||||
|
||||
return csiState, nil
|
||||
}
|
||||
|
||||
func (csiState CsiParamState) Transition(s State) error {
|
||||
logger.Infof("CsiParam::Transition %s --> %s", csiState.Name(), s.Name())
|
||||
csiState.BaseState.Transition(s)
|
||||
|
||||
switch s {
|
||||
case csiState.parser.Ground:
|
||||
return csiState.parser.csiDispatch()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
36
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/escape_intermediate_state.go
generated
vendored
Normal file
36
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/escape_intermediate_state.go
generated
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
package ansiterm
|
||||
|
||||
type EscapeIntermediateState struct {
|
||||
BaseState
|
||||
}
|
||||
|
||||
func (escState EscapeIntermediateState) Handle(b byte) (s State, e error) {
|
||||
logger.Infof("EscapeIntermediateState::Handle %#x", b)
|
||||
nextState, err := escState.BaseState.Handle(b)
|
||||
if nextState != nil || err != nil {
|
||||
return nextState, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case sliceContains(Intermeds, b):
|
||||
return escState, escState.parser.collectInter()
|
||||
case sliceContains(Executors, b):
|
||||
return escState, escState.parser.execute()
|
||||
case sliceContains(EscapeIntermediateToGroundBytes, b):
|
||||
return escState.parser.Ground, nil
|
||||
}
|
||||
|
||||
return escState, nil
|
||||
}
|
||||
|
||||
func (escState EscapeIntermediateState) Transition(s State) error {
|
||||
logger.Infof("EscapeIntermediateState::Transition %s --> %s", escState.Name(), s.Name())
|
||||
escState.BaseState.Transition(s)
|
||||
|
||||
switch s {
|
||||
case escState.parser.Ground:
|
||||
return escState.parser.escDispatch()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
47
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/escape_state.go
generated
vendored
Normal file
47
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/escape_state.go
generated
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
package ansiterm
|
||||
|
||||
type EscapeState struct {
|
||||
BaseState
|
||||
}
|
||||
|
||||
func (escState EscapeState) Handle(b byte) (s State, e error) {
|
||||
logger.Infof("EscapeState::Handle %#x", b)
|
||||
nextState, err := escState.BaseState.Handle(b)
|
||||
if nextState != nil || err != nil {
|
||||
return nextState, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case b == ANSI_ESCAPE_SECONDARY:
|
||||
return escState.parser.CsiEntry, nil
|
||||
case b == ANSI_OSC_STRING_ENTRY:
|
||||
return escState.parser.OscString, nil
|
||||
case sliceContains(Executors, b):
|
||||
return escState, escState.parser.execute()
|
||||
case sliceContains(EscapeToGroundBytes, b):
|
||||
return escState.parser.Ground, nil
|
||||
case sliceContains(Intermeds, b):
|
||||
return escState.parser.EscapeIntermediate, nil
|
||||
}
|
||||
|
||||
return escState, nil
|
||||
}
|
||||
|
||||
func (escState EscapeState) Transition(s State) error {
|
||||
logger.Infof("Escape::Transition %s --> %s", escState.Name(), s.Name())
|
||||
escState.BaseState.Transition(s)
|
||||
|
||||
switch s {
|
||||
case escState.parser.Ground:
|
||||
return escState.parser.escDispatch()
|
||||
case escState.parser.EscapeIntermediate:
|
||||
return escState.parser.collectInter()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (escState EscapeState) Enter() error {
|
||||
escState.parser.clear()
|
||||
return nil
|
||||
}
|
90
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/event_handler.go
generated
vendored
Normal file
90
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/event_handler.go
generated
vendored
Normal file
|
@ -0,0 +1,90 @@
|
|||
package ansiterm
|
||||
|
||||
type AnsiEventHandler interface {
|
||||
// Print
|
||||
Print(b byte) error
|
||||
|
||||
// Execute C0 commands
|
||||
Execute(b byte) error
|
||||
|
||||
// CUrsor Up
|
||||
CUU(int) error
|
||||
|
||||
// CUrsor Down
|
||||
CUD(int) error
|
||||
|
||||
// CUrsor Forward
|
||||
CUF(int) error
|
||||
|
||||
// CUrsor Backward
|
||||
CUB(int) error
|
||||
|
||||
// Cursor to Next Line
|
||||
CNL(int) error
|
||||
|
||||
// Cursor to Previous Line
|
||||
CPL(int) error
|
||||
|
||||
// Cursor Horizontal position Absolute
|
||||
CHA(int) error
|
||||
|
||||
// Vertical line Position Absolute
|
||||
VPA(int) error
|
||||
|
||||
// CUrsor Position
|
||||
CUP(int, int) error
|
||||
|
||||
// Horizontal and Vertical Position (depends on PUM)
|
||||
HVP(int, int) error
|
||||
|
||||
// Text Cursor Enable Mode
|
||||
DECTCEM(bool) error
|
||||
|
||||
// Origin Mode
|
||||
DECOM(bool) error
|
||||
|
||||
// 132 Column Mode
|
||||
DECCOLM(bool) error
|
||||
|
||||
// Erase in Display
|
||||
ED(int) error
|
||||
|
||||
// Erase in Line
|
||||
EL(int) error
|
||||
|
||||
// Insert Line
|
||||
IL(int) error
|
||||
|
||||
// Delete Line
|
||||
DL(int) error
|
||||
|
||||
// Insert Character
|
||||
ICH(int) error
|
||||
|
||||
// Delete Character
|
||||
DCH(int) error
|
||||
|
||||
// Set Graphics Rendition
|
||||
SGR([]int) error
|
||||
|
||||
// Pan Down
|
||||
SU(int) error
|
||||
|
||||
// Pan Up
|
||||
SD(int) error
|
||||
|
||||
// Device Attributes
|
||||
DA([]string) error
|
||||
|
||||
// Set Top and Bottom Margins
|
||||
DECSTBM(int, int) error
|
||||
|
||||
// Index
|
||||
IND() error
|
||||
|
||||
// Reverse Index
|
||||
RI() error
|
||||
|
||||
// Flush updates from previous commands
|
||||
Flush() error
|
||||
}
|
24
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/ground_state.go
generated
vendored
Normal file
24
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/ground_state.go
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
package ansiterm
|
||||
|
||||
type GroundState struct {
|
||||
BaseState
|
||||
}
|
||||
|
||||
func (gs GroundState) Handle(b byte) (s State, e error) {
|
||||
gs.parser.context.currentChar = b
|
||||
|
||||
nextState, err := gs.BaseState.Handle(b)
|
||||
if nextState != nil || err != nil {
|
||||
return nextState, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case sliceContains(Printables, b):
|
||||
return gs, gs.parser.print()
|
||||
|
||||
case sliceContains(Executors, b):
|
||||
return gs, gs.parser.execute()
|
||||
}
|
||||
|
||||
return gs, nil
|
||||
}
|
31
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/osc_string_state.go
generated
vendored
Normal file
31
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/osc_string_state.go
generated
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
package ansiterm
|
||||
|
||||
type OscStringState struct {
|
||||
BaseState
|
||||
}
|
||||
|
||||
func (oscState OscStringState) Handle(b byte) (s State, e error) {
|
||||
logger.Infof("OscString::Handle %#x", b)
|
||||
nextState, err := oscState.BaseState.Handle(b)
|
||||
if nextState != nil || err != nil {
|
||||
return nextState, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case isOscStringTerminator(b):
|
||||
return oscState.parser.Ground, nil
|
||||
}
|
||||
|
||||
return oscState, nil
|
||||
}
|
||||
|
||||
// See below for OSC string terminators for linux
|
||||
// http://man7.org/linux/man-pages/man4/console_codes.4.html
|
||||
func isOscStringTerminator(b byte) bool {
|
||||
|
||||
if b == ANSI_BEL || b == 0x5C {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
137
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser.go
generated
vendored
Normal file
137
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser.go
generated
vendored
Normal file
|
@ -0,0 +1,137 @@
|
|||
package ansiterm
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
var logger *logrus.Logger
|
||||
|
||||
type AnsiParser struct {
|
||||
currState State
|
||||
eventHandler AnsiEventHandler
|
||||
context *AnsiContext
|
||||
CsiEntry State
|
||||
CsiParam State
|
||||
DcsEntry State
|
||||
Escape State
|
||||
EscapeIntermediate State
|
||||
Error State
|
||||
Ground State
|
||||
OscString State
|
||||
stateMap []State
|
||||
}
|
||||
|
||||
func CreateParser(initialState string, evtHandler AnsiEventHandler) *AnsiParser {
|
||||
logFile := ioutil.Discard
|
||||
|
||||
if isDebugEnv := os.Getenv(LogEnv); isDebugEnv == "1" {
|
||||
logFile, _ = os.Create("ansiParser.log")
|
||||
}
|
||||
|
||||
logger = &logrus.Logger{
|
||||
Out: logFile,
|
||||
Formatter: new(logrus.TextFormatter),
|
||||
Level: logrus.InfoLevel,
|
||||
}
|
||||
|
||||
parser := &AnsiParser{
|
||||
eventHandler: evtHandler,
|
||||
context: &AnsiContext{},
|
||||
}
|
||||
|
||||
parser.CsiEntry = CsiEntryState{BaseState{name: "CsiEntry", parser: parser}}
|
||||
parser.CsiParam = CsiParamState{BaseState{name: "CsiParam", parser: parser}}
|
||||
parser.DcsEntry = DcsEntryState{BaseState{name: "DcsEntry", parser: parser}}
|
||||
parser.Escape = EscapeState{BaseState{name: "Escape", parser: parser}}
|
||||
parser.EscapeIntermediate = EscapeIntermediateState{BaseState{name: "EscapeIntermediate", parser: parser}}
|
||||
parser.Error = ErrorState{BaseState{name: "Error", parser: parser}}
|
||||
parser.Ground = GroundState{BaseState{name: "Ground", parser: parser}}
|
||||
parser.OscString = OscStringState{BaseState{name: "OscString", parser: parser}}
|
||||
|
||||
parser.stateMap = []State{
|
||||
parser.CsiEntry,
|
||||
parser.CsiParam,
|
||||
parser.DcsEntry,
|
||||
parser.Escape,
|
||||
parser.EscapeIntermediate,
|
||||
parser.Error,
|
||||
parser.Ground,
|
||||
parser.OscString,
|
||||
}
|
||||
|
||||
parser.currState = getState(initialState, parser.stateMap)
|
||||
|
||||
logger.Infof("CreateParser: parser %p", parser)
|
||||
return parser
|
||||
}
|
||||
|
||||
func getState(name string, states []State) State {
|
||||
for _, el := range states {
|
||||
if el.Name() == name {
|
||||
return el
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) Parse(bytes []byte) (int, error) {
|
||||
for i, b := range bytes {
|
||||
if err := ap.handle(b); err != nil {
|
||||
return i, err
|
||||
}
|
||||
}
|
||||
|
||||
return len(bytes), ap.eventHandler.Flush()
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) handle(b byte) error {
|
||||
ap.context.currentChar = b
|
||||
newState, err := ap.currState.Handle(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if newState == nil {
|
||||
logger.Warning("newState is nil")
|
||||
return errors.New(fmt.Sprintf("New state of 'nil' is invalid."))
|
||||
}
|
||||
|
||||
if newState != ap.currState {
|
||||
if err := ap.changeState(newState); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) changeState(newState State) error {
|
||||
logger.Infof("ChangeState %s --> %s", ap.currState.Name(), newState.Name())
|
||||
|
||||
// Exit old state
|
||||
if err := ap.currState.Exit(); err != nil {
|
||||
logger.Infof("Exit state '%s' failed with : '%v'", ap.currState.Name(), err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Perform transition action
|
||||
if err := ap.currState.Transition(newState); err != nil {
|
||||
logger.Infof("Transition from '%s' to '%s' failed with: '%v'", ap.currState.Name(), newState.Name, err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Enter new state
|
||||
if err := newState.Enter(); err != nil {
|
||||
logger.Infof("Enter state '%s' failed with: '%v'", newState.Name(), err)
|
||||
return err
|
||||
}
|
||||
|
||||
ap.currState = newState
|
||||
return nil
|
||||
}
|
103
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_action_helpers.go
generated
vendored
Normal file
103
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_action_helpers.go
generated
vendored
Normal file
|
@ -0,0 +1,103 @@
|
|||
package ansiterm
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func parseParams(bytes []byte) ([]string, error) {
|
||||
paramBuff := make([]byte, 0, 0)
|
||||
params := []string{}
|
||||
|
||||
for _, v := range bytes {
|
||||
if v == ';' {
|
||||
if len(paramBuff) > 0 {
|
||||
// Completed parameter, append it to the list
|
||||
s := string(paramBuff)
|
||||
params = append(params, s)
|
||||
paramBuff = make([]byte, 0, 0)
|
||||
}
|
||||
} else {
|
||||
paramBuff = append(paramBuff, v)
|
||||
}
|
||||
}
|
||||
|
||||
// Last parameter may not be terminated with ';'
|
||||
if len(paramBuff) > 0 {
|
||||
s := string(paramBuff)
|
||||
params = append(params, s)
|
||||
}
|
||||
|
||||
logger.Infof("Parsed params: %v with length: %d", params, len(params))
|
||||
return params, nil
|
||||
}
|
||||
|
||||
func parseCmd(context AnsiContext) (string, error) {
|
||||
return string(context.currentChar), nil
|
||||
}
|
||||
|
||||
func getInt(params []string, dflt int) int {
|
||||
i := getInts(params, 1, dflt)[0]
|
||||
logger.Infof("getInt: %v", i)
|
||||
return i
|
||||
}
|
||||
|
||||
func getInts(params []string, minCount int, dflt int) []int {
|
||||
ints := []int{}
|
||||
|
||||
for _, v := range params {
|
||||
i, _ := strconv.Atoi(v)
|
||||
// Zero is mapped to the default value in VT100.
|
||||
if i == 0 {
|
||||
i = dflt
|
||||
}
|
||||
ints = append(ints, i)
|
||||
}
|
||||
|
||||
if len(ints) < minCount {
|
||||
remaining := minCount - len(ints)
|
||||
for i := 0; i < remaining; i++ {
|
||||
ints = append(ints, dflt)
|
||||
}
|
||||
}
|
||||
|
||||
logger.Infof("getInts: %v", ints)
|
||||
|
||||
return ints
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) modeDispatch(param string, set bool) error {
|
||||
switch param {
|
||||
case "?3":
|
||||
return ap.eventHandler.DECCOLM(set)
|
||||
case "?6":
|
||||
return ap.eventHandler.DECOM(set)
|
||||
case "?25":
|
||||
return ap.eventHandler.DECTCEM(set)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) hDispatch(params []string) error {
|
||||
if len(params) == 1 {
|
||||
return ap.modeDispatch(params[0], true)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) lDispatch(params []string) error {
|
||||
if len(params) == 1 {
|
||||
return ap.modeDispatch(params[0], false)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getEraseParam(params []string) int {
|
||||
param := getInt(params, 0)
|
||||
if param < 0 || 3 < param {
|
||||
param = 0
|
||||
}
|
||||
|
||||
return param
|
||||
}
|
122
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_actions.go
generated
vendored
Normal file
122
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_actions.go
generated
vendored
Normal file
|
@ -0,0 +1,122 @@
|
|||
package ansiterm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func (ap *AnsiParser) collectParam() error {
|
||||
currChar := ap.context.currentChar
|
||||
logger.Infof("collectParam %#x", currChar)
|
||||
ap.context.paramBuffer = append(ap.context.paramBuffer, currChar)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) collectInter() error {
|
||||
currChar := ap.context.currentChar
|
||||
logger.Infof("collectInter %#x", currChar)
|
||||
ap.context.paramBuffer = append(ap.context.interBuffer, currChar)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) escDispatch() error {
|
||||
cmd, _ := parseCmd(*ap.context)
|
||||
intermeds := ap.context.interBuffer
|
||||
logger.Infof("escDispatch currentChar: %#x", ap.context.currentChar)
|
||||
logger.Infof("escDispatch: %v(%v)", cmd, intermeds)
|
||||
|
||||
switch cmd {
|
||||
case "D": // IND
|
||||
return ap.eventHandler.IND()
|
||||
case "E": // NEL, equivalent to CRLF
|
||||
err := ap.eventHandler.Execute(ANSI_CARRIAGE_RETURN)
|
||||
if err == nil {
|
||||
err = ap.eventHandler.Execute(ANSI_LINE_FEED)
|
||||
}
|
||||
return err
|
||||
case "M": // RI
|
||||
return ap.eventHandler.RI()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) csiDispatch() error {
|
||||
cmd, _ := parseCmd(*ap.context)
|
||||
params, _ := parseParams(ap.context.paramBuffer)
|
||||
|
||||
logger.Infof("csiDispatch: %v(%v)", cmd, params)
|
||||
|
||||
switch cmd {
|
||||
case "@":
|
||||
return ap.eventHandler.ICH(getInt(params, 1))
|
||||
case "A":
|
||||
return ap.eventHandler.CUU(getInt(params, 1))
|
||||
case "B":
|
||||
return ap.eventHandler.CUD(getInt(params, 1))
|
||||
case "C":
|
||||
return ap.eventHandler.CUF(getInt(params, 1))
|
||||
case "D":
|
||||
return ap.eventHandler.CUB(getInt(params, 1))
|
||||
case "E":
|
||||
return ap.eventHandler.CNL(getInt(params, 1))
|
||||
case "F":
|
||||
return ap.eventHandler.CPL(getInt(params, 1))
|
||||
case "G":
|
||||
return ap.eventHandler.CHA(getInt(params, 1))
|
||||
case "H":
|
||||
ints := getInts(params, 2, 1)
|
||||
x, y := ints[0], ints[1]
|
||||
return ap.eventHandler.CUP(x, y)
|
||||
case "J":
|
||||
param := getEraseParam(params)
|
||||
return ap.eventHandler.ED(param)
|
||||
case "K":
|
||||
param := getEraseParam(params)
|
||||
return ap.eventHandler.EL(param)
|
||||
case "L":
|
||||
return ap.eventHandler.IL(getInt(params, 1))
|
||||
case "M":
|
||||
return ap.eventHandler.DL(getInt(params, 1))
|
||||
case "P":
|
||||
return ap.eventHandler.DCH(getInt(params, 1))
|
||||
case "S":
|
||||
return ap.eventHandler.SU(getInt(params, 1))
|
||||
case "T":
|
||||
return ap.eventHandler.SD(getInt(params, 1))
|
||||
case "c":
|
||||
return ap.eventHandler.DA(params)
|
||||
case "d":
|
||||
return ap.eventHandler.VPA(getInt(params, 1))
|
||||
case "f":
|
||||
ints := getInts(params, 2, 1)
|
||||
x, y := ints[0], ints[1]
|
||||
return ap.eventHandler.HVP(x, y)
|
||||
case "h":
|
||||
return ap.hDispatch(params)
|
||||
case "l":
|
||||
return ap.lDispatch(params)
|
||||
case "m":
|
||||
return ap.eventHandler.SGR(getInts(params, 1, 0))
|
||||
case "r":
|
||||
ints := getInts(params, 2, 1)
|
||||
top, bottom := ints[0], ints[1]
|
||||
return ap.eventHandler.DECSTBM(top, bottom)
|
||||
default:
|
||||
logger.Errorf(fmt.Sprintf("Unsupported CSI command: '%s', with full context: %v", cmd, ap.context))
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) print() error {
|
||||
return ap.eventHandler.Print(ap.context.currentChar)
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) clear() error {
|
||||
ap.context = &AnsiContext{}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ap *AnsiParser) execute() error {
|
||||
return ap.eventHandler.Execute(ap.context.currentChar)
|
||||
}
|
114
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_test_helpers.go
generated
vendored
Normal file
114
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_test_helpers.go
generated
vendored
Normal file
|
@ -0,0 +1,114 @@
|
|||
package ansiterm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func getStateNames() []string {
|
||||
parser, _ := createTestParser("Ground")
|
||||
|
||||
stateNames := []string{}
|
||||
for _, state := range parser.stateMap {
|
||||
stateNames = append(stateNames, state.Name())
|
||||
}
|
||||
|
||||
return stateNames
|
||||
}
|
||||
|
||||
func stateTransitionHelper(t *testing.T, start string, end string, bytes []byte) {
|
||||
for _, b := range bytes {
|
||||
bytes := []byte{byte(b)}
|
||||
parser, _ := createTestParser(start)
|
||||
parser.Parse(bytes)
|
||||
validateState(t, parser.currState, end)
|
||||
}
|
||||
}
|
||||
|
||||
func anyToXHelper(t *testing.T, bytes []byte, expectedState string) {
|
||||
for _, s := range getStateNames() {
|
||||
stateTransitionHelper(t, s, expectedState, bytes)
|
||||
}
|
||||
}
|
||||
|
||||
func funcCallParamHelper(t *testing.T, bytes []byte, start string, expected string, expectedCalls []string) {
|
||||
parser, evtHandler := createTestParser(start)
|
||||
parser.Parse(bytes)
|
||||
validateState(t, parser.currState, expected)
|
||||
validateFuncCalls(t, evtHandler.FunctionCalls, expectedCalls)
|
||||
}
|
||||
|
||||
func parseParamsHelper(t *testing.T, bytes []byte, expectedParams []string) {
|
||||
params, err := parseParams(bytes)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Parameter parse error: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if len(params) != len(expectedParams) {
|
||||
t.Errorf("Parsed parameters: %v", params)
|
||||
t.Errorf("Expected parameters: %v", expectedParams)
|
||||
t.Errorf("Parameter length failure: %d != %d", len(params), len(expectedParams))
|
||||
return
|
||||
}
|
||||
|
||||
for i, v := range expectedParams {
|
||||
if v != params[i] {
|
||||
t.Errorf("Parsed parameters: %v", params)
|
||||
t.Errorf("Expected parameters: %v", expectedParams)
|
||||
t.Errorf("Parameter parse failure: %s != %s at position %d", v, params[i], i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func cursorSingleParamHelper(t *testing.T, command byte, funcName string) {
|
||||
funcCallParamHelper(t, []byte{command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)})
|
||||
funcCallParamHelper(t, []byte{'0', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)})
|
||||
funcCallParamHelper(t, []byte{'2', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2])", funcName)})
|
||||
funcCallParamHelper(t, []byte{'2', '3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([23])", funcName)})
|
||||
funcCallParamHelper(t, []byte{'2', ';', '3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2])", funcName)})
|
||||
funcCallParamHelper(t, []byte{'2', ';', '3', ';', '4', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2])", funcName)})
|
||||
}
|
||||
|
||||
func cursorTwoParamHelper(t *testing.T, command byte, funcName string) {
|
||||
funcCallParamHelper(t, []byte{command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1 1])", funcName)})
|
||||
funcCallParamHelper(t, []byte{'0', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1 1])", funcName)})
|
||||
funcCallParamHelper(t, []byte{'2', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2 1])", funcName)})
|
||||
funcCallParamHelper(t, []byte{'2', '3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([23 1])", funcName)})
|
||||
funcCallParamHelper(t, []byte{'2', ';', '3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2 3])", funcName)})
|
||||
funcCallParamHelper(t, []byte{'2', ';', '3', ';', '4', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2 3])", funcName)})
|
||||
}
|
||||
|
||||
func eraseHelper(t *testing.T, command byte, funcName string) {
|
||||
funcCallParamHelper(t, []byte{command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([0])", funcName)})
|
||||
funcCallParamHelper(t, []byte{'0', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([0])", funcName)})
|
||||
funcCallParamHelper(t, []byte{'1', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)})
|
||||
funcCallParamHelper(t, []byte{'2', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([2])", funcName)})
|
||||
funcCallParamHelper(t, []byte{'3', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([3])", funcName)})
|
||||
funcCallParamHelper(t, []byte{'4', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([0])", funcName)})
|
||||
funcCallParamHelper(t, []byte{'1', ';', '2', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)})
|
||||
}
|
||||
|
||||
func scrollHelper(t *testing.T, command byte, funcName string) {
|
||||
funcCallParamHelper(t, []byte{command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)})
|
||||
funcCallParamHelper(t, []byte{'0', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)})
|
||||
funcCallParamHelper(t, []byte{'1', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([1])", funcName)})
|
||||
funcCallParamHelper(t, []byte{'5', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([5])", funcName)})
|
||||
funcCallParamHelper(t, []byte{'4', ';', '6', command}, "CsiEntry", "Ground", []string{fmt.Sprintf("%s([4])", funcName)})
|
||||
}
|
||||
|
||||
func clearOnStateChangeHelper(t *testing.T, start string, end string, bytes []byte) {
|
||||
p, _ := createTestParser(start)
|
||||
fillContext(p.context)
|
||||
p.Parse(bytes)
|
||||
validateState(t, p.currState, end)
|
||||
validateEmptyContext(t, p.context)
|
||||
}
|
||||
|
||||
func c0Helper(t *testing.T, bytes []byte, expectedState string, expectedCalls []string) {
|
||||
parser, evtHandler := createTestParser("Ground")
|
||||
parser.Parse(bytes)
|
||||
validateState(t, parser.currState, expectedState)
|
||||
validateFuncCalls(t, evtHandler.FunctionCalls, expectedCalls)
|
||||
}
|
66
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_test_utilities.go
generated
vendored
Normal file
66
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/parser_test_utilities.go
generated
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
package ansiterm
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func createTestParser(s string) (*AnsiParser, *TestAnsiEventHandler) {
|
||||
evtHandler := CreateTestAnsiEventHandler()
|
||||
parser := CreateParser(s, evtHandler)
|
||||
|
||||
return parser, evtHandler
|
||||
}
|
||||
|
||||
func validateState(t *testing.T, actualState State, expectedStateName string) {
|
||||
actualName := "Nil"
|
||||
|
||||
if actualState != nil {
|
||||
actualName = actualState.Name()
|
||||
}
|
||||
|
||||
if actualName != expectedStateName {
|
||||
t.Errorf("Invalid State: '%s' != '%s'", actualName, expectedStateName)
|
||||
}
|
||||
}
|
||||
|
||||
func validateFuncCalls(t *testing.T, actualCalls []string, expectedCalls []string) {
|
||||
actualCount := len(actualCalls)
|
||||
expectedCount := len(expectedCalls)
|
||||
|
||||
if actualCount != expectedCount {
|
||||
t.Errorf("Actual calls: %v", actualCalls)
|
||||
t.Errorf("Expected calls: %v", expectedCalls)
|
||||
t.Errorf("Call count error: %d != %d", actualCount, expectedCount)
|
||||
return
|
||||
}
|
||||
|
||||
for i, v := range actualCalls {
|
||||
if v != expectedCalls[i] {
|
||||
t.Errorf("Actual calls: %v", actualCalls)
|
||||
t.Errorf("Expected calls: %v", expectedCalls)
|
||||
t.Errorf("Mismatched calls: %s != %s with lengths %d and %d", v, expectedCalls[i], len(v), len(expectedCalls[i]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func fillContext(context *AnsiContext) {
|
||||
context.currentChar = 'A'
|
||||
context.paramBuffer = []byte{'C', 'D', 'E'}
|
||||
context.interBuffer = []byte{'F', 'G', 'H'}
|
||||
}
|
||||
|
||||
func validateEmptyContext(t *testing.T, context *AnsiContext) {
|
||||
var expectedCurrChar byte = 0x0
|
||||
if context.currentChar != expectedCurrChar {
|
||||
t.Errorf("Currentchar mismatch '%#x' != '%#x'", context.currentChar, expectedCurrChar)
|
||||
}
|
||||
|
||||
if len(context.paramBuffer) != 0 {
|
||||
t.Errorf("Non-empty parameter buffer: %v", context.paramBuffer)
|
||||
}
|
||||
|
||||
if len(context.paramBuffer) != 0 {
|
||||
t.Errorf("Non-empty intermediate buffer: %v", context.interBuffer)
|
||||
}
|
||||
|
||||
}
|
71
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/states.go
generated
vendored
Normal file
71
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/states.go
generated
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
package ansiterm
|
||||
|
||||
type StateId int
|
||||
|
||||
type State interface {
|
||||
Enter() error
|
||||
Exit() error
|
||||
Handle(byte) (State, error)
|
||||
Name() string
|
||||
Transition(State) error
|
||||
}
|
||||
|
||||
type BaseState struct {
|
||||
name string
|
||||
parser *AnsiParser
|
||||
}
|
||||
|
||||
func (base BaseState) Enter() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (base BaseState) Exit() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (base BaseState) Handle(b byte) (s State, e error) {
|
||||
|
||||
switch {
|
||||
case b == CSI_ENTRY:
|
||||
return base.parser.CsiEntry, nil
|
||||
case b == DCS_ENTRY:
|
||||
return base.parser.DcsEntry, nil
|
||||
case b == ANSI_ESCAPE_PRIMARY:
|
||||
return base.parser.Escape, nil
|
||||
case b == OSC_STRING:
|
||||
return base.parser.OscString, nil
|
||||
case sliceContains(ToGroundBytes, b):
|
||||
return base.parser.Ground, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (base BaseState) Name() string {
|
||||
return base.name
|
||||
}
|
||||
|
||||
func (base BaseState) Transition(s State) error {
|
||||
if s == base.parser.Ground {
|
||||
execBytes := []byte{0x18}
|
||||
execBytes = append(execBytes, 0x1A)
|
||||
execBytes = append(execBytes, getByteRange(0x80, 0x8F)...)
|
||||
execBytes = append(execBytes, getByteRange(0x91, 0x97)...)
|
||||
execBytes = append(execBytes, 0x99)
|
||||
execBytes = append(execBytes, 0x9A)
|
||||
|
||||
if sliceContains(execBytes, base.parser.context.currentChar) {
|
||||
return base.parser.execute()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type DcsEntryState struct {
|
||||
BaseState
|
||||
}
|
||||
|
||||
type ErrorState struct {
|
||||
BaseState
|
||||
}
|
173
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/test_event_handler.go
generated
vendored
Normal file
173
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/test_event_handler.go
generated
vendored
Normal file
|
@ -0,0 +1,173 @@
|
|||
package ansiterm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type TestAnsiEventHandler struct {
|
||||
FunctionCalls []string
|
||||
}
|
||||
|
||||
func CreateTestAnsiEventHandler() *TestAnsiEventHandler {
|
||||
evtHandler := TestAnsiEventHandler{}
|
||||
evtHandler.FunctionCalls = make([]string, 0)
|
||||
return &evtHandler
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) recordCall(call string, params []string) {
|
||||
s := fmt.Sprintf("%s(%v)", call, params)
|
||||
h.FunctionCalls = append(h.FunctionCalls, s)
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) Print(b byte) error {
|
||||
h.recordCall("Print", []string{string(b)})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) Execute(b byte) error {
|
||||
h.recordCall("Execute", []string{string(b)})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) CUU(param int) error {
|
||||
h.recordCall("CUU", []string{strconv.Itoa(param)})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) CUD(param int) error {
|
||||
h.recordCall("CUD", []string{strconv.Itoa(param)})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) CUF(param int) error {
|
||||
h.recordCall("CUF", []string{strconv.Itoa(param)})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) CUB(param int) error {
|
||||
h.recordCall("CUB", []string{strconv.Itoa(param)})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) CNL(param int) error {
|
||||
h.recordCall("CNL", []string{strconv.Itoa(param)})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) CPL(param int) error {
|
||||
h.recordCall("CPL", []string{strconv.Itoa(param)})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) CHA(param int) error {
|
||||
h.recordCall("CHA", []string{strconv.Itoa(param)})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) VPA(param int) error {
|
||||
h.recordCall("VPA", []string{strconv.Itoa(param)})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) CUP(x int, y int) error {
|
||||
xS, yS := strconv.Itoa(x), strconv.Itoa(y)
|
||||
h.recordCall("CUP", []string{xS, yS})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) HVP(x int, y int) error {
|
||||
xS, yS := strconv.Itoa(x), strconv.Itoa(y)
|
||||
h.recordCall("HVP", []string{xS, yS})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) DECTCEM(visible bool) error {
|
||||
h.recordCall("DECTCEM", []string{strconv.FormatBool(visible)})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) DECOM(visible bool) error {
|
||||
h.recordCall("DECOM", []string{strconv.FormatBool(visible)})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) DECCOLM(use132 bool) error {
|
||||
h.recordCall("DECOLM", []string{strconv.FormatBool(use132)})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) ED(param int) error {
|
||||
h.recordCall("ED", []string{strconv.Itoa(param)})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) EL(param int) error {
|
||||
h.recordCall("EL", []string{strconv.Itoa(param)})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) IL(param int) error {
|
||||
h.recordCall("IL", []string{strconv.Itoa(param)})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) DL(param int) error {
|
||||
h.recordCall("DL", []string{strconv.Itoa(param)})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) ICH(param int) error {
|
||||
h.recordCall("ICH", []string{strconv.Itoa(param)})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) DCH(param int) error {
|
||||
h.recordCall("DCH", []string{strconv.Itoa(param)})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) SGR(params []int) error {
|
||||
strings := []string{}
|
||||
for _, v := range params {
|
||||
strings = append(strings, strconv.Itoa(v))
|
||||
}
|
||||
|
||||
h.recordCall("SGR", strings)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) SU(param int) error {
|
||||
h.recordCall("SU", []string{strconv.Itoa(param)})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) SD(param int) error {
|
||||
h.recordCall("SD", []string{strconv.Itoa(param)})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) DA(params []string) error {
|
||||
h.recordCall("DA", params)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) DECSTBM(top int, bottom int) error {
|
||||
topS, bottomS := strconv.Itoa(top), strconv.Itoa(bottom)
|
||||
h.recordCall("DECSTBM", []string{topS, bottomS})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) RI() error {
|
||||
h.recordCall("RI", nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) IND() error {
|
||||
h.recordCall("IND", nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *TestAnsiEventHandler) Flush() error {
|
||||
return nil
|
||||
}
|
21
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/utilities.go
generated
vendored
Normal file
21
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/utilities.go
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
package ansiterm
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func sliceContains(bytes []byte, b byte) bool {
|
||||
for _, v := range bytes {
|
||||
if v == b {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func convertBytesToInteger(bytes []byte) int {
|
||||
s := string(bytes)
|
||||
i, _ := strconv.Atoi(s)
|
||||
return i
|
||||
}
|
182
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/ansi.go
generated
vendored
Normal file
182
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/ansi.go
generated
vendored
Normal file
|
@ -0,0 +1,182 @@
|
|||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
. "github.com/Azure/go-ansiterm"
|
||||
)
|
||||
|
||||
// Windows keyboard constants
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx.
|
||||
const (
|
||||
VK_PRIOR = 0x21 // PAGE UP key
|
||||
VK_NEXT = 0x22 // PAGE DOWN key
|
||||
VK_END = 0x23 // END key
|
||||
VK_HOME = 0x24 // HOME key
|
||||
VK_LEFT = 0x25 // LEFT ARROW key
|
||||
VK_UP = 0x26 // UP ARROW key
|
||||
VK_RIGHT = 0x27 // RIGHT ARROW key
|
||||
VK_DOWN = 0x28 // DOWN ARROW key
|
||||
VK_SELECT = 0x29 // SELECT key
|
||||
VK_PRINT = 0x2A // PRINT key
|
||||
VK_EXECUTE = 0x2B // EXECUTE key
|
||||
VK_SNAPSHOT = 0x2C // PRINT SCREEN key
|
||||
VK_INSERT = 0x2D // INS key
|
||||
VK_DELETE = 0x2E // DEL key
|
||||
VK_HELP = 0x2F // HELP key
|
||||
VK_F1 = 0x70 // F1 key
|
||||
VK_F2 = 0x71 // F2 key
|
||||
VK_F3 = 0x72 // F3 key
|
||||
VK_F4 = 0x73 // F4 key
|
||||
VK_F5 = 0x74 // F5 key
|
||||
VK_F6 = 0x75 // F6 key
|
||||
VK_F7 = 0x76 // F7 key
|
||||
VK_F8 = 0x77 // F8 key
|
||||
VK_F9 = 0x78 // F9 key
|
||||
VK_F10 = 0x79 // F10 key
|
||||
VK_F11 = 0x7A // F11 key
|
||||
VK_F12 = 0x7B // F12 key
|
||||
|
||||
RIGHT_ALT_PRESSED = 0x0001
|
||||
LEFT_ALT_PRESSED = 0x0002
|
||||
RIGHT_CTRL_PRESSED = 0x0004
|
||||
LEFT_CTRL_PRESSED = 0x0008
|
||||
SHIFT_PRESSED = 0x0010
|
||||
NUMLOCK_ON = 0x0020
|
||||
SCROLLLOCK_ON = 0x0040
|
||||
CAPSLOCK_ON = 0x0080
|
||||
ENHANCED_KEY = 0x0100
|
||||
)
|
||||
|
||||
type ansiCommand struct {
|
||||
CommandBytes []byte
|
||||
Command string
|
||||
Parameters []string
|
||||
IsSpecial bool
|
||||
}
|
||||
|
||||
func newAnsiCommand(command []byte) *ansiCommand {
|
||||
|
||||
if isCharacterSelectionCmdChar(command[1]) {
|
||||
// Is Character Set Selection commands
|
||||
return &ansiCommand{
|
||||
CommandBytes: command,
|
||||
Command: string(command),
|
||||
IsSpecial: true,
|
||||
}
|
||||
}
|
||||
|
||||
// last char is command character
|
||||
lastCharIndex := len(command) - 1
|
||||
|
||||
ac := &ansiCommand{
|
||||
CommandBytes: command,
|
||||
Command: string(command[lastCharIndex]),
|
||||
IsSpecial: false,
|
||||
}
|
||||
|
||||
// more than a single escape
|
||||
if lastCharIndex != 0 {
|
||||
start := 1
|
||||
// skip if double char escape sequence
|
||||
if command[0] == ANSI_ESCAPE_PRIMARY && command[1] == ANSI_ESCAPE_SECONDARY {
|
||||
start++
|
||||
}
|
||||
// convert this to GetNextParam method
|
||||
ac.Parameters = strings.Split(string(command[start:lastCharIndex]), ANSI_PARAMETER_SEP)
|
||||
}
|
||||
|
||||
return ac
|
||||
}
|
||||
|
||||
func (ac *ansiCommand) paramAsSHORT(index int, defaultValue SHORT) SHORT {
|
||||
if index < 0 || index >= len(ac.Parameters) {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
param, err := strconv.ParseInt(ac.Parameters[index], 10, 16)
|
||||
if err != nil {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
return SHORT(param)
|
||||
}
|
||||
|
||||
func (ac *ansiCommand) String() string {
|
||||
return fmt.Sprintf("0x%v \"%v\" (\"%v\")",
|
||||
bytesToHex(ac.CommandBytes),
|
||||
ac.Command,
|
||||
strings.Join(ac.Parameters, "\",\""))
|
||||
}
|
||||
|
||||
// isAnsiCommandChar returns true if the passed byte falls within the range of ANSI commands.
|
||||
// See http://manpages.ubuntu.com/manpages/intrepid/man4/console_codes.4.html.
|
||||
func isAnsiCommandChar(b byte) bool {
|
||||
switch {
|
||||
case ANSI_COMMAND_FIRST <= b && b <= ANSI_COMMAND_LAST && b != ANSI_ESCAPE_SECONDARY:
|
||||
return true
|
||||
case b == ANSI_CMD_G1 || b == ANSI_CMD_OSC || b == ANSI_CMD_DECPAM || b == ANSI_CMD_DECPNM:
|
||||
// non-CSI escape sequence terminator
|
||||
return true
|
||||
case b == ANSI_CMD_STR_TERM || b == ANSI_BEL:
|
||||
// String escape sequence terminator
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isXtermOscSequence(command []byte, current byte) bool {
|
||||
return (len(command) >= 2 && command[0] == ANSI_ESCAPE_PRIMARY && command[1] == ANSI_CMD_OSC && current != ANSI_BEL)
|
||||
}
|
||||
|
||||
func isCharacterSelectionCmdChar(b byte) bool {
|
||||
return (b == ANSI_CMD_G0 || b == ANSI_CMD_G1 || b == ANSI_CMD_G2 || b == ANSI_CMD_G3)
|
||||
}
|
||||
|
||||
// bytesToHex converts a slice of bytes to a human-readable string.
|
||||
func bytesToHex(b []byte) string {
|
||||
hex := make([]string, len(b))
|
||||
for i, ch := range b {
|
||||
hex[i] = fmt.Sprintf("%X", ch)
|
||||
}
|
||||
return strings.Join(hex, "")
|
||||
}
|
||||
|
||||
// ensureInRange adjusts the passed value, if necessary, to ensure it is within
|
||||
// the passed min / max range.
|
||||
func ensureInRange(n SHORT, min SHORT, max SHORT) SHORT {
|
||||
if n < min {
|
||||
return min
|
||||
} else if n > max {
|
||||
return max
|
||||
} else {
|
||||
return n
|
||||
}
|
||||
}
|
||||
|
||||
func GetStdFile(nFile int) (*os.File, uintptr) {
|
||||
var file *os.File
|
||||
switch nFile {
|
||||
case syscall.STD_INPUT_HANDLE:
|
||||
file = os.Stdin
|
||||
case syscall.STD_OUTPUT_HANDLE:
|
||||
file = os.Stdout
|
||||
case syscall.STD_ERROR_HANDLE:
|
||||
file = os.Stderr
|
||||
default:
|
||||
panic(fmt.Errorf("Invalid standard handle identifier: %v", nFile))
|
||||
}
|
||||
|
||||
fd, err := syscall.GetStdHandle(nFile)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("Invalid standard handle indentifier: %v -- %v", nFile, err))
|
||||
}
|
||||
|
||||
return file, uintptr(fd)
|
||||
}
|
329
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/api.go
generated
vendored
Normal file
329
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/api.go
generated
vendored
Normal file
|
@ -0,0 +1,329 @@
|
|||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//===========================================================================================================
|
||||
// IMPORTANT NOTE:
|
||||
//
|
||||
// The methods below make extensive use of the "unsafe" package to obtain the required pointers.
|
||||
// Beginning in Go 1.3, the garbage collector may release local variables (e.g., incoming arguments, stack
|
||||
// variables) the pointers reference *before* the API completes.
|
||||
//
|
||||
// As a result, in those cases, the code must hint that the variables remain in active by invoking the
|
||||
// dummy method "use" (see below). Newer versions of Go are planned to change the mechanism to no longer
|
||||
// require unsafe pointers.
|
||||
//
|
||||
// If you add or modify methods, ENSURE protection of local variables through the "use" builtin to inform
|
||||
// the garbage collector the variables remain in use if:
|
||||
//
|
||||
// -- The value is not a pointer (e.g., int32, struct)
|
||||
// -- The value is not referenced by the method after passing the pointer to Windows
|
||||
//
|
||||
// See http://golang.org/doc/go1.3.
|
||||
//===========================================================================================================
|
||||
|
||||
var (
|
||||
kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
|
||||
|
||||
getConsoleCursorInfoProc = kernel32DLL.NewProc("GetConsoleCursorInfo")
|
||||
setConsoleCursorInfoProc = kernel32DLL.NewProc("SetConsoleCursorInfo")
|
||||
setConsoleCursorPositionProc = kernel32DLL.NewProc("SetConsoleCursorPosition")
|
||||
setConsoleModeProc = kernel32DLL.NewProc("SetConsoleMode")
|
||||
getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo")
|
||||
setConsoleScreenBufferSizeProc = kernel32DLL.NewProc("SetConsoleScreenBufferSize")
|
||||
scrollConsoleScreenBufferProc = kernel32DLL.NewProc("ScrollConsoleScreenBufferA")
|
||||
setConsoleTextAttributeProc = kernel32DLL.NewProc("SetConsoleTextAttribute")
|
||||
setConsoleWindowInfoProc = kernel32DLL.NewProc("SetConsoleWindowInfo")
|
||||
writeConsoleOutputProc = kernel32DLL.NewProc("WriteConsoleOutputW")
|
||||
readConsoleInputProc = kernel32DLL.NewProc("ReadConsoleInputW")
|
||||
waitForSingleObjectProc = kernel32DLL.NewProc("WaitForSingleObject")
|
||||
)
|
||||
|
||||
// Windows Console constants
|
||||
const (
|
||||
// Console modes
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
|
||||
ENABLE_PROCESSED_INPUT = 0x0001
|
||||
ENABLE_LINE_INPUT = 0x0002
|
||||
ENABLE_ECHO_INPUT = 0x0004
|
||||
ENABLE_WINDOW_INPUT = 0x0008
|
||||
ENABLE_MOUSE_INPUT = 0x0010
|
||||
ENABLE_INSERT_MODE = 0x0020
|
||||
ENABLE_QUICK_EDIT_MODE = 0x0040
|
||||
ENABLE_EXTENDED_FLAGS = 0x0080
|
||||
|
||||
ENABLE_PROCESSED_OUTPUT = 0x0001
|
||||
ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
|
||||
|
||||
// Character attributes
|
||||
// Note:
|
||||
// -- The attributes are combined to produce various colors (e.g., Blue + Green will create Cyan).
|
||||
// Clearing all foreground or background colors results in black; setting all creates white.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682088(v=vs.85).aspx#_win32_character_attributes.
|
||||
FOREGROUND_BLUE WORD = 0x0001
|
||||
FOREGROUND_GREEN WORD = 0x0002
|
||||
FOREGROUND_RED WORD = 0x0004
|
||||
FOREGROUND_INTENSITY WORD = 0x0008
|
||||
FOREGROUND_MASK WORD = 0x000F
|
||||
|
||||
BACKGROUND_BLUE WORD = 0x0010
|
||||
BACKGROUND_GREEN WORD = 0x0020
|
||||
BACKGROUND_RED WORD = 0x0040
|
||||
BACKGROUND_INTENSITY WORD = 0x0080
|
||||
BACKGROUND_MASK WORD = 0x00F0
|
||||
|
||||
COMMON_LVB_MASK WORD = 0xFF00
|
||||
COMMON_LVB_REVERSE_VIDEO WORD = 0x4000
|
||||
COMMON_LVB_UNDERSCORE WORD = 0x8000
|
||||
|
||||
// Input event types
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
|
||||
KEY_EVENT = 0x0001
|
||||
MOUSE_EVENT = 0x0002
|
||||
WINDOW_BUFFER_SIZE_EVENT = 0x0004
|
||||
MENU_EVENT = 0x0008
|
||||
FOCUS_EVENT = 0x0010
|
||||
|
||||
// WaitForSingleObject return codes
|
||||
WAIT_ABANDONED = 0x00000080
|
||||
WAIT_FAILED = 0xFFFFFFFF
|
||||
WAIT_SIGNALED = 0x0000000
|
||||
WAIT_TIMEOUT = 0x00000102
|
||||
|
||||
// WaitForSingleObject wait duration
|
||||
WAIT_INFINITE = 0xFFFFFFFF
|
||||
WAIT_ONE_SECOND = 1000
|
||||
WAIT_HALF_SECOND = 500
|
||||
WAIT_QUARTER_SECOND = 250
|
||||
)
|
||||
|
||||
// Windows API Console types
|
||||
// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx for core types (e.g., SHORT)
|
||||
// -- See https://msdn.microsoft.com/en-us/library/windows/desktop/ms682101(v=vs.85).aspx for Console specific types (e.g., COORD)
|
||||
// -- See https://msdn.microsoft.com/en-us/library/aa296569(v=vs.60).aspx for comments on alignment
|
||||
type (
|
||||
SHORT int16
|
||||
BOOL int32
|
||||
WORD uint16
|
||||
WCHAR uint16
|
||||
DWORD uint32
|
||||
|
||||
CHAR_INFO struct {
|
||||
UnicodeChar WCHAR
|
||||
Attributes WORD
|
||||
}
|
||||
|
||||
CONSOLE_CURSOR_INFO struct {
|
||||
Size DWORD
|
||||
Visible BOOL
|
||||
}
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO struct {
|
||||
Size COORD
|
||||
CursorPosition COORD
|
||||
Attributes WORD
|
||||
Window SMALL_RECT
|
||||
MaximumWindowSize COORD
|
||||
}
|
||||
|
||||
COORD struct {
|
||||
X SHORT
|
||||
Y SHORT
|
||||
}
|
||||
|
||||
SMALL_RECT struct {
|
||||
Left SHORT
|
||||
Top SHORT
|
||||
Right SHORT
|
||||
Bottom SHORT
|
||||
}
|
||||
|
||||
// INPUT_RECORD is a C/C++ union of which KEY_EVENT_RECORD is one case, it is also the largest
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683499(v=vs.85).aspx.
|
||||
INPUT_RECORD struct {
|
||||
EventType WORD
|
||||
KeyEvent KEY_EVENT_RECORD
|
||||
}
|
||||
|
||||
KEY_EVENT_RECORD struct {
|
||||
KeyDown BOOL
|
||||
RepeatCount WORD
|
||||
VirtualKeyCode WORD
|
||||
VirtualScanCode WORD
|
||||
UnicodeChar WCHAR
|
||||
ControlKeyState DWORD
|
||||
}
|
||||
|
||||
WINDOW_BUFFER_SIZE struct {
|
||||
Size COORD
|
||||
}
|
||||
)
|
||||
|
||||
// boolToBOOL converts a Go bool into a Windows BOOL.
|
||||
func boolToBOOL(f bool) BOOL {
|
||||
if f {
|
||||
return BOOL(1)
|
||||
} else {
|
||||
return BOOL(0)
|
||||
}
|
||||
}
|
||||
|
||||
// GetConsoleCursorInfo retrieves information about the size and visiblity of the console cursor.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683163(v=vs.85).aspx.
|
||||
func GetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
|
||||
r1, r2, err := getConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
// SetConsoleCursorInfo sets the size and visiblity of the console cursor.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686019(v=vs.85).aspx.
|
||||
func SetConsoleCursorInfo(handle uintptr, cursorInfo *CONSOLE_CURSOR_INFO) error {
|
||||
r1, r2, err := setConsoleCursorInfoProc.Call(handle, uintptr(unsafe.Pointer(cursorInfo)), 0)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
// SetConsoleCursorPosition location of the console cursor.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686025(v=vs.85).aspx.
|
||||
func SetConsoleCursorPosition(handle uintptr, coord COORD) error {
|
||||
r1, r2, err := setConsoleCursorPositionProc.Call(handle, coordToPointer(coord))
|
||||
use(coord)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
// GetConsoleMode gets the console mode for given file descriptor
|
||||
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx.
|
||||
func GetConsoleMode(handle uintptr) (mode uint32, err error) {
|
||||
err = syscall.GetConsoleMode(syscall.Handle(handle), &mode)
|
||||
return mode, err
|
||||
}
|
||||
|
||||
// SetConsoleMode sets the console mode for given file descriptor
|
||||
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx.
|
||||
func SetConsoleMode(handle uintptr, mode uint32) error {
|
||||
r1, r2, err := setConsoleModeProc.Call(handle, uintptr(mode), 0)
|
||||
use(mode)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
// GetConsoleScreenBufferInfo retrieves information about the specified console screen buffer.
|
||||
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms683171(v=vs.85).aspx.
|
||||
func GetConsoleScreenBufferInfo(handle uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) {
|
||||
info := CONSOLE_SCREEN_BUFFER_INFO{}
|
||||
err := checkError(getConsoleScreenBufferInfoProc.Call(handle, uintptr(unsafe.Pointer(&info)), 0))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &info, nil
|
||||
}
|
||||
|
||||
func ScrollConsoleScreenBuffer(handle uintptr, scrollRect SMALL_RECT, clipRect SMALL_RECT, destOrigin COORD, char CHAR_INFO) error {
|
||||
r1, r2, err := scrollConsoleScreenBufferProc.Call(handle, uintptr(unsafe.Pointer(&scrollRect)), uintptr(unsafe.Pointer(&clipRect)), coordToPointer(destOrigin), uintptr(unsafe.Pointer(&char)))
|
||||
use(scrollRect)
|
||||
use(clipRect)
|
||||
use(destOrigin)
|
||||
use(char)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
// SetConsoleScreenBufferSize sets the size of the console screen buffer.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686044(v=vs.85).aspx.
|
||||
func SetConsoleScreenBufferSize(handle uintptr, coord COORD) error {
|
||||
r1, r2, err := setConsoleScreenBufferSizeProc.Call(handle, coordToPointer(coord))
|
||||
use(coord)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
// SetConsoleTextAttribute sets the attributes of characters written to the
|
||||
// console screen buffer by the WriteFile or WriteConsole function.
|
||||
// See http://msdn.microsoft.com/en-us/library/windows/desktop/ms686047(v=vs.85).aspx.
|
||||
func SetConsoleTextAttribute(handle uintptr, attribute WORD) error {
|
||||
r1, r2, err := setConsoleTextAttributeProc.Call(handle, uintptr(attribute), 0)
|
||||
use(attribute)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
// SetConsoleWindowInfo sets the size and position of the console screen buffer's window.
|
||||
// Note that the size and location must be within and no larger than the backing console screen buffer.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms686125(v=vs.85).aspx.
|
||||
func SetConsoleWindowInfo(handle uintptr, isAbsolute bool, rect SMALL_RECT) error {
|
||||
r1, r2, err := setConsoleWindowInfoProc.Call(handle, uintptr(boolToBOOL(isAbsolute)), uintptr(unsafe.Pointer(&rect)))
|
||||
use(isAbsolute)
|
||||
use(rect)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
// WriteConsoleOutput writes the CHAR_INFOs from the provided buffer to the active console buffer.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687404(v=vs.85).aspx.
|
||||
func WriteConsoleOutput(handle uintptr, buffer []CHAR_INFO, bufferSize COORD, bufferCoord COORD, writeRegion *SMALL_RECT) error {
|
||||
r1, r2, err := writeConsoleOutputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), coordToPointer(bufferSize), coordToPointer(bufferCoord), uintptr(unsafe.Pointer(writeRegion)))
|
||||
use(buffer)
|
||||
use(bufferSize)
|
||||
use(bufferCoord)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
// ReadConsoleInput reads (and removes) data from the console input buffer.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms684961(v=vs.85).aspx.
|
||||
func ReadConsoleInput(handle uintptr, buffer []INPUT_RECORD, count *uint32) error {
|
||||
r1, r2, err := readConsoleInputProc.Call(handle, uintptr(unsafe.Pointer(&buffer[0])), uintptr(len(buffer)), uintptr(unsafe.Pointer(count)))
|
||||
use(buffer)
|
||||
return checkError(r1, r2, err)
|
||||
}
|
||||
|
||||
// WaitForSingleObject waits for the passed handle to be signaled.
|
||||
// It returns true if the handle was signaled; false otherwise.
|
||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx.
|
||||
func WaitForSingleObject(handle uintptr, msWait uint32) (bool, error) {
|
||||
r1, _, err := waitForSingleObjectProc.Call(handle, uintptr(DWORD(msWait)))
|
||||
switch r1 {
|
||||
case WAIT_ABANDONED, WAIT_TIMEOUT:
|
||||
return false, nil
|
||||
case WAIT_SIGNALED:
|
||||
return true, nil
|
||||
}
|
||||
use(msWait)
|
||||
return false, err
|
||||
}
|
||||
|
||||
// String helpers
|
||||
func (info CONSOLE_SCREEN_BUFFER_INFO) String() string {
|
||||
return fmt.Sprintf("Size(%v) Cursor(%v) Window(%v) Max(%v)", info.Size, info.CursorPosition, info.Window, info.MaximumWindowSize)
|
||||
}
|
||||
|
||||
func (coord COORD) String() string {
|
||||
return fmt.Sprintf("%v,%v", coord.X, coord.Y)
|
||||
}
|
||||
|
||||
func (rect SMALL_RECT) String() string {
|
||||
return fmt.Sprintf("(%v,%v),(%v,%v)", rect.Left, rect.Top, rect.Right, rect.Bottom)
|
||||
}
|
||||
|
||||
// checkError evaluates the results of a Windows API call and returns the error if it failed.
|
||||
func checkError(r1, r2 uintptr, err error) error {
|
||||
// Windows APIs return non-zero to indicate success
|
||||
if r1 != 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Return the error if provided, otherwise default to EINVAL
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return syscall.EINVAL
|
||||
}
|
||||
|
||||
// coordToPointer converts a COORD into a uintptr (by fooling the type system).
|
||||
func coordToPointer(c COORD) uintptr {
|
||||
// Note: This code assumes the two SHORTs are correctly laid out; the "cast" to DWORD is just to get a pointer to pass.
|
||||
return uintptr(*((*DWORD)(unsafe.Pointer(&c))))
|
||||
}
|
||||
|
||||
// use is a no-op, but the compiler cannot see that it is.
|
||||
// Calling use(p) ensures that p is kept live until that point.
|
||||
func use(p interface{}) {}
|
102
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/attr_translation.go
generated
vendored
Normal file
102
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/attr_translation.go
generated
vendored
Normal file
|
@ -0,0 +1,102 @@
|
|||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
import (
|
||||
. "github.com/Azure/go-ansiterm"
|
||||
)
|
||||
|
||||
const (
|
||||
FOREGROUND_COLOR_MASK = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
|
||||
BACKGROUND_COLOR_MASK = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
|
||||
)
|
||||
|
||||
// collectAnsiIntoWindowsAttributes modifies the passed Windows text mode flags to reflect the
|
||||
// request represented by the passed ANSI mode.
|
||||
func collectAnsiIntoWindowsAttributes(windowsMode WORD, inverted bool, baseMode WORD, ansiMode SHORT) (WORD, bool) {
|
||||
switch ansiMode {
|
||||
|
||||
// Mode styles
|
||||
case ANSI_SGR_BOLD:
|
||||
windowsMode = windowsMode | FOREGROUND_INTENSITY
|
||||
|
||||
case ANSI_SGR_DIM, ANSI_SGR_BOLD_DIM_OFF:
|
||||
windowsMode &^= FOREGROUND_INTENSITY
|
||||
|
||||
case ANSI_SGR_UNDERLINE:
|
||||
windowsMode = windowsMode | COMMON_LVB_UNDERSCORE
|
||||
|
||||
case ANSI_SGR_REVERSE:
|
||||
inverted = true
|
||||
|
||||
case ANSI_SGR_REVERSE_OFF:
|
||||
inverted = false
|
||||
|
||||
case ANSI_SGR_UNDERLINE_OFF:
|
||||
windowsMode &^= COMMON_LVB_UNDERSCORE
|
||||
|
||||
// Foreground colors
|
||||
case ANSI_SGR_FOREGROUND_DEFAULT:
|
||||
windowsMode = (windowsMode &^ FOREGROUND_MASK) | (baseMode & FOREGROUND_MASK)
|
||||
|
||||
case ANSI_SGR_FOREGROUND_BLACK:
|
||||
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK)
|
||||
|
||||
case ANSI_SGR_FOREGROUND_RED:
|
||||
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED
|
||||
|
||||
case ANSI_SGR_FOREGROUND_GREEN:
|
||||
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN
|
||||
|
||||
case ANSI_SGR_FOREGROUND_YELLOW:
|
||||
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN
|
||||
|
||||
case ANSI_SGR_FOREGROUND_BLUE:
|
||||
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_BLUE
|
||||
|
||||
case ANSI_SGR_FOREGROUND_MAGENTA:
|
||||
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_BLUE
|
||||
|
||||
case ANSI_SGR_FOREGROUND_CYAN:
|
||||
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_GREEN | FOREGROUND_BLUE
|
||||
|
||||
case ANSI_SGR_FOREGROUND_WHITE:
|
||||
windowsMode = (windowsMode &^ FOREGROUND_COLOR_MASK) | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
|
||||
|
||||
// Background colors
|
||||
case ANSI_SGR_BACKGROUND_DEFAULT:
|
||||
// Black with no intensity
|
||||
windowsMode = (windowsMode &^ BACKGROUND_MASK) | (baseMode & BACKGROUND_MASK)
|
||||
|
||||
case ANSI_SGR_BACKGROUND_BLACK:
|
||||
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK)
|
||||
|
||||
case ANSI_SGR_BACKGROUND_RED:
|
||||
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED
|
||||
|
||||
case ANSI_SGR_BACKGROUND_GREEN:
|
||||
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN
|
||||
|
||||
case ANSI_SGR_BACKGROUND_YELLOW:
|
||||
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN
|
||||
|
||||
case ANSI_SGR_BACKGROUND_BLUE:
|
||||
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_BLUE
|
||||
|
||||
case ANSI_SGR_BACKGROUND_MAGENTA:
|
||||
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_BLUE
|
||||
|
||||
case ANSI_SGR_BACKGROUND_CYAN:
|
||||
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_GREEN | BACKGROUND_BLUE
|
||||
|
||||
case ANSI_SGR_BACKGROUND_WHITE:
|
||||
windowsMode = (windowsMode &^ BACKGROUND_COLOR_MASK) | BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
|
||||
}
|
||||
|
||||
return windowsMode, inverted
|
||||
}
|
||||
|
||||
// invertAttributes inverts the foreground and background colors of a Windows attributes value
|
||||
func invertAttributes(windowsMode WORD) WORD {
|
||||
return (COMMON_LVB_MASK & windowsMode) | ((FOREGROUND_MASK & windowsMode) << 4) | ((BACKGROUND_MASK & windowsMode) >> 4)
|
||||
}
|
101
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go
generated
vendored
Normal file
101
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/cursor_helpers.go
generated
vendored
Normal file
|
@ -0,0 +1,101 @@
|
|||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
const (
|
||||
Horizontal = iota
|
||||
Vertical
|
||||
)
|
||||
|
||||
func (h *WindowsAnsiEventHandler) getCursorWindow(info *CONSOLE_SCREEN_BUFFER_INFO) SMALL_RECT {
|
||||
if h.originMode {
|
||||
sr := h.effectiveSr(info.Window)
|
||||
return SMALL_RECT{
|
||||
Top: sr.top,
|
||||
Bottom: sr.bottom,
|
||||
Left: 0,
|
||||
Right: info.Size.X - 1,
|
||||
}
|
||||
} else {
|
||||
return SMALL_RECT{
|
||||
Top: info.Window.Top,
|
||||
Bottom: info.Window.Bottom,
|
||||
Left: 0,
|
||||
Right: info.Size.X - 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setCursorPosition sets the cursor to the specified position, bounded to the screen size
|
||||
func (h *WindowsAnsiEventHandler) setCursorPosition(position COORD, window SMALL_RECT) error {
|
||||
position.X = ensureInRange(position.X, window.Left, window.Right)
|
||||
position.Y = ensureInRange(position.Y, window.Top, window.Bottom)
|
||||
err := SetConsoleCursorPosition(h.fd, position)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("Cursor position set: (%d, %d)", position.X, position.Y)
|
||||
return err
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) moveCursorVertical(param int) error {
|
||||
return h.moveCursor(Vertical, param)
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) moveCursorHorizontal(param int) error {
|
||||
return h.moveCursor(Horizontal, param)
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) moveCursor(moveMode int, param int) error {
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
position := info.CursorPosition
|
||||
switch moveMode {
|
||||
case Horizontal:
|
||||
position.X += SHORT(param)
|
||||
case Vertical:
|
||||
position.Y += SHORT(param)
|
||||
}
|
||||
|
||||
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) moveCursorLine(param int) error {
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
position := info.CursorPosition
|
||||
position.X = 0
|
||||
position.Y += SHORT(param)
|
||||
|
||||
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) moveCursorColumn(param int) error {
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
position := info.CursorPosition
|
||||
position.X = SHORT(param) - 1
|
||||
|
||||
if err = h.setCursorPosition(position, h.getCursorWindow(info)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
86
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/erase_helpers.go
generated
vendored
Normal file
86
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/erase_helpers.go
generated
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
import (
|
||||
. "github.com/Azure/go-ansiterm"
|
||||
)
|
||||
|
||||
func (h *WindowsAnsiEventHandler) clearRange(attributes WORD, fromCoord COORD, toCoord COORD) error {
|
||||
// Ignore an invalid (negative area) request
|
||||
if toCoord.Y < fromCoord.Y {
|
||||
return nil
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
var coordStart = COORD{}
|
||||
var coordEnd = COORD{}
|
||||
|
||||
xCurrent, yCurrent := fromCoord.X, fromCoord.Y
|
||||
xEnd, yEnd := toCoord.X, toCoord.Y
|
||||
|
||||
// Clear any partial initial line
|
||||
if xCurrent > 0 {
|
||||
coordStart.X, coordStart.Y = xCurrent, yCurrent
|
||||
coordEnd.X, coordEnd.Y = xEnd, yCurrent
|
||||
|
||||
err = h.clearRect(attributes, coordStart, coordEnd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
xCurrent = 0
|
||||
yCurrent += 1
|
||||
}
|
||||
|
||||
// Clear intervening rectangular section
|
||||
if yCurrent < yEnd {
|
||||
coordStart.X, coordStart.Y = xCurrent, yCurrent
|
||||
coordEnd.X, coordEnd.Y = xEnd, yEnd-1
|
||||
|
||||
err = h.clearRect(attributes, coordStart, coordEnd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
xCurrent = 0
|
||||
yCurrent = yEnd
|
||||
}
|
||||
|
||||
// Clear remaining partial ending line
|
||||
coordStart.X, coordStart.Y = xCurrent, yCurrent
|
||||
coordEnd.X, coordEnd.Y = xEnd, yEnd
|
||||
|
||||
err = h.clearRect(attributes, coordStart, coordEnd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) clearRect(attributes WORD, fromCoord COORD, toCoord COORD) error {
|
||||
region := SMALL_RECT{Top: fromCoord.Y, Left: fromCoord.X, Bottom: toCoord.Y, Right: toCoord.X}
|
||||
width := toCoord.X - fromCoord.X + 1
|
||||
height := toCoord.Y - fromCoord.Y + 1
|
||||
size := uint32(width) * uint32(height)
|
||||
|
||||
if size <= 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
buffer := make([]CHAR_INFO, size)
|
||||
|
||||
char := CHAR_INFO{WCHAR(FILL_CHARACTER), attributes}
|
||||
for i := 0; i < int(size); i++ {
|
||||
buffer[i] = char
|
||||
}
|
||||
|
||||
err := WriteConsoleOutput(h.fd, buffer, COORD{X: width, Y: height}, COORD{X: 0, Y: 0}, ®ion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
118
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/scroll_helper.go
generated
vendored
Normal file
118
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/scroll_helper.go
generated
vendored
Normal file
|
@ -0,0 +1,118 @@
|
|||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
// effectiveSr gets the current effective scroll region in buffer coordinates
|
||||
func (h *WindowsAnsiEventHandler) effectiveSr(window SMALL_RECT) scrollRegion {
|
||||
top := AddInRange(window.Top, h.sr.top, window.Top, window.Bottom)
|
||||
bottom := AddInRange(window.Top, h.sr.bottom, window.Top, window.Bottom)
|
||||
if top >= bottom {
|
||||
top = window.Top
|
||||
bottom = window.Bottom
|
||||
}
|
||||
return scrollRegion{top: top, bottom: bottom}
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) scrollUp(param int) error {
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sr := h.effectiveSr(info.Window)
|
||||
return h.scroll(param, sr, info)
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) scrollDown(param int) error {
|
||||
return h.scrollUp(-param)
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) deleteLines(param int) error {
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
start := info.CursorPosition.Y
|
||||
sr := h.effectiveSr(info.Window)
|
||||
// Lines cannot be inserted or deleted outside the scrolling region.
|
||||
if start >= sr.top && start <= sr.bottom {
|
||||
sr.top = start
|
||||
return h.scroll(param, sr, info)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) insertLines(param int) error {
|
||||
return h.deleteLines(-param)
|
||||
}
|
||||
|
||||
// scroll scrolls the provided scroll region by param lines. The scroll region is in buffer coordinates.
|
||||
func (h *WindowsAnsiEventHandler) scroll(param int, sr scrollRegion, info *CONSOLE_SCREEN_BUFFER_INFO) error {
|
||||
logger.Infof("scroll: scrollTop: %d, scrollBottom: %d", sr.top, sr.bottom)
|
||||
logger.Infof("scroll: windowTop: %d, windowBottom: %d", info.Window.Top, info.Window.Bottom)
|
||||
|
||||
// Copy from and clip to the scroll region (full buffer width)
|
||||
scrollRect := SMALL_RECT{
|
||||
Top: sr.top,
|
||||
Bottom: sr.bottom,
|
||||
Left: 0,
|
||||
Right: info.Size.X - 1,
|
||||
}
|
||||
|
||||
// Origin to which area should be copied
|
||||
destOrigin := COORD{
|
||||
X: 0,
|
||||
Y: sr.top - SHORT(param),
|
||||
}
|
||||
|
||||
char := CHAR_INFO{
|
||||
UnicodeChar: ' ',
|
||||
Attributes: h.attributes,
|
||||
}
|
||||
|
||||
if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) deleteCharacters(param int) error {
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return h.scrollLine(param, info.CursorPosition, info)
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) insertCharacters(param int) error {
|
||||
return h.deleteCharacters(-param)
|
||||
}
|
||||
|
||||
// scrollLine scrolls a line horizontally starting at the provided position by a number of columns.
|
||||
func (h *WindowsAnsiEventHandler) scrollLine(columns int, position COORD, info *CONSOLE_SCREEN_BUFFER_INFO) error {
|
||||
// Copy from and clip to the scroll region (full buffer width)
|
||||
scrollRect := SMALL_RECT{
|
||||
Top: position.Y,
|
||||
Bottom: position.Y,
|
||||
Left: position.X,
|
||||
Right: info.Size.X - 1,
|
||||
}
|
||||
|
||||
// Origin to which area should be copied
|
||||
destOrigin := COORD{
|
||||
X: position.X - SHORT(columns),
|
||||
Y: position.Y,
|
||||
}
|
||||
|
||||
char := CHAR_INFO{
|
||||
UnicodeChar: ' ',
|
||||
Attributes: h.attributes,
|
||||
}
|
||||
|
||||
if err := ScrollConsoleScreenBuffer(h.fd, scrollRect, scrollRect, destOrigin, char); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
9
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/utilities.go
generated
vendored
Normal file
9
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/utilities.go
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
// AddInRange increments a value by the passed quantity while ensuring the values
|
||||
// always remain within the supplied min / max range.
|
||||
func AddInRange(n SHORT, increment SHORT, min SHORT, max SHORT) SHORT {
|
||||
return ensureInRange(n+increment, min, max)
|
||||
}
|
725
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/win_event_handler.go
generated
vendored
Normal file
725
libnetwork/Godeps/_workspace/src/github.com/Azure/go-ansiterm/winterm/win_event_handler.go
generated
vendored
Normal file
|
@ -0,0 +1,725 @@
|
|||
// +build windows
|
||||
|
||||
package winterm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
. "github.com/Azure/go-ansiterm"
|
||||
"github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
var logger *logrus.Logger
|
||||
|
||||
type WindowsAnsiEventHandler struct {
|
||||
fd uintptr
|
||||
file *os.File
|
||||
infoReset *CONSOLE_SCREEN_BUFFER_INFO
|
||||
sr scrollRegion
|
||||
buffer bytes.Buffer
|
||||
attributes WORD
|
||||
inverted bool
|
||||
wrapNext bool
|
||||
drewMarginByte bool
|
||||
originMode bool
|
||||
marginByte byte
|
||||
curInfo *CONSOLE_SCREEN_BUFFER_INFO
|
||||
curPos COORD
|
||||
}
|
||||
|
||||
func CreateWinEventHandler(fd uintptr, file *os.File) AnsiEventHandler {
|
||||
logFile := ioutil.Discard
|
||||
|
||||
if isDebugEnv := os.Getenv(LogEnv); isDebugEnv == "1" {
|
||||
logFile, _ = os.Create("winEventHandler.log")
|
||||
}
|
||||
|
||||
logger = &logrus.Logger{
|
||||
Out: logFile,
|
||||
Formatter: new(logrus.TextFormatter),
|
||||
Level: logrus.DebugLevel,
|
||||
}
|
||||
|
||||
infoReset, err := GetConsoleScreenBufferInfo(fd)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &WindowsAnsiEventHandler{
|
||||
fd: fd,
|
||||
file: file,
|
||||
infoReset: infoReset,
|
||||
attributes: infoReset.Attributes,
|
||||
}
|
||||
}
|
||||
|
||||
type scrollRegion struct {
|
||||
top SHORT
|
||||
bottom SHORT
|
||||
}
|
||||
|
||||
// simulateLF simulates a LF or CR+LF by scrolling if necessary to handle the
|
||||
// current cursor position and scroll region settings, in which case it returns
|
||||
// true. If no special handling is necessary, then it does nothing and returns
|
||||
// false.
|
||||
//
|
||||
// In the false case, the caller should ensure that a carriage return
|
||||
// and line feed are inserted or that the text is otherwise wrapped.
|
||||
func (h *WindowsAnsiEventHandler) simulateLF(includeCR bool) (bool, error) {
|
||||
if h.wrapNext {
|
||||
if err := h.Flush(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
h.clearWrap()
|
||||
}
|
||||
pos, info, err := h.getCurrentInfo()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
sr := h.effectiveSr(info.Window)
|
||||
if pos.Y == sr.bottom {
|
||||
// Scrolling is necessary. Let Windows automatically scroll if the scrolling region
|
||||
// is the full window.
|
||||
if sr.top == info.Window.Top && sr.bottom == info.Window.Bottom {
|
||||
if includeCR {
|
||||
pos.X = 0
|
||||
h.updatePos(pos)
|
||||
}
|
||||
return false, nil
|
||||
} else {
|
||||
// A custom scroll region is active. Scroll the window manually to simulate
|
||||
// the LF.
|
||||
if err := h.Flush(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
logger.Info("Simulating LF inside scroll region")
|
||||
if err := h.scrollUp(1); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if includeCR {
|
||||
pos.X = 0
|
||||
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
} else if pos.Y < info.Window.Bottom {
|
||||
// Let Windows handle the LF.
|
||||
pos.Y++
|
||||
if includeCR {
|
||||
pos.X = 0
|
||||
}
|
||||
h.updatePos(pos)
|
||||
return false, nil
|
||||
} else {
|
||||
// The cursor is at the bottom of the screen but outside the scroll
|
||||
// region. Skip the LF.
|
||||
logger.Info("Simulating LF outside scroll region")
|
||||
if includeCR {
|
||||
if err := h.Flush(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
pos.X = 0
|
||||
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
// executeLF executes a LF without a CR.
|
||||
func (h *WindowsAnsiEventHandler) executeLF() error {
|
||||
handled, err := h.simulateLF(false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !handled {
|
||||
// Windows LF will reset the cursor column position. Write the LF
|
||||
// and restore the cursor position.
|
||||
pos, _, err := h.getCurrentInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h.buffer.WriteByte(ANSI_LINE_FEED)
|
||||
if pos.X != 0 {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Info("Resetting cursor position for LF without CR")
|
||||
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) Print(b byte) error {
|
||||
if h.wrapNext {
|
||||
h.buffer.WriteByte(h.marginByte)
|
||||
h.clearWrap()
|
||||
if _, err := h.simulateLF(true); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
pos, info, err := h.getCurrentInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if pos.X == info.Size.X-1 {
|
||||
h.wrapNext = true
|
||||
h.marginByte = b
|
||||
} else {
|
||||
pos.X++
|
||||
h.updatePos(pos)
|
||||
h.buffer.WriteByte(b)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) Execute(b byte) error {
|
||||
switch b {
|
||||
case ANSI_TAB:
|
||||
logger.Info("Execute(TAB)")
|
||||
// Move to the next tab stop, but preserve auto-wrap if already set.
|
||||
if !h.wrapNext {
|
||||
pos, info, err := h.getCurrentInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
pos.X = (pos.X + 8) - pos.X%8
|
||||
if pos.X >= info.Size.X {
|
||||
pos.X = info.Size.X - 1
|
||||
}
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
case ANSI_BEL:
|
||||
h.buffer.WriteByte(ANSI_BEL)
|
||||
return nil
|
||||
|
||||
case ANSI_BACKSPACE:
|
||||
if h.wrapNext {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
h.clearWrap()
|
||||
}
|
||||
pos, _, err := h.getCurrentInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if pos.X > 0 {
|
||||
pos.X--
|
||||
h.updatePos(pos)
|
||||
h.buffer.WriteByte(ANSI_BACKSPACE)
|
||||
}
|
||||
return nil
|
||||
|
||||
case ANSI_VERTICAL_TAB, ANSI_FORM_FEED:
|
||||
// Treat as true LF.
|
||||
return h.executeLF()
|
||||
|
||||
case ANSI_LINE_FEED:
|
||||
// Simulate a CR and LF for now since there is no way in go-ansiterm
|
||||
// to tell if the LF should include CR (and more things break when it's
|
||||
// missing than when it's incorrectly added).
|
||||
handled, err := h.simulateLF(true)
|
||||
if handled || err != nil {
|
||||
return err
|
||||
}
|
||||
return h.buffer.WriteByte(ANSI_LINE_FEED)
|
||||
|
||||
case ANSI_CARRIAGE_RETURN:
|
||||
if h.wrapNext {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
h.clearWrap()
|
||||
}
|
||||
pos, _, err := h.getCurrentInfo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if pos.X != 0 {
|
||||
pos.X = 0
|
||||
h.updatePos(pos)
|
||||
h.buffer.WriteByte(ANSI_CARRIAGE_RETURN)
|
||||
}
|
||||
return nil
|
||||
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) CUU(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("CUU: [%v]", []string{strconv.Itoa(param)})
|
||||
h.clearWrap()
|
||||
return h.moveCursorVertical(-param)
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) CUD(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("CUD: [%v]", []string{strconv.Itoa(param)})
|
||||
h.clearWrap()
|
||||
return h.moveCursorVertical(param)
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) CUF(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("CUF: [%v]", []string{strconv.Itoa(param)})
|
||||
h.clearWrap()
|
||||
return h.moveCursorHorizontal(param)
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) CUB(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("CUB: [%v]", []string{strconv.Itoa(param)})
|
||||
h.clearWrap()
|
||||
return h.moveCursorHorizontal(-param)
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) CNL(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("CNL: [%v]", []string{strconv.Itoa(param)})
|
||||
h.clearWrap()
|
||||
return h.moveCursorLine(param)
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) CPL(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("CPL: [%v]", []string{strconv.Itoa(param)})
|
||||
h.clearWrap()
|
||||
return h.moveCursorLine(-param)
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) CHA(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("CHA: [%v]", []string{strconv.Itoa(param)})
|
||||
h.clearWrap()
|
||||
return h.moveCursorColumn(param)
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) VPA(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("VPA: [[%d]]", param)
|
||||
h.clearWrap()
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
window := h.getCursorWindow(info)
|
||||
position := info.CursorPosition
|
||||
position.Y = window.Top + SHORT(param) - 1
|
||||
return h.setCursorPosition(position, window)
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) CUP(row int, col int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("CUP: [[%d %d]]", row, col)
|
||||
h.clearWrap()
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
window := h.getCursorWindow(info)
|
||||
position := COORD{window.Left + SHORT(col) - 1, window.Top + SHORT(row) - 1}
|
||||
return h.setCursorPosition(position, window)
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) HVP(row int, col int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("HVP: [[%d %d]]", row, col)
|
||||
h.clearWrap()
|
||||
return h.CUP(row, col)
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) DECTCEM(visible bool) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("DECTCEM: [%v]", []string{strconv.FormatBool(visible)})
|
||||
h.clearWrap()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) DECOM(enable bool) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("DECOM: [%v]", []string{strconv.FormatBool(enable)})
|
||||
h.clearWrap()
|
||||
h.originMode = enable
|
||||
return h.CUP(1, 1)
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) DECCOLM(use132 bool) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("DECCOLM: [%v]", []string{strconv.FormatBool(use132)})
|
||||
h.clearWrap()
|
||||
if err := h.ED(2); err != nil {
|
||||
return err
|
||||
}
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
targetWidth := SHORT(80)
|
||||
if use132 {
|
||||
targetWidth = 132
|
||||
}
|
||||
if info.Size.X < targetWidth {
|
||||
if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
|
||||
logger.Info("set buffer failed:", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
window := info.Window
|
||||
window.Left = 0
|
||||
window.Right = targetWidth - 1
|
||||
if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
|
||||
logger.Info("set window failed:", err)
|
||||
return err
|
||||
}
|
||||
if info.Size.X > targetWidth {
|
||||
if err := SetConsoleScreenBufferSize(h.fd, COORD{targetWidth, info.Size.Y}); err != nil {
|
||||
logger.Info("set buffer failed:", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return SetConsoleCursorPosition(h.fd, COORD{0, 0})
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) ED(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("ED: [%v]", []string{strconv.Itoa(param)})
|
||||
h.clearWrap()
|
||||
|
||||
// [J -- Erases from the cursor to the end of the screen, including the cursor position.
|
||||
// [1J -- Erases from the beginning of the screen to the cursor, including the cursor position.
|
||||
// [2J -- Erases the complete display. The cursor does not move.
|
||||
// Notes:
|
||||
// -- Clearing the entire buffer, versus just the Window, works best for Windows Consoles
|
||||
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var start COORD
|
||||
var end COORD
|
||||
|
||||
switch param {
|
||||
case 0:
|
||||
start = info.CursorPosition
|
||||
end = COORD{info.Size.X - 1, info.Size.Y - 1}
|
||||
|
||||
case 1:
|
||||
start = COORD{0, 0}
|
||||
end = info.CursorPosition
|
||||
|
||||
case 2:
|
||||
start = COORD{0, 0}
|
||||
end = COORD{info.Size.X - 1, info.Size.Y - 1}
|
||||
}
|
||||
|
||||
err = h.clearRange(h.attributes, start, end)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If the whole buffer was cleared, move the window to the top while preserving
|
||||
// the window-relative cursor position.
|
||||
if param == 2 {
|
||||
pos := info.CursorPosition
|
||||
window := info.Window
|
||||
pos.Y -= window.Top
|
||||
window.Bottom -= window.Top
|
||||
window.Top = 0
|
||||
if err := SetConsoleCursorPosition(h.fd, pos); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := SetConsoleWindowInfo(h.fd, true, window); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) EL(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("EL: [%v]", strconv.Itoa(param))
|
||||
h.clearWrap()
|
||||
|
||||
// [K -- Erases from the cursor to the end of the line, including the cursor position.
|
||||
// [1K -- Erases from the beginning of the line to the cursor, including the cursor position.
|
||||
// [2K -- Erases the complete line.
|
||||
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var start COORD
|
||||
var end COORD
|
||||
|
||||
switch param {
|
||||
case 0:
|
||||
start = info.CursorPosition
|
||||
end = COORD{info.Size.X, info.CursorPosition.Y}
|
||||
|
||||
case 1:
|
||||
start = COORD{0, info.CursorPosition.Y}
|
||||
end = info.CursorPosition
|
||||
|
||||
case 2:
|
||||
start = COORD{0, info.CursorPosition.Y}
|
||||
end = COORD{info.Size.X, info.CursorPosition.Y}
|
||||
}
|
||||
|
||||
err = h.clearRange(h.attributes, start, end)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) IL(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("IL: [%v]", strconv.Itoa(param))
|
||||
h.clearWrap()
|
||||
return h.insertLines(param)
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) DL(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("DL: [%v]", strconv.Itoa(param))
|
||||
h.clearWrap()
|
||||
return h.deleteLines(param)
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) ICH(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("ICH: [%v]", strconv.Itoa(param))
|
||||
h.clearWrap()
|
||||
return h.insertCharacters(param)
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) DCH(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("DCH: [%v]", strconv.Itoa(param))
|
||||
h.clearWrap()
|
||||
return h.deleteCharacters(param)
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) SGR(params []int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
strings := []string{}
|
||||
for _, v := range params {
|
||||
strings = append(strings, strconv.Itoa(v))
|
||||
}
|
||||
|
||||
logger.Infof("SGR: [%v]", strings)
|
||||
|
||||
if len(params) <= 0 {
|
||||
h.attributes = h.infoReset.Attributes
|
||||
h.inverted = false
|
||||
} else {
|
||||
for _, attr := range params {
|
||||
|
||||
if attr == ANSI_SGR_RESET {
|
||||
h.attributes = h.infoReset.Attributes
|
||||
h.inverted = false
|
||||
continue
|
||||
}
|
||||
|
||||
h.attributes, h.inverted = collectAnsiIntoWindowsAttributes(h.attributes, h.inverted, h.infoReset.Attributes, SHORT(attr))
|
||||
}
|
||||
}
|
||||
|
||||
attributes := h.attributes
|
||||
if h.inverted {
|
||||
attributes = invertAttributes(attributes)
|
||||
}
|
||||
err := SetConsoleTextAttribute(h.fd, attributes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) SU(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("SU: [%v]", []string{strconv.Itoa(param)})
|
||||
h.clearWrap()
|
||||
return h.scrollUp(param)
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) SD(param int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("SD: [%v]", []string{strconv.Itoa(param)})
|
||||
h.clearWrap()
|
||||
return h.scrollDown(param)
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) DA(params []string) error {
|
||||
logger.Infof("DA: [%v]", params)
|
||||
// DA cannot be implemented because it must send data on the VT100 input stream,
|
||||
// which is not available to go-ansiterm.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) DECSTBM(top int, bottom int) error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Infof("DECSTBM: [%d, %d]", top, bottom)
|
||||
|
||||
// Windows is 0 indexed, Linux is 1 indexed
|
||||
h.sr.top = SHORT(top - 1)
|
||||
h.sr.bottom = SHORT(bottom - 1)
|
||||
|
||||
// This command also moves the cursor to the origin.
|
||||
h.clearWrap()
|
||||
return h.CUP(1, 1)
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) RI() error {
|
||||
if err := h.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Info("RI: []")
|
||||
h.clearWrap()
|
||||
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sr := h.effectiveSr(info.Window)
|
||||
if info.CursorPosition.Y == sr.top {
|
||||
return h.scrollDown(1)
|
||||
} else {
|
||||
return h.moveCursorVertical(-1)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) IND() error {
|
||||
logger.Info("IND: []")
|
||||
return h.executeLF()
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) Flush() error {
|
||||
h.curInfo = nil
|
||||
if h.buffer.Len() > 0 {
|
||||
logger.Infof("Flush: [%s]", h.buffer.Bytes())
|
||||
if _, err := h.buffer.WriteTo(h.file); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if h.wrapNext && !h.drewMarginByte {
|
||||
logger.Infof("Flush: drawing margin byte '%c'", h.marginByte)
|
||||
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
charInfo := []CHAR_INFO{{UnicodeChar: WCHAR(h.marginByte), Attributes: info.Attributes}}
|
||||
size := COORD{1, 1}
|
||||
position := COORD{0, 0}
|
||||
region := SMALL_RECT{Left: info.CursorPosition.X, Top: info.CursorPosition.Y, Right: info.CursorPosition.X, Bottom: info.CursorPosition.Y}
|
||||
if err := WriteConsoleOutput(h.fd, charInfo, size, position, ®ion); err != nil {
|
||||
return err
|
||||
}
|
||||
h.drewMarginByte = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// cacheConsoleInfo ensures that the current console screen information has been queried
|
||||
// since the last call to Flush(). It must be called before accessing h.curInfo or h.curPos.
|
||||
func (h *WindowsAnsiEventHandler) getCurrentInfo() (COORD, *CONSOLE_SCREEN_BUFFER_INFO, error) {
|
||||
if h.curInfo == nil {
|
||||
info, err := GetConsoleScreenBufferInfo(h.fd)
|
||||
if err != nil {
|
||||
return COORD{}, nil, err
|
||||
}
|
||||
h.curInfo = info
|
||||
h.curPos = info.CursorPosition
|
||||
}
|
||||
return h.curPos, h.curInfo, nil
|
||||
}
|
||||
|
||||
func (h *WindowsAnsiEventHandler) updatePos(pos COORD) {
|
||||
if h.curInfo == nil {
|
||||
panic("failed to call getCurrentInfo before calling updatePos")
|
||||
}
|
||||
h.curPos = pos
|
||||
}
|
||||
|
||||
// clearWrap clears the state where the cursor is in the margin
|
||||
// waiting for the next character before wrapping the line. This must
|
||||
// be done before most operations that act on the cursor.
|
||||
func (h *WindowsAnsiEventHandler) clearWrap() {
|
||||
h.wrapNext = false
|
||||
h.drewMarginByte = false
|
||||
}
|
26
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/longpath/longpath.go
generated
vendored
Normal file
26
libnetwork/Godeps/_workspace/src/github.com/docker/docker/pkg/longpath/longpath.go
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
// longpath introduces some constants and helper functions for handling long paths
|
||||
// in Windows, which are expected to be prepended with `\\?\` and followed by either
|
||||
// a drive letter, a UNC server\share, or a volume identifier.
|
||||
|
||||
package longpath
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Prefix is the longpath prefix for Windows file paths.
|
||||
const Prefix = `\\?\`
|
||||
|
||||
// AddPrefix will add the Windows long path prefix to the path provided if
|
||||
// it does not already have it.
|
||||
func AddPrefix(path string) string {
|
||||
if !strings.HasPrefix(path, Prefix) {
|
||||
if strings.HasPrefix(path, `\\`) {
|
||||
// This is a UNC path, so we need to add 'UNC' to the path as well.
|
||||
path = Prefix + `UNC` + path[1:]
|
||||
} else {
|
||||
path = Prefix + path
|
||||
}
|
||||
}
|
||||
return path
|
||||
}
|
4
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/.gitignore
generated
vendored
Normal file
4
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
*.6
|
||||
tags
|
||||
test.out
|
||||
a.out
|
7
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/.travis.yml
generated
vendored
Normal file
7
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
language: go
|
||||
sudo: false
|
||||
go:
|
||||
- 1.4
|
||||
- 1.5
|
||||
script:
|
||||
- go test -race -v -bench=.
|
1
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/AUTHORS
generated
vendored
Normal file
1
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/AUTHORS
generated
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
Miek Gieben <miek@miek.nl>
|
9
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/CONTRIBUTORS
generated
vendored
Normal file
9
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/CONTRIBUTORS
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
Alex A. Skinner
|
||||
Andrew Tunnell-Jones
|
||||
Ask Bjørn Hansen
|
||||
Dave Cheney
|
||||
Dusty Wilson
|
||||
Marek Majkowski
|
||||
Peter van Dijk
|
||||
Omri Bahumi
|
||||
Alex Sergeyev
|
9
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/COPYRIGHT
generated
vendored
Normal file
9
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/COPYRIGHT
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
Copyright 2009 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.
|
||||
Extensions of the original work are copyright (c) 2011 Miek Gieben
|
||||
|
||||
Copyright 2011 Miek Gieben. All rights reserved. Use of this source code is
|
||||
governed by a BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
Copyright 2014 CloudFlare. All rights reserved. Use of this source code is
|
||||
governed by a BSD-style license that can be found in the LICENSE file.
|
32
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/LICENSE
generated
vendored
Normal file
32
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
Extensions of the original work are copyright (c) 2011 Miek Gieben
|
||||
|
||||
As this is fork of the official Go code the same license applies:
|
||||
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
153
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/README.md
generated
vendored
Normal file
153
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/README.md
generated
vendored
Normal file
|
@ -0,0 +1,153 @@
|
|||
[](https://travis-ci.org/miekg/dns)
|
||||
|
||||
# Alternative (more granular) approach to a DNS library
|
||||
|
||||
> 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.
|
||||
|
||||
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, currently: 1.4 and 1.5.
|
||||
|
||||
# Goals
|
||||
|
||||
* KISS;
|
||||
* Fast;
|
||||
* Small API, if its easy to code in Go, don't make a function for it.
|
||||
|
||||
# Users
|
||||
|
||||
A not-so-up-to-date-list-that-may-be-actually-current:
|
||||
|
||||
* https://cloudflare.com
|
||||
* https://github.com/abh/geodns
|
||||
* http://www.statdns.com/
|
||||
* http://www.dnsinspect.com/
|
||||
* https://github.com/chuangbo/jianbing-dictionary-dns
|
||||
* http://www.dns-lg.com/
|
||||
* https://github.com/fcambus/rrda
|
||||
* https://github.com/kenshinx/godns
|
||||
* https://github.com/skynetservices/skydns
|
||||
* https://github.com/DevelopersPL/godnsagent
|
||||
* https://github.com/duedil-ltd/discodns
|
||||
* https://github.com/StalkR/dns-reverse-proxy
|
||||
* 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.tk/
|
||||
* https://namesmith.io
|
||||
* https://github.com/miekg/unbound
|
||||
* https://github.com/miekg/exdns
|
||||
|
||||
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 and ECDSA;
|
||||
* EDNS0, NSID;
|
||||
* AXFR/IXFR;
|
||||
* TSIG, SIG(0);
|
||||
* DNS name compression;
|
||||
* Depends only on the standard library.
|
||||
|
||||
Have fun!
|
||||
|
||||
Miek Gieben - 2010-2012 - <miek@miek.nl>
|
||||
|
||||
# Building
|
||||
|
||||
Building is done with the `go` tool. If you have setup your GOPATH
|
||||
correctly, the following should work:
|
||||
|
||||
go get github.com/miekg/dns
|
||||
go build github.com/miekg/dns
|
||||
|
||||
## Examples
|
||||
|
||||
A short "how to use the API" is at the beginning of doc.go (this also will show
|
||||
when you call `godoc github.com/miekg/dns`).
|
||||
|
||||
Example programs can be found in the `github.com/miekg/exdns` repository.
|
||||
|
||||
## Supported RFCs
|
||||
|
||||
*all of them*
|
||||
|
||||
* 103{4,5} - DNS standard
|
||||
* 1348 - NSAP record (removed the record)
|
||||
* 1982 - Serial Arithmetic
|
||||
* 1876 - LOC record
|
||||
* 1995 - IXFR
|
||||
* 1996 - DNS notify
|
||||
* 2136 - DNS Update (dynamic updates)
|
||||
* 2181 - RRset definition - there is no RRset type though, just []RR
|
||||
* 2537 - RSAMD5 DNS keys
|
||||
* 2065 - DNSSEC (updated in later RFCs)
|
||||
* 2671 - EDNS record
|
||||
* 2782 - SRV record
|
||||
* 2845 - TSIG record
|
||||
* 2915 - NAPTR record
|
||||
* 2929 - DNS IANA Considerations
|
||||
* 3110 - RSASHA1 DNS keys
|
||||
* 3225 - DO bit (DNSSEC OK)
|
||||
* 340{1,2,3} - NAPTR record
|
||||
* 3445 - Limiting the scope of (DNS)KEY
|
||||
* 3597 - Unknown RRs
|
||||
* 4025 - IPSECKEY
|
||||
* 403{3,4,5} - DNSSEC + validation functions
|
||||
* 4255 - SSHFP record
|
||||
* 4343 - Case insensitivity
|
||||
* 4408 - SPF record
|
||||
* 4509 - SHA256 Hash in DS
|
||||
* 4592 - Wildcards in the DNS
|
||||
* 4635 - HMAC SHA TSIG
|
||||
* 4701 - DHCID
|
||||
* 4892 - id.server
|
||||
* 5001 - NSID
|
||||
* 5155 - NSEC3 record
|
||||
* 5205 - HIP record
|
||||
* 5702 - SHA2 in the DNS
|
||||
* 5936 - AXFR
|
||||
* 5966 - TCP implementation recommendations
|
||||
* 6605 - ECDSA
|
||||
* 6725 - IANA Registry Update
|
||||
* 6742 - ILNP DNS
|
||||
* 6840 - Clarifications and Implementation Notes for DNS Security
|
||||
* 6844 - CAA record
|
||||
* 6891 - EDNS0 update
|
||||
* 6895 - DNS IANA considerations
|
||||
* 6975 - Algorithm Understanding in DNSSEC
|
||||
* 7043 - EUI48/EUI64 records
|
||||
* 7314 - DNS (EDNS) EXPIRE Option
|
||||
* 7553 - URI record
|
||||
* xxxx - EDNS0 DNS Update Lease (draft)
|
||||
|
||||
## Loosely based upon
|
||||
|
||||
* `ldns`
|
||||
* `NSD`
|
||||
* `Net::DNS`
|
||||
* `GRONG`
|
||||
|
||||
## TODO
|
||||
|
||||
* privatekey.Precompute() when signing?
|
||||
* Last remaining RRs: APL, ATMA, A6, NSAP and NXT.
|
||||
* Missing in parsing: ISDN, UNSPEC, NSAP and ATMA.
|
||||
* NSEC(3) cover/match/closest enclose.
|
||||
* Replies with TC bit are not parsed to the end.
|
385
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/client.go
generated
vendored
Normal file
385
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/client.go
generated
vendored
Normal file
|
@ -0,0 +1,385 @@
|
|||
package dns
|
||||
|
||||
// A client implementation.
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
const dnsTimeout time.Duration = 2 * time.Second
|
||||
const tcpIdleTimeout time.Duration = 8 * time.Second
|
||||
|
||||
// A Conn represents a connection to a DNS server.
|
||||
type Conn struct {
|
||||
net.Conn // a net.Conn holding the connection
|
||||
UDPSize uint16 // minimum receive buffer for UDP messages
|
||||
TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be fully qualified
|
||||
rtt time.Duration
|
||||
t time.Time
|
||||
tsigRequestMAC string
|
||||
}
|
||||
|
||||
// A Client defines parameters for a DNS client.
|
||||
type Client struct {
|
||||
Net string // if "tcp" a TCP query will be initiated, otherwise an UDP one (default is "" for UDP)
|
||||
UDPSize uint16 // minimum receive buffer for UDP messages
|
||||
DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds
|
||||
ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds
|
||||
WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds
|
||||
TsigSecret map[string]string // secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be fully qualified
|
||||
SingleInflight bool // if true suppress multiple outstanding queries for the same Qname, Qtype and Qclass
|
||||
group singleflight
|
||||
}
|
||||
|
||||
// Exchange performs a synchronous UDP query. It sends the message m to the address
|
||||
// contained in a and waits for an reply. Exchange does not retry a failed query, nor
|
||||
// will it fall back to TCP in case of truncation.
|
||||
// If you need to send a DNS message on an already existing connection, you can use the
|
||||
// following:
|
||||
//
|
||||
// co := &dns.Conn{Conn: c} // c is your net.Conn
|
||||
// co.WriteMsg(m)
|
||||
// in, err := co.ReadMsg()
|
||||
// co.Close()
|
||||
//
|
||||
func Exchange(m *Msg, a string) (r *Msg, err error) {
|
||||
var co *Conn
|
||||
co, err = DialTimeout("udp", a, dnsTimeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer co.Close()
|
||||
|
||||
opt := m.IsEdns0()
|
||||
// If EDNS0 is used use that for size.
|
||||
if opt != nil && opt.UDPSize() >= MinMsgSize {
|
||||
co.UDPSize = opt.UDPSize()
|
||||
}
|
||||
|
||||
co.SetWriteDeadline(time.Now().Add(dnsTimeout))
|
||||
if err = co.WriteMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
co.SetReadDeadline(time.Now().Add(dnsTimeout))
|
||||
r, err = co.ReadMsg()
|
||||
if err == nil && r.Id != m.Id {
|
||||
err = ErrId
|
||||
}
|
||||
return r, err
|
||||
}
|
||||
|
||||
// ExchangeConn performs a synchronous query. It sends the message m via the connection
|
||||
// c and waits for a reply. The connection c is not closed by ExchangeConn.
|
||||
// This function is going away, but can easily be mimicked:
|
||||
//
|
||||
// co := &dns.Conn{Conn: c} // c is your net.Conn
|
||||
// co.WriteMsg(m)
|
||||
// in, _ := co.ReadMsg()
|
||||
// co.Close()
|
||||
//
|
||||
func ExchangeConn(c net.Conn, m *Msg) (r *Msg, err error) {
|
||||
println("dns: this function is deprecated")
|
||||
co := new(Conn)
|
||||
co.Conn = c
|
||||
if err = co.WriteMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r, err = co.ReadMsg()
|
||||
if err == nil && r.Id != m.Id {
|
||||
err = ErrId
|
||||
}
|
||||
return r, err
|
||||
}
|
||||
|
||||
// Exchange performs an synchronous query. It sends the message m to the address
|
||||
// contained in a and waits for an reply. Basic use pattern with a *dns.Client:
|
||||
//
|
||||
// c := new(dns.Client)
|
||||
// in, rtt, err := c.Exchange(message, "127.0.0.1:53")
|
||||
//
|
||||
// Exchange does not retry a failed query, nor will it fall back to TCP in
|
||||
// case of truncation.
|
||||
func (c *Client) Exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
|
||||
if !c.SingleInflight {
|
||||
return c.exchange(m, a)
|
||||
}
|
||||
// This adds a bunch of garbage, TODO(miek).
|
||||
t := "nop"
|
||||
if t1, ok := TypeToString[m.Question[0].Qtype]; ok {
|
||||
t = t1
|
||||
}
|
||||
cl := "nop"
|
||||
if cl1, ok := ClassToString[m.Question[0].Qclass]; ok {
|
||||
cl = cl1
|
||||
}
|
||||
r, rtt, err, shared := c.group.Do(m.Question[0].Name+t+cl, func() (*Msg, time.Duration, error) {
|
||||
return c.exchange(m, a)
|
||||
})
|
||||
if err != nil {
|
||||
return r, rtt, err
|
||||
}
|
||||
if shared {
|
||||
return r.Copy(), rtt, nil
|
||||
}
|
||||
return r, rtt, nil
|
||||
}
|
||||
|
||||
func (c *Client) dialTimeout() time.Duration {
|
||||
if c.DialTimeout != 0 {
|
||||
return c.DialTimeout
|
||||
}
|
||||
return dnsTimeout
|
||||
}
|
||||
|
||||
func (c *Client) readTimeout() time.Duration {
|
||||
if c.ReadTimeout != 0 {
|
||||
return c.ReadTimeout
|
||||
}
|
||||
return dnsTimeout
|
||||
}
|
||||
|
||||
func (c *Client) writeTimeout() time.Duration {
|
||||
if c.WriteTimeout != 0 {
|
||||
return c.WriteTimeout
|
||||
}
|
||||
return dnsTimeout
|
||||
}
|
||||
|
||||
func (c *Client) exchange(m *Msg, a string) (r *Msg, rtt time.Duration, err error) {
|
||||
var co *Conn
|
||||
if c.Net == "" {
|
||||
co, err = DialTimeout("udp", a, c.dialTimeout())
|
||||
} else {
|
||||
co, err = DialTimeout(c.Net, a, c.dialTimeout())
|
||||
}
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
defer co.Close()
|
||||
|
||||
opt := m.IsEdns0()
|
||||
// If EDNS0 is used use that for size.
|
||||
if opt != nil && opt.UDPSize() >= MinMsgSize {
|
||||
co.UDPSize = opt.UDPSize()
|
||||
}
|
||||
// Otherwise use the client's configured UDP size.
|
||||
if opt == nil && c.UDPSize >= MinMsgSize {
|
||||
co.UDPSize = c.UDPSize
|
||||
}
|
||||
|
||||
co.TsigSecret = c.TsigSecret
|
||||
co.SetWriteDeadline(time.Now().Add(c.writeTimeout()))
|
||||
if err = co.WriteMsg(m); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
co.SetReadDeadline(time.Now().Add(c.readTimeout()))
|
||||
r, err = co.ReadMsg()
|
||||
if err == nil && r.Id != m.Id {
|
||||
err = ErrId
|
||||
}
|
||||
return r, co.rtt, err
|
||||
}
|
||||
|
||||
// ReadMsg reads a message from the connection co.
|
||||
// If the received message contains a TSIG record the transaction
|
||||
// signature is verified.
|
||||
func (co *Conn) ReadMsg() (*Msg, error) {
|
||||
p, err := co.ReadMsgHeader(nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m := new(Msg)
|
||||
if err := m.Unpack(p); err != nil {
|
||||
// If ErrTruncated was returned, we still want to allow the user to use
|
||||
// the message, but naively they can just check err if they don't want
|
||||
// to use a truncated message
|
||||
if err == ErrTruncated {
|
||||
return m, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if t := m.IsTsig(); t != nil {
|
||||
if _, ok := co.TsigSecret[t.Hdr.Name]; !ok {
|
||||
return m, ErrSecret
|
||||
}
|
||||
// Need to work on the original message p, as that was used to calculate the tsig.
|
||||
err = TsigVerify(p, co.TsigSecret[t.Hdr.Name], co.tsigRequestMAC, false)
|
||||
}
|
||||
return m, err
|
||||
}
|
||||
|
||||
// ReadMsgHeader reads a DNS message, parses and populates hdr (when hdr is not nil).
|
||||
// Returns message as a byte slice to be parsed with Msg.Unpack later on.
|
||||
// Note that error handling on the message body is not possible as only the header is parsed.
|
||||
func (co *Conn) ReadMsgHeader(hdr *Header) ([]byte, error) {
|
||||
var (
|
||||
p []byte
|
||||
n int
|
||||
err error
|
||||
)
|
||||
|
||||
if t, ok := co.Conn.(*net.TCPConn); ok {
|
||||
// First two bytes specify the length of the entire message.
|
||||
l, err := tcpMsgLen(t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p = make([]byte, l)
|
||||
n, err = tcpRead(t, p)
|
||||
} else {
|
||||
if co.UDPSize > MinMsgSize {
|
||||
p = make([]byte, co.UDPSize)
|
||||
} else {
|
||||
p = make([]byte, MinMsgSize)
|
||||
}
|
||||
n, err = co.Read(p)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if n < headerSize {
|
||||
return nil, ErrShortRead
|
||||
}
|
||||
|
||||
p = p[:n]
|
||||
if hdr != nil {
|
||||
if _, err = UnpackStruct(hdr, p, 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return p, err
|
||||
}
|
||||
|
||||
// tcpMsgLen is a helper func to read first two bytes of stream as uint16 packet length.
|
||||
func tcpMsgLen(t *net.TCPConn) (int, error) {
|
||||
p := []byte{0, 0}
|
||||
n, err := t.Read(p)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if n != 2 {
|
||||
return 0, ErrShortRead
|
||||
}
|
||||
l, _ := unpackUint16(p, 0)
|
||||
if l == 0 {
|
||||
return 0, ErrShortRead
|
||||
}
|
||||
return int(l), nil
|
||||
}
|
||||
|
||||
// tcpRead calls TCPConn.Read enough times to fill allocated buffer.
|
||||
func tcpRead(t *net.TCPConn, p []byte) (int, error) {
|
||||
n, err := t.Read(p)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
for n < len(p) {
|
||||
j, err := t.Read(p[n:])
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
n += j
|
||||
}
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Read implements the net.Conn read method.
|
||||
func (co *Conn) Read(p []byte) (n int, err error) {
|
||||
if co.Conn == nil {
|
||||
return 0, ErrConnEmpty
|
||||
}
|
||||
if len(p) < 2 {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
if t, ok := co.Conn.(*net.TCPConn); ok {
|
||||
l, err := tcpMsgLen(t)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if l > len(p) {
|
||||
return int(l), io.ErrShortBuffer
|
||||
}
|
||||
return tcpRead(t, p[:l])
|
||||
}
|
||||
// UDP connection
|
||||
n, err = co.Conn.Read(p)
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
|
||||
co.rtt = time.Since(co.t)
|
||||
return n, err
|
||||
}
|
||||
|
||||
// WriteMsg sends a message throught the connection co.
|
||||
// If the message m contains a TSIG record the transaction
|
||||
// signature is calculated.
|
||||
func (co *Conn) WriteMsg(m *Msg) (err error) {
|
||||
var out []byte
|
||||
if t := m.IsTsig(); t != nil {
|
||||
mac := ""
|
||||
if _, ok := co.TsigSecret[t.Hdr.Name]; !ok {
|
||||
return ErrSecret
|
||||
}
|
||||
out, mac, err = TsigGenerate(m, co.TsigSecret[t.Hdr.Name], co.tsigRequestMAC, false)
|
||||
// Set for the next read, allthough only used in zone transfers
|
||||
co.tsigRequestMAC = mac
|
||||
} else {
|
||||
out, err = m.Pack()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
co.t = time.Now()
|
||||
if _, err = co.Write(out); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Write implements the net.Conn Write method.
|
||||
func (co *Conn) Write(p []byte) (n int, err error) {
|
||||
if t, ok := co.Conn.(*net.TCPConn); ok {
|
||||
lp := len(p)
|
||||
if lp < 2 {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
if lp > MaxMsgSize {
|
||||
return 0, &Error{err: "message too large"}
|
||||
}
|
||||
l := make([]byte, 2, lp+2)
|
||||
l[0], l[1] = packUint16(uint16(lp))
|
||||
p = append(l, p...)
|
||||
n, err := io.Copy(t, bytes.NewReader(p))
|
||||
return int(n), err
|
||||
}
|
||||
n, err = co.Conn.(*net.UDPConn).Write(p)
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Dial connects to the address on the named network.
|
||||
func Dial(network, address string) (conn *Conn, err error) {
|
||||
conn = new(Conn)
|
||||
conn.Conn, err = net.Dial(network, address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// DialTimeout acts like Dial but takes a timeout.
|
||||
func DialTimeout(network, address string, timeout time.Duration) (conn *Conn, err error) {
|
||||
conn = new(Conn)
|
||||
conn.Conn, err = net.DialTimeout(network, address, timeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return conn, nil
|
||||
}
|
99
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/clientconfig.go
generated
vendored
Normal file
99
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/clientconfig.go
generated
vendored
Normal file
|
@ -0,0 +1,99 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ClientConfig wraps the contents of the /etc/resolv.conf file.
|
||||
type ClientConfig struct {
|
||||
Servers []string // servers to use
|
||||
Search []string // suffixes to append to local name
|
||||
Port string // what port to use
|
||||
Ndots int // number of dots in name to trigger absolute lookup
|
||||
Timeout int // seconds before giving up on packet
|
||||
Attempts int // lost packets before giving up on server, not used in the package dns
|
||||
}
|
||||
|
||||
// ClientConfigFromFile parses a resolv.conf(5) like file and returns
|
||||
// a *ClientConfig.
|
||||
func ClientConfigFromFile(resolvconf string) (*ClientConfig, error) {
|
||||
file, err := os.Open(resolvconf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
c := new(ClientConfig)
|
||||
scanner := bufio.NewScanner(file)
|
||||
c.Servers = make([]string, 0)
|
||||
c.Search = make([]string, 0)
|
||||
c.Port = "53"
|
||||
c.Ndots = 1
|
||||
c.Timeout = 5
|
||||
c.Attempts = 2
|
||||
|
||||
for scanner.Scan() {
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
line := scanner.Text()
|
||||
f := strings.Fields(line)
|
||||
if len(f) < 1 {
|
||||
continue
|
||||
}
|
||||
switch f[0] {
|
||||
case "nameserver": // add one name server
|
||||
if len(f) > 1 {
|
||||
// One more check: make sure server name is
|
||||
// just an IP address. Otherwise we need DNS
|
||||
// to look it up.
|
||||
name := f[1]
|
||||
c.Servers = append(c.Servers, name)
|
||||
}
|
||||
|
||||
case "domain": // set search path to just this domain
|
||||
if len(f) > 1 {
|
||||
c.Search = make([]string, 1)
|
||||
c.Search[0] = f[1]
|
||||
} else {
|
||||
c.Search = make([]string, 0)
|
||||
}
|
||||
|
||||
case "search": // set search path to given servers
|
||||
c.Search = make([]string, len(f)-1)
|
||||
for i := 0; i < len(c.Search); i++ {
|
||||
c.Search[i] = f[i+1]
|
||||
}
|
||||
|
||||
case "options": // magic options
|
||||
for i := 1; i < len(f); i++ {
|
||||
s := f[i]
|
||||
switch {
|
||||
case len(s) >= 6 && s[:6] == "ndots:":
|
||||
n, _ := strconv.Atoi(s[6:])
|
||||
if n < 1 {
|
||||
n = 1
|
||||
}
|
||||
c.Ndots = n
|
||||
case len(s) >= 8 && s[:8] == "timeout:":
|
||||
n, _ := strconv.Atoi(s[8:])
|
||||
if n < 1 {
|
||||
n = 1
|
||||
}
|
||||
c.Timeout = n
|
||||
case len(s) >= 8 && s[:9] == "attempts:":
|
||||
n, _ := strconv.Atoi(s[9:])
|
||||
if n < 1 {
|
||||
n = 1
|
||||
}
|
||||
c.Attempts = n
|
||||
case s == "rotate":
|
||||
/* not imp */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return c, nil
|
||||
}
|
278
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/defaults.go
generated
vendored
Normal file
278
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/defaults.go
generated
vendored
Normal file
|
@ -0,0 +1,278 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const hexDigit = "0123456789abcdef"
|
||||
|
||||
// Everything is assumed in ClassINET.
|
||||
|
||||
// SetReply creates a reply message from a request message.
|
||||
func (dns *Msg) SetReply(request *Msg) *Msg {
|
||||
dns.Id = request.Id
|
||||
dns.RecursionDesired = request.RecursionDesired // Copy rd bit
|
||||
dns.Response = true
|
||||
dns.Opcode = OpcodeQuery
|
||||
dns.Rcode = RcodeSuccess
|
||||
if len(request.Question) > 0 {
|
||||
dns.Question = make([]Question, 1)
|
||||
dns.Question[0] = request.Question[0]
|
||||
}
|
||||
return dns
|
||||
}
|
||||
|
||||
// SetQuestion creates a question message, it sets the Question
|
||||
// section, generates an Id and sets the RecursionDesired (RD)
|
||||
// bit to true.
|
||||
func (dns *Msg) SetQuestion(z string, t uint16) *Msg {
|
||||
dns.Id = Id()
|
||||
dns.RecursionDesired = true
|
||||
dns.Question = make([]Question, 1)
|
||||
dns.Question[0] = Question{z, t, ClassINET}
|
||||
return dns
|
||||
}
|
||||
|
||||
// SetNotify creates a notify message, it sets the Question
|
||||
// section, generates an Id and sets the Authoritative (AA)
|
||||
// bit to true.
|
||||
func (dns *Msg) SetNotify(z string) *Msg {
|
||||
dns.Opcode = OpcodeNotify
|
||||
dns.Authoritative = true
|
||||
dns.Id = Id()
|
||||
dns.Question = make([]Question, 1)
|
||||
dns.Question[0] = Question{z, TypeSOA, ClassINET}
|
||||
return dns
|
||||
}
|
||||
|
||||
// SetRcode creates an error message suitable for the request.
|
||||
func (dns *Msg) SetRcode(request *Msg, rcode int) *Msg {
|
||||
dns.SetReply(request)
|
||||
dns.Rcode = rcode
|
||||
return dns
|
||||
}
|
||||
|
||||
// SetRcodeFormatError creates a message with FormError set.
|
||||
func (dns *Msg) SetRcodeFormatError(request *Msg) *Msg {
|
||||
dns.Rcode = RcodeFormatError
|
||||
dns.Opcode = OpcodeQuery
|
||||
dns.Response = true
|
||||
dns.Authoritative = false
|
||||
dns.Id = request.Id
|
||||
return dns
|
||||
}
|
||||
|
||||
// SetUpdate makes the message a dynamic update message. It
|
||||
// sets the ZONE section to: z, TypeSOA, ClassINET.
|
||||
func (dns *Msg) SetUpdate(z string) *Msg {
|
||||
dns.Id = Id()
|
||||
dns.Response = false
|
||||
dns.Opcode = OpcodeUpdate
|
||||
dns.Compress = false // BIND9 cannot handle compression
|
||||
dns.Question = make([]Question, 1)
|
||||
dns.Question[0] = Question{z, TypeSOA, ClassINET}
|
||||
return dns
|
||||
}
|
||||
|
||||
// SetIxfr creates message for requesting an IXFR.
|
||||
func (dns *Msg) SetIxfr(z string, serial uint32, ns, mbox string) *Msg {
|
||||
dns.Id = Id()
|
||||
dns.Question = make([]Question, 1)
|
||||
dns.Ns = make([]RR, 1)
|
||||
s := new(SOA)
|
||||
s.Hdr = RR_Header{z, TypeSOA, ClassINET, defaultTtl, 0}
|
||||
s.Serial = serial
|
||||
s.Ns = ns
|
||||
s.Mbox = mbox
|
||||
dns.Question[0] = Question{z, TypeIXFR, ClassINET}
|
||||
dns.Ns[0] = s
|
||||
return dns
|
||||
}
|
||||
|
||||
// SetAxfr creates message for requesting an AXFR.
|
||||
func (dns *Msg) SetAxfr(z string) *Msg {
|
||||
dns.Id = Id()
|
||||
dns.Question = make([]Question, 1)
|
||||
dns.Question[0] = Question{z, TypeAXFR, ClassINET}
|
||||
return dns
|
||||
}
|
||||
|
||||
// SetTsig appends a TSIG RR to the message.
|
||||
// This is only a skeleton TSIG RR that is added as the last RR in the
|
||||
// additional section. The Tsig is calculated when the message is being send.
|
||||
func (dns *Msg) SetTsig(z, algo string, fudge, timesigned int64) *Msg {
|
||||
t := new(TSIG)
|
||||
t.Hdr = RR_Header{z, TypeTSIG, ClassANY, 0, 0}
|
||||
t.Algorithm = algo
|
||||
t.Fudge = 300
|
||||
t.TimeSigned = uint64(timesigned)
|
||||
t.OrigId = dns.Id
|
||||
dns.Extra = append(dns.Extra, t)
|
||||
return dns
|
||||
}
|
||||
|
||||
// SetEdns0 appends a EDNS0 OPT RR to the message.
|
||||
// TSIG should always the last RR in a message.
|
||||
func (dns *Msg) SetEdns0(udpsize uint16, do bool) *Msg {
|
||||
e := new(OPT)
|
||||
e.Hdr.Name = "."
|
||||
e.Hdr.Rrtype = TypeOPT
|
||||
e.SetUDPSize(udpsize)
|
||||
if do {
|
||||
e.SetDo()
|
||||
}
|
||||
dns.Extra = append(dns.Extra, e)
|
||||
return dns
|
||||
}
|
||||
|
||||
// IsTsig checks if the message has a TSIG record as the last record
|
||||
// in the additional section. It returns the TSIG record found or nil.
|
||||
func (dns *Msg) IsTsig() *TSIG {
|
||||
if len(dns.Extra) > 0 {
|
||||
if dns.Extra[len(dns.Extra)-1].Header().Rrtype == TypeTSIG {
|
||||
return dns.Extra[len(dns.Extra)-1].(*TSIG)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsEdns0 checks if the message has a EDNS0 (OPT) record, any EDNS0
|
||||
// record in the additional section will do. It returns the OPT record
|
||||
// found or nil.
|
||||
func (dns *Msg) IsEdns0() *OPT {
|
||||
for _, r := range dns.Extra {
|
||||
if r.Header().Rrtype == TypeOPT {
|
||||
return r.(*OPT)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsDomainName checks if s is a valid domain name, it returns the number of
|
||||
// labels and true, when a domain name is valid. Note that non fully qualified
|
||||
// domain name is considered valid, in this case the last label is counted in
|
||||
// the number of labels. When false is returned the number of labels is not
|
||||
// defined. Also note that this function is extremely liberal; almost any
|
||||
// string is a valid domain name as the DNS is 8 bit protocol. It checks if each
|
||||
// label fits in 63 characters, but there is no length check for the entire
|
||||
// string s. I.e. a domain name longer than 255 characters is considered valid.
|
||||
func IsDomainName(s string) (labels int, ok bool) {
|
||||
_, labels, err := packDomainName(s, nil, 0, nil, false)
|
||||
return labels, err == nil
|
||||
}
|
||||
|
||||
// IsSubDomain checks if child is indeed a child of the parent. Both child and
|
||||
// parent are *not* downcased before doing the comparison.
|
||||
func IsSubDomain(parent, child string) bool {
|
||||
// Entire child is contained in parent
|
||||
return CompareDomainName(parent, child) == CountLabel(parent)
|
||||
}
|
||||
|
||||
// IsMsg sanity checks buf and returns an error if it isn't a valid DNS packet.
|
||||
// The checking is performed on the binary payload.
|
||||
func IsMsg(buf []byte) error {
|
||||
// Header
|
||||
if len(buf) < 12 {
|
||||
return errors.New("dns: bad message header")
|
||||
}
|
||||
// Header: Opcode
|
||||
// TODO(miek): more checks here, e.g. check all header bits.
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsFqdn checks if a domain name is fully qualified.
|
||||
func IsFqdn(s string) bool {
|
||||
l := len(s)
|
||||
if l == 0 {
|
||||
return false
|
||||
}
|
||||
return s[l-1] == '.'
|
||||
}
|
||||
|
||||
// IsRRset checks if a set of RRs is a valid RRset as defined by RFC 2181.
|
||||
// This means the RRs need to have the same type, name, and class. Returns true
|
||||
// if the RR set is valid, otherwise false.
|
||||
func IsRRset(rrset []RR) bool {
|
||||
if len(rrset) == 0 {
|
||||
return false
|
||||
}
|
||||
if len(rrset) == 1 {
|
||||
return true
|
||||
}
|
||||
rrHeader := rrset[0].Header()
|
||||
rrType := rrHeader.Rrtype
|
||||
rrClass := rrHeader.Class
|
||||
rrName := rrHeader.Name
|
||||
|
||||
for _, rr := range rrset[1:] {
|
||||
curRRHeader := rr.Header()
|
||||
if curRRHeader.Rrtype != rrType || curRRHeader.Class != rrClass || curRRHeader.Name != rrName {
|
||||
// Mismatch between the records, so this is not a valid rrset for
|
||||
//signing/verifying
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Fqdn return the fully qualified domain name from s.
|
||||
// If s is already fully qualified, it behaves as the identity function.
|
||||
func Fqdn(s string) string {
|
||||
if IsFqdn(s) {
|
||||
return s
|
||||
}
|
||||
return s + "."
|
||||
}
|
||||
|
||||
// Copied from the official Go code.
|
||||
|
||||
// ReverseAddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
|
||||
// address suitable for reverse DNS (PTR) record lookups or an error if it fails
|
||||
// to parse the IP address.
|
||||
func ReverseAddr(addr string) (arpa string, err error) {
|
||||
ip := net.ParseIP(addr)
|
||||
if ip == nil {
|
||||
return "", &Error{err: "unrecognized address: " + addr}
|
||||
}
|
||||
if ip.To4() != nil {
|
||||
return strconv.Itoa(int(ip[15])) + "." + strconv.Itoa(int(ip[14])) + "." + strconv.Itoa(int(ip[13])) + "." +
|
||||
strconv.Itoa(int(ip[12])) + ".in-addr.arpa.", nil
|
||||
}
|
||||
// Must be IPv6
|
||||
buf := make([]byte, 0, len(ip)*4+len("ip6.arpa."))
|
||||
// Add it, in reverse, to the buffer
|
||||
for i := len(ip) - 1; i >= 0; i-- {
|
||||
v := ip[i]
|
||||
buf = append(buf, hexDigit[v&0xF])
|
||||
buf = append(buf, '.')
|
||||
buf = append(buf, hexDigit[v>>4])
|
||||
buf = append(buf, '.')
|
||||
}
|
||||
// Append "ip6.arpa." and return (buf already has the final .)
|
||||
buf = append(buf, "ip6.arpa."...)
|
||||
return string(buf), nil
|
||||
}
|
||||
|
||||
// String returns the string representation for the type t.
|
||||
func (t Type) String() string {
|
||||
if t1, ok := TypeToString[uint16(t)]; ok {
|
||||
return t1
|
||||
}
|
||||
return "TYPE" + strconv.Itoa(int(t))
|
||||
}
|
||||
|
||||
// String returns the string representation for the class c.
|
||||
func (c Class) String() string {
|
||||
if c1, ok := ClassToString[uint16(c)]; ok {
|
||||
return c1
|
||||
}
|
||||
return "CLASS" + strconv.Itoa(int(c))
|
||||
}
|
||||
|
||||
// String returns the string representation for the name n.
|
||||
func (n Name) String() string {
|
||||
return sprintName(string(n))
|
||||
}
|
100
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/dns.go
generated
vendored
Normal file
100
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/dns.go
generated
vendored
Normal file
|
@ -0,0 +1,100 @@
|
|||
package dns
|
||||
|
||||
import "strconv"
|
||||
|
||||
const (
|
||||
year68 = 1 << 31 // For RFC1982 (Serial Arithmetic) calculations in 32 bits.
|
||||
// DefaultMsgSize is the standard default for messages larger than 512 bytes.
|
||||
DefaultMsgSize = 4096
|
||||
// MinMsgSize is the minimal size of a DNS packet.
|
||||
MinMsgSize = 512
|
||||
// MaxMsgSize is the largest possible DNS packet.
|
||||
MaxMsgSize = 65535
|
||||
defaultTtl = 3600 // Default internal TTL.
|
||||
)
|
||||
|
||||
// Error represents a DNS error
|
||||
type Error struct{ err string }
|
||||
|
||||
func (e *Error) Error() string {
|
||||
if e == nil {
|
||||
return "dns: <nil>"
|
||||
}
|
||||
return "dns: " + e.err
|
||||
}
|
||||
|
||||
// An RR represents a resource record.
|
||||
type RR interface {
|
||||
// Header returns the header of an resource record. The header contains
|
||||
// everything up to the rdata.
|
||||
Header() *RR_Header
|
||||
// String returns the text representation of the resource record.
|
||||
String() string
|
||||
// copy returns a copy of the RR
|
||||
copy() RR
|
||||
// len returns the length (in octets) of the uncompressed RR in wire format.
|
||||
len() int
|
||||
}
|
||||
|
||||
// RR_Header is the header all DNS resource records share.
|
||||
type RR_Header struct {
|
||||
Name string `dns:"cdomain-name"`
|
||||
Rrtype uint16
|
||||
Class uint16
|
||||
Ttl uint32
|
||||
Rdlength uint16 // length of data after header
|
||||
}
|
||||
|
||||
// Header returns itself. This is here to make RR_Header implement the RR interface.
|
||||
func (h *RR_Header) Header() *RR_Header { return h }
|
||||
|
||||
// Just to imlement the RR interface.
|
||||
func (h *RR_Header) copy() RR { return nil }
|
||||
|
||||
func (h *RR_Header) copyHeader() *RR_Header {
|
||||
r := new(RR_Header)
|
||||
r.Name = h.Name
|
||||
r.Rrtype = h.Rrtype
|
||||
r.Class = h.Class
|
||||
r.Ttl = h.Ttl
|
||||
r.Rdlength = h.Rdlength
|
||||
return r
|
||||
}
|
||||
|
||||
func (h *RR_Header) String() string {
|
||||
var s string
|
||||
|
||||
if h.Rrtype == TypeOPT {
|
||||
s = ";"
|
||||
// and maybe other things
|
||||
}
|
||||
|
||||
s += sprintName(h.Name) + "\t"
|
||||
s += strconv.FormatInt(int64(h.Ttl), 10) + "\t"
|
||||
s += Class(h.Class).String() + "\t"
|
||||
s += Type(h.Rrtype).String() + "\t"
|
||||
return s
|
||||
}
|
||||
|
||||
func (h *RR_Header) len() int {
|
||||
l := len(h.Name) + 1
|
||||
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 := PackStruct(r, buf, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf = buf[:off]
|
||||
rawSetRdlength(buf, 0, off)
|
||||
_, err = UnpackStruct(rr, buf, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
664
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/dnssec.go
generated
vendored
Normal file
664
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/dnssec.go
generated
vendored
Normal file
|
@ -0,0 +1,664 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/dsa"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
_ "crypto/md5"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
_ "crypto/sha1"
|
||||
_ "crypto/sha256"
|
||||
_ "crypto/sha512"
|
||||
"encoding/asn1"
|
||||
"encoding/hex"
|
||||
"math/big"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DNSSEC encryption algorithm codes.
|
||||
const (
|
||||
_ uint8 = iota
|
||||
RSAMD5
|
||||
DH
|
||||
DSA
|
||||
_ // Skip 4, RFC 6725, section 2.1
|
||||
RSASHA1
|
||||
DSANSEC3SHA1
|
||||
RSASHA1NSEC3SHA1
|
||||
RSASHA256
|
||||
_ // Skip 9, RFC 6725, section 2.1
|
||||
RSASHA512
|
||||
_ // Skip 11, RFC 6725, section 2.1
|
||||
ECCGOST
|
||||
ECDSAP256SHA256
|
||||
ECDSAP384SHA384
|
||||
INDIRECT uint8 = 252
|
||||
PRIVATEDNS uint8 = 253 // Private (experimental keys)
|
||||
PRIVATEOID uint8 = 254
|
||||
)
|
||||
|
||||
// Map for algorithm names.
|
||||
var AlgorithmToString = map[uint8]string{
|
||||
RSAMD5: "RSAMD5",
|
||||
DH: "DH",
|
||||
DSA: "DSA",
|
||||
RSASHA1: "RSASHA1",
|
||||
DSANSEC3SHA1: "DSA-NSEC3-SHA1",
|
||||
RSASHA1NSEC3SHA1: "RSASHA1-NSEC3-SHA1",
|
||||
RSASHA256: "RSASHA256",
|
||||
RSASHA512: "RSASHA512",
|
||||
ECCGOST: "ECC-GOST",
|
||||
ECDSAP256SHA256: "ECDSAP256SHA256",
|
||||
ECDSAP384SHA384: "ECDSAP384SHA384",
|
||||
INDIRECT: "INDIRECT",
|
||||
PRIVATEDNS: "PRIVATEDNS",
|
||||
PRIVATEOID: "PRIVATEOID",
|
||||
}
|
||||
|
||||
// Map of algorithm strings.
|
||||
var StringToAlgorithm = reverseInt8(AlgorithmToString)
|
||||
|
||||
// Map of algorithm crypto hashes.
|
||||
var AlgorithmToHash = map[uint8]crypto.Hash{
|
||||
RSAMD5: crypto.MD5, // Deprecated in RFC 6725
|
||||
RSASHA1: crypto.SHA1,
|
||||
RSASHA1NSEC3SHA1: crypto.SHA1,
|
||||
RSASHA256: crypto.SHA256,
|
||||
ECDSAP256SHA256: crypto.SHA256,
|
||||
ECDSAP384SHA384: crypto.SHA384,
|
||||
RSASHA512: crypto.SHA512,
|
||||
}
|
||||
|
||||
// DNSSEC hashing algorithm codes.
|
||||
const (
|
||||
_ uint8 = iota
|
||||
SHA1 // RFC 4034
|
||||
SHA256 // RFC 4509
|
||||
GOST94 // RFC 5933
|
||||
SHA384 // Experimental
|
||||
SHA512 // Experimental
|
||||
)
|
||||
|
||||
// Map for hash names.
|
||||
var HashToString = map[uint8]string{
|
||||
SHA1: "SHA1",
|
||||
SHA256: "SHA256",
|
||||
GOST94: "GOST94",
|
||||
SHA384: "SHA384",
|
||||
SHA512: "SHA512",
|
||||
}
|
||||
|
||||
// Map of hash strings.
|
||||
var StringToHash = reverseInt8(HashToString)
|
||||
|
||||
// DNSKEY flag values.
|
||||
const (
|
||||
SEP = 1
|
||||
REVOKE = 1 << 7
|
||||
ZONE = 1 << 8
|
||||
)
|
||||
|
||||
// The RRSIG needs to be converted to wireformat with some of
|
||||
// the rdata (the signature) missing. Use this struct to ease
|
||||
// the conversion (and re-use the pack/unpack functions).
|
||||
type rrsigWireFmt struct {
|
||||
TypeCovered uint16
|
||||
Algorithm uint8
|
||||
Labels uint8
|
||||
OrigTtl uint32
|
||||
Expiration uint32
|
||||
Inception uint32
|
||||
KeyTag uint16
|
||||
SignerName string `dns:"domain-name"`
|
||||
/* No Signature */
|
||||
}
|
||||
|
||||
// Used for converting DNSKEY's rdata to wirefmt.
|
||||
type dnskeyWireFmt struct {
|
||||
Flags uint16
|
||||
Protocol uint8
|
||||
Algorithm uint8
|
||||
PublicKey string `dns:"base64"`
|
||||
/* Nothing is left out */
|
||||
}
|
||||
|
||||
func divRoundUp(a, b int) int {
|
||||
return (a + b - 1) / b
|
||||
}
|
||||
|
||||
// KeyTag calculates the keytag (or key-id) of the DNSKEY.
|
||||
func (k *DNSKEY) KeyTag() uint16 {
|
||||
if k == nil {
|
||||
return 0
|
||||
}
|
||||
var keytag int
|
||||
switch k.Algorithm {
|
||||
case RSAMD5:
|
||||
// Look at the bottom two bytes of the modules, which the last
|
||||
// item in the pubkey. We could do this faster by looking directly
|
||||
// at the base64 values. But I'm lazy.
|
||||
modulus, _ := fromBase64([]byte(k.PublicKey))
|
||||
if len(modulus) > 1 {
|
||||
x, _ := unpackUint16(modulus, len(modulus)-2)
|
||||
keytag = int(x)
|
||||
}
|
||||
default:
|
||||
keywire := new(dnskeyWireFmt)
|
||||
keywire.Flags = k.Flags
|
||||
keywire.Protocol = k.Protocol
|
||||
keywire.Algorithm = k.Algorithm
|
||||
keywire.PublicKey = k.PublicKey
|
||||
wire := make([]byte, DefaultMsgSize)
|
||||
n, err := PackStruct(keywire, wire, 0)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
wire = wire[:n]
|
||||
for i, v := range wire {
|
||||
if i&1 != 0 {
|
||||
keytag += int(v) // must be larger than uint32
|
||||
} else {
|
||||
keytag += int(v) << 8
|
||||
}
|
||||
}
|
||||
keytag += (keytag >> 16) & 0xFFFF
|
||||
keytag &= 0xFFFF
|
||||
}
|
||||
return uint16(keytag)
|
||||
}
|
||||
|
||||
// ToDS converts a DNSKEY record to a DS record.
|
||||
func (k *DNSKEY) ToDS(h uint8) *DS {
|
||||
if k == nil {
|
||||
return nil
|
||||
}
|
||||
ds := new(DS)
|
||||
ds.Hdr.Name = k.Hdr.Name
|
||||
ds.Hdr.Class = k.Hdr.Class
|
||||
ds.Hdr.Rrtype = TypeDS
|
||||
ds.Hdr.Ttl = k.Hdr.Ttl
|
||||
ds.Algorithm = k.Algorithm
|
||||
ds.DigestType = h
|
||||
ds.KeyTag = k.KeyTag()
|
||||
|
||||
keywire := new(dnskeyWireFmt)
|
||||
keywire.Flags = k.Flags
|
||||
keywire.Protocol = k.Protocol
|
||||
keywire.Algorithm = k.Algorithm
|
||||
keywire.PublicKey = k.PublicKey
|
||||
wire := make([]byte, DefaultMsgSize)
|
||||
n, err := PackStruct(keywire, wire, 0)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
wire = wire[:n]
|
||||
|
||||
owner := make([]byte, 255)
|
||||
off, err1 := PackDomainName(strings.ToLower(k.Hdr.Name), owner, 0, nil, false)
|
||||
if err1 != nil {
|
||||
return nil
|
||||
}
|
||||
owner = owner[:off]
|
||||
// RFC4034:
|
||||
// digest = digest_algorithm( DNSKEY owner name | DNSKEY RDATA);
|
||||
// "|" denotes concatenation
|
||||
// DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key.
|
||||
|
||||
// digest buffer
|
||||
digest := append(owner, wire...) // another copy
|
||||
|
||||
var hash crypto.Hash
|
||||
switch h {
|
||||
case SHA1:
|
||||
hash = crypto.SHA1
|
||||
case SHA256:
|
||||
hash = crypto.SHA256
|
||||
case SHA384:
|
||||
hash = crypto.SHA384
|
||||
case SHA512:
|
||||
hash = crypto.SHA512
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
s := hash.New()
|
||||
s.Write(digest)
|
||||
ds.Digest = hex.EncodeToString(s.Sum(nil))
|
||||
return ds
|
||||
}
|
||||
|
||||
// ToCDNSKEY converts a DNSKEY record to a CDNSKEY record.
|
||||
func (k *DNSKEY) ToCDNSKEY() *CDNSKEY {
|
||||
c := &CDNSKEY{DNSKEY: *k}
|
||||
c.Hdr = *k.Hdr.copyHeader()
|
||||
c.Hdr.Rrtype = TypeCDNSKEY
|
||||
return c
|
||||
}
|
||||
|
||||
// ToCDS converts a DS record to a CDS record.
|
||||
func (d *DS) ToCDS() *CDS {
|
||||
c := &CDS{DS: *d}
|
||||
c.Hdr = *d.Hdr.copyHeader()
|
||||
c.Hdr.Rrtype = TypeCDS
|
||||
return c
|
||||
}
|
||||
|
||||
// Sign signs an RRSet. The signature needs to be filled in with the values:
|
||||
// Inception, Expiration, KeyTag, SignerName and Algorithm. The rest is copied
|
||||
// from the RRset. Sign returns a non-nill error when the signing went OK.
|
||||
// There is no check if RRSet is a proper (RFC 2181) RRSet. If OrigTTL is non
|
||||
// zero, it is used as-is, otherwise the TTL of the RRset is used as the
|
||||
// OrigTTL.
|
||||
func (rr *RRSIG) Sign(k crypto.Signer, rrset []RR) error {
|
||||
if k == nil {
|
||||
return ErrPrivKey
|
||||
}
|
||||
// s.Inception and s.Expiration may be 0 (rollover etc.), the rest must be set
|
||||
if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 {
|
||||
return ErrKey
|
||||
}
|
||||
|
||||
rr.Hdr.Rrtype = TypeRRSIG
|
||||
rr.Hdr.Name = rrset[0].Header().Name
|
||||
rr.Hdr.Class = rrset[0].Header().Class
|
||||
if rr.OrigTtl == 0 { // If set don't override
|
||||
rr.OrigTtl = rrset[0].Header().Ttl
|
||||
}
|
||||
rr.TypeCovered = rrset[0].Header().Rrtype
|
||||
rr.Labels = uint8(CountLabel(rrset[0].Header().Name))
|
||||
|
||||
if strings.HasPrefix(rrset[0].Header().Name, "*") {
|
||||
rr.Labels-- // wildcard, remove from label count
|
||||
}
|
||||
|
||||
sigwire := new(rrsigWireFmt)
|
||||
sigwire.TypeCovered = rr.TypeCovered
|
||||
sigwire.Algorithm = rr.Algorithm
|
||||
sigwire.Labels = rr.Labels
|
||||
sigwire.OrigTtl = rr.OrigTtl
|
||||
sigwire.Expiration = rr.Expiration
|
||||
sigwire.Inception = rr.Inception
|
||||
sigwire.KeyTag = rr.KeyTag
|
||||
// For signing, lowercase this name
|
||||
sigwire.SignerName = strings.ToLower(rr.SignerName)
|
||||
|
||||
// Create the desired binary blob
|
||||
signdata := make([]byte, DefaultMsgSize)
|
||||
n, err := PackStruct(sigwire, signdata, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
signdata = signdata[:n]
|
||||
wire, err := rawSignatureData(rrset, rr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
signdata = append(signdata, wire...)
|
||||
|
||||
hash, ok := AlgorithmToHash[rr.Algorithm]
|
||||
if !ok {
|
||||
return ErrAlg
|
||||
}
|
||||
|
||||
h := hash.New()
|
||||
h.Write(signdata)
|
||||
|
||||
signature, err := sign(k, h.Sum(nil), hash, rr.Algorithm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rr.Signature = toBase64(signature)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func sign(k crypto.Signer, hashed []byte, hash crypto.Hash, alg uint8) ([]byte, error) {
|
||||
signature, err := k.Sign(rand.Reader, hashed, hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch alg {
|
||||
case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512:
|
||||
return signature, nil
|
||||
|
||||
case ECDSAP256SHA256, ECDSAP384SHA384:
|
||||
ecdsaSignature := &struct {
|
||||
R, S *big.Int
|
||||
}{}
|
||||
if _, err := asn1.Unmarshal(signature, ecdsaSignature); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var intlen int
|
||||
switch alg {
|
||||
case ECDSAP256SHA256:
|
||||
intlen = 32
|
||||
case ECDSAP384SHA384:
|
||||
intlen = 48
|
||||
}
|
||||
|
||||
signature := intToBytes(ecdsaSignature.R, intlen)
|
||||
signature = append(signature, intToBytes(ecdsaSignature.S, intlen)...)
|
||||
return signature, nil
|
||||
|
||||
// There is no defined interface for what a DSA backed crypto.Signer returns
|
||||
case DSA, DSANSEC3SHA1:
|
||||
// t := divRoundUp(divRoundUp(p.PublicKey.Y.BitLen(), 8)-64, 8)
|
||||
// signature := []byte{byte(t)}
|
||||
// signature = append(signature, intToBytes(r1, 20)...)
|
||||
// signature = append(signature, intToBytes(s1, 20)...)
|
||||
// rr.Signature = signature
|
||||
}
|
||||
|
||||
return nil, ErrAlg
|
||||
}
|
||||
|
||||
// Verify validates an RRSet with the signature and key. This is only the
|
||||
// cryptographic test, the signature validity period must be checked separately.
|
||||
// This function copies the rdata of some RRs (to lowercase domain names) for the validation to work.
|
||||
func (rr *RRSIG) Verify(k *DNSKEY, rrset []RR) error {
|
||||
// First the easy checks
|
||||
if !IsRRset(rrset) {
|
||||
return ErrRRset
|
||||
}
|
||||
if rr.KeyTag != k.KeyTag() {
|
||||
return ErrKey
|
||||
}
|
||||
if rr.Hdr.Class != k.Hdr.Class {
|
||||
return ErrKey
|
||||
}
|
||||
if rr.Algorithm != k.Algorithm {
|
||||
return ErrKey
|
||||
}
|
||||
if strings.ToLower(rr.SignerName) != strings.ToLower(k.Hdr.Name) {
|
||||
return ErrKey
|
||||
}
|
||||
if k.Protocol != 3 {
|
||||
return ErrKey
|
||||
}
|
||||
|
||||
// IsRRset checked that we have at least one RR and that the RRs in
|
||||
// the set have consistent type, class, and name. Also check that type and
|
||||
// class matches the RRSIG record.
|
||||
if rrset[0].Header().Class != rr.Hdr.Class {
|
||||
return ErrRRset
|
||||
}
|
||||
if rrset[0].Header().Rrtype != rr.TypeCovered {
|
||||
return ErrRRset
|
||||
}
|
||||
|
||||
// RFC 4035 5.3.2. Reconstructing the Signed Data
|
||||
// Copy the sig, except the rrsig data
|
||||
sigwire := new(rrsigWireFmt)
|
||||
sigwire.TypeCovered = rr.TypeCovered
|
||||
sigwire.Algorithm = rr.Algorithm
|
||||
sigwire.Labels = rr.Labels
|
||||
sigwire.OrigTtl = rr.OrigTtl
|
||||
sigwire.Expiration = rr.Expiration
|
||||
sigwire.Inception = rr.Inception
|
||||
sigwire.KeyTag = rr.KeyTag
|
||||
sigwire.SignerName = strings.ToLower(rr.SignerName)
|
||||
// Create the desired binary blob
|
||||
signeddata := make([]byte, DefaultMsgSize)
|
||||
n, err := PackStruct(sigwire, signeddata, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
signeddata = signeddata[:n]
|
||||
wire, err := rawSignatureData(rrset, rr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
signeddata = append(signeddata, wire...)
|
||||
|
||||
sigbuf := rr.sigBuf() // Get the binary signature data
|
||||
if rr.Algorithm == PRIVATEDNS { // PRIVATEOID
|
||||
// TODO(miek)
|
||||
// remove the domain name and assume its ours?
|
||||
}
|
||||
|
||||
hash, ok := AlgorithmToHash[rr.Algorithm]
|
||||
if !ok {
|
||||
return ErrAlg
|
||||
}
|
||||
|
||||
switch rr.Algorithm {
|
||||
case RSASHA1, RSASHA1NSEC3SHA1, RSASHA256, RSASHA512, RSAMD5:
|
||||
// TODO(mg): this can be done quicker, ie. cache the pubkey data somewhere??
|
||||
pubkey := k.publicKeyRSA() // Get the key
|
||||
if pubkey == nil {
|
||||
return ErrKey
|
||||
}
|
||||
|
||||
h := hash.New()
|
||||
h.Write(signeddata)
|
||||
return rsa.VerifyPKCS1v15(pubkey, hash, h.Sum(nil), sigbuf)
|
||||
|
||||
case ECDSAP256SHA256, ECDSAP384SHA384:
|
||||
pubkey := k.publicKeyECDSA()
|
||||
if pubkey == nil {
|
||||
return ErrKey
|
||||
}
|
||||
|
||||
// Split sigbuf into the r and s coordinates
|
||||
r := new(big.Int).SetBytes(sigbuf[:len(sigbuf)/2])
|
||||
s := new(big.Int).SetBytes(sigbuf[len(sigbuf)/2:])
|
||||
|
||||
h := hash.New()
|
||||
h.Write(signeddata)
|
||||
if ecdsa.Verify(pubkey, h.Sum(nil), r, s) {
|
||||
return nil
|
||||
}
|
||||
return ErrSig
|
||||
|
||||
default:
|
||||
return ErrAlg
|
||||
}
|
||||
}
|
||||
|
||||
// ValidityPeriod uses RFC1982 serial arithmetic to calculate
|
||||
// if a signature period is valid. If t is the zero time, the
|
||||
// current time is taken other t is. Returns true if the signature
|
||||
// is valid at the given time, otherwise returns false.
|
||||
func (rr *RRSIG) ValidityPeriod(t time.Time) bool {
|
||||
var utc int64
|
||||
if t.IsZero() {
|
||||
utc = time.Now().UTC().Unix()
|
||||
} else {
|
||||
utc = t.UTC().Unix()
|
||||
}
|
||||
modi := (int64(rr.Inception) - utc) / year68
|
||||
mode := (int64(rr.Expiration) - utc) / year68
|
||||
ti := int64(rr.Inception) + (modi * year68)
|
||||
te := int64(rr.Expiration) + (mode * year68)
|
||||
return ti <= utc && utc <= te
|
||||
}
|
||||
|
||||
// Return the signatures base64 encodedig sigdata as a byte slice.
|
||||
func (rr *RRSIG) sigBuf() []byte {
|
||||
sigbuf, err := fromBase64([]byte(rr.Signature))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return sigbuf
|
||||
}
|
||||
|
||||
// publicKeyRSA returns the RSA public key from a DNSKEY record.
|
||||
func (k *DNSKEY) publicKeyRSA() *rsa.PublicKey {
|
||||
keybuf, err := fromBase64([]byte(k.PublicKey))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// RFC 2537/3110, section 2. RSA Public KEY Resource Records
|
||||
// Length is in the 0th byte, unless its zero, then it
|
||||
// it in bytes 1 and 2 and its a 16 bit number
|
||||
explen := uint16(keybuf[0])
|
||||
keyoff := 1
|
||||
if explen == 0 {
|
||||
explen = uint16(keybuf[1])<<8 | uint16(keybuf[2])
|
||||
keyoff = 3
|
||||
}
|
||||
pubkey := new(rsa.PublicKey)
|
||||
|
||||
pubkey.N = big.NewInt(0)
|
||||
shift := uint64((explen - 1) * 8)
|
||||
expo := uint64(0)
|
||||
for i := int(explen - 1); i > 0; i-- {
|
||||
expo += uint64(keybuf[keyoff+i]) << shift
|
||||
shift -= 8
|
||||
}
|
||||
// Remainder
|
||||
expo += uint64(keybuf[keyoff])
|
||||
if expo > 2<<31 {
|
||||
// Larger expo than supported.
|
||||
// println("dns: F5 primes (or larger) are not supported")
|
||||
return nil
|
||||
}
|
||||
pubkey.E = int(expo)
|
||||
|
||||
pubkey.N.SetBytes(keybuf[keyoff+int(explen):])
|
||||
return pubkey
|
||||
}
|
||||
|
||||
// publicKeyECDSA returns the Curve public key from the DNSKEY record.
|
||||
func (k *DNSKEY) publicKeyECDSA() *ecdsa.PublicKey {
|
||||
keybuf, err := fromBase64([]byte(k.PublicKey))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
pubkey := new(ecdsa.PublicKey)
|
||||
switch k.Algorithm {
|
||||
case ECDSAP256SHA256:
|
||||
pubkey.Curve = elliptic.P256()
|
||||
if len(keybuf) != 64 {
|
||||
// wrongly encoded key
|
||||
return nil
|
||||
}
|
||||
case ECDSAP384SHA384:
|
||||
pubkey.Curve = elliptic.P384()
|
||||
if len(keybuf) != 96 {
|
||||
// Wrongly encoded key
|
||||
return nil
|
||||
}
|
||||
}
|
||||
pubkey.X = big.NewInt(0)
|
||||
pubkey.X.SetBytes(keybuf[:len(keybuf)/2])
|
||||
pubkey.Y = big.NewInt(0)
|
||||
pubkey.Y.SetBytes(keybuf[len(keybuf)/2:])
|
||||
return pubkey
|
||||
}
|
||||
|
||||
func (k *DNSKEY) publicKeyDSA() *dsa.PublicKey {
|
||||
keybuf, err := fromBase64([]byte(k.PublicKey))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if len(keybuf) < 22 {
|
||||
return nil
|
||||
}
|
||||
t, keybuf := int(keybuf[0]), keybuf[1:]
|
||||
size := 64 + t*8
|
||||
q, keybuf := keybuf[:20], keybuf[20:]
|
||||
if len(keybuf) != 3*size {
|
||||
return nil
|
||||
}
|
||||
p, keybuf := keybuf[:size], keybuf[size:]
|
||||
g, y := keybuf[:size], keybuf[size:]
|
||||
pubkey := new(dsa.PublicKey)
|
||||
pubkey.Parameters.Q = big.NewInt(0).SetBytes(q)
|
||||
pubkey.Parameters.P = big.NewInt(0).SetBytes(p)
|
||||
pubkey.Parameters.G = big.NewInt(0).SetBytes(g)
|
||||
pubkey.Y = big.NewInt(0).SetBytes(y)
|
||||
return pubkey
|
||||
}
|
||||
|
||||
type wireSlice [][]byte
|
||||
|
||||
func (p wireSlice) Len() int { return len(p) }
|
||||
func (p wireSlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
|
||||
func (p wireSlice) Less(i, j int) bool {
|
||||
_, ioff, _ := UnpackDomainName(p[i], 0)
|
||||
_, joff, _ := UnpackDomainName(p[j], 0)
|
||||
return bytes.Compare(p[i][ioff+10:], p[j][joff+10:]) < 0
|
||||
}
|
||||
|
||||
// Return the raw signature data.
|
||||
func rawSignatureData(rrset []RR, s *RRSIG) (buf []byte, err error) {
|
||||
wires := make(wireSlice, len(rrset))
|
||||
for i, r := range rrset {
|
||||
r1 := r.copy()
|
||||
r1.Header().Ttl = s.OrigTtl
|
||||
labels := SplitDomainName(r1.Header().Name)
|
||||
// 6.2. Canonical RR Form. (4) - wildcards
|
||||
if len(labels) > int(s.Labels) {
|
||||
// Wildcard
|
||||
r1.Header().Name = "*." + strings.Join(labels[len(labels)-int(s.Labels):], ".") + "."
|
||||
}
|
||||
// RFC 4034: 6.2. Canonical RR Form. (2) - domain name to lowercase
|
||||
r1.Header().Name = strings.ToLower(r1.Header().Name)
|
||||
// 6.2. Canonical RR Form. (3) - domain rdata to lowercase.
|
||||
// NS, MD, MF, CNAME, SOA, MB, MG, MR, PTR,
|
||||
// HINFO, MINFO, MX, RP, AFSDB, RT, SIG, PX, NXT, NAPTR, KX,
|
||||
// SRV, DNAME, A6
|
||||
//
|
||||
// RFC 6840 - Clarifications and Implementation Notes for DNS Security (DNSSEC):
|
||||
// Section 6.2 of [RFC4034] also erroneously lists HINFO as a record
|
||||
// that needs conversion to lowercase, and twice at that. Since HINFO
|
||||
// records contain no domain names, they are not subject to case
|
||||
// conversion.
|
||||
switch x := r1.(type) {
|
||||
case *NS:
|
||||
x.Ns = strings.ToLower(x.Ns)
|
||||
case *CNAME:
|
||||
x.Target = strings.ToLower(x.Target)
|
||||
case *SOA:
|
||||
x.Ns = strings.ToLower(x.Ns)
|
||||
x.Mbox = strings.ToLower(x.Mbox)
|
||||
case *MB:
|
||||
x.Mb = strings.ToLower(x.Mb)
|
||||
case *MG:
|
||||
x.Mg = strings.ToLower(x.Mg)
|
||||
case *MR:
|
||||
x.Mr = strings.ToLower(x.Mr)
|
||||
case *PTR:
|
||||
x.Ptr = strings.ToLower(x.Ptr)
|
||||
case *MINFO:
|
||||
x.Rmail = strings.ToLower(x.Rmail)
|
||||
x.Email = strings.ToLower(x.Email)
|
||||
case *MX:
|
||||
x.Mx = strings.ToLower(x.Mx)
|
||||
case *NAPTR:
|
||||
x.Replacement = strings.ToLower(x.Replacement)
|
||||
case *KX:
|
||||
x.Exchanger = strings.ToLower(x.Exchanger)
|
||||
case *SRV:
|
||||
x.Target = strings.ToLower(x.Target)
|
||||
case *DNAME:
|
||||
x.Target = strings.ToLower(x.Target)
|
||||
}
|
||||
// 6.2. Canonical RR Form. (5) - origTTL
|
||||
wire := make([]byte, r1.len()+1) // +1 to be safe(r)
|
||||
off, err1 := PackRR(r1, wire, 0, nil, false)
|
||||
if err1 != nil {
|
||||
return nil, err1
|
||||
}
|
||||
wire = wire[:off]
|
||||
wires[i] = wire
|
||||
}
|
||||
sort.Sort(wires)
|
||||
for i, wire := range wires {
|
||||
if i > 0 && bytes.Equal(wire, wires[i-1]) {
|
||||
continue
|
||||
}
|
||||
buf = append(buf, wire...)
|
||||
}
|
||||
return buf, nil
|
||||
}
|
156
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/dnssec_keygen.go
generated
vendored
Normal file
156
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/dnssec_keygen.go
generated
vendored
Normal file
|
@ -0,0 +1,156 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/dsa"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
// Generate generates a DNSKEY of the given bit size.
|
||||
// The public part is put inside the DNSKEY record.
|
||||
// The Algorithm in the key must be set as this will define
|
||||
// what kind of DNSKEY will be generated.
|
||||
// The ECDSA algorithms imply a fixed keysize, in that case
|
||||
// bits should be set to the size of the algorithm.
|
||||
func (k *DNSKEY) Generate(bits int) (crypto.PrivateKey, error) {
|
||||
switch k.Algorithm {
|
||||
case DSA, DSANSEC3SHA1:
|
||||
if bits != 1024 {
|
||||
return nil, ErrKeySize
|
||||
}
|
||||
case RSAMD5, RSASHA1, RSASHA256, RSASHA1NSEC3SHA1:
|
||||
if bits < 512 || bits > 4096 {
|
||||
return nil, ErrKeySize
|
||||
}
|
||||
case RSASHA512:
|
||||
if bits < 1024 || bits > 4096 {
|
||||
return nil, ErrKeySize
|
||||
}
|
||||
case ECDSAP256SHA256:
|
||||
if bits != 256 {
|
||||
return nil, ErrKeySize
|
||||
}
|
||||
case ECDSAP384SHA384:
|
||||
if bits != 384 {
|
||||
return nil, ErrKeySize
|
||||
}
|
||||
}
|
||||
|
||||
switch k.Algorithm {
|
||||
case DSA, DSANSEC3SHA1:
|
||||
params := new(dsa.Parameters)
|
||||
if err := dsa.GenerateParameters(params, rand.Reader, dsa.L1024N160); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
priv := new(dsa.PrivateKey)
|
||||
priv.PublicKey.Parameters = *params
|
||||
err := dsa.GenerateKey(priv, rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
k.setPublicKeyDSA(params.Q, params.P, params.G, priv.PublicKey.Y)
|
||||
return priv, nil
|
||||
case RSAMD5, RSASHA1, RSASHA256, RSASHA512, RSASHA1NSEC3SHA1:
|
||||
priv, err := rsa.GenerateKey(rand.Reader, bits)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
k.setPublicKeyRSA(priv.PublicKey.E, priv.PublicKey.N)
|
||||
return priv, nil
|
||||
case ECDSAP256SHA256, ECDSAP384SHA384:
|
||||
var c elliptic.Curve
|
||||
switch k.Algorithm {
|
||||
case ECDSAP256SHA256:
|
||||
c = elliptic.P256()
|
||||
case ECDSAP384SHA384:
|
||||
c = elliptic.P384()
|
||||
}
|
||||
priv, err := ecdsa.GenerateKey(c, rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
k.setPublicKeyECDSA(priv.PublicKey.X, priv.PublicKey.Y)
|
||||
return priv, nil
|
||||
default:
|
||||
return nil, ErrAlg
|
||||
}
|
||||
}
|
||||
|
||||
// Set the public key (the value E and N)
|
||||
func (k *DNSKEY) setPublicKeyRSA(_E int, _N *big.Int) bool {
|
||||
if _E == 0 || _N == nil {
|
||||
return false
|
||||
}
|
||||
buf := exponentToBuf(_E)
|
||||
buf = append(buf, _N.Bytes()...)
|
||||
k.PublicKey = toBase64(buf)
|
||||
return true
|
||||
}
|
||||
|
||||
// Set the public key for Elliptic Curves
|
||||
func (k *DNSKEY) setPublicKeyECDSA(_X, _Y *big.Int) bool {
|
||||
if _X == nil || _Y == nil {
|
||||
return false
|
||||
}
|
||||
var intlen int
|
||||
switch k.Algorithm {
|
||||
case ECDSAP256SHA256:
|
||||
intlen = 32
|
||||
case ECDSAP384SHA384:
|
||||
intlen = 48
|
||||
}
|
||||
k.PublicKey = toBase64(curveToBuf(_X, _Y, intlen))
|
||||
return true
|
||||
}
|
||||
|
||||
// Set the public key for DSA
|
||||
func (k *DNSKEY) setPublicKeyDSA(_Q, _P, _G, _Y *big.Int) bool {
|
||||
if _Q == nil || _P == nil || _G == nil || _Y == nil {
|
||||
return false
|
||||
}
|
||||
buf := dsaToBuf(_Q, _P, _G, _Y)
|
||||
k.PublicKey = toBase64(buf)
|
||||
return true
|
||||
}
|
||||
|
||||
// Set the public key (the values E and N) for RSA
|
||||
// RFC 3110: Section 2. RSA Public KEY Resource Records
|
||||
func exponentToBuf(_E int) []byte {
|
||||
var buf []byte
|
||||
i := big.NewInt(int64(_E))
|
||||
if len(i.Bytes()) < 256 {
|
||||
buf = make([]byte, 1)
|
||||
buf[0] = uint8(len(i.Bytes()))
|
||||
} else {
|
||||
buf = make([]byte, 3)
|
||||
buf[0] = 0
|
||||
buf[1] = uint8(len(i.Bytes()) >> 8)
|
||||
buf[2] = uint8(len(i.Bytes()))
|
||||
}
|
||||
buf = append(buf, i.Bytes()...)
|
||||
return buf
|
||||
}
|
||||
|
||||
// Set the public key for X and Y for Curve. The two
|
||||
// values are just concatenated.
|
||||
func curveToBuf(_X, _Y *big.Int, intlen int) []byte {
|
||||
buf := intToBytes(_X, intlen)
|
||||
buf = append(buf, intToBytes(_Y, intlen)...)
|
||||
return buf
|
||||
}
|
||||
|
||||
// Set the public key for X and Y for Curve. The two
|
||||
// values are just concatenated.
|
||||
func dsaToBuf(_Q, _P, _G, _Y *big.Int) []byte {
|
||||
t := divRoundUp(divRoundUp(_G.BitLen(), 8)-64, 8)
|
||||
buf := []byte{byte(t)}
|
||||
buf = append(buf, intToBytes(_Q, 20)...)
|
||||
buf = append(buf, intToBytes(_P, 64+t*8)...)
|
||||
buf = append(buf, intToBytes(_G, 64+t*8)...)
|
||||
buf = append(buf, intToBytes(_Y, 64+t*8)...)
|
||||
return buf
|
||||
}
|
249
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/dnssec_keyscan.go
generated
vendored
Normal file
249
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/dnssec_keyscan.go
generated
vendored
Normal file
|
@ -0,0 +1,249 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/dsa"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rsa"
|
||||
"io"
|
||||
"math/big"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// NewPrivateKey returns a PrivateKey by parsing the string s.
|
||||
// s should be in the same form of the BIND private key files.
|
||||
func (k *DNSKEY) NewPrivateKey(s string) (crypto.PrivateKey, error) {
|
||||
if s[len(s)-1] != '\n' { // We need a closing newline
|
||||
return k.ReadPrivateKey(strings.NewReader(s+"\n"), "")
|
||||
}
|
||||
return k.ReadPrivateKey(strings.NewReader(s), "")
|
||||
}
|
||||
|
||||
// ReadPrivateKey reads a private key from the io.Reader q. The string file is
|
||||
// only used in error reporting.
|
||||
// The public key must be known, because some cryptographic algorithms embed
|
||||
// the public inside the privatekey.
|
||||
func (k *DNSKEY) ReadPrivateKey(q io.Reader, file string) (crypto.PrivateKey, error) {
|
||||
m, e := parseKey(q, file)
|
||||
if m == nil {
|
||||
return nil, e
|
||||
}
|
||||
if _, ok := m["private-key-format"]; !ok {
|
||||
return nil, ErrPrivKey
|
||||
}
|
||||
if m["private-key-format"] != "v1.2" && m["private-key-format"] != "v1.3" {
|
||||
return nil, ErrPrivKey
|
||||
}
|
||||
// TODO(mg): check if the pubkey matches the private key
|
||||
algo, err := strconv.Atoi(strings.SplitN(m["algorithm"], " ", 2)[0])
|
||||
if err != nil {
|
||||
return nil, ErrPrivKey
|
||||
}
|
||||
switch uint8(algo) {
|
||||
case DSA:
|
||||
priv, e := readPrivateKeyDSA(m)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
pub := k.publicKeyDSA()
|
||||
if pub == nil {
|
||||
return nil, ErrKey
|
||||
}
|
||||
priv.PublicKey = *pub
|
||||
return priv, e
|
||||
case RSAMD5:
|
||||
fallthrough
|
||||
case RSASHA1:
|
||||
fallthrough
|
||||
case RSASHA1NSEC3SHA1:
|
||||
fallthrough
|
||||
case RSASHA256:
|
||||
fallthrough
|
||||
case RSASHA512:
|
||||
priv, e := readPrivateKeyRSA(m)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
pub := k.publicKeyRSA()
|
||||
if pub == nil {
|
||||
return nil, ErrKey
|
||||
}
|
||||
priv.PublicKey = *pub
|
||||
return priv, e
|
||||
case ECCGOST:
|
||||
return nil, ErrPrivKey
|
||||
case ECDSAP256SHA256:
|
||||
fallthrough
|
||||
case ECDSAP384SHA384:
|
||||
priv, e := readPrivateKeyECDSA(m)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
pub := k.publicKeyECDSA()
|
||||
if pub == nil {
|
||||
return nil, ErrKey
|
||||
}
|
||||
priv.PublicKey = *pub
|
||||
return priv, e
|
||||
default:
|
||||
return nil, ErrPrivKey
|
||||
}
|
||||
}
|
||||
|
||||
// Read a private key (file) string and create a public key. Return the private key.
|
||||
func readPrivateKeyRSA(m map[string]string) (*rsa.PrivateKey, error) {
|
||||
p := new(rsa.PrivateKey)
|
||||
p.Primes = []*big.Int{nil, nil}
|
||||
for k, v := range m {
|
||||
switch k {
|
||||
case "modulus", "publicexponent", "privateexponent", "prime1", "prime2":
|
||||
v1, err := fromBase64([]byte(v))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch k {
|
||||
case "modulus":
|
||||
p.PublicKey.N = big.NewInt(0)
|
||||
p.PublicKey.N.SetBytes(v1)
|
||||
case "publicexponent":
|
||||
i := big.NewInt(0)
|
||||
i.SetBytes(v1)
|
||||
p.PublicKey.E = int(i.Int64()) // int64 should be large enough
|
||||
case "privateexponent":
|
||||
p.D = big.NewInt(0)
|
||||
p.D.SetBytes(v1)
|
||||
case "prime1":
|
||||
p.Primes[0] = big.NewInt(0)
|
||||
p.Primes[0].SetBytes(v1)
|
||||
case "prime2":
|
||||
p.Primes[1] = big.NewInt(0)
|
||||
p.Primes[1].SetBytes(v1)
|
||||
}
|
||||
case "exponent1", "exponent2", "coefficient":
|
||||
// not used in Go (yet)
|
||||
case "created", "publish", "activate":
|
||||
// not used in Go (yet)
|
||||
}
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func readPrivateKeyDSA(m map[string]string) (*dsa.PrivateKey, error) {
|
||||
p := new(dsa.PrivateKey)
|
||||
p.X = big.NewInt(0)
|
||||
for k, v := range m {
|
||||
switch k {
|
||||
case "private_value(x)":
|
||||
v1, err := fromBase64([]byte(v))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.X.SetBytes(v1)
|
||||
case "created", "publish", "activate":
|
||||
/* not used in Go (yet) */
|
||||
}
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func readPrivateKeyECDSA(m map[string]string) (*ecdsa.PrivateKey, error) {
|
||||
p := new(ecdsa.PrivateKey)
|
||||
p.D = big.NewInt(0)
|
||||
// TODO: validate that the required flags are present
|
||||
for k, v := range m {
|
||||
switch k {
|
||||
case "privatekey":
|
||||
v1, err := fromBase64([]byte(v))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.D.SetBytes(v1)
|
||||
case "created", "publish", "activate":
|
||||
/* not used in Go (yet) */
|
||||
}
|
||||
}
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// 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 := scanInit(r)
|
||||
m := make(map[string]string)
|
||||
c := make(chan lex)
|
||||
k := ""
|
||||
// Start the lexer
|
||||
go klexer(s, c)
|
||||
for l := range c {
|
||||
// It should alternate
|
||||
switch l.value {
|
||||
case zKey:
|
||||
k = l.token
|
||||
case zValue:
|
||||
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 = ""
|
||||
}
|
||||
}
|
||||
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
|
||||
switch x {
|
||||
case ':':
|
||||
if commt {
|
||||
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
|
||||
}
|
||||
case ';':
|
||||
commt = true
|
||||
case '\n':
|
||||
if commt {
|
||||
// Reset a comment
|
||||
commt = false
|
||||
}
|
||||
l.value = zValue
|
||||
l.token = str
|
||||
c <- l
|
||||
str = ""
|
||||
commt = false
|
||||
key = true
|
||||
default:
|
||||
if commt {
|
||||
break
|
||||
}
|
||||
str += string(x)
|
||||
}
|
||||
x, err = s.tokenText()
|
||||
}
|
||||
if len(str) > 0 {
|
||||
// Send remainder
|
||||
l.token = str
|
||||
l.value = zValue
|
||||
c <- l
|
||||
}
|
||||
}
|
85
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/dnssec_privkey.go
generated
vendored
Normal file
85
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/dnssec_privkey.go
generated
vendored
Normal file
|
@ -0,0 +1,85 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/dsa"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rsa"
|
||||
"math/big"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const format = "Private-key-format: v1.3\n"
|
||||
|
||||
// PrivateKeyString converts a PrivateKey to a string. This string has the same
|
||||
// format as the private-key-file of BIND9 (Private-key-format: v1.3).
|
||||
// It needs some info from the key (the algorithm), so its a method of the DNSKEY
|
||||
// It supports rsa.PrivateKey, ecdsa.PrivateKey and dsa.PrivateKey
|
||||
func (r *DNSKEY) PrivateKeyString(p crypto.PrivateKey) string {
|
||||
algorithm := strconv.Itoa(int(r.Algorithm))
|
||||
algorithm += " (" + AlgorithmToString[r.Algorithm] + ")"
|
||||
|
||||
switch p := p.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
modulus := toBase64(p.PublicKey.N.Bytes())
|
||||
e := big.NewInt(int64(p.PublicKey.E))
|
||||
publicExponent := toBase64(e.Bytes())
|
||||
privateExponent := toBase64(p.D.Bytes())
|
||||
prime1 := toBase64(p.Primes[0].Bytes())
|
||||
prime2 := toBase64(p.Primes[1].Bytes())
|
||||
// Calculate Exponent1/2 and Coefficient as per: http://en.wikipedia.org/wiki/RSA#Using_the_Chinese_remainder_algorithm
|
||||
// and from: http://code.google.com/p/go/issues/detail?id=987
|
||||
one := big.NewInt(1)
|
||||
p1 := big.NewInt(0).Sub(p.Primes[0], one)
|
||||
q1 := big.NewInt(0).Sub(p.Primes[1], one)
|
||||
exp1 := big.NewInt(0).Mod(p.D, p1)
|
||||
exp2 := big.NewInt(0).Mod(p.D, q1)
|
||||
coeff := big.NewInt(0).ModInverse(p.Primes[1], p.Primes[0])
|
||||
|
||||
exponent1 := toBase64(exp1.Bytes())
|
||||
exponent2 := toBase64(exp2.Bytes())
|
||||
coefficient := toBase64(coeff.Bytes())
|
||||
|
||||
return format +
|
||||
"Algorithm: " + algorithm + "\n" +
|
||||
"Modulus: " + modulus + "\n" +
|
||||
"PublicExponent: " + publicExponent + "\n" +
|
||||
"PrivateExponent: " + privateExponent + "\n" +
|
||||
"Prime1: " + prime1 + "\n" +
|
||||
"Prime2: " + prime2 + "\n" +
|
||||
"Exponent1: " + exponent1 + "\n" +
|
||||
"Exponent2: " + exponent2 + "\n" +
|
||||
"Coefficient: " + coefficient + "\n"
|
||||
|
||||
case *ecdsa.PrivateKey:
|
||||
var intlen int
|
||||
switch r.Algorithm {
|
||||
case ECDSAP256SHA256:
|
||||
intlen = 32
|
||||
case ECDSAP384SHA384:
|
||||
intlen = 48
|
||||
}
|
||||
private := toBase64(intToBytes(p.D, intlen))
|
||||
return format +
|
||||
"Algorithm: " + algorithm + "\n" +
|
||||
"PrivateKey: " + private + "\n"
|
||||
|
||||
case *dsa.PrivateKey:
|
||||
T := divRoundUp(divRoundUp(p.PublicKey.Parameters.G.BitLen(), 8)-64, 8)
|
||||
prime := toBase64(intToBytes(p.PublicKey.Parameters.P, 64+T*8))
|
||||
subprime := toBase64(intToBytes(p.PublicKey.Parameters.Q, 20))
|
||||
base := toBase64(intToBytes(p.PublicKey.Parameters.G, 64+T*8))
|
||||
priv := toBase64(intToBytes(p.X, 20))
|
||||
pub := toBase64(intToBytes(p.PublicKey.Y, 64+T*8))
|
||||
return format +
|
||||
"Algorithm: " + algorithm + "\n" +
|
||||
"Prime(p): " + prime + "\n" +
|
||||
"Subprime(q): " + subprime + "\n" +
|
||||
"Base(g): " + base + "\n" +
|
||||
"Private_value(x): " + priv + "\n" +
|
||||
"Public_value(y): " + pub + "\n"
|
||||
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
251
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/doc.go
generated
vendored
Normal file
251
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,251 @@
|
|||
/*
|
||||
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 send out to the DNS. The package
|
||||
API follows the less-is-more principle, by presenting a small, clean interface.
|
||||
|
||||
The package dns 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
|
||||
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:
|
||||
|
||||
r := new(dns.MX)
|
||||
r.Hdr = dns.RR_Header{Name: "miek.nl.", Rrtype: dns.TypeMX,
|
||||
Class: dns.ClassINET, Ttl: 3600}
|
||||
r.Preference = 10
|
||||
r.Mx = "mx.miek.nl."
|
||||
|
||||
Or directly from a string:
|
||||
|
||||
mx, err := dns.NewRR("miek.nl. 3600 IN MX 10 mx.miek.nl.")
|
||||
|
||||
Or when the default TTL (3600) and class (IN) suit you:
|
||||
|
||||
mx, err := dns.NewRR("miek.nl. MX 10 mx.miek.nl.")
|
||||
|
||||
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:
|
||||
|
||||
m := new(dns.Msg)
|
||||
m.SetQuestion("miek.nl.", dns.TypeMX)
|
||||
|
||||
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 following is slightly more verbose, but more flexible:
|
||||
|
||||
m1 := new(dns.Msg)
|
||||
m1.Id = dns.Id()
|
||||
m1.RecursionDesired = true
|
||||
m1.Question = make([]dns.Question, 1)
|
||||
m1.Question[0] = dns.Question{"miek.nl.", dns.TypeMX, dns.ClassINET}
|
||||
|
||||
After creating a message it can be send.
|
||||
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")
|
||||
|
||||
Suppressing multiple outstanding queries (with the same question, type and
|
||||
class) is as easy as setting:
|
||||
|
||||
c.SingleInflight = true
|
||||
|
||||
If these "advanced" features are not needed, a simple UDP query can be send,
|
||||
with:
|
||||
|
||||
in, err := dns.Exchange(m1, "127.0.0.1:53")
|
||||
|
||||
When this functions returns you will get dns message. A dns message consists
|
||||
out of four sections.
|
||||
The question section: in.Question, the answer section: in.Answer,
|
||||
the authority section: in.Ns and the additional section: in.Extra.
|
||||
|
||||
Each of these sections (except the Question section) contain a []RR. Basic
|
||||
use pattern for accessing the rdata of a TXT RR as the first RR in
|
||||
the Answer section:
|
||||
|
||||
if t, ok := in.Answer[0].(*dns.TXT); ok {
|
||||
// do something with t.Txt
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
Requesting DNSSEC information for a zone is done by adding the DO (DNSSEC OK) bit
|
||||
to an request.
|
||||
|
||||
m := new(dns.Msg)
|
||||
m.SetEdns0(4096, true)
|
||||
|
||||
Signature generation, signature verification and key generation are all supported.
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
should be added or removed. The table from RFC 2136 supplemented with the Go
|
||||
DNS function shows which functions exist to specify the prerequisites.
|
||||
|
||||
3.2.4 - Table Of Metavalues Used In Prerequisite Section
|
||||
|
||||
CLASS TYPE RDATA Meaning Function
|
||||
--------------------------------------------------------------
|
||||
ANY ANY empty Name is in use dns.NameUsed
|
||||
ANY rrset empty RRset exists (value indep) dns.RRsetUsed
|
||||
NONE ANY empty Name is not in use dns.NameNotUsed
|
||||
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.
|
||||
|
||||
3.4.2.6 - Table Of Metavalues Used In Update Section
|
||||
|
||||
CLASS TYPE RDATA Meaning Function
|
||||
---------------------------------------------------------------
|
||||
ANY ANY empty Delete all RRsets from name dns.RemoveName
|
||||
ANY rrset empty Delete an RRset dns.RemoveRRset
|
||||
NONE rrset rr Delete an RR from RRset dns.Remove
|
||||
zone rrset rr Add to an RRset dns.Insert
|
||||
|
||||
TRANSACTION SIGNATURE
|
||||
|
||||
An TSIG or transaction signature adds a HMAC TSIG record to each message sent.
|
||||
The supported algorithms include: HmacMD5, HmacSHA1, HmacSHA256 and HmacSHA512.
|
||||
|
||||
Basic use pattern when querying with a TSIG name "axfr." (note that these key names
|
||||
must be fully qualified - as they are domain names) and the base64 secret
|
||||
"so6ZGir4GPAqINNh9U5c3A==":
|
||||
|
||||
c := new(dns.Client)
|
||||
c.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
|
||||
m := new(dns.Msg)
|
||||
m.SetQuestion("miek.nl.", dns.TypeMX)
|
||||
m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
|
||||
...
|
||||
// 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:
|
||||
|
||||
t := new(dns.Transfer)
|
||||
m := new(dns.Msg)
|
||||
t.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
|
||||
m.SetAxfr("miek.nl.")
|
||||
m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
|
||||
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.
|
||||
|
||||
Basic use pattern validating and replying to a message that has TSIG set.
|
||||
|
||||
server := &dns.Server{Addr: ":53", Net: "udp"}
|
||||
server.TsigSecret = map[string]string{"axfr.": "so6ZGir4GPAqINNh9U5c3A=="}
|
||||
go server.ListenAndServe()
|
||||
dns.HandleFunc(".", handleRequest)
|
||||
|
||||
func handleRequest(w dns.ResponseWriter, r *dns.Msg) {
|
||||
m := new(dns.Msg)
|
||||
m.SetReply(r)
|
||||
if r.IsTsig() {
|
||||
if w.TsigStatus() == nil {
|
||||
// *Msg r has an TSIG record and it was validated
|
||||
m.SetTsig("axfr.", dns.HmacMD5, 300, time.Now().Unix())
|
||||
} else {
|
||||
// *Msg r has an TSIG records and it was not valided
|
||||
}
|
||||
}
|
||||
w.WriteMsg(m)
|
||||
}
|
||||
|
||||
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
|
||||
can be used, before requesting an official type code from IANA.
|
||||
|
||||
see http://miek.nl/posts/2014/Sep/21/Private%20RRs%20and%20IDN%20in%20Go%20DNS/ 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
|
||||
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:
|
||||
|
||||
// o is a dns.OPT
|
||||
for _, s := range o.Option {
|
||||
switch e := s.(type) {
|
||||
case *dns.EDNS0_NSID:
|
||||
// do stuff with e.Nsid
|
||||
case *dns.EDNS0_SUBNET:
|
||||
// access e.Family, e.Address, etc.
|
||||
}
|
||||
}
|
||||
|
||||
SIG(0)
|
||||
|
||||
From RFC 2931:
|
||||
|
||||
SIG(0) provides protection for DNS transactions and requests ....
|
||||
... 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.
|
||||
|
||||
Signing subsequent messages in multi-message sessions is not implemented.
|
||||
*/
|
||||
package dns
|
505
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/edns.go
generated
vendored
Normal file
505
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/edns.go
generated
vendored
Normal file
|
@ -0,0 +1,505 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"net"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// EDNS0 Option codes.
|
||||
const (
|
||||
EDNS0LLQ = 0x1 // long lived queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
|
||||
EDNS0UL = 0x2 // update lease draft: http://files.dns-sd.org/draft-sekar-dns-ul.txt
|
||||
EDNS0NSID = 0x3 // nsid (RFC5001)
|
||||
EDNS0DAU = 0x5 // DNSSEC Algorithm Understood
|
||||
EDNS0DHU = 0x6 // DS Hash Understood
|
||||
EDNS0N3U = 0x7 // NSEC3 Hash Understood
|
||||
EDNS0SUBNET = 0x8 // client-subnet (RFC6891)
|
||||
EDNS0EXPIRE = 0x9 // EDNS0 expire
|
||||
EDNS0SUBNETDRAFT = 0x50fa // Don't use! Use EDNS0SUBNET
|
||||
EDNS0LOCALSTART = 0xFDE9 // Beginning of range reserved for local/experimental use (RFC6891)
|
||||
EDNS0LOCALEND = 0xFFFE // End of range reserved for local/experimental use (RFC6891)
|
||||
_DO = 1 << 15 // dnssec ok
|
||||
)
|
||||
|
||||
// OPT is the EDNS0 RR appended to messages to convey extra (meta) information.
|
||||
// See RFC 6891.
|
||||
type OPT struct {
|
||||
Hdr RR_Header
|
||||
Option []EDNS0 `dns:"opt"`
|
||||
}
|
||||
|
||||
func (rr *OPT) String() string {
|
||||
s := "\n;; OPT PSEUDOSECTION:\n; EDNS: version " + strconv.Itoa(int(rr.Version())) + "; "
|
||||
if rr.Do() {
|
||||
s += "flags: do; "
|
||||
} else {
|
||||
s += "flags: ; "
|
||||
}
|
||||
s += "udp: " + strconv.Itoa(int(rr.UDPSize()))
|
||||
|
||||
for _, o := range rr.Option {
|
||||
switch o.(type) {
|
||||
case *EDNS0_NSID:
|
||||
s += "\n; NSID: " + o.String()
|
||||
h, e := o.pack()
|
||||
var r string
|
||||
if e == nil {
|
||||
for _, c := range h {
|
||||
r += "(" + string(c) + ")"
|
||||
}
|
||||
s += " " + r
|
||||
}
|
||||
case *EDNS0_SUBNET:
|
||||
s += "\n; SUBNET: " + o.String()
|
||||
if o.(*EDNS0_SUBNET).DraftOption {
|
||||
s += " (draft)"
|
||||
}
|
||||
case *EDNS0_UL:
|
||||
s += "\n; UPDATE LEASE: " + o.String()
|
||||
case *EDNS0_LLQ:
|
||||
s += "\n; LONG LIVED QUERIES: " + o.String()
|
||||
case *EDNS0_DAU:
|
||||
s += "\n; DNSSEC ALGORITHM UNDERSTOOD: " + o.String()
|
||||
case *EDNS0_DHU:
|
||||
s += "\n; DS HASH UNDERSTOOD: " + o.String()
|
||||
case *EDNS0_N3U:
|
||||
s += "\n; NSEC3 HASH UNDERSTOOD: " + o.String()
|
||||
case *EDNS0_LOCAL:
|
||||
s += "\n; LOCAL OPT: " + o.String()
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (rr *OPT) len() int {
|
||||
l := rr.Hdr.len()
|
||||
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()
|
||||
l += len(lo)
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// return the old value -> delete SetVersion?
|
||||
|
||||
// Version returns the EDNS version used. Only zero is defined.
|
||||
func (rr *OPT) Version() uint8 {
|
||||
return uint8((rr.Hdr.Ttl & 0x00FF0000) >> 16)
|
||||
}
|
||||
|
||||
// SetVersion sets the version of EDNS. This is usually zero.
|
||||
func (rr *OPT) SetVersion(v uint8) {
|
||||
rr.Hdr.Ttl = rr.Hdr.Ttl&0xFF00FFFF | (uint32(v) << 16)
|
||||
}
|
||||
|
||||
// ExtendedRcode returns the EDNS extended RCODE field (the upper 8 bits of the TTL).
|
||||
func (rr *OPT) ExtendedRcode() uint8 {
|
||||
return uint8((rr.Hdr.Ttl & 0xFF000000) >> 24)
|
||||
}
|
||||
|
||||
// SetExtendedRcode sets the EDNS extended RCODE field.
|
||||
func (rr *OPT) SetExtendedRcode(v uint8) {
|
||||
rr.Hdr.Ttl = rr.Hdr.Ttl&0x00FFFFFF | (uint32(v) << 24)
|
||||
}
|
||||
|
||||
// UDPSize returns the UDP buffer size.
|
||||
func (rr *OPT) UDPSize() uint16 {
|
||||
return rr.Hdr.Class
|
||||
}
|
||||
|
||||
// SetUDPSize sets the UDP buffer size.
|
||||
func (rr *OPT) SetUDPSize(size uint16) {
|
||||
rr.Hdr.Class = size
|
||||
}
|
||||
|
||||
// Do returns the value of the DO (DNSSEC OK) bit.
|
||||
func (rr *OPT) Do() bool {
|
||||
return rr.Hdr.Ttl&_DO == _DO
|
||||
}
|
||||
|
||||
// SetDo sets the DO (DNSSEC OK) bit.
|
||||
func (rr *OPT) SetDo() {
|
||||
rr.Hdr.Ttl |= _DO
|
||||
}
|
||||
|
||||
// EDNS0 defines an EDNS0 Option. An OPT RR can have multiple options appended to
|
||||
// it.
|
||||
type EDNS0 interface {
|
||||
// Option returns the option code for the option.
|
||||
Option() uint16
|
||||
// pack returns the bytes of the option data.
|
||||
pack() ([]byte, error)
|
||||
// unpack sets the data as found in the buffer. Is also sets
|
||||
// the length of the slice as the length of the option data.
|
||||
unpack([]byte) error
|
||||
// String returns the string representation of the option.
|
||||
String() string
|
||||
}
|
||||
|
||||
// The nsid EDNS0 option is used to retrieve a nameserver
|
||||
// identifier. When sending a request Nsid must be set to the empty string
|
||||
// The identifier is an opaque string encoded as hex.
|
||||
// Basic use pattern for creating an nsid option:
|
||||
//
|
||||
// o := new(dns.OPT)
|
||||
// o.Hdr.Name = "."
|
||||
// o.Hdr.Rrtype = dns.TypeOPT
|
||||
// e := new(dns.EDNS0_NSID)
|
||||
// e.Code = dns.EDNS0NSID
|
||||
// e.Nsid = "AA"
|
||||
// o.Option = append(o.Option, e)
|
||||
type EDNS0_NSID struct {
|
||||
Code uint16 // Always EDNS0NSID
|
||||
Nsid string // This string needs to be hex encoded
|
||||
}
|
||||
|
||||
func (e *EDNS0_NSID) pack() ([]byte, error) {
|
||||
h, err := hex.DecodeString(e.Nsid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func (e *EDNS0_NSID) Option() uint16 { return EDNS0NSID }
|
||||
func (e *EDNS0_NSID) unpack(b []byte) error { e.Nsid = hex.EncodeToString(b); return nil }
|
||||
func (e *EDNS0_NSID) String() string { return string(e.Nsid) }
|
||||
|
||||
// EDNS0_SUBNET is the subnet option that is used to give the remote nameserver
|
||||
// an idea of where the client lives. It can then give back a different
|
||||
// answer depending on the location or network topology.
|
||||
// Basic use pattern for creating an subnet option:
|
||||
//
|
||||
// o := new(dns.OPT)
|
||||
// o.Hdr.Name = "."
|
||||
// o.Hdr.Rrtype = dns.TypeOPT
|
||||
// e := new(dns.EDNS0_SUBNET)
|
||||
// e.Code = dns.EDNS0SUBNET
|
||||
// e.Family = 1 // 1 for IPv4 source address, 2 for IPv6
|
||||
// e.NetMask = 32 // 32 for IPV4, 128 for IPv6
|
||||
// e.SourceScope = 0
|
||||
// e.Address = net.ParseIP("127.0.0.1").To4() // for IPv4
|
||||
// // e.Address = net.ParseIP("2001:7b8:32a::2") // for IPV6
|
||||
// o.Option = append(o.Option, e)
|
||||
//
|
||||
// Note: the spec (draft-ietf-dnsop-edns-client-subnet-00) has some insane logic
|
||||
// for which netmask applies to the address. This code will parse all the
|
||||
// available bits when unpacking (up to optlen). When packing it will apply
|
||||
// SourceNetmask. If you need more advanced logic, patches welcome and good luck.
|
||||
type EDNS0_SUBNET struct {
|
||||
Code uint16 // Always EDNS0SUBNET
|
||||
Family uint16 // 1 for IP, 2 for IP6
|
||||
SourceNetmask uint8
|
||||
SourceScope uint8
|
||||
Address net.IP
|
||||
DraftOption bool // Set to true if using the old (0x50fa) option code
|
||||
}
|
||||
|
||||
func (e *EDNS0_SUBNET) Option() uint16 {
|
||||
if e.DraftOption {
|
||||
return EDNS0SUBNETDRAFT
|
||||
}
|
||||
return EDNS0SUBNET
|
||||
}
|
||||
|
||||
func (e *EDNS0_SUBNET) pack() ([]byte, error) {
|
||||
b := make([]byte, 4)
|
||||
b[0], b[1] = packUint16(e.Family)
|
||||
b[2] = e.SourceNetmask
|
||||
b[3] = e.SourceScope
|
||||
switch e.Family {
|
||||
case 1:
|
||||
if e.SourceNetmask > net.IPv4len*8 {
|
||||
return nil, errors.New("dns: bad netmask")
|
||||
}
|
||||
if len(e.Address.To4()) != net.IPv4len {
|
||||
return nil, errors.New("dns: bad address")
|
||||
}
|
||||
ip := e.Address.To4().Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv4len*8))
|
||||
needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up
|
||||
b = append(b, ip[:needLength]...)
|
||||
case 2:
|
||||
if e.SourceNetmask > net.IPv6len*8 {
|
||||
return nil, errors.New("dns: bad netmask")
|
||||
}
|
||||
if len(e.Address) != net.IPv6len {
|
||||
return nil, errors.New("dns: bad address")
|
||||
}
|
||||
ip := e.Address.Mask(net.CIDRMask(int(e.SourceNetmask), net.IPv6len*8))
|
||||
needLength := (e.SourceNetmask + 8 - 1) / 8 // division rounding up
|
||||
b = append(b, ip[:needLength]...)
|
||||
default:
|
||||
return nil, errors.New("dns: bad address family")
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (e *EDNS0_SUBNET) unpack(b []byte) error {
|
||||
if len(b) < 4 {
|
||||
return ErrBuf
|
||||
}
|
||||
e.Family, _ = unpackUint16(b, 0)
|
||||
e.SourceNetmask = b[2]
|
||||
e.SourceScope = b[3]
|
||||
switch e.Family {
|
||||
case 1:
|
||||
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])
|
||||
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]}
|
||||
default:
|
||||
return errors.New("dns: bad address family")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *EDNS0_SUBNET) String() (s string) {
|
||||
if e.Address == nil {
|
||||
s = "<nil>"
|
||||
} else if e.Address.To4() != nil {
|
||||
s = e.Address.String()
|
||||
} else {
|
||||
s = "[" + e.Address.String() + "]"
|
||||
}
|
||||
s += "/" + strconv.Itoa(int(e.SourceNetmask)) + "/" + strconv.Itoa(int(e.SourceScope))
|
||||
return
|
||||
}
|
||||
|
||||
// The EDNS0_UL (Update Lease) (draft RFC) option is used to tell the server to set
|
||||
// an expiration on an update RR. This is helpful for clients that cannot clean
|
||||
// up after themselves. This is a draft RFC and more information can be found at
|
||||
// http://files.dns-sd.org/draft-sekar-dns-ul.txt
|
||||
//
|
||||
// o := new(dns.OPT)
|
||||
// o.Hdr.Name = "."
|
||||
// o.Hdr.Rrtype = dns.TypeOPT
|
||||
// e := new(dns.EDNS0_UL)
|
||||
// e.Code = dns.EDNS0UL
|
||||
// e.Lease = 120 // in seconds
|
||||
// o.Option = append(o.Option, e)
|
||||
type EDNS0_UL struct {
|
||||
Code uint16 // Always EDNS0UL
|
||||
Lease uint32
|
||||
}
|
||||
|
||||
func (e *EDNS0_UL) Option() uint16 { return EDNS0UL }
|
||||
func (e *EDNS0_UL) String() string { return strconv.FormatUint(uint64(e.Lease), 10) }
|
||||
|
||||
// Copied: http://golang.org/src/pkg/net/dnsmsg.go
|
||||
func (e *EDNS0_UL) pack() ([]byte, error) {
|
||||
b := make([]byte, 4)
|
||||
b[0] = byte(e.Lease >> 24)
|
||||
b[1] = byte(e.Lease >> 16)
|
||||
b[2] = byte(e.Lease >> 8)
|
||||
b[3] = byte(e.Lease)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (e *EDNS0_UL) unpack(b []byte) error {
|
||||
if len(b) < 4 {
|
||||
return ErrBuf
|
||||
}
|
||||
e.Lease = uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])
|
||||
return nil
|
||||
}
|
||||
|
||||
// EDNS0_LLQ stands for Long Lived Queries: http://tools.ietf.org/html/draft-sekar-dns-llq-01
|
||||
// Implemented for completeness, as the EDNS0 type code is assigned.
|
||||
type EDNS0_LLQ struct {
|
||||
Code uint16 // Always EDNS0LLQ
|
||||
Version uint16
|
||||
Opcode uint16
|
||||
Error uint16
|
||||
Id uint64
|
||||
LeaseLife uint32
|
||||
}
|
||||
|
||||
func (e *EDNS0_LLQ) Option() uint16 { return EDNS0LLQ }
|
||||
|
||||
func (e *EDNS0_LLQ) pack() ([]byte, error) {
|
||||
b := make([]byte, 18)
|
||||
b[0], b[1] = packUint16(e.Version)
|
||||
b[2], b[3] = packUint16(e.Opcode)
|
||||
b[4], b[5] = packUint16(e.Error)
|
||||
b[6] = byte(e.Id >> 56)
|
||||
b[7] = byte(e.Id >> 48)
|
||||
b[8] = byte(e.Id >> 40)
|
||||
b[9] = byte(e.Id >> 32)
|
||||
b[10] = byte(e.Id >> 24)
|
||||
b[11] = byte(e.Id >> 16)
|
||||
b[12] = byte(e.Id >> 8)
|
||||
b[13] = byte(e.Id)
|
||||
b[14] = byte(e.LeaseLife >> 24)
|
||||
b[15] = byte(e.LeaseLife >> 16)
|
||||
b[16] = byte(e.LeaseLife >> 8)
|
||||
b[17] = byte(e.LeaseLife)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (e *EDNS0_LLQ) unpack(b []byte) error {
|
||||
if len(b) < 18 {
|
||||
return ErrBuf
|
||||
}
|
||||
e.Version, _ = unpackUint16(b, 0)
|
||||
e.Opcode, _ = unpackUint16(b, 2)
|
||||
e.Error, _ = unpackUint16(b, 4)
|
||||
e.Id = uint64(b[6])<<56 | uint64(b[6+1])<<48 | uint64(b[6+2])<<40 |
|
||||
uint64(b[6+3])<<32 | uint64(b[6+4])<<24 | uint64(b[6+5])<<16 | uint64(b[6+6])<<8 | uint64(b[6+7])
|
||||
e.LeaseLife = uint32(b[14])<<24 | uint32(b[14+1])<<16 | uint32(b[14+2])<<8 | uint32(b[14+3])
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *EDNS0_LLQ) String() string {
|
||||
s := strconv.FormatUint(uint64(e.Version), 10) + " " + strconv.FormatUint(uint64(e.Opcode), 10) +
|
||||
" " + strconv.FormatUint(uint64(e.Error), 10) + " " + strconv.FormatUint(uint64(e.Id), 10) +
|
||||
" " + strconv.FormatUint(uint64(e.LeaseLife), 10)
|
||||
return s
|
||||
}
|
||||
|
||||
type EDNS0_DAU struct {
|
||||
Code uint16 // Always EDNS0DAU
|
||||
AlgCode []uint8
|
||||
}
|
||||
|
||||
func (e *EDNS0_DAU) Option() uint16 { return EDNS0DAU }
|
||||
func (e *EDNS0_DAU) pack() ([]byte, error) { return e.AlgCode, nil }
|
||||
func (e *EDNS0_DAU) unpack(b []byte) error { e.AlgCode = b; return nil }
|
||||
|
||||
func (e *EDNS0_DAU) String() string {
|
||||
s := ""
|
||||
for i := 0; i < len(e.AlgCode); i++ {
|
||||
if a, ok := AlgorithmToString[e.AlgCode[i]]; ok {
|
||||
s += " " + a
|
||||
} else {
|
||||
s += " " + strconv.Itoa(int(e.AlgCode[i]))
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
type EDNS0_DHU struct {
|
||||
Code uint16 // Always EDNS0DHU
|
||||
AlgCode []uint8
|
||||
}
|
||||
|
||||
func (e *EDNS0_DHU) Option() uint16 { return EDNS0DHU }
|
||||
func (e *EDNS0_DHU) pack() ([]byte, error) { return e.AlgCode, nil }
|
||||
func (e *EDNS0_DHU) unpack(b []byte) error { e.AlgCode = b; return nil }
|
||||
|
||||
func (e *EDNS0_DHU) String() string {
|
||||
s := ""
|
||||
for i := 0; i < len(e.AlgCode); i++ {
|
||||
if a, ok := HashToString[e.AlgCode[i]]; ok {
|
||||
s += " " + a
|
||||
} else {
|
||||
s += " " + strconv.Itoa(int(e.AlgCode[i]))
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
type EDNS0_N3U struct {
|
||||
Code uint16 // Always EDNS0N3U
|
||||
AlgCode []uint8
|
||||
}
|
||||
|
||||
func (e *EDNS0_N3U) Option() uint16 { return EDNS0N3U }
|
||||
func (e *EDNS0_N3U) pack() ([]byte, error) { return e.AlgCode, nil }
|
||||
func (e *EDNS0_N3U) unpack(b []byte) error { e.AlgCode = b; return nil }
|
||||
|
||||
func (e *EDNS0_N3U) String() string {
|
||||
// Re-use the hash map
|
||||
s := ""
|
||||
for i := 0; i < len(e.AlgCode); i++ {
|
||||
if a, ok := HashToString[e.AlgCode[i]]; ok {
|
||||
s += " " + a
|
||||
} else {
|
||||
s += " " + strconv.Itoa(int(e.AlgCode[i]))
|
||||
}
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
type EDNS0_EXPIRE struct {
|
||||
Code uint16 // Always EDNS0EXPIRE
|
||||
Expire uint32
|
||||
}
|
||||
|
||||
func (e *EDNS0_EXPIRE) Option() uint16 { return EDNS0EXPIRE }
|
||||
func (e *EDNS0_EXPIRE) String() string { return strconv.FormatUint(uint64(e.Expire), 10) }
|
||||
|
||||
func (e *EDNS0_EXPIRE) pack() ([]byte, error) {
|
||||
b := make([]byte, 4)
|
||||
b[0] = byte(e.Expire >> 24)
|
||||
b[1] = byte(e.Expire >> 16)
|
||||
b[2] = byte(e.Expire >> 8)
|
||||
b[3] = byte(e.Expire)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (e *EDNS0_EXPIRE) unpack(b []byte) error {
|
||||
if len(b) < 4 {
|
||||
return ErrBuf
|
||||
}
|
||||
e.Expire = uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])
|
||||
return nil
|
||||
}
|
||||
|
||||
// The EDNS0_LOCAL option is used for local/experimental purposes. The option
|
||||
// code is recommended to be within the range [EDNS0LOCALSTART, EDNS0LOCALEND]
|
||||
// (RFC6891), although any unassigned code can actually be used. The content of
|
||||
// the option is made available in Data, unaltered.
|
||||
// Basic use pattern for creating a local option:
|
||||
//
|
||||
// o := new(dns.OPT)
|
||||
// o.Hdr.Name = "."
|
||||
// o.Hdr.Rrtype = dns.TypeOPT
|
||||
// e := new(dns.EDNS0_LOCAL)
|
||||
// e.Code = dns.EDNS0LOCALSTART
|
||||
// e.Data = []byte{72, 82, 74}
|
||||
// o.Option = append(o.Option, e)
|
||||
type EDNS0_LOCAL struct {
|
||||
Code uint16
|
||||
Data []byte
|
||||
}
|
||||
|
||||
func (e *EDNS0_LOCAL) Option() uint16 { return e.Code }
|
||||
func (e *EDNS0_LOCAL) String() string {
|
||||
return strconv.FormatInt(int64(e.Code), 10) + ":0x" + hex.EncodeToString(e.Data)
|
||||
}
|
||||
|
||||
func (e *EDNS0_LOCAL) pack() ([]byte, error) {
|
||||
b := make([]byte, len(e.Data))
|
||||
copied := copy(b, e.Data)
|
||||
if copied != len(e.Data) {
|
||||
return nil, ErrBuf
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (e *EDNS0_LOCAL) unpack(b []byte) error {
|
||||
e.Data = make([]byte, len(b))
|
||||
copied := copy(e.Data, b)
|
||||
if copied != len(b) {
|
||||
return ErrBuf
|
||||
}
|
||||
return nil
|
||||
}
|
96
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/format.go
generated
vendored
Normal file
96
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/format.go
generated
vendored
Normal file
|
@ -0,0 +1,96 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"net"
|
||||
"reflect"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// NumField returns the number of rdata fields r has.
|
||||
func NumField(r RR) int {
|
||||
return reflect.ValueOf(r).Elem().NumField() - 1 // Remove RR_Header
|
||||
}
|
||||
|
||||
// Field returns the rdata field i as a string. Fields are indexed starting from 1.
|
||||
// RR types that holds slice data, for instance the NSEC type bitmap will return a single
|
||||
// string where the types are concatenated using a space.
|
||||
// Accessing non existing fields will cause a panic.
|
||||
func Field(r RR, i int) string {
|
||||
if i == 0 {
|
||||
return ""
|
||||
}
|
||||
d := reflect.ValueOf(r).Elem().Field(i)
|
||||
switch k := d.Kind(); k {
|
||||
case reflect.String:
|
||||
return d.String()
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return strconv.FormatInt(d.Int(), 10)
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return strconv.FormatUint(d.Uint(), 10)
|
||||
case reflect.Slice:
|
||||
switch reflect.ValueOf(r).Elem().Type().Field(i).Tag {
|
||||
case `dns:"a"`:
|
||||
// TODO(miek): Hmm store this as 16 bytes
|
||||
if d.Len() < net.IPv6len {
|
||||
return net.IPv4(byte(d.Index(0).Uint()),
|
||||
byte(d.Index(1).Uint()),
|
||||
byte(d.Index(2).Uint()),
|
||||
byte(d.Index(3).Uint())).String()
|
||||
}
|
||||
return net.IPv4(byte(d.Index(12).Uint()),
|
||||
byte(d.Index(13).Uint()),
|
||||
byte(d.Index(14).Uint()),
|
||||
byte(d.Index(15).Uint())).String()
|
||||
case `dns:"aaaa"`:
|
||||
return net.IP{
|
||||
byte(d.Index(0).Uint()),
|
||||
byte(d.Index(1).Uint()),
|
||||
byte(d.Index(2).Uint()),
|
||||
byte(d.Index(3).Uint()),
|
||||
byte(d.Index(4).Uint()),
|
||||
byte(d.Index(5).Uint()),
|
||||
byte(d.Index(6).Uint()),
|
||||
byte(d.Index(7).Uint()),
|
||||
byte(d.Index(8).Uint()),
|
||||
byte(d.Index(9).Uint()),
|
||||
byte(d.Index(10).Uint()),
|
||||
byte(d.Index(11).Uint()),
|
||||
byte(d.Index(12).Uint()),
|
||||
byte(d.Index(13).Uint()),
|
||||
byte(d.Index(14).Uint()),
|
||||
byte(d.Index(15).Uint()),
|
||||
}.String()
|
||||
case `dns:"nsec"`:
|
||||
if d.Len() == 0 {
|
||||
return ""
|
||||
}
|
||||
s := Type(d.Index(0).Uint()).String()
|
||||
for i := 1; i < d.Len(); i++ {
|
||||
s += " " + Type(d.Index(i).Uint()).String()
|
||||
}
|
||||
return s
|
||||
case `dns:"wks"`:
|
||||
if d.Len() == 0 {
|
||||
return ""
|
||||
}
|
||||
s := strconv.Itoa(int(d.Index(0).Uint()))
|
||||
for i := 0; i < d.Len(); i++ {
|
||||
s += " " + strconv.Itoa(int(d.Index(i).Uint()))
|
||||
}
|
||||
return s
|
||||
default:
|
||||
// if it does not have a tag its a string slice
|
||||
fallthrough
|
||||
case `dns:"txt"`:
|
||||
if d.Len() == 0 {
|
||||
return ""
|
||||
}
|
||||
s := d.Index(0).String()
|
||||
for i := 1; i < d.Len(); i++ {
|
||||
s += " " + d.Index(i).String()
|
||||
}
|
||||
return s
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
2346
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/idn/code_points.go
generated
vendored
Normal file
2346
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/idn/code_points.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
373
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/idn/punycode.go
generated
vendored
Normal file
373
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/idn/punycode.go
generated
vendored
Normal file
|
@ -0,0 +1,373 @@
|
|||
// Package idn implements encoding from and to punycode as speficied by RFC 3492.
|
||||
package idn
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Implementation idea from RFC itself and from from IDNA::Punycode created by
|
||||
// Tatsuhiko Miyagawa <miyagawa@bulknews.net> and released under Perl Artistic
|
||||
// License in 2002.
|
||||
|
||||
const (
|
||||
_MIN rune = 1
|
||||
_MAX rune = 26
|
||||
_SKEW rune = 38
|
||||
_BASE rune = 36
|
||||
_BIAS rune = 72
|
||||
_N rune = 128
|
||||
_DAMP rune = 700
|
||||
|
||||
_DELIMITER = '-'
|
||||
_PREFIX = "xn--"
|
||||
)
|
||||
|
||||
// ToPunycode converts unicode domain names to DNS-appropriate punycode names.
|
||||
// This function will return an empty string result for domain names with
|
||||
// invalid unicode strings. This function expects domain names in lowercase.
|
||||
func ToPunycode(s string) string {
|
||||
// Early check to see if encoding is needed.
|
||||
// This will prevent making heap allocations when not needed.
|
||||
if !needToPunycode(s) {
|
||||
return s
|
||||
}
|
||||
|
||||
tokens := dns.SplitDomainName(s)
|
||||
switch {
|
||||
case s == "":
|
||||
return ""
|
||||
case tokens == nil: // s == .
|
||||
return "."
|
||||
case s[len(s)-1] == '.':
|
||||
tokens = append(tokens, "")
|
||||
}
|
||||
|
||||
for i := range tokens {
|
||||
t := encode([]byte(tokens[i]))
|
||||
if t == nil {
|
||||
return ""
|
||||
}
|
||||
tokens[i] = string(t)
|
||||
}
|
||||
return strings.Join(tokens, ".")
|
||||
}
|
||||
|
||||
// FromPunycode returns unicode domain name from provided punycode string.
|
||||
// This function expects punycode strings in lowercase.
|
||||
func FromPunycode(s string) string {
|
||||
// Early check to see if decoding is needed.
|
||||
// This will prevent making heap allocations when not needed.
|
||||
if !needFromPunycode(s) {
|
||||
return s
|
||||
}
|
||||
|
||||
tokens := dns.SplitDomainName(s)
|
||||
switch {
|
||||
case s == "":
|
||||
return ""
|
||||
case tokens == nil: // s == .
|
||||
return "."
|
||||
case s[len(s)-1] == '.':
|
||||
tokens = append(tokens, "")
|
||||
}
|
||||
for i := range tokens {
|
||||
tokens[i] = string(decode([]byte(tokens[i])))
|
||||
}
|
||||
return strings.Join(tokens, ".")
|
||||
}
|
||||
|
||||
// digitval converts single byte into meaningful value that's used to calculate decoded unicode character.
|
||||
const errdigit = 0xffff
|
||||
|
||||
func digitval(code rune) rune {
|
||||
switch {
|
||||
case code >= 'A' && code <= 'Z':
|
||||
return code - 'A'
|
||||
case code >= 'a' && code <= 'z':
|
||||
return code - 'a'
|
||||
case code >= '0' && code <= '9':
|
||||
return code - '0' + 26
|
||||
}
|
||||
return errdigit
|
||||
}
|
||||
|
||||
// lettercode finds BASE36 byte (a-z0-9) based on calculated number.
|
||||
func lettercode(digit rune) rune {
|
||||
switch {
|
||||
case digit >= 0 && digit <= 25:
|
||||
return digit + 'a'
|
||||
case digit >= 26 && digit <= 36:
|
||||
return digit - 26 + '0'
|
||||
}
|
||||
panic("dns: not reached")
|
||||
}
|
||||
|
||||
// adapt calculates next bias to be used for next iteration delta.
|
||||
func adapt(delta rune, numpoints int, firsttime bool) rune {
|
||||
if firsttime {
|
||||
delta /= _DAMP
|
||||
} else {
|
||||
delta /= 2
|
||||
}
|
||||
|
||||
var k rune
|
||||
for delta = delta + delta/rune(numpoints); delta > (_BASE-_MIN)*_MAX/2; k += _BASE {
|
||||
delta /= _BASE - _MIN
|
||||
}
|
||||
|
||||
return k + ((_BASE-_MIN+1)*delta)/(delta+_SKEW)
|
||||
}
|
||||
|
||||
// next finds minimal rune (one with lowest codepoint value) that should be equal or above boundary.
|
||||
func next(b []rune, boundary rune) rune {
|
||||
if len(b) == 0 {
|
||||
panic("dns: invalid set of runes to determine next one")
|
||||
}
|
||||
m := b[0]
|
||||
for _, x := range b[1:] {
|
||||
if x >= boundary && (m < boundary || x < m) {
|
||||
m = x
|
||||
}
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// preprune converts unicode rune to lower case. At this time it's not
|
||||
// supporting all things described in RFCs.
|
||||
func preprune(r rune) rune {
|
||||
if unicode.IsUpper(r) {
|
||||
r = unicode.ToLower(r)
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// tfunc is a function that helps calculate each character weight.
|
||||
func tfunc(k, bias rune) rune {
|
||||
switch {
|
||||
case k <= bias:
|
||||
return _MIN
|
||||
case k >= bias+_MAX:
|
||||
return _MAX
|
||||
}
|
||||
return k - bias
|
||||
}
|
||||
|
||||
// needToPunycode returns true for strings that require punycode encoding
|
||||
// (contain unicode characters).
|
||||
func needToPunycode(s string) bool {
|
||||
// This function is very similar to bytes.Runes. We don't use bytes.Runes
|
||||
// because it makes a heap allocation that's not needed here.
|
||||
for i := 0; len(s) > 0; i++ {
|
||||
r, l := utf8.DecodeRuneInString(s)
|
||||
if r > 0x7f {
|
||||
return true
|
||||
}
|
||||
s = s[l:]
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// needFromPunycode returns true for strings that require punycode decoding.
|
||||
func needFromPunycode(s string) bool {
|
||||
if s == "." {
|
||||
return false
|
||||
}
|
||||
|
||||
off := 0
|
||||
end := false
|
||||
pl := len(_PREFIX)
|
||||
sl := len(s)
|
||||
|
||||
// If s starts with _PREFIX.
|
||||
if sl > pl && s[off:off+pl] == _PREFIX {
|
||||
return true
|
||||
}
|
||||
|
||||
for {
|
||||
// Find the part after the next ".".
|
||||
off, end = dns.NextLabel(s, off)
|
||||
if end {
|
||||
return false
|
||||
}
|
||||
// If this parts starts with _PREFIX.
|
||||
if sl-off > pl && s[off:off+pl] == _PREFIX {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// encode transforms Unicode input bytes (that represent DNS label) into
|
||||
// punycode bytestream. This function would return nil if there's an invalid
|
||||
// character in the label.
|
||||
func encode(input []byte) []byte {
|
||||
n, bias := _N, _BIAS
|
||||
|
||||
b := bytes.Runes(input)
|
||||
for i := range b {
|
||||
if !isValidRune(b[i]) {
|
||||
return nil
|
||||
}
|
||||
|
||||
b[i] = preprune(b[i])
|
||||
}
|
||||
|
||||
basic := make([]byte, 0, len(b))
|
||||
for _, ltr := range b {
|
||||
if ltr <= 0x7f {
|
||||
basic = append(basic, byte(ltr))
|
||||
}
|
||||
}
|
||||
basiclen := len(basic)
|
||||
fulllen := len(b)
|
||||
if basiclen == fulllen {
|
||||
return basic
|
||||
}
|
||||
|
||||
var out bytes.Buffer
|
||||
|
||||
out.WriteString(_PREFIX)
|
||||
if basiclen > 0 {
|
||||
out.Write(basic)
|
||||
out.WriteByte(_DELIMITER)
|
||||
}
|
||||
|
||||
var (
|
||||
ltr, nextltr rune
|
||||
delta, q rune // delta calculation (see rfc)
|
||||
t, k, cp rune // weight and codepoint calculation
|
||||
)
|
||||
|
||||
s := &bytes.Buffer{}
|
||||
for h := basiclen; h < fulllen; n, delta = n+1, delta+1 {
|
||||
nextltr = next(b, n)
|
||||
s.Truncate(0)
|
||||
s.WriteRune(nextltr)
|
||||
delta, n = delta+(nextltr-n)*rune(h+1), nextltr
|
||||
|
||||
for _, ltr = range b {
|
||||
if ltr < n {
|
||||
delta++
|
||||
}
|
||||
if ltr == n {
|
||||
q = delta
|
||||
for k = _BASE; ; k += _BASE {
|
||||
t = tfunc(k, bias)
|
||||
if q < t {
|
||||
break
|
||||
}
|
||||
cp = t + ((q - t) % (_BASE - t))
|
||||
out.WriteRune(lettercode(cp))
|
||||
q = (q - t) / (_BASE - t)
|
||||
}
|
||||
|
||||
out.WriteRune(lettercode(q))
|
||||
|
||||
bias = adapt(delta, h+1, h == basiclen)
|
||||
h, delta = h+1, 0
|
||||
}
|
||||
}
|
||||
}
|
||||
return out.Bytes()
|
||||
}
|
||||
|
||||
// decode transforms punycode input bytes (that represent DNS label) into Unicode bytestream.
|
||||
func decode(b []byte) []byte {
|
||||
src := b // b would move and we need to keep it
|
||||
|
||||
n, bias := _N, _BIAS
|
||||
if !bytes.HasPrefix(b, []byte(_PREFIX)) {
|
||||
return b
|
||||
}
|
||||
out := make([]rune, 0, len(b))
|
||||
b = b[len(_PREFIX):]
|
||||
for pos := len(b) - 1; pos >= 0; pos-- {
|
||||
// only last delimiter is our interest
|
||||
if b[pos] == _DELIMITER {
|
||||
out = append(out, bytes.Runes(b[:pos])...)
|
||||
b = b[pos+1:] // trim source string
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(b) == 0 {
|
||||
return src
|
||||
}
|
||||
var (
|
||||
i, oldi, w rune
|
||||
ch byte
|
||||
t, digit rune
|
||||
ln int
|
||||
)
|
||||
|
||||
for i = 0; len(b) > 0; i++ {
|
||||
oldi, w = i, 1
|
||||
for k := _BASE; len(b) > 0; k += _BASE {
|
||||
ch, b = b[0], b[1:]
|
||||
digit = digitval(rune(ch))
|
||||
if digit == errdigit {
|
||||
return src
|
||||
}
|
||||
i += digit * w
|
||||
if i < 0 {
|
||||
// safety check for rune overflow
|
||||
return src
|
||||
}
|
||||
|
||||
t = tfunc(k, bias)
|
||||
if digit < t {
|
||||
break
|
||||
}
|
||||
|
||||
w *= _BASE - t
|
||||
}
|
||||
ln = len(out) + 1
|
||||
bias = adapt(i-oldi, ln, oldi == 0)
|
||||
n += i / rune(ln)
|
||||
i = i % rune(ln)
|
||||
// insert
|
||||
out = append(out, 0)
|
||||
copy(out[i+1:], out[i:])
|
||||
out[i] = n
|
||||
}
|
||||
|
||||
var ret bytes.Buffer
|
||||
for _, r := range out {
|
||||
ret.WriteRune(r)
|
||||
}
|
||||
return ret.Bytes()
|
||||
}
|
||||
|
||||
// isValidRune checks if the character is valid. We will look for the
|
||||
// character property in the code points list. For now we aren't checking special
|
||||
// rules in case of contextual property
|
||||
func isValidRune(r rune) bool {
|
||||
return findProperty(r) == propertyPVALID
|
||||
}
|
||||
|
||||
// findProperty will try to check the code point property of the given
|
||||
// character. It will use a binary search algorithm as we have a slice of
|
||||
// ordered ranges (average case performance O(log n))
|
||||
func findProperty(r rune) property {
|
||||
imin, imax := 0, len(codePoints)
|
||||
|
||||
for imax >= imin {
|
||||
imid := (imin + imax) / 2
|
||||
|
||||
codePoint := codePoints[imid]
|
||||
if (codePoint.start == r && codePoint.end == 0) || (codePoint.start <= r && codePoint.end >= r) {
|
||||
return codePoint.state
|
||||
}
|
||||
|
||||
if (codePoint.end > 0 && codePoint.end < r) || (codePoint.end == 0 && codePoint.start < r) {
|
||||
imin = imid + 1
|
||||
} else {
|
||||
imax = imid - 1
|
||||
}
|
||||
}
|
||||
|
||||
return propertyUnknown
|
||||
}
|
162
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/labels.go
generated
vendored
Normal file
162
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/labels.go
generated
vendored
Normal file
|
@ -0,0 +1,162 @@
|
|||
package dns
|
||||
|
||||
// Holds a bunch of helper functions for dealing with labels.
|
||||
|
||||
// SplitDomainName splits a name string into it's labels.
|
||||
// www.miek.nl. returns []string{"www", "miek", "nl"}
|
||||
// The root label (.) returns nil. Note that using
|
||||
// strings.Split(s) will work in most cases, but does not handle
|
||||
// escaped dots (\.) for instance.
|
||||
func SplitDomainName(s string) (labels []string) {
|
||||
if len(s) == 0 {
|
||||
return nil
|
||||
}
|
||||
fqdnEnd := 0 // offset of the final '.' or the length of the name
|
||||
idx := Split(s)
|
||||
begin := 0
|
||||
if s[len(s)-1] == '.' {
|
||||
fqdnEnd = len(s) - 1
|
||||
} else {
|
||||
fqdnEnd = len(s)
|
||||
}
|
||||
|
||||
switch len(idx) {
|
||||
case 0:
|
||||
return nil
|
||||
case 1:
|
||||
// no-op
|
||||
default:
|
||||
end := 0
|
||||
for i := 1; i < len(idx); i++ {
|
||||
end = idx[i]
|
||||
labels = append(labels, s[begin:end-1])
|
||||
begin = end
|
||||
}
|
||||
}
|
||||
|
||||
labels = append(labels, s[begin:fqdnEnd])
|
||||
return labels
|
||||
}
|
||||
|
||||
// CompareDomainName compares the names s1 and s2 and
|
||||
// returns how many labels they have in common starting from the *right*.
|
||||
// The comparison stops at the first inequality. The names are not downcased
|
||||
// before the comparison.
|
||||
//
|
||||
// www.miek.nl. and miek.nl. have two labels in common: miek and nl
|
||||
// www.miek.nl. and www.bla.nl. have one label in common: nl
|
||||
func CompareDomainName(s1, s2 string) (n int) {
|
||||
s1 = Fqdn(s1)
|
||||
s2 = Fqdn(s2)
|
||||
l1 := Split(s1)
|
||||
l2 := Split(s2)
|
||||
|
||||
// the first check: root label
|
||||
if l1 == nil || l2 == nil {
|
||||
return
|
||||
}
|
||||
|
||||
j1 := len(l1) - 1 // end
|
||||
i1 := len(l1) - 2 // start
|
||||
j2 := len(l2) - 1
|
||||
i2 := len(l2) - 2
|
||||
// the second check can be done here: last/only label
|
||||
// before we fall through into the for-loop below
|
||||
if s1[l1[j1]:] == s2[l2[j2]:] {
|
||||
n++
|
||||
} else {
|
||||
return
|
||||
}
|
||||
for {
|
||||
if i1 < 0 || i2 < 0 {
|
||||
break
|
||||
}
|
||||
if s1[l1[i1]:l1[j1]] == s2[l2[i2]:l2[j2]] {
|
||||
n++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
j1--
|
||||
i1--
|
||||
j2--
|
||||
i2--
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// CountLabel counts the the number of labels in the string s.
|
||||
func CountLabel(s string) (labels int) {
|
||||
if s == "." {
|
||||
return
|
||||
}
|
||||
off := 0
|
||||
end := false
|
||||
for {
|
||||
off, end = NextLabel(s, off)
|
||||
labels++
|
||||
if end {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Split splits a name s into its label indexes.
|
||||
// www.miek.nl. returns []int{0, 4, 9}, www.miek.nl also returns []int{0, 4, 9}.
|
||||
// The root name (.) returns nil. Also see SplitDomainName.
|
||||
func Split(s string) []int {
|
||||
if s == "." {
|
||||
return nil
|
||||
}
|
||||
idx := make([]int, 1, 3)
|
||||
off := 0
|
||||
end := false
|
||||
|
||||
for {
|
||||
off, end = NextLabel(s, off)
|
||||
if end {
|
||||
return idx
|
||||
}
|
||||
idx = append(idx, off)
|
||||
}
|
||||
}
|
||||
|
||||
// NextLabel returns the index of the start of the next label in the
|
||||
// string s starting at offset.
|
||||
// The bool end is true when the end of the string has been reached.
|
||||
// Also see PrevLabel.
|
||||
func NextLabel(s string, offset int) (i int, end bool) {
|
||||
quote := false
|
||||
for i = offset; i < len(s)-1; i++ {
|
||||
switch s[i] {
|
||||
case '\\':
|
||||
quote = !quote
|
||||
default:
|
||||
quote = false
|
||||
case '.':
|
||||
if quote {
|
||||
quote = !quote
|
||||
continue
|
||||
}
|
||||
return i + 1, false
|
||||
}
|
||||
}
|
||||
return i + 1, true
|
||||
}
|
||||
|
||||
// PrevLabel returns the index of the label when starting from the right and
|
||||
// jumping n labels to the left.
|
||||
// The bool start is true when the start of the string has been overshot.
|
||||
// Also see NextLabel.
|
||||
func PrevLabel(s string, n int) (i int, start bool) {
|
||||
if n == 0 {
|
||||
return len(s), false
|
||||
}
|
||||
lab := Split(s)
|
||||
if lab == nil {
|
||||
return 0, true
|
||||
}
|
||||
if n > len(lab) {
|
||||
return 0, true
|
||||
}
|
||||
return lab[len(lab)-n], false
|
||||
}
|
1945
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/msg.go
generated
vendored
Normal file
1945
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/msg.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
112
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/nsecx.go
generated
vendored
Normal file
112
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/nsecx.go
generated
vendored
Normal file
|
@ -0,0 +1,112 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"hash"
|
||||
"io"
|
||||
"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 := PackStruct(saltwire, wire, 0)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
wire = wire[: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 ""
|
||||
}
|
||||
|
||||
// k = 0
|
||||
name = append(name, wire...)
|
||||
io.WriteString(s, string(name))
|
||||
nsec3 := s.Sum(nil)
|
||||
// k > 0
|
||||
for k := uint16(0); k < iter; k++ {
|
||||
s.Reset()
|
||||
nsec3 = append(nsec3, wire...)
|
||||
io.WriteString(s, string(nsec3))
|
||||
nsec3 = s.Sum(nil)
|
||||
}
|
||||
return toBase32(nsec3)
|
||||
}
|
||||
|
||||
// Denialer is an interface that should be implemented by types that are used to denial
|
||||
// answers in DNSSEC.
|
||||
type Denialer interface {
|
||||
// Cover will check if the (unhashed) name is being covered by this NSEC or NSEC3.
|
||||
Cover(name string) bool
|
||||
// Match will check if the ownername matches the (unhashed) name for this NSEC3 or NSEC3.
|
||||
Match(name string) bool
|
||||
}
|
||||
|
||||
// Cover implements the Denialer interface.
|
||||
func (rr *NSEC) Cover(name string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Match implements the Denialer interface.
|
||||
func (rr *NSEC) Match(name string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Cover implements the Denialer interface.
|
||||
func (rr *NSEC3) Cover(name string) bool {
|
||||
// FIXME(miek): check if the zones match
|
||||
// FIXME(miek): check if we're not dealing with parent nsec3
|
||||
hname := HashName(name, rr.Hash, rr.Iterations, rr.Salt)
|
||||
labels := Split(rr.Hdr.Name)
|
||||
if len(labels) < 2 {
|
||||
return false
|
||||
}
|
||||
hash := strings.ToUpper(rr.Hdr.Name[labels[0] : labels[1]-1]) // -1 to remove the dot
|
||||
if hash == rr.NextDomain {
|
||||
return false // empty interval
|
||||
}
|
||||
if hash > rr.NextDomain { // last name, points to apex
|
||||
// hname > hash
|
||||
// hname > rr.NextDomain
|
||||
// TODO(miek)
|
||||
}
|
||||
if hname <= hash {
|
||||
return false
|
||||
}
|
||||
if hname >= rr.NextDomain {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Match implements the Denialer interface.
|
||||
func (rr *NSEC3) Match(name string) bool {
|
||||
// FIXME(miek): Check if we are in the same zone
|
||||
hname := HashName(name, rr.Hash, rr.Iterations, rr.Salt)
|
||||
labels := Split(rr.Hdr.Name)
|
||||
if len(labels) < 2 {
|
||||
return false
|
||||
}
|
||||
hash := strings.ToUpper(rr.Hdr.Name[labels[0] : labels[1]-1]) // -1 to remove the .
|
||||
if hash == hname {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
117
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/privaterr.go
generated
vendored
Normal file
117
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/privaterr.go
generated
vendored
Normal file
|
@ -0,0 +1,117 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// PrivateRdata is an interface used for implementing "Private Use" RR types, see
|
||||
// RFC 6895. This allows one to experiment with new RR types, without requesting an
|
||||
// official type code. Also see dns.PrivateHandle and dns.PrivateHandleRemove.
|
||||
type PrivateRdata interface {
|
||||
// String returns the text presentaton of the Rdata of the Private RR.
|
||||
String() string
|
||||
// Parse parses the Rdata of the private RR.
|
||||
Parse([]string) error
|
||||
// Pack is used when packing a private RR into a buffer.
|
||||
Pack([]byte) (int, error)
|
||||
// Unpack is used when unpacking a private RR from a buffer.
|
||||
// TODO(miek): diff. signature than Pack, see edns0.go for instance.
|
||||
Unpack([]byte) (int, error)
|
||||
// Copy copies the Rdata.
|
||||
Copy(PrivateRdata) error
|
||||
// Len returns the length in octets of the Rdata.
|
||||
Len() int
|
||||
}
|
||||
|
||||
// PrivateRR represents an RR that uses a PrivateRdata user-defined type.
|
||||
// It mocks normal RRs and implements dns.RR interface.
|
||||
type PrivateRR struct {
|
||||
Hdr RR_Header
|
||||
Data PrivateRdata
|
||||
}
|
||||
|
||||
func mkPrivateRR(rrtype uint16) *PrivateRR {
|
||||
// Panics if RR is not an instance of PrivateRR.
|
||||
rrfunc, ok := TypeToRR[rrtype]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("dns: invalid operation with Private RR type %d", rrtype))
|
||||
}
|
||||
|
||||
anyrr := rrfunc()
|
||||
switch rr := anyrr.(type) {
|
||||
case *PrivateRR:
|
||||
return rr
|
||||
}
|
||||
panic(fmt.Sprintf("dns: RR is not a PrivateRR, TypeToRR[%d] generator returned %T", rrtype, anyrr))
|
||||
}
|
||||
|
||||
// Header return the RR header of r.
|
||||
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) copy() RR {
|
||||
// make new RR like this:
|
||||
rr := mkPrivateRR(r.Hdr.Rrtype)
|
||||
newh := r.Hdr.copyHeader()
|
||||
rr.Hdr = *newh
|
||||
|
||||
err := r.Data.Copy(rr.Data)
|
||||
if err != nil {
|
||||
panic("dns: got value that could not be used to copy Private rdata")
|
||||
}
|
||||
return rr
|
||||
}
|
||||
|
||||
// PrivateHandle registers a private resource record type. It requires
|
||||
// string and numeric representation of private RR type and generator function as argument.
|
||||
func PrivateHandle(rtypestr string, rtype uint16, generator func() PrivateRdata) {
|
||||
rtypestr = strings.ToUpper(rtypestr)
|
||||
|
||||
TypeToRR[rtype] = func() RR { return &PrivateRR{RR_Header{}, generator()} }
|
||||
TypeToString[rtype] = rtypestr
|
||||
StringToType[rtypestr] = rtype
|
||||
|
||||
setPrivateRR := func(h RR_Header, c chan lex, o, f string) (RR, *ParseError, string) {
|
||||
rr := mkPrivateRR(h.Rrtype)
|
||||
rr.Hdr = h
|
||||
|
||||
var l lex
|
||||
text := make([]string, 0, 2) // could be 0..N elements, median is probably 1
|
||||
FETCH:
|
||||
for {
|
||||
// TODO(miek): we could also be returning _QUOTE, this might or might not
|
||||
// be an issue (basically parsing TXT becomes hard)
|
||||
switch l = <-c; l.value {
|
||||
case zNewline, zEOF:
|
||||
break FETCH
|
||||
case zString:
|
||||
text = append(text, l.token)
|
||||
}
|
||||
}
|
||||
|
||||
err := rr.Data.Parse(text)
|
||||
if err != nil {
|
||||
return nil, &ParseError{f, err.Error(), l}, ""
|
||||
}
|
||||
|
||||
return rr, nil, ""
|
||||
}
|
||||
|
||||
typeToparserFunc[rtype] = parserFunc{setPrivateRR, true}
|
||||
}
|
||||
|
||||
// PrivateHandleRemove removes defenitions required to support private RR type.
|
||||
func PrivateHandleRemove(rtype uint16) {
|
||||
rtypestr, ok := TypeToString[rtype]
|
||||
if ok {
|
||||
delete(TypeToRR, rtype)
|
||||
delete(TypeToString, rtype)
|
||||
delete(typeToparserFunc, rtype)
|
||||
delete(StringToType, rtypestr)
|
||||
}
|
||||
return
|
||||
}
|
95
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/rawmsg.go
generated
vendored
Normal file
95
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/rawmsg.go
generated
vendored
Normal file
|
@ -0,0 +1,95 @@
|
|||
package dns
|
||||
|
||||
// These raw* functions do not use reflection, they directly set the values
|
||||
// in the buffer. There are faster than their reflection counterparts.
|
||||
|
||||
// RawSetId sets the message id in buf.
|
||||
func rawSetId(msg []byte, i uint16) bool {
|
||||
if len(msg) < 2 {
|
||||
return false
|
||||
}
|
||||
msg[0], msg[1] = packUint16(i)
|
||||
return true
|
||||
}
|
||||
|
||||
// rawSetQuestionLen sets the length of the question section.
|
||||
func rawSetQuestionLen(msg []byte, i uint16) bool {
|
||||
if len(msg) < 6 {
|
||||
return false
|
||||
}
|
||||
msg[4], msg[5] = packUint16(i)
|
||||
return true
|
||||
}
|
||||
|
||||
// rawSetAnswerLen sets the lenght of the answer section.
|
||||
func rawSetAnswerLen(msg []byte, i uint16) bool {
|
||||
if len(msg) < 8 {
|
||||
return false
|
||||
}
|
||||
msg[6], msg[7] = packUint16(i)
|
||||
return true
|
||||
}
|
||||
|
||||
// rawSetsNsLen sets the lenght of the authority section.
|
||||
func rawSetNsLen(msg []byte, i uint16) bool {
|
||||
if len(msg) < 10 {
|
||||
return false
|
||||
}
|
||||
msg[8], msg[9] = packUint16(i)
|
||||
return true
|
||||
}
|
||||
|
||||
// rawSetExtraLen sets the lenght of the additional section.
|
||||
func rawSetExtraLen(msg []byte, i uint16) bool {
|
||||
if len(msg) < 12 {
|
||||
return false
|
||||
}
|
||||
msg[10], msg[11] = packUint16(i)
|
||||
return true
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
msg[off], msg[off+1] = packUint16(uint16(rdatalen))
|
||||
return true
|
||||
}
|
84
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/sanitize.go
generated
vendored
Normal file
84
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/sanitize.go
generated
vendored
Normal file
|
@ -0,0 +1,84 @@
|
|||
package dns
|
||||
|
||||
// Dedup removes identical RRs from rrs. It preserves the original ordering.
|
||||
// The lowest TTL of any duplicates is used in the remaining one. Dedup modifies
|
||||
// rrs.
|
||||
// m is used to store the RRs temporay. If it is nil a new map will be allocated.
|
||||
func Dedup(rrs []RR, m map[string]RR) []RR {
|
||||
if m == nil {
|
||||
m = make(map[string]RR)
|
||||
}
|
||||
// Save the keys, so we don't have to call normalizedString twice.
|
||||
keys := make([]*string, 0, len(rrs))
|
||||
|
||||
for _, r := range rrs {
|
||||
key := normalizedString(r)
|
||||
keys = append(keys, &key)
|
||||
if _, ok := m[key]; ok {
|
||||
// Shortest TTL wins.
|
||||
if m[key].Header().Ttl > r.Header().Ttl {
|
||||
m[key].Header().Ttl = r.Header().Ttl
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
m[key] = r
|
||||
}
|
||||
// If the length of the result map equals the amount of RRs we got,
|
||||
// it means they were all different. We can then just return the original rrset.
|
||||
if len(m) == len(rrs) {
|
||||
return rrs
|
||||
}
|
||||
|
||||
j := 0
|
||||
for i, r := range rrs {
|
||||
// If keys[i] lives in the map, we should copy and remove it.
|
||||
if _, ok := m[*keys[i]]; ok {
|
||||
delete(m, *keys[i])
|
||||
rrs[j] = r
|
||||
j++
|
||||
}
|
||||
|
||||
if len(m) == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return rrs[:j]
|
||||
}
|
||||
|
||||
// normalizedString returns a normalized string from r. The TTL
|
||||
// is removed and the domain name is lowercased. We go from this:
|
||||
// DomainName<TAB>TTL<TAB>CLASS<TAB>TYPE<TAB>RDATA to:
|
||||
// lowercasename<TAB>CLASS<TAB>TYPE...
|
||||
func normalizedString(r RR) string {
|
||||
// A string Go DNS makes has: domainname<TAB>TTL<TAB>...
|
||||
b := []byte(r.String())
|
||||
|
||||
// find the first non-escaped tab, then another, so we capture where the TTL lives.
|
||||
esc := false
|
||||
ttlStart, ttlEnd := 0, 0
|
||||
for i := 0; i < len(b) && ttlEnd == 0; i++ {
|
||||
switch {
|
||||
case b[i] == '\\':
|
||||
esc = !esc
|
||||
case b[i] == '\t' && !esc:
|
||||
if ttlStart == 0 {
|
||||
ttlStart = i
|
||||
continue
|
||||
}
|
||||
if ttlEnd == 0 {
|
||||
ttlEnd = i
|
||||
}
|
||||
case b[i] >= 'A' && b[i] <= 'Z' && !esc:
|
||||
b[i] += 32
|
||||
default:
|
||||
esc = false
|
||||
}
|
||||
}
|
||||
|
||||
// remove TTL.
|
||||
copy(b[ttlStart:], b[ttlEnd:])
|
||||
cut := ttlEnd - ttlStart
|
||||
return string(b[:len(b)-cut])
|
||||
}
|
43
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/scanner.go
generated
vendored
Normal file
43
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/scanner.go
generated
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
package dns
|
||||
|
||||
// Implement a simple scanner, return a byte stream from an io reader.
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"io"
|
||||
"text/scanner"
|
||||
)
|
||||
|
||||
type scan struct {
|
||||
src *bufio.Reader
|
||||
position scanner.Position
|
||||
eof bool // Have we just seen a eof
|
||||
}
|
||||
|
||||
func scanInit(r io.Reader) *scan {
|
||||
s := new(scan)
|
||||
s.src = bufio.NewReader(r)
|
||||
s.position.Line = 1
|
||||
return s
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
// 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
|
||||
}
|
687
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/server.go
generated
vendored
Normal file
687
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/server.go
generated
vendored
Normal file
|
@ -0,0 +1,687 @@
|
|||
// DNS server implementation.
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Maximum number of TCP queries before we close the socket.
|
||||
const maxTCPQueries = 128
|
||||
|
||||
// Handler is implemented by any value that implements ServeDNS.
|
||||
type Handler interface {
|
||||
ServeDNS(w ResponseWriter, r *Msg)
|
||||
}
|
||||
|
||||
// A ResponseWriter interface is used by an DNS handler to
|
||||
// construct an DNS response.
|
||||
type ResponseWriter interface {
|
||||
// LocalAddr returns the net.Addr of the server
|
||||
LocalAddr() net.Addr
|
||||
// RemoteAddr returns the net.Addr of the client that sent the current request.
|
||||
RemoteAddr() net.Addr
|
||||
// WriteMsg writes a reply back to the client.
|
||||
WriteMsg(*Msg) error
|
||||
// Write writes a raw buffer back to the client.
|
||||
Write([]byte) (int, error)
|
||||
// Close closes the connection.
|
||||
Close() error
|
||||
// TsigStatus returns the status of the Tsig.
|
||||
TsigStatus() error
|
||||
// TsigTimersOnly sets the tsig timers only boolean.
|
||||
TsigTimersOnly(bool)
|
||||
// Hijack lets the caller take over the connection.
|
||||
// After a call to Hijack(), the DNS package will not do anything with the connection.
|
||||
Hijack()
|
||||
}
|
||||
|
||||
type response struct {
|
||||
hijacked bool // connection has been hijacked by handler
|
||||
tsigStatus error
|
||||
tsigTimersOnly bool
|
||||
tsigRequestMAC string
|
||||
tsigSecret map[string]string // the tsig secrets
|
||||
udp *net.UDPConn // i/o connection if UDP was used
|
||||
tcp *net.TCPConn // i/o connection if TCP was used
|
||||
udpSession *SessionUDP // oob data to get egress interface right
|
||||
remoteAddr net.Addr // address of the client
|
||||
writer Writer // writer to output the raw DNS bits
|
||||
}
|
||||
|
||||
// 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)
|
||||
m.SetRcode(r, RcodeServerFailure)
|
||||
// does not matter if this write fails
|
||||
w.WriteMsg(m)
|
||||
}
|
||||
|
||||
func failedHandler() Handler { return HandlerFunc(HandleFailed) }
|
||||
|
||||
// ListenAndServe Starts a server on addresss and network speficied. Invoke handler
|
||||
// for incoming queries.
|
||||
func ListenAndServe(addr string, network string, handler Handler) error {
|
||||
server := &Server{Addr: addr, Net: network, Handler: handler}
|
||||
return server.ListenAndServe()
|
||||
}
|
||||
|
||||
// ActivateAndServe activates a server with a listener from systemd,
|
||||
// l and p should not both be non-nil.
|
||||
// If both l and p are not nil only p will be used.
|
||||
// Invoke handler for incoming queries.
|
||||
func ActivateAndServe(l net.Listener, p net.PacketConn, handler Handler) error {
|
||||
server := &Server{Listener: l, PacketConn: p, Handler: handler}
|
||||
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
|
||||
}
|
||||
|
||||
// Reader reads raw DNS messages; each call to ReadTCP or ReadUDP should return an entire message.
|
||||
type Reader interface {
|
||||
// ReadTCP reads a raw message from a TCP connection. Implementations may alter
|
||||
// connection properties, for example the read-deadline.
|
||||
ReadTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, error)
|
||||
// ReadUDP reads a raw message from a UDP connection. Implementations may alter
|
||||
// connection properties, for example the read-deadline.
|
||||
ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error)
|
||||
}
|
||||
|
||||
// defaultReader is an adapter for the Server struct that implements the Reader interface
|
||||
// using the readTCP and readUDP func of the embedded Server.
|
||||
type defaultReader struct {
|
||||
*Server
|
||||
}
|
||||
|
||||
func (dr *defaultReader) ReadTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, error) {
|
||||
return dr.readTCP(conn, timeout)
|
||||
}
|
||||
|
||||
func (dr *defaultReader) ReadUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) {
|
||||
return dr.readUDP(conn, timeout)
|
||||
}
|
||||
|
||||
// DecorateReader is a decorator hook for extending or supplanting the functionality of a Reader.
|
||||
// Implementations should never return a nil Reader.
|
||||
type DecorateReader func(Reader) Reader
|
||||
|
||||
// DecorateWriter is a decorator hook for extending or supplanting the functionality of a Writer.
|
||||
// Implementations should never return a nil Writer.
|
||||
type DecorateWriter func(Writer) Writer
|
||||
|
||||
// A Server defines parameters for running an DNS server.
|
||||
type Server struct {
|
||||
// Address to listen on, ":dns" if empty.
|
||||
Addr string
|
||||
// if "tcp" it will invoke a TCP listener, otherwise an UDP one.
|
||||
Net string
|
||||
// TCP Listener to use, this is to aid in systemd's socket activation.
|
||||
Listener net.Listener
|
||||
// UDP "Listener" to use, this is to aid in systemd's socket activation.
|
||||
PacketConn net.PacketConn
|
||||
// Handler to invoke, dns.DefaultServeMux if nil.
|
||||
Handler Handler
|
||||
// Default buffer size to use to read incoming UDP messages. If not set
|
||||
// it defaults to MinMsgSize (512 B).
|
||||
UDPSize int
|
||||
// The net.Conn.SetReadTimeout value for new connections, defaults to 2 * time.Second.
|
||||
ReadTimeout time.Duration
|
||||
// The net.Conn.SetWriteTimeout value for new connections, defaults to 2 * time.Second.
|
||||
WriteTimeout time.Duration
|
||||
// TCP idle timeout for multiple queries, if nil, defaults to 8 * time.Second (RFC 5966).
|
||||
IdleTimeout func() time.Duration
|
||||
// Secret(s) for Tsig map[<zonename>]<base64 secret>.
|
||||
TsigSecret map[string]string
|
||||
// Unsafe instructs the server to disregard any sanity checks and directly hand the message to
|
||||
// the handler. It will specfically 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.
|
||||
DecorateReader DecorateReader
|
||||
// DecorateWriter is optional, allows customization of the process that writes raw DNS messages.
|
||||
DecorateWriter DecorateWriter
|
||||
|
||||
// Graceful shutdown handling
|
||||
|
||||
inFlight sync.WaitGroup
|
||||
|
||||
lock sync.RWMutex
|
||||
started bool
|
||||
}
|
||||
|
||||
// ListenAndServe starts a nameserver on the configured address in *Server.
|
||||
func (srv *Server) ListenAndServe() error {
|
||||
srv.lock.Lock()
|
||||
defer srv.lock.Unlock()
|
||||
if srv.started {
|
||||
return &Error{err: "server already started"}
|
||||
}
|
||||
addr := srv.Addr
|
||||
if addr == "" {
|
||||
addr = ":domain"
|
||||
}
|
||||
if srv.UDPSize == 0 {
|
||||
srv.UDPSize = MinMsgSize
|
||||
}
|
||||
switch srv.Net {
|
||||
case "tcp", "tcp4", "tcp6":
|
||||
a, e := net.ResolveTCPAddr(srv.Net, addr)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
l, e := net.ListenTCP(srv.Net, a)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
srv.Listener = l
|
||||
srv.started = true
|
||||
srv.lock.Unlock()
|
||||
e = srv.serveTCP(l)
|
||||
srv.lock.Lock() // to satisfy the defer at the top
|
||||
return e
|
||||
case "udp", "udp4", "udp6":
|
||||
a, e := net.ResolveUDPAddr(srv.Net, addr)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
l, e := net.ListenUDP(srv.Net, a)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
if e := setUDPSocketOptions(l); e != nil {
|
||||
return e
|
||||
}
|
||||
srv.PacketConn = l
|
||||
srv.started = true
|
||||
srv.lock.Unlock()
|
||||
e = srv.serveUDP(l)
|
||||
srv.lock.Lock() // to satisfy the defer at the top
|
||||
return e
|
||||
}
|
||||
return &Error{err: "bad network"}
|
||||
}
|
||||
|
||||
// ActivateAndServe starts a nameserver with the PacketConn or Listener
|
||||
// configured in *Server. Its main use is to start a server from systemd.
|
||||
func (srv *Server) ActivateAndServe() error {
|
||||
srv.lock.Lock()
|
||||
defer srv.lock.Unlock()
|
||||
if srv.started {
|
||||
return &Error{err: "server already started"}
|
||||
}
|
||||
pConn := srv.PacketConn
|
||||
l := srv.Listener
|
||||
if pConn != nil {
|
||||
if srv.UDPSize == 0 {
|
||||
srv.UDPSize = MinMsgSize
|
||||
}
|
||||
if t, ok := pConn.(*net.UDPConn); ok {
|
||||
if e := setUDPSocketOptions(t); e != nil {
|
||||
return e
|
||||
}
|
||||
srv.started = true
|
||||
srv.lock.Unlock()
|
||||
e := srv.serveUDP(t)
|
||||
srv.lock.Lock() // to satisfy the defer at the top
|
||||
return e
|
||||
}
|
||||
}
|
||||
if l != nil {
|
||||
if t, ok := l.(*net.TCPListener); ok {
|
||||
srv.started = true
|
||||
srv.lock.Unlock()
|
||||
e := srv.serveTCP(t)
|
||||
srv.lock.Lock() // to satisfy the defer at the top
|
||||
return e
|
||||
}
|
||||
}
|
||||
return &Error{err: "bad listeners"}
|
||||
}
|
||||
|
||||
// Shutdown gracefully shuts down a server. After a call to Shutdown, ListenAndServe and
|
||||
// ActivateAndServe will return. All in progress queries are completed before the server
|
||||
// is taken down. If the Shutdown is taking longer than the reading timeout an error
|
||||
// is returned.
|
||||
func (srv *Server) Shutdown() error {
|
||||
srv.lock.Lock()
|
||||
if !srv.started {
|
||||
srv.lock.Unlock()
|
||||
return &Error{err: "server not started"}
|
||||
}
|
||||
srv.started = false
|
||||
srv.lock.Unlock()
|
||||
|
||||
if srv.PacketConn != nil {
|
||||
srv.PacketConn.Close()
|
||||
}
|
||||
if srv.Listener != nil {
|
||||
srv.Listener.Close()
|
||||
}
|
||||
|
||||
fin := make(chan bool)
|
||||
go func() {
|
||||
srv.inFlight.Wait()
|
||||
fin <- true
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-time.After(srv.getReadTimeout()):
|
||||
return &Error{err: "server shutdown is pending"}
|
||||
case <-fin:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// getReadTimeout is a helper func to use system timeout if server did not intend to change it.
|
||||
func (srv *Server) getReadTimeout() time.Duration {
|
||||
rtimeout := dnsTimeout
|
||||
if srv.ReadTimeout != 0 {
|
||||
rtimeout = srv.ReadTimeout
|
||||
}
|
||||
return rtimeout
|
||||
}
|
||||
|
||||
// serveTCP starts a TCP listener for the server.
|
||||
// Each request is handled in a separate goroutine.
|
||||
func (srv *Server) serveTCP(l *net.TCPListener) error {
|
||||
defer l.Close()
|
||||
|
||||
if srv.NotifyStartedFunc != nil {
|
||||
srv.NotifyStartedFunc()
|
||||
}
|
||||
|
||||
reader := Reader(&defaultReader{srv})
|
||||
if srv.DecorateReader != nil {
|
||||
reader = srv.DecorateReader(reader)
|
||||
}
|
||||
|
||||
handler := srv.Handler
|
||||
if handler == nil {
|
||||
handler = DefaultServeMux
|
||||
}
|
||||
rtimeout := srv.getReadTimeout()
|
||||
// deadline is not used here
|
||||
for {
|
||||
rw, e := l.AcceptTCP()
|
||||
if e != nil {
|
||||
if neterr, ok := e.(net.Error); ok && neterr.Temporary() {
|
||||
continue
|
||||
}
|
||||
return e
|
||||
}
|
||||
m, e := reader.ReadTCP(rw, rtimeout)
|
||||
srv.lock.RLock()
|
||||
if !srv.started {
|
||||
srv.lock.RUnlock()
|
||||
return nil
|
||||
}
|
||||
srv.lock.RUnlock()
|
||||
if e != nil {
|
||||
continue
|
||||
}
|
||||
srv.inFlight.Add(1)
|
||||
go srv.serve(rw.RemoteAddr(), handler, m, nil, nil, rw)
|
||||
}
|
||||
}
|
||||
|
||||
// serveUDP starts a UDP listener for the server.
|
||||
// Each request is handled in a separate goroutine.
|
||||
func (srv *Server) serveUDP(l *net.UDPConn) error {
|
||||
defer l.Close()
|
||||
|
||||
if srv.NotifyStartedFunc != nil {
|
||||
srv.NotifyStartedFunc()
|
||||
}
|
||||
|
||||
reader := Reader(&defaultReader{srv})
|
||||
if srv.DecorateReader != nil {
|
||||
reader = srv.DecorateReader(reader)
|
||||
}
|
||||
|
||||
handler := srv.Handler
|
||||
if handler == nil {
|
||||
handler = DefaultServeMux
|
||||
}
|
||||
rtimeout := srv.getReadTimeout()
|
||||
// deadline is not used here
|
||||
for {
|
||||
m, s, e := reader.ReadUDP(l, rtimeout)
|
||||
srv.lock.RLock()
|
||||
if !srv.started {
|
||||
srv.lock.RUnlock()
|
||||
return nil
|
||||
}
|
||||
srv.lock.RUnlock()
|
||||
if e != nil {
|
||||
continue
|
||||
}
|
||||
srv.inFlight.Add(1)
|
||||
go srv.serve(s.RemoteAddr(), handler, m, l, s, nil)
|
||||
}
|
||||
}
|
||||
|
||||
// Serve a new connection.
|
||||
func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *SessionUDP, t *net.TCPConn) {
|
||||
defer srv.inFlight.Done()
|
||||
|
||||
w := &response{tsigSecret: srv.TsigSecret, udp: u, tcp: t, remoteAddr: a, udpSession: s}
|
||||
if srv.DecorateWriter != nil {
|
||||
w.writer = srv.DecorateWriter(w)
|
||||
} else {
|
||||
w.writer = w
|
||||
}
|
||||
|
||||
q := 0 // counter for the amount of TCP queries we get
|
||||
|
||||
reader := Reader(&defaultReader{srv})
|
||||
if srv.DecorateReader != nil {
|
||||
reader = srv.DecorateReader(reader)
|
||||
}
|
||||
Redo:
|
||||
req := new(Msg)
|
||||
err := req.Unpack(m)
|
||||
if err != nil { // Send a FormatError back
|
||||
x := new(Msg)
|
||||
x.SetRcodeFormatError(req)
|
||||
w.WriteMsg(x)
|
||||
goto Exit
|
||||
}
|
||||
if !srv.Unsafe && req.Response {
|
||||
goto Exit
|
||||
}
|
||||
|
||||
w.tsigStatus = nil
|
||||
if w.tsigSecret != nil {
|
||||
if t := req.IsTsig(); t != nil {
|
||||
secret := t.Hdr.Name
|
||||
if _, ok := w.tsigSecret[secret]; !ok {
|
||||
w.tsigStatus = ErrKeyAlg
|
||||
}
|
||||
w.tsigStatus = TsigVerify(m, w.tsigSecret[secret], "", false)
|
||||
w.tsigTimersOnly = false
|
||||
w.tsigRequestMAC = req.Extra[len(req.Extra)-1].(*TSIG).MAC
|
||||
}
|
||||
}
|
||||
h.ServeDNS(w, req) // Writes back to the client
|
||||
|
||||
Exit:
|
||||
// TODO(miek): make this number configurable?
|
||||
if q > maxTCPQueries { // close socket after this many queries
|
||||
w.Close()
|
||||
return
|
||||
}
|
||||
|
||||
if w.hijacked {
|
||||
return // client calls Close()
|
||||
}
|
||||
if u != nil { // UDP, "close" and return
|
||||
w.Close()
|
||||
return
|
||||
}
|
||||
idleTimeout := tcpIdleTimeout
|
||||
if srv.IdleTimeout != nil {
|
||||
idleTimeout = srv.IdleTimeout()
|
||||
}
|
||||
m, e := reader.ReadTCP(w.tcp, idleTimeout)
|
||||
if e == nil {
|
||||
q++
|
||||
goto Redo
|
||||
}
|
||||
w.Close()
|
||||
return
|
||||
}
|
||||
|
||||
func (srv *Server) readTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, error) {
|
||||
conn.SetReadDeadline(time.Now().Add(timeout))
|
||||
l := make([]byte, 2)
|
||||
n, err := conn.Read(l)
|
||||
if err != nil || n != 2 {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, ErrShortRead
|
||||
}
|
||||
length, _ := unpackUint16(l, 0)
|
||||
if length == 0 {
|
||||
return nil, ErrShortRead
|
||||
}
|
||||
m := make([]byte, int(length))
|
||||
n, err = conn.Read(m[:int(length)])
|
||||
if err != nil || n == 0 {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, ErrShortRead
|
||||
}
|
||||
i := n
|
||||
for i < int(length) {
|
||||
j, err := conn.Read(m[i:int(length)])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
i += j
|
||||
}
|
||||
n = i
|
||||
m = m[:n]
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *SessionUDP, error) {
|
||||
conn.SetReadDeadline(time.Now().Add(timeout))
|
||||
m := make([]byte, srv.UDPSize)
|
||||
n, s, e := ReadFromSessionUDP(conn, m)
|
||||
if e != nil || n == 0 {
|
||||
if e != nil {
|
||||
return nil, nil, e
|
||||
}
|
||||
return nil, nil, ErrShortRead
|
||||
}
|
||||
m = m[:n]
|
||||
return m, s, nil
|
||||
}
|
||||
|
||||
// WriteMsg implements the ResponseWriter.WriteMsg method.
|
||||
func (w *response) WriteMsg(m *Msg) (err error) {
|
||||
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 {
|
||||
data, w.tsigRequestMAC, err = TsigGenerate(m, w.tsigSecret[t.Hdr.Name], w.tsigRequestMAC, w.tsigTimersOnly)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = w.writer.Write(data)
|
||||
return err
|
||||
}
|
||||
}
|
||||
data, err = m.Pack()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = w.writer.Write(data)
|
||||
return err
|
||||
}
|
||||
|
||||
// Write implements the ResponseWriter.Write method.
|
||||
func (w *response) Write(m []byte) (int, error) {
|
||||
switch {
|
||||
case w.udp != nil:
|
||||
n, err := WriteToSessionUDP(w.udp, m, w.udpSession)
|
||||
return n, err
|
||||
case w.tcp != nil:
|
||||
lm := len(m)
|
||||
if lm < 2 {
|
||||
return 0, io.ErrShortBuffer
|
||||
}
|
||||
if lm > MaxMsgSize {
|
||||
return 0, &Error{err: "message too large"}
|
||||
}
|
||||
l := make([]byte, 2, 2+lm)
|
||||
l[0], l[1] = packUint16(uint16(lm))
|
||||
m = append(l, m...)
|
||||
|
||||
n, err := io.Copy(w.tcp, bytes.NewReader(m))
|
||||
return int(n), err
|
||||
}
|
||||
panic("not reached")
|
||||
}
|
||||
|
||||
// LocalAddr implements the ResponseWriter.LocalAddr method.
|
||||
func (w *response) LocalAddr() net.Addr {
|
||||
if w.tcp != nil {
|
||||
return w.tcp.LocalAddr()
|
||||
}
|
||||
return w.udp.LocalAddr()
|
||||
}
|
||||
|
||||
// RemoteAddr implements the ResponseWriter.RemoteAddr method.
|
||||
func (w *response) RemoteAddr() net.Addr { return w.remoteAddr }
|
||||
|
||||
// TsigStatus implements the ResponseWriter.TsigStatus method.
|
||||
func (w *response) TsigStatus() error { return w.tsigStatus }
|
||||
|
||||
// TsigTimersOnly implements the ResponseWriter.TsigTimersOnly method.
|
||||
func (w *response) TsigTimersOnly(b bool) { w.tsigTimersOnly = b }
|
||||
|
||||
// Hijack implements the ResponseWriter.Hijack method.
|
||||
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
|
||||
}
|
||||
return nil
|
||||
}
|
216
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/sig0.go
generated
vendored
Normal file
216
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/sig0.go
generated
vendored
Normal file
|
@ -0,0 +1,216 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/dsa"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rsa"
|
||||
"math/big"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Sign signs a dns.Msg. It fills the signature with the appropriate data.
|
||||
// The SIG record should have the SignerName, KeyTag, Algorithm, Inception
|
||||
// and Expiration set.
|
||||
func (rr *SIG) Sign(k crypto.Signer, m *Msg) ([]byte, error) {
|
||||
if k == nil {
|
||||
return nil, ErrPrivKey
|
||||
}
|
||||
if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 {
|
||||
return nil, ErrKey
|
||||
}
|
||||
rr.Header().Rrtype = TypeSIG
|
||||
rr.Header().Class = ClassANY
|
||||
rr.Header().Ttl = 0
|
||||
rr.Header().Name = "."
|
||||
rr.OrigTtl = 0
|
||||
rr.TypeCovered = 0
|
||||
rr.Labels = 0
|
||||
|
||||
buf := make([]byte, m.Len()+rr.len())
|
||||
mbuf, err := m.PackBuffer(buf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if &buf[0] != &mbuf[0] {
|
||||
return nil, ErrBuf
|
||||
}
|
||||
off, err := PackRR(rr, buf, len(mbuf), nil, false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf = buf[:off:cap(buf)]
|
||||
|
||||
hash, ok := AlgorithmToHash[rr.Algorithm]
|
||||
if !ok {
|
||||
return nil, ErrAlg
|
||||
}
|
||||
|
||||
hasher := hash.New()
|
||||
// Write SIG rdata
|
||||
hasher.Write(buf[len(mbuf)+1+2+2+4+2:])
|
||||
// Write message
|
||||
hasher.Write(buf[:len(mbuf)])
|
||||
|
||||
signature, err := sign(k, hasher.Sum(nil), hash, rr.Algorithm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rr.Signature = toBase64(signature)
|
||||
sig := string(signature)
|
||||
|
||||
buf = append(buf, sig...)
|
||||
if len(buf) > int(^uint16(0)) {
|
||||
return nil, ErrBuf
|
||||
}
|
||||
// Adjust sig data length
|
||||
rdoff := len(mbuf) + 1 + 2 + 2 + 4
|
||||
rdlen, _ := unpackUint16(buf, rdoff)
|
||||
rdlen += uint16(len(sig))
|
||||
buf[rdoff], buf[rdoff+1] = packUint16(rdlen)
|
||||
// Adjust additional count
|
||||
adc, _ := unpackUint16(buf, 10)
|
||||
adc++
|
||||
buf[10], buf[11] = packUint16(adc)
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
// Verify validates the message buf using the key k.
|
||||
// It's assumed that buf is a valid message from which rr was unpacked.
|
||||
func (rr *SIG) Verify(k *KEY, buf []byte) error {
|
||||
if k == nil {
|
||||
return ErrKey
|
||||
}
|
||||
if rr.KeyTag == 0 || len(rr.SignerName) == 0 || rr.Algorithm == 0 {
|
||||
return ErrKey
|
||||
}
|
||||
|
||||
var hash crypto.Hash
|
||||
switch rr.Algorithm {
|
||||
case DSA, RSASHA1:
|
||||
hash = crypto.SHA1
|
||||
case RSASHA256, ECDSAP256SHA256:
|
||||
hash = crypto.SHA256
|
||||
case ECDSAP384SHA384:
|
||||
hash = crypto.SHA384
|
||||
case RSASHA512:
|
||||
hash = crypto.SHA512
|
||||
default:
|
||||
return ErrAlg
|
||||
}
|
||||
hasher := hash.New()
|
||||
|
||||
buflen := len(buf)
|
||||
qdc, _ := unpackUint16(buf, 4)
|
||||
anc, _ := unpackUint16(buf, 6)
|
||||
auc, _ := unpackUint16(buf, 8)
|
||||
adc, offset := unpackUint16(buf, 10)
|
||||
var err error
|
||||
for i := uint16(0); i < qdc && offset < buflen; i++ {
|
||||
_, offset, err = UnpackDomainName(buf, offset)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Skip past Type and Class
|
||||
offset += 2 + 2
|
||||
}
|
||||
for i := uint16(1); i < anc+auc+adc && offset < buflen; i++ {
|
||||
_, offset, err = UnpackDomainName(buf, offset)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Skip past Type, Class and TTL
|
||||
offset += 2 + 2 + 4
|
||||
if offset+1 >= buflen {
|
||||
continue
|
||||
}
|
||||
var rdlen uint16
|
||||
rdlen, offset = unpackUint16(buf, offset)
|
||||
offset += int(rdlen)
|
||||
}
|
||||
if offset >= buflen {
|
||||
return &Error{err: "overflowing unpacking signed message"}
|
||||
}
|
||||
|
||||
// offset should be just prior to SIG
|
||||
bodyend := offset
|
||||
// owner name SHOULD be root
|
||||
_, offset, err = UnpackDomainName(buf, offset)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Skip Type, Class, TTL, RDLen
|
||||
offset += 2 + 2 + 4 + 2
|
||||
sigstart := offset
|
||||
// Skip Type Covered, Algorithm, Labels, Original TTL
|
||||
offset += 2 + 1 + 1 + 4
|
||||
if offset+4+4 >= buflen {
|
||||
return &Error{err: "overflow unpacking signed message"}
|
||||
}
|
||||
expire := uint32(buf[offset])<<24 | uint32(buf[offset+1])<<16 | uint32(buf[offset+2])<<8 | uint32(buf[offset+3])
|
||||
offset += 4
|
||||
incept := uint32(buf[offset])<<24 | uint32(buf[offset+1])<<16 | uint32(buf[offset+2])<<8 | uint32(buf[offset+3])
|
||||
offset += 4
|
||||
now := uint32(time.Now().Unix())
|
||||
if now < incept || now > expire {
|
||||
return ErrTime
|
||||
}
|
||||
// Skip key tag
|
||||
offset += 2
|
||||
var signername string
|
||||
signername, offset, err = UnpackDomainName(buf, offset)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// 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) {
|
||||
return &Error{err: "signer name doesn't match key name"}
|
||||
}
|
||||
sigend := offset
|
||||
hasher.Write(buf[sigstart:sigend])
|
||||
hasher.Write(buf[:10])
|
||||
hasher.Write([]byte{
|
||||
byte((adc - 1) << 8),
|
||||
byte(adc - 1),
|
||||
})
|
||||
hasher.Write(buf[12:bodyend])
|
||||
|
||||
hashed := hasher.Sum(nil)
|
||||
sig := buf[sigend:]
|
||||
switch k.Algorithm {
|
||||
case DSA:
|
||||
pk := k.publicKeyDSA()
|
||||
sig = sig[1:]
|
||||
r := big.NewInt(0)
|
||||
r.SetBytes(sig[:len(sig)/2])
|
||||
s := big.NewInt(0)
|
||||
s.SetBytes(sig[len(sig)/2:])
|
||||
if pk != nil {
|
||||
if dsa.Verify(pk, hashed, r, s) {
|
||||
return nil
|
||||
}
|
||||
return ErrSig
|
||||
}
|
||||
case RSASHA1, RSASHA256, RSASHA512:
|
||||
pk := k.publicKeyRSA()
|
||||
if pk != nil {
|
||||
return rsa.VerifyPKCS1v15(pk, hash, hashed, sig)
|
||||
}
|
||||
case ECDSAP256SHA256, ECDSAP384SHA384:
|
||||
pk := k.publicKeyECDSA()
|
||||
r := big.NewInt(0)
|
||||
r.SetBytes(sig[:len(sig)/2])
|
||||
s := big.NewInt(0)
|
||||
s.SetBytes(sig[len(sig)/2:])
|
||||
if pk != nil {
|
||||
if ecdsa.Verify(pk, hashed, r, s) {
|
||||
return nil
|
||||
}
|
||||
return ErrSig
|
||||
}
|
||||
}
|
||||
return ErrKeyAlg
|
||||
}
|
57
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/singleinflight.go
generated
vendored
Normal file
57
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/singleinflight.go
generated
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
// Copyright 2013 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.
|
||||
|
||||
// Adapted for dns package usage by Miek Gieben.
|
||||
|
||||
package dns
|
||||
|
||||
import "sync"
|
||||
import "time"
|
||||
|
||||
// call is an in-flight or completed singleflight.Do call
|
||||
type call struct {
|
||||
wg sync.WaitGroup
|
||||
val *Msg
|
||||
rtt time.Duration
|
||||
err error
|
||||
dups int
|
||||
}
|
||||
|
||||
// singleflight represents a class of work and forms a namespace in
|
||||
// which units of work can be executed with duplicate suppression.
|
||||
type singleflight struct {
|
||||
sync.Mutex // protects m
|
||||
m map[string]*call // lazily initialized
|
||||
}
|
||||
|
||||
// Do executes and returns the results of the given function, making
|
||||
// sure that only one execution is in-flight for a given key at a
|
||||
// time. If a duplicate comes in, the duplicate caller waits for the
|
||||
// original to complete and receives the same results.
|
||||
// The return value shared indicates whether v was given to multiple callers.
|
||||
func (g *singleflight) Do(key string, fn func() (*Msg, time.Duration, error)) (v *Msg, rtt time.Duration, err error, shared bool) {
|
||||
g.Lock()
|
||||
if g.m == nil {
|
||||
g.m = make(map[string]*call)
|
||||
}
|
||||
if c, ok := g.m[key]; ok {
|
||||
c.dups++
|
||||
g.Unlock()
|
||||
c.wg.Wait()
|
||||
return c.val, c.rtt, c.err, true
|
||||
}
|
||||
c := new(call)
|
||||
c.wg.Add(1)
|
||||
g.m[key] = c
|
||||
g.Unlock()
|
||||
|
||||
c.val, c.rtt, c.err = fn()
|
||||
c.wg.Done()
|
||||
|
||||
g.Lock()
|
||||
delete(g.m, key)
|
||||
g.Unlock()
|
||||
|
||||
return c.val, c.rtt, c.err, c.dups > 0
|
||||
}
|
86
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/tlsa.go
generated
vendored
Normal file
86
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/tlsa.go
generated
vendored
Normal file
|
@ -0,0 +1,86 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"crypto/x509"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// CertificateToDANE converts a certificate to a hex string as used in the TLSA record.
|
||||
func CertificateToDANE(selector, matchingType uint8, cert *x509.Certificate) (string, error) {
|
||||
switch matchingType {
|
||||
case 0:
|
||||
switch selector {
|
||||
case 0:
|
||||
return hex.EncodeToString(cert.Raw), nil
|
||||
case 1:
|
||||
return hex.EncodeToString(cert.RawSubjectPublicKeyInfo), nil
|
||||
}
|
||||
case 1:
|
||||
h := sha256.New()
|
||||
switch selector {
|
||||
case 0:
|
||||
io.WriteString(h, string(cert.Raw))
|
||||
return hex.EncodeToString(h.Sum(nil)), nil
|
||||
case 1:
|
||||
io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
|
||||
return hex.EncodeToString(h.Sum(nil)), nil
|
||||
}
|
||||
case 2:
|
||||
h := sha512.New()
|
||||
switch selector {
|
||||
case 0:
|
||||
io.WriteString(h, string(cert.Raw))
|
||||
return hex.EncodeToString(h.Sum(nil)), nil
|
||||
case 1:
|
||||
io.WriteString(h, string(cert.RawSubjectPublicKeyInfo))
|
||||
return hex.EncodeToString(h.Sum(nil)), nil
|
||||
}
|
||||
}
|
||||
return "", errors.New("dns: bad TLSA MatchingType or TLSA Selector")
|
||||
}
|
||||
|
||||
// Sign creates a TLSA record from an SSL certificate.
|
||||
func (r *TLSA) Sign(usage, selector, matchingType int, cert *x509.Certificate) (err error) {
|
||||
r.Hdr.Rrtype = TypeTLSA
|
||||
r.Usage = uint8(usage)
|
||||
r.Selector = uint8(selector)
|
||||
r.MatchingType = uint8(matchingType)
|
||||
|
||||
r.Certificate, err = CertificateToDANE(r.Selector, r.MatchingType, cert)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Verify verifies a TLSA record against an SSL certificate. If it is OK
|
||||
// a nil error is returned.
|
||||
func (r *TLSA) Verify(cert *x509.Certificate) error {
|
||||
c, err := CertificateToDANE(r.Selector, r.MatchingType, cert)
|
||||
if err != nil {
|
||||
return err // Not also ErrSig?
|
||||
}
|
||||
if r.Certificate == c {
|
||||
return nil
|
||||
}
|
||||
return ErrSig // ErrSig, really?
|
||||
}
|
||||
|
||||
// TLSAName returns the ownername of a TLSA resource record as per the
|
||||
// rules specified in RFC 6698, Section 3.
|
||||
func TLSAName(name, service, network string) (string, error) {
|
||||
if !IsFqdn(name) {
|
||||
return "", ErrFqdn
|
||||
}
|
||||
p, e := net.LookupPort(network, service)
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
return "_" + strconv.Itoa(p) + "_" + network + "." + name, nil
|
||||
}
|
320
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/tsig.go
generated
vendored
Normal file
320
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/tsig.go
generated
vendored
Normal file
|
@ -0,0 +1,320 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"encoding/hex"
|
||||
"hash"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// HMAC hashing codes. These are transmitted as domain names.
|
||||
const (
|
||||
HmacMD5 = "hmac-md5.sig-alg.reg.int."
|
||||
HmacSHA1 = "hmac-sha1."
|
||||
HmacSHA256 = "hmac-sha256."
|
||||
HmacSHA512 = "hmac-sha512."
|
||||
)
|
||||
|
||||
// TSIG is the RR the holds the transaction signature of a message.
|
||||
// See RFC 2845 and RFC 4635.
|
||||
type TSIG struct {
|
||||
Hdr RR_Header
|
||||
Algorithm string `dns:"domain-name"`
|
||||
TimeSigned uint64 `dns:"uint48"`
|
||||
Fudge uint16
|
||||
MACSize uint16
|
||||
MAC string `dns:"size-hex"`
|
||||
OrigId uint16
|
||||
Error uint16
|
||||
OtherLen uint16
|
||||
OtherData string `dns:"size-hex"`
|
||||
}
|
||||
|
||||
// TSIG has no official presentation format, but this will suffice.
|
||||
|
||||
func (rr *TSIG) String() string {
|
||||
s := "\n;; TSIG PSEUDOSECTION:\n"
|
||||
s += rr.Hdr.String() +
|
||||
" " + rr.Algorithm +
|
||||
" " + tsigTimeToString(rr.TimeSigned) +
|
||||
" " + strconv.Itoa(int(rr.Fudge)) +
|
||||
" " + strconv.Itoa(int(rr.MACSize)) +
|
||||
" " + strings.ToUpper(rr.MAC) +
|
||||
" " + strconv.Itoa(int(rr.OrigId)) +
|
||||
" " + strconv.Itoa(int(rr.Error)) + // BIND prints NOERROR
|
||||
" " + strconv.Itoa(int(rr.OtherLen)) +
|
||||
" " + rr.OtherData
|
||||
return s
|
||||
}
|
||||
|
||||
// The following values must be put in wireformat, so that the MAC can be calculated.
|
||||
// RFC 2845, section 3.4.2. TSIG Variables.
|
||||
type tsigWireFmt struct {
|
||||
// From RR_Header
|
||||
Name string `dns:"domain-name"`
|
||||
Class uint16
|
||||
Ttl uint32
|
||||
// Rdata of the TSIG
|
||||
Algorithm string `dns:"domain-name"`
|
||||
TimeSigned uint64 `dns:"uint48"`
|
||||
Fudge uint16
|
||||
// MACSize, MAC and OrigId excluded
|
||||
Error uint16
|
||||
OtherLen uint16
|
||||
OtherData string `dns:"size-hex"`
|
||||
}
|
||||
|
||||
// If we have the MAC use this type to convert it to wiredata.
|
||||
// Section 3.4.3. Request MAC
|
||||
type macWireFmt struct {
|
||||
MACSize uint16
|
||||
MAC string `dns:"size-hex"`
|
||||
}
|
||||
|
||||
// 3.3. Time values used in TSIG calculations
|
||||
type timerWireFmt struct {
|
||||
TimeSigned uint64 `dns:"uint48"`
|
||||
Fudge uint16
|
||||
}
|
||||
|
||||
// TsigGenerate fills out the TSIG record attached to the message.
|
||||
// The message should contain
|
||||
// a "stub" TSIG RR with the algorithm, key name (owner name of the RR),
|
||||
// time fudge (defaults to 300 seconds) and the current time
|
||||
// The TSIG MAC is saved in that Tsig RR.
|
||||
// When TsigGenerate is called for the first time requestMAC is set to the empty string and
|
||||
// timersOnly is false.
|
||||
// If something goes wrong an error is returned, otherwise it is nil.
|
||||
func TsigGenerate(m *Msg, secret, requestMAC string, timersOnly bool) ([]byte, string, error) {
|
||||
if m.IsTsig() == nil {
|
||||
panic("dns: TSIG not last RR in additional")
|
||||
}
|
||||
// If we barf here, the caller is to blame
|
||||
rawsecret, err := fromBase64([]byte(secret))
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
rr := m.Extra[len(m.Extra)-1].(*TSIG)
|
||||
m.Extra = m.Extra[0 : len(m.Extra)-1] // kill the TSIG from the msg
|
||||
mbuf, err := m.Pack()
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
buf := tsigBuffer(mbuf, rr, requestMAC, timersOnly)
|
||||
|
||||
t := new(TSIG)
|
||||
var h hash.Hash
|
||||
switch rr.Algorithm {
|
||||
case HmacMD5:
|
||||
h = hmac.New(md5.New, []byte(rawsecret))
|
||||
case HmacSHA1:
|
||||
h = hmac.New(sha1.New, []byte(rawsecret))
|
||||
case HmacSHA256:
|
||||
h = hmac.New(sha256.New, []byte(rawsecret))
|
||||
case HmacSHA512:
|
||||
h = hmac.New(sha512.New, []byte(rawsecret))
|
||||
default:
|
||||
return nil, "", ErrKeyAlg
|
||||
}
|
||||
io.WriteString(h, string(buf))
|
||||
t.MAC = hex.EncodeToString(h.Sum(nil))
|
||||
t.MACSize = uint16(len(t.MAC) / 2) // Size is half!
|
||||
|
||||
t.Hdr = RR_Header{Name: rr.Hdr.Name, Rrtype: TypeTSIG, Class: ClassANY, Ttl: 0}
|
||||
t.Fudge = rr.Fudge
|
||||
t.TimeSigned = rr.TimeSigned
|
||||
t.Algorithm = rr.Algorithm
|
||||
t.OrigId = m.Id
|
||||
|
||||
tbuf := make([]byte, t.len())
|
||||
if off, err := PackRR(t, tbuf, 0, nil, false); err == nil {
|
||||
tbuf = tbuf[:off] // reset to actual size used
|
||||
} else {
|
||||
return nil, "", err
|
||||
}
|
||||
mbuf = append(mbuf, tbuf...)
|
||||
rawSetExtraLen(mbuf, uint16(len(m.Extra)+1))
|
||||
return mbuf, t.MAC, nil
|
||||
}
|
||||
|
||||
// TsigVerify verifies the TSIG on a message.
|
||||
// If the signature does not validate err contains the
|
||||
// error, otherwise it is nil.
|
||||
func TsigVerify(msg []byte, secret, requestMAC string, timersOnly bool) error {
|
||||
rawsecret, err := fromBase64([]byte(secret))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Strip the TSIG from the incoming msg
|
||||
stripped, tsig, err := stripTsig(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msgMAC, err := hex.DecodeString(tsig.MAC)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buf := tsigBuffer(stripped, tsig, requestMAC, timersOnly)
|
||||
|
||||
// Fudge factor works both ways. A message can arrive before it was signed because
|
||||
// of clock skew.
|
||||
now := uint64(time.Now().Unix())
|
||||
ti := now - tsig.TimeSigned
|
||||
if now < tsig.TimeSigned {
|
||||
ti = tsig.TimeSigned - now
|
||||
}
|
||||
if uint64(tsig.Fudge) < ti {
|
||||
return ErrTime
|
||||
}
|
||||
|
||||
var h hash.Hash
|
||||
switch tsig.Algorithm {
|
||||
case HmacMD5:
|
||||
h = hmac.New(md5.New, rawsecret)
|
||||
case HmacSHA1:
|
||||
h = hmac.New(sha1.New, rawsecret)
|
||||
case HmacSHA256:
|
||||
h = hmac.New(sha256.New, rawsecret)
|
||||
case HmacSHA512:
|
||||
h = hmac.New(sha512.New, rawsecret)
|
||||
default:
|
||||
return ErrKeyAlg
|
||||
}
|
||||
h.Write(buf)
|
||||
if !hmac.Equal(h.Sum(nil), msgMAC) {
|
||||
return ErrSig
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create a wiredata buffer for the MAC calculation.
|
||||
func tsigBuffer(msgbuf []byte, rr *TSIG, requestMAC string, timersOnly bool) []byte {
|
||||
var buf []byte
|
||||
if rr.TimeSigned == 0 {
|
||||
rr.TimeSigned = uint64(time.Now().Unix())
|
||||
}
|
||||
if rr.Fudge == 0 {
|
||||
rr.Fudge = 300 // Standard (RFC) default.
|
||||
}
|
||||
|
||||
if requestMAC != "" {
|
||||
m := new(macWireFmt)
|
||||
m.MACSize = uint16(len(requestMAC) / 2)
|
||||
m.MAC = requestMAC
|
||||
buf = make([]byte, len(requestMAC)) // long enough
|
||||
n, _ := PackStruct(m, buf, 0)
|
||||
buf = buf[:n]
|
||||
}
|
||||
|
||||
tsigvar := make([]byte, DefaultMsgSize)
|
||||
if timersOnly {
|
||||
tsig := new(timerWireFmt)
|
||||
tsig.TimeSigned = rr.TimeSigned
|
||||
tsig.Fudge = rr.Fudge
|
||||
n, _ := PackStruct(tsig, tsigvar, 0)
|
||||
tsigvar = tsigvar[:n]
|
||||
} else {
|
||||
tsig := new(tsigWireFmt)
|
||||
tsig.Name = strings.ToLower(rr.Hdr.Name)
|
||||
tsig.Class = ClassANY
|
||||
tsig.Ttl = rr.Hdr.Ttl
|
||||
tsig.Algorithm = strings.ToLower(rr.Algorithm)
|
||||
tsig.TimeSigned = rr.TimeSigned
|
||||
tsig.Fudge = rr.Fudge
|
||||
tsig.Error = rr.Error
|
||||
tsig.OtherLen = rr.OtherLen
|
||||
tsig.OtherData = rr.OtherData
|
||||
n, _ := PackStruct(tsig, tsigvar, 0)
|
||||
tsigvar = tsigvar[:n]
|
||||
}
|
||||
|
||||
if requestMAC != "" {
|
||||
x := append(buf, msgbuf...)
|
||||
buf = append(x, tsigvar...)
|
||||
} else {
|
||||
buf = append(msgbuf, tsigvar...)
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
// Strip the TSIG from the raw message.
|
||||
func stripTsig(msg []byte) ([]byte, *TSIG, error) {
|
||||
// Copied from msg.go's Unpack()
|
||||
// Header.
|
||||
var dh Header
|
||||
var err error
|
||||
dns := new(Msg)
|
||||
rr := new(TSIG)
|
||||
off := 0
|
||||
tsigoff := 0
|
||||
if off, err = UnpackStruct(&dh, msg, off); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if dh.Arcount == 0 {
|
||||
return nil, nil, ErrNoSig
|
||||
}
|
||||
// Rcode, see msg.go Unpack()
|
||||
if int(dh.Bits&0xF) == RcodeNotAuth {
|
||||
return nil, nil, ErrAuth
|
||||
}
|
||||
|
||||
// Arrays.
|
||||
dns.Question = make([]Question, dh.Qdcount)
|
||||
dns.Answer = make([]RR, dh.Ancount)
|
||||
dns.Ns = make([]RR, dh.Nscount)
|
||||
dns.Extra = make([]RR, dh.Arcount)
|
||||
|
||||
for i := 0; i < len(dns.Question); i++ {
|
||||
off, err = UnpackStruct(&dns.Question[i], msg, off)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(dns.Answer); i++ {
|
||||
dns.Answer[i], off, err = UnpackRR(msg, off)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(dns.Ns); i++ {
|
||||
dns.Ns[i], off, err = UnpackRR(msg, off)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(dns.Extra); i++ {
|
||||
tsigoff = off
|
||||
dns.Extra[i], off, err = UnpackRR(msg, off)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if dns.Extra[i].Header().Rrtype == TypeTSIG {
|
||||
rr = dns.Extra[i].(*TSIG)
|
||||
// Adjust Arcount.
|
||||
arcount, _ := unpackUint16(msg, 10)
|
||||
msg[10], msg[11] = packUint16(arcount - 1)
|
||||
break
|
||||
}
|
||||
}
|
||||
if rr == nil {
|
||||
return nil, nil, ErrNoSig
|
||||
}
|
||||
return msg[:tsigoff], rr, nil
|
||||
}
|
||||
|
||||
// Translate the TSIG time signed into a date. There is no
|
||||
// need for RFC1982 calculations as this date is 48 bits.
|
||||
func tsigTimeToString(t uint64) string {
|
||||
ti := time.Unix(int64(t), 0).UTC()
|
||||
return ti.Format("20060102150405")
|
||||
}
|
1328
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/types.go
generated
vendored
Normal file
1328
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/types.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
266
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/types_generate.go
generated
vendored
Normal file
266
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/types_generate.go
generated
vendored
Normal file
|
@ -0,0 +1,266 @@
|
|||
//+build ignore
|
||||
|
||||
// types_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 generate conversion tables (TypeToRR and TypeToString) and banal
|
||||
// methods (len, Header, copy) based on the struct tags. The generated source is
|
||||
// written to ztypes.go, and is meant to be checked into git.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"go/importer"
|
||||
"go/types"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
var skipLen = map[string]struct{}{
|
||||
"NSEC": struct{}{},
|
||||
"NSEC3": struct{}{},
|
||||
"OPT": struct{}{},
|
||||
"WKS": struct{}{},
|
||||
"IPSECKEY": struct{}{},
|
||||
}
|
||||
|
||||
var packageHdr = `
|
||||
// *** DO NOT MODIFY ***
|
||||
// AUTOGENERATED BY go generate
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"net"
|
||||
)
|
||||
|
||||
`
|
||||
|
||||
var TypeToRR = template.Must(template.New("TypeToRR").Parse(`
|
||||
// TypeToRR is a map of constructors for each RR type.
|
||||
var TypeToRR = map[uint16]func() RR{
|
||||
{{range .}}{{if ne . "RFC3597"}} Type{{.}}: func() RR { return new({{.}}) },
|
||||
{{end}}{{end}} }
|
||||
|
||||
`))
|
||||
|
||||
var typeToString = template.Must(template.New("typeToString").Parse(`
|
||||
// TypeToString is a map of strings for each RR type.
|
||||
var TypeToString = map[uint16]string{
|
||||
{{range .}}{{if ne . "NSAPPTR"}} Type{{.}}: "{{.}}",
|
||||
{{end}}{{end}} TypeNSAPPTR: "NSAP-PTR",
|
||||
}
|
||||
|
||||
`))
|
||||
|
||||
var headerFunc = template.Must(template.New("headerFunc").Parse(`
|
||||
// Header() functions
|
||||
{{range .}} func (rr *{{.}}) Header() *RR_Header { return &rr.Hdr }
|
||||
{{end}}
|
||||
|
||||
`))
|
||||
|
||||
// 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()
|
||||
|
||||
// Collect constants like TypeX
|
||||
var numberedTypes []string
|
||||
for _, name := range scope.Names() {
|
||||
o := scope.Lookup(name)
|
||||
if o == nil || !o.Exported() {
|
||||
continue
|
||||
}
|
||||
b, ok := o.Type().(*types.Basic)
|
||||
if !ok || b.Kind() != types.Uint16 {
|
||||
continue
|
||||
}
|
||||
if !strings.HasPrefix(o.Name(), "Type") {
|
||||
continue
|
||||
}
|
||||
name := strings.TrimPrefix(o.Name(), "Type")
|
||||
if name == "PrivateRR" {
|
||||
continue
|
||||
}
|
||||
numberedTypes = append(numberedTypes, name)
|
||||
}
|
||||
|
||||
// Collect actual types (*X)
|
||||
var namedTypes []string
|
||||
for _, name := range scope.Names() {
|
||||
o := scope.Lookup(name)
|
||||
if o == nil || !o.Exported() {
|
||||
continue
|
||||
}
|
||||
if st, _ := getTypeStruct(o.Type(), scope); st == nil {
|
||||
continue
|
||||
}
|
||||
if name == "PrivateRR" {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if corresponding TypeX exists
|
||||
if scope.Lookup("Type"+o.Name()) == nil && o.Name() != "RFC3597" {
|
||||
log.Fatalf("Constant Type%s does not exist.", o.Name())
|
||||
}
|
||||
|
||||
namedTypes = append(namedTypes, o.Name())
|
||||
}
|
||||
|
||||
b := &bytes.Buffer{}
|
||||
b.WriteString(packageHdr)
|
||||
|
||||
// Generate TypeToRR
|
||||
fatalIfErr(TypeToRR.Execute(b, namedTypes))
|
||||
|
||||
// Generate typeToString
|
||||
fatalIfErr(typeToString.Execute(b, numberedTypes))
|
||||
|
||||
// Generate headerFunc
|
||||
fatalIfErr(headerFunc.Execute(b, namedTypes))
|
||||
|
||||
// Generate len()
|
||||
fmt.Fprint(b, "// len() functions\n")
|
||||
for _, name := range namedTypes {
|
||||
if _, ok := skipLen[name]; ok {
|
||||
continue
|
||||
}
|
||||
o := scope.Lookup(name)
|
||||
st, isEmbedded := getTypeStruct(o.Type(), scope)
|
||||
if isEmbedded {
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(b, "func (rr *%s) len() int {\n", name)
|
||||
fmt.Fprintf(b, "l := rr.Hdr.len()\n")
|
||||
for i := 1; i < st.NumFields(); i++ {
|
||||
o := func(s string) { fmt.Fprintf(b, s, st.Field(i).Name()) }
|
||||
|
||||
if _, ok := st.Field(i).Type().(*types.Slice); ok {
|
||||
switch st.Tag(i) {
|
||||
case `dns:"-"`:
|
||||
// ignored
|
||||
case `dns:"cdomain-name"`, `dns:"domain-name"`, `dns:"txt"`:
|
||||
o("for _, x := range rr.%s { l += len(x) + 1 }\n")
|
||||
default:
|
||||
log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
switch st.Tag(i) {
|
||||
case `dns:"-"`:
|
||||
// ignored
|
||||
case `dns:"cdomain-name"`, `dns:"domain-name"`:
|
||||
o("l += len(rr.%s) + 1\n")
|
||||
case `dns:"octet"`:
|
||||
o("l += len(rr.%s)\n")
|
||||
case `dns:"base64"`:
|
||||
o("l += base64.StdEncoding.DecodedLen(len(rr.%s))\n")
|
||||
case `dns:"size-hex"`, `dns:"hex"`:
|
||||
o("l += len(rr.%s)/2 + 1\n")
|
||||
case `dns:"a"`:
|
||||
o("l += net.IPv4len // %s\n")
|
||||
case `dns:"aaaa"`:
|
||||
o("l += net.IPv6len // %s\n")
|
||||
case `dns:"txt"`:
|
||||
o("for _, t := range rr.%s { l += len(t) + 1 }\n")
|
||||
case `dns:"uint48"`:
|
||||
o("l += 6 // %s\n")
|
||||
case "":
|
||||
switch st.Field(i).Type().(*types.Basic).Kind() {
|
||||
case types.Uint8:
|
||||
o("l += 1 // %s\n")
|
||||
case types.Uint16:
|
||||
o("l += 2 // %s\n")
|
||||
case types.Uint32:
|
||||
o("l += 4 // %s\n")
|
||||
case types.Uint64:
|
||||
o("l += 8 // %s\n")
|
||||
case types.String:
|
||||
o("l += len(rr.%s) + 1\n")
|
||||
default:
|
||||
log.Fatalln(name, st.Field(i).Name())
|
||||
}
|
||||
default:
|
||||
log.Fatalln(name, st.Field(i).Name(), st.Tag(i))
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(b, "return l }\n")
|
||||
}
|
||||
|
||||
// Generate copy()
|
||||
fmt.Fprint(b, "// copy() functions\n")
|
||||
for _, name := range namedTypes {
|
||||
o := scope.Lookup(name)
|
||||
st, isEmbedded := getTypeStruct(o.Type(), scope)
|
||||
if isEmbedded {
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(b, "func (rr *%s) copy() RR {\n", name)
|
||||
fields := []string{"*rr.Hdr.copyHeader()"}
|
||||
for i := 1; i < st.NumFields(); i++ {
|
||||
f := st.Field(i).Name()
|
||||
if sl, ok := st.Field(i).Type().(*types.Slice); ok {
|
||||
t := sl.Underlying().String()
|
||||
t = strings.TrimPrefix(t, "[]")
|
||||
t = strings.TrimPrefix(t, "github.com/miekg/dns.")
|
||||
fmt.Fprintf(b, "%s := make([]%s, len(rr.%s)); copy(%s, rr.%s)\n",
|
||||
f, t, f, f, f)
|
||||
fields = append(fields, f)
|
||||
continue
|
||||
}
|
||||
if st.Field(i).Type().String() == "net.IP" {
|
||||
fields = append(fields, "copyIP(rr."+f+")")
|
||||
continue
|
||||
}
|
||||
fields = append(fields, "rr."+f)
|
||||
}
|
||||
fmt.Fprintf(b, "return &%s{%s}\n", name, strings.Join(fields, ","))
|
||||
fmt.Fprintf(b, "}\n")
|
||||
}
|
||||
|
||||
// gofmt
|
||||
res, err := format.Source(b.Bytes())
|
||||
if err != nil {
|
||||
b.WriteTo(os.Stderr)
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// write result
|
||||
f, err := os.Create("ztypes.go")
|
||||
fatalIfErr(err)
|
||||
defer f.Close()
|
||||
f.Write(res)
|
||||
}
|
||||
|
||||
func fatalIfErr(err error) {
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
58
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/udp.go
generated
vendored
Normal file
58
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/udp.go
generated
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
// +build !windows
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// SessionUDP holds the remote address and the associated
|
||||
// out-of-band data.
|
||||
type SessionUDP struct {
|
||||
raddr *net.UDPAddr
|
||||
context []byte
|
||||
}
|
||||
|
||||
// RemoteAddr returns the remote network address.
|
||||
func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
|
||||
|
||||
// setUDPSocketOptions sets the UDP socket options.
|
||||
// This function is implemented on a per platform basis. See udp_*.go for more details
|
||||
func setUDPSocketOptions(conn *net.UDPConn) error {
|
||||
sa, err := getUDPSocketName(conn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch sa.(type) {
|
||||
case *syscall.SockaddrInet6:
|
||||
v6only, err := getUDPSocketOptions6Only(conn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
setUDPSocketOptions6(conn)
|
||||
if !v6only {
|
||||
setUDPSocketOptions4(conn)
|
||||
}
|
||||
case *syscall.SockaddrInet4:
|
||||
setUDPSocketOptions4(conn)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
|
||||
// net.UDPAddr.
|
||||
func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
|
||||
oob := make([]byte, 40)
|
||||
n, oobn, _, raddr, err := conn.ReadMsgUDP(b, oob)
|
||||
if err != nil {
|
||||
return n, nil, err
|
||||
}
|
||||
return n, &SessionUDP{raddr, oob[:oobn]}, err
|
||||
}
|
||||
|
||||
// WriteToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *SessionUDP instead of a net.Addr.
|
||||
func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) {
|
||||
n, _, err := conn.WriteMsgUDP(b, session.context, session.raddr)
|
||||
return n, err
|
||||
}
|
63
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/udp_linux.go
generated
vendored
Normal file
63
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/udp_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,63 @@
|
|||
// +build linux
|
||||
|
||||
package dns
|
||||
|
||||
// See:
|
||||
// * http://stackoverflow.com/questions/3062205/setting-the-source-ip-for-a-udp-socket and
|
||||
// * http://blog.powerdns.com/2012/10/08/on-binding-datagram-udp-sockets-to-the-any-addresses/
|
||||
//
|
||||
// Why do we need this: When listening on 0.0.0.0 with UDP so kernel decides what is the outgoing
|
||||
// interface, this might not always be the correct one. This code will make sure the egress
|
||||
// packet's interface matched the ingress' one.
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// setUDPSocketOptions4 prepares the v4 socket for sessions.
|
||||
func setUDPSocketOptions4(conn *net.UDPConn) error {
|
||||
file, err := conn.File()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IP, syscall.IP_PKTINFO, 1); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// setUDPSocketOptions6 prepares the v6 socket for sessions.
|
||||
func setUDPSocketOptions6(conn *net.UDPConn) error {
|
||||
file, err := conn.File()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := syscall.SetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_RECVPKTINFO, 1); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getUDPSocketOption6Only return true if the socket is v6 only and false when it is v4/v6 combined
|
||||
// (dualstack).
|
||||
func getUDPSocketOptions6Only(conn *net.UDPConn) (bool, error) {
|
||||
file, err := conn.File()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
// dual stack. See http://stackoverflow.com/questions/1618240/how-to-support-both-ipv4-and-ipv6-connections
|
||||
v6only, err := syscall.GetsockoptInt(int(file.Fd()), syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return v6only == 1, nil
|
||||
}
|
||||
|
||||
func getUDPSocketName(conn *net.UDPConn) (syscall.Sockaddr, error) {
|
||||
file, err := conn.File()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return syscall.Getsockname(int(file.Fd()))
|
||||
}
|
17
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/udp_other.go
generated
vendored
Normal file
17
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/udp_other.go
generated
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
// +build !linux
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
"net"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// These do nothing. See udp_linux.go for an example of how to implement this.
|
||||
|
||||
// We tried to adhire to some kind of naming scheme.
|
||||
|
||||
func setUDPSocketOptions4(conn *net.UDPConn) error { return nil }
|
||||
func setUDPSocketOptions6(conn *net.UDPConn) error { return nil }
|
||||
func getUDPSocketOptions6Only(conn *net.UDPConn) (bool, error) { return false, nil }
|
||||
func getUDPSocketName(conn *net.UDPConn) (syscall.Sockaddr, error) { return nil, nil }
|
34
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/udp_windows.go
generated
vendored
Normal file
34
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/udp_windows.go
generated
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
// +build windows
|
||||
|
||||
package dns
|
||||
|
||||
import "net"
|
||||
|
||||
type SessionUDP struct {
|
||||
raddr *net.UDPAddr
|
||||
}
|
||||
|
||||
// ReadFromSessionUDP acts just like net.UDPConn.ReadFrom(), but returns a session object instead of a
|
||||
// net.UDPAddr.
|
||||
func ReadFromSessionUDP(conn *net.UDPConn, b []byte) (int, *SessionUDP, error) {
|
||||
n, raddr, err := conn.ReadFrom(b)
|
||||
if err != nil {
|
||||
return n, nil, err
|
||||
}
|
||||
session := &SessionUDP{raddr.(*net.UDPAddr)}
|
||||
return n, session, err
|
||||
}
|
||||
|
||||
// WriteToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *SessionUDP instead of a net.Addr.
|
||||
func WriteToSessionUDP(conn *net.UDPConn, b []byte, session *SessionUDP) (int, error) {
|
||||
n, err := conn.WriteTo(b, session.raddr)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (s *SessionUDP) RemoteAddr() net.Addr { return s.raddr }
|
||||
|
||||
// setUDPSocketOptions sets the UDP socket options.
|
||||
// This function is implemented on a per platform basis. See udp_*.go for more details
|
||||
func setUDPSocketOptions(conn *net.UDPConn) error {
|
||||
return nil
|
||||
}
|
94
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/update.go
generated
vendored
Normal file
94
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/update.go
generated
vendored
Normal file
|
@ -0,0 +1,94 @@
|
|||
package dns
|
||||
|
||||
// NameUsed sets the RRs in the prereq section to
|
||||
// "Name is in use" RRs. RFC 2136 section 2.4.4.
|
||||
func (u *Msg) NameUsed(rr []RR) {
|
||||
u.Answer = make([]RR, len(rr))
|
||||
for i, r := range rr {
|
||||
u.Answer[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}}
|
||||
}
|
||||
}
|
||||
|
||||
// NameNotUsed sets the RRs in the prereq section to
|
||||
// "Name is in not use" RRs. RFC 2136 section 2.4.5.
|
||||
func (u *Msg) NameNotUsed(rr []RR) {
|
||||
u.Answer = make([]RR, len(rr))
|
||||
for i, r := range rr {
|
||||
u.Answer[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassNONE}}
|
||||
}
|
||||
}
|
||||
|
||||
// Used sets the RRs in the prereq section to
|
||||
// "RRset exists (value dependent -- with rdata)" RRs. RFC 2136 section 2.4.2.
|
||||
func (u *Msg) Used(rr []RR) {
|
||||
if len(u.Question) == 0 {
|
||||
panic("dns: empty question section")
|
||||
}
|
||||
u.Answer = make([]RR, len(rr))
|
||||
for i, r := range rr {
|
||||
u.Answer[i] = r
|
||||
u.Answer[i].Header().Class = u.Question[0].Qclass
|
||||
}
|
||||
}
|
||||
|
||||
// RRsetUsed sets the RRs in the prereq section to
|
||||
// "RRset exists (value independent -- no rdata)" RRs. RFC 2136 section 2.4.1.
|
||||
func (u *Msg) RRsetUsed(rr []RR) {
|
||||
u.Answer = make([]RR, len(rr))
|
||||
for i, r := range rr {
|
||||
u.Answer[i] = r
|
||||
u.Answer[i].Header().Class = ClassANY
|
||||
u.Answer[i].Header().Ttl = 0
|
||||
u.Answer[i].Header().Rdlength = 0
|
||||
}
|
||||
}
|
||||
|
||||
// RRsetNotUsed sets the RRs in the prereq section to
|
||||
// "RRset does not exist" RRs. RFC 2136 section 2.4.3.
|
||||
func (u *Msg) RRsetNotUsed(rr []RR) {
|
||||
u.Answer = make([]RR, len(rr))
|
||||
for i, r := range rr {
|
||||
u.Answer[i] = r
|
||||
u.Answer[i].Header().Class = ClassNONE
|
||||
u.Answer[i].Header().Rdlength = 0
|
||||
u.Answer[i].Header().Ttl = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Insert creates a dynamic update packet that adds an complete RRset, see RFC 2136 section 2.5.1.
|
||||
func (u *Msg) Insert(rr []RR) {
|
||||
if len(u.Question) == 0 {
|
||||
panic("dns: empty question section")
|
||||
}
|
||||
u.Ns = make([]RR, len(rr))
|
||||
for i, r := range rr {
|
||||
u.Ns[i] = r
|
||||
u.Ns[i].Header().Class = u.Question[0].Qclass
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveRRset creates a dynamic update packet that deletes an RRset, see RFC 2136 section 2.5.2.
|
||||
func (u *Msg) RemoveRRset(rr []RR) {
|
||||
u.Ns = make([]RR, len(rr))
|
||||
for i, r := range rr {
|
||||
u.Ns[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: r.Header().Rrtype, Class: ClassANY}}
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveName creates a dynamic update packet that deletes all RRsets of a name, see RFC 2136 section 2.5.3
|
||||
func (u *Msg) RemoveName(rr []RR) {
|
||||
u.Ns = make([]RR, len(rr))
|
||||
for i, r := range rr {
|
||||
u.Ns[i] = &ANY{Hdr: RR_Header{Name: r.Header().Name, Ttl: 0, Rrtype: TypeANY, Class: ClassANY}}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove creates a dynamic update packet deletes RR from the RRSset, see RFC 2136 section 2.5.4
|
||||
func (u *Msg) Remove(rr []RR) {
|
||||
u.Ns = make([]RR, len(rr))
|
||||
for i, r := range rr {
|
||||
u.Ns[i] = r
|
||||
u.Ns[i].Header().Class = ClassNONE
|
||||
u.Ns[i].Header().Ttl = 0
|
||||
}
|
||||
}
|
244
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/xfr.go
generated
vendored
Normal file
244
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/xfr.go
generated
vendored
Normal file
|
@ -0,0 +1,244 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Envelope is used when doing a zone transfer with a remote server.
|
||||
type Envelope struct {
|
||||
RR []RR // The set of RRs in the answer section of the xfr reply message.
|
||||
Error error // If something went wrong, this contains the error.
|
||||
}
|
||||
|
||||
// A Transfer defines parameters that are used during a zone transfer.
|
||||
type Transfer struct {
|
||||
*Conn
|
||||
DialTimeout time.Duration // net.DialTimeout, defaults to 2 seconds
|
||||
ReadTimeout time.Duration // net.Conn.SetReadTimeout value for connections, defaults to 2 seconds
|
||||
WriteTimeout time.Duration // net.Conn.SetWriteTimeout value for connections, defaults to 2 seconds
|
||||
TsigSecret map[string]string // Secret(s) for Tsig map[<zonename>]<base64 secret>, zonename must be fully qualified
|
||||
tsigTimersOnly bool
|
||||
}
|
||||
|
||||
// Think we need to away to stop the transfer
|
||||
|
||||
// In performs an incoming transfer with the server in a.
|
||||
// If you would like to set the source IP, or some other attribute
|
||||
// of a Dialer for a Transfer, you can do so by specifying the attributes
|
||||
// in the Transfer.Conn:
|
||||
//
|
||||
// d := net.Dialer{LocalAddr: transfer_source}
|
||||
// con, err := d.Dial("tcp", master)
|
||||
// dnscon := &dns.Conn{Conn:con}
|
||||
// transfer = &dns.Transfer{Conn: dnscon}
|
||||
// channel, err := transfer.In(message, master)
|
||||
//
|
||||
func (t *Transfer) In(q *Msg, a string) (env chan *Envelope, err error) {
|
||||
timeout := dnsTimeout
|
||||
if t.DialTimeout != 0 {
|
||||
timeout = t.DialTimeout
|
||||
}
|
||||
if t.Conn == nil {
|
||||
t.Conn, err = DialTimeout("tcp", a, timeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err := t.WriteMsg(q); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
env = make(chan *Envelope)
|
||||
go func() {
|
||||
if q.Question[0].Qtype == TypeAXFR {
|
||||
go t.inAxfr(q.Id, env)
|
||||
return
|
||||
}
|
||||
if q.Question[0].Qtype == TypeIXFR {
|
||||
go t.inIxfr(q.Id, env)
|
||||
return
|
||||
}
|
||||
}()
|
||||
return env, nil
|
||||
}
|
||||
|
||||
func (t *Transfer) inAxfr(id uint16, c chan *Envelope) {
|
||||
first := true
|
||||
defer t.Close()
|
||||
defer close(c)
|
||||
timeout := dnsTimeout
|
||||
if t.ReadTimeout != 0 {
|
||||
timeout = t.ReadTimeout
|
||||
}
|
||||
for {
|
||||
t.Conn.SetReadDeadline(time.Now().Add(timeout))
|
||||
in, err := t.ReadMsg()
|
||||
if err != nil {
|
||||
c <- &Envelope{nil, err}
|
||||
return
|
||||
}
|
||||
if id != in.Id {
|
||||
c <- &Envelope{in.Answer, ErrId}
|
||||
return
|
||||
}
|
||||
if first {
|
||||
if !isSOAFirst(in) {
|
||||
c <- &Envelope{in.Answer, ErrSoa}
|
||||
return
|
||||
}
|
||||
first = !first
|
||||
// only one answer that is SOA, receive more
|
||||
if len(in.Answer) == 1 {
|
||||
t.tsigTimersOnly = true
|
||||
c <- &Envelope{in.Answer, nil}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if !first {
|
||||
t.tsigTimersOnly = true // Subsequent envelopes use this.
|
||||
if isSOALast(in) {
|
||||
c <- &Envelope{in.Answer, nil}
|
||||
return
|
||||
}
|
||||
c <- &Envelope{in.Answer, nil}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transfer) inIxfr(id uint16, c chan *Envelope) {
|
||||
serial := uint32(0) // The first serial seen is the current server serial
|
||||
first := true
|
||||
defer t.Close()
|
||||
defer close(c)
|
||||
timeout := dnsTimeout
|
||||
if t.ReadTimeout != 0 {
|
||||
timeout = t.ReadTimeout
|
||||
}
|
||||
for {
|
||||
t.SetReadDeadline(time.Now().Add(timeout))
|
||||
in, err := t.ReadMsg()
|
||||
if err != nil {
|
||||
c <- &Envelope{nil, err}
|
||||
return
|
||||
}
|
||||
if id != in.Id {
|
||||
c <- &Envelope{in.Answer, ErrId}
|
||||
return
|
||||
}
|
||||
if first {
|
||||
// A single SOA RR signals "no changes"
|
||||
if len(in.Answer) == 1 && isSOAFirst(in) {
|
||||
c <- &Envelope{in.Answer, nil}
|
||||
return
|
||||
}
|
||||
|
||||
// Check if the returned answer is ok
|
||||
if !isSOAFirst(in) {
|
||||
c <- &Envelope{in.Answer, ErrSoa}
|
||||
return
|
||||
}
|
||||
// This serial is important
|
||||
serial = in.Answer[0].(*SOA).Serial
|
||||
first = !first
|
||||
}
|
||||
|
||||
// Now we need to check each message for SOA records, to see what we need to do
|
||||
if !first {
|
||||
t.tsigTimersOnly = true
|
||||
// If the last record in the IXFR contains the servers' SOA, we should quit
|
||||
if v, ok := in.Answer[len(in.Answer)-1].(*SOA); ok {
|
||||
if v.Serial == serial {
|
||||
c <- &Envelope{in.Answer, nil}
|
||||
return
|
||||
}
|
||||
}
|
||||
c <- &Envelope{in.Answer, nil}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Out performs an outgoing transfer with the client connecting in w.
|
||||
// Basic use pattern:
|
||||
//
|
||||
// ch := make(chan *dns.Envelope)
|
||||
// tr := new(dns.Transfer)
|
||||
// tr.Out(w, r, ch)
|
||||
// c <- &dns.Envelope{RR: []dns.RR{soa, rr1, rr2, rr3, soa}}
|
||||
// close(ch)
|
||||
// w.Hijack()
|
||||
// // w.Close() // Client closes connection
|
||||
//
|
||||
// The server is responsible for sending the correct sequence of RRs through the
|
||||
// channel ch.
|
||||
func (t *Transfer) Out(w ResponseWriter, q *Msg, ch chan *Envelope) error {
|
||||
for x := range ch {
|
||||
r := new(Msg)
|
||||
// Compress?
|
||||
r.SetReply(q)
|
||||
r.Authoritative = true
|
||||
// assume it fits TODO(miek): fix
|
||||
r.Answer = append(r.Answer, x.RR...)
|
||||
if err := w.WriteMsg(r); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
w.TsigTimersOnly(true)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadMsg reads a message from the transfer connection t.
|
||||
func (t *Transfer) ReadMsg() (*Msg, error) {
|
||||
m := new(Msg)
|
||||
p := make([]byte, MaxMsgSize)
|
||||
n, err := t.Read(p)
|
||||
if err != nil && n == 0 {
|
||||
return nil, err
|
||||
}
|
||||
p = p[:n]
|
||||
if err := m.Unpack(p); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ts := m.IsTsig(); ts != nil && t.TsigSecret != nil {
|
||||
if _, ok := t.TsigSecret[ts.Hdr.Name]; !ok {
|
||||
return m, ErrSecret
|
||||
}
|
||||
// Need to work on the original message p, as that was used to calculate the tsig.
|
||||
err = TsigVerify(p, t.TsigSecret[ts.Hdr.Name], t.tsigRequestMAC, t.tsigTimersOnly)
|
||||
t.tsigRequestMAC = ts.MAC
|
||||
}
|
||||
return m, err
|
||||
}
|
||||
|
||||
// WriteMsg writes a message through the transfer connection t.
|
||||
func (t *Transfer) WriteMsg(m *Msg) (err error) {
|
||||
var out []byte
|
||||
if ts := m.IsTsig(); ts != nil && t.TsigSecret != nil {
|
||||
if _, ok := t.TsigSecret[ts.Hdr.Name]; !ok {
|
||||
return ErrSecret
|
||||
}
|
||||
out, t.tsigRequestMAC, err = TsigGenerate(m, t.TsigSecret[ts.Hdr.Name], t.tsigRequestMAC, t.tsigTimersOnly)
|
||||
} else {
|
||||
out, err = m.Pack()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = t.Write(out); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isSOAFirst(in *Msg) bool {
|
||||
if len(in.Answer) > 0 {
|
||||
return in.Answer[0].Header().Rrtype == TypeSOA
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isSOALast(in *Msg) bool {
|
||||
if len(in.Answer) > 0 {
|
||||
return in.Answer[len(in.Answer)-1].Header().Rrtype == TypeSOA
|
||||
}
|
||||
return false
|
||||
}
|
158
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/zgenerate.go
generated
vendored
Normal file
158
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/zgenerate.go
generated
vendored
Normal file
|
@ -0,0 +1,158 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Parse the $GENERATE statement as used in BIND9 zones.
|
||||
// See http://www.zytrax.com/books/dns/ch8/generate.html for instance.
|
||||
// We are called after '$GENERATE '. After which we expect:
|
||||
// * the range (12-24/2)
|
||||
// * lhs (ownername)
|
||||
// * [[ttl][class]]
|
||||
// * type
|
||||
// * rhs (rdata)
|
||||
// But we are lazy here, only the range is parsed *all* occurences
|
||||
// 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 {
|
||||
step := 1
|
||||
if i := strings.IndexAny(l.token, "/"); i != -1 {
|
||||
if i+1 == len(l.token) {
|
||||
return "bad step in $GENERATE range"
|
||||
}
|
||||
if s, e := strconv.Atoi(l.token[i+1:]); e == nil {
|
||||
if s < 0 {
|
||||
return "bad step in $GENERATE range"
|
||||
}
|
||||
step = s
|
||||
} else {
|
||||
return "bad step in $GENERATE range"
|
||||
}
|
||||
l.token = l.token[:i]
|
||||
}
|
||||
sx := strings.SplitN(l.token, "-", 2)
|
||||
if len(sx) != 2 {
|
||||
return "bad start-stop in $GENERATE range"
|
||||
}
|
||||
start, err := strconv.Atoi(sx[0])
|
||||
if err != nil {
|
||||
return "bad start in $GENERATE range"
|
||||
}
|
||||
end, err := strconv.Atoi(sx[1])
|
||||
if err != nil {
|
||||
return "bad stop in $GENERATE range"
|
||||
}
|
||||
if end < 0 || start < 0 || end < start {
|
||||
return "bad range in $GENERATE range"
|
||||
}
|
||||
|
||||
<-c // _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 string
|
||||
offset int
|
||||
)
|
||||
|
||||
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 != "" {
|
||||
return err
|
||||
}
|
||||
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, e := NewRR("$ORIGIN " + o + "\n" + dom.String())
|
||||
if e != nil {
|
||||
return e.(*ParseError).err
|
||||
}
|
||||
t <- &Token{RR: rx}
|
||||
// Its more efficient to first built the rrlist and then parse it in
|
||||
// one go! But is this a problem?
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Convert a $GENERATE modifier 0,0,d to something Printf can deal with.
|
||||
func modToPrintf(s string) (string, int, string) {
|
||||
xs := strings.SplitN(s, ",", 3)
|
||||
if len(xs) != 3 {
|
||||
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, "bad base in $GENERATE"
|
||||
}
|
||||
offset, err := strconv.Atoi(xs[0])
|
||||
if err != nil || offset > 255 {
|
||||
return "", 0, "bad offset in $GENERATE"
|
||||
}
|
||||
width, err := strconv.Atoi(xs[1])
|
||||
if err != nil || width > 255 {
|
||||
return "", offset, "bad width in $GENERATE"
|
||||
}
|
||||
switch {
|
||||
case width < 0:
|
||||
return "", offset, "bad width in $GENERATE"
|
||||
case width == 0:
|
||||
return "%" + xs[1] + xs[2], offset, ""
|
||||
}
|
||||
return "%0" + xs[1] + xs[2], offset, ""
|
||||
}
|
974
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/zscan.go
generated
vendored
Normal file
974
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/zscan.go
generated
vendored
Normal file
|
@ -0,0 +1,974 @@
|
|||
package dns
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type debugging bool
|
||||
|
||||
const debug debugging = false
|
||||
|
||||
func (d debugging) Printf(format string, args ...interface{}) {
|
||||
if d {
|
||||
log.Printf(format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
const maxTok = 2048 // Largest token we can return.
|
||||
const maxUint16 = 1<<16 - 1
|
||||
|
||||
// Tokinize a RFC 1035 zone file. The tokenizer will normalize it:
|
||||
// * Add ownernames if they are left blank;
|
||||
// * Suppress sequences of spaces;
|
||||
// * Make each RR fit on one line (_NEWLINE is send as last)
|
||||
// * Handle comments: ;
|
||||
// * Handle braces - anywhere.
|
||||
const (
|
||||
// Zonefile
|
||||
zEOF = iota
|
||||
zString
|
||||
zBlank
|
||||
zQuote
|
||||
zNewline
|
||||
zRrtpe
|
||||
zOwner
|
||||
zClass
|
||||
zDirOrigin // $ORIGIN
|
||||
zDirTtl // $TTL
|
||||
zDirInclude // $INCLUDE
|
||||
zDirGenerate // $GENERATE
|
||||
|
||||
// Privatekey file
|
||||
zValue
|
||||
zKey
|
||||
|
||||
zExpectOwnerDir // Ownername
|
||||
zExpectOwnerBl // Whitespace after the ownername
|
||||
zExpectAny // Expect rrtype, ttl or class
|
||||
zExpectAnyNoClass // Expect rrtype or ttl
|
||||
zExpectAnyNoClassBl // The whitespace after _EXPECT_ANY_NOCLASS
|
||||
zExpectAnyNoTtl // Expect rrtype or class
|
||||
zExpectAnyNoTtlBl // Whitespace after _EXPECT_ANY_NOTTL
|
||||
zExpectRrtype // Expect rrtype
|
||||
zExpectRrtypeBl // Whitespace BEFORE rrtype
|
||||
zExpectRdata // The first element of the rdata
|
||||
zExpectDirTtlBl // Space after directive $TTL
|
||||
zExpectDirTtl // Directive $TTL
|
||||
zExpectDirOriginBl // Space after directive $ORIGIN
|
||||
zExpectDirOrigin // Directive $ORIGIN
|
||||
zExpectDirIncludeBl // Space after directive $INCLUDE
|
||||
zExpectDirInclude // Directive $INCLUDE
|
||||
zExpectDirGenerate // Directive $GENERATE
|
||||
zExpectDirGenerateBl // Space after directive $GENERATE
|
||||
)
|
||||
|
||||
// ParseError is a parsing error. It contains the parse error and the location in the io.Reader
|
||||
// where the error occured.
|
||||
type ParseError struct {
|
||||
file string
|
||||
err string
|
||||
lex lex
|
||||
}
|
||||
|
||||
func (e *ParseError) Error() (s string) {
|
||||
if e.file != "" {
|
||||
s = e.file + ": "
|
||||
}
|
||||
s += "dns: " + e.err + ": " + strconv.QuoteToASCII(e.lex.token) + " at line: " +
|
||||
strconv.Itoa(e.lex.line) + ":" + strconv.Itoa(e.lex.column)
|
||||
return
|
||||
}
|
||||
|
||||
type lex struct {
|
||||
token string // text of the token
|
||||
tokenUpper string // uppercase text of the token
|
||||
length int // lenght of the token
|
||||
err bool // when true, token text has lexer error
|
||||
value uint8 // value: zString, _BLANK, etc.
|
||||
line int // line in the file
|
||||
column int // column in the file
|
||||
torc uint16 // type or class as parsed in the lexer, we only need to look this up in the grammar
|
||||
comment string // any comment text seen
|
||||
}
|
||||
|
||||
// Token holds the token that are returned when a zone file is parsed.
|
||||
type Token struct {
|
||||
// The scanned resource record when error is not nil.
|
||||
RR
|
||||
// When an error occured, this has the error specifics.
|
||||
Error *ParseError
|
||||
// A potential comment positioned after the RR and on the same line.
|
||||
Comment string
|
||||
}
|
||||
|
||||
// NewRR reads the RR contained in the string s. Only the first RR is
|
||||
// returned. If s contains no RR, return nil with no error. The class
|
||||
// defaults to IN and TTL defaults to 3600. The full zone file syntax
|
||||
// like $TTL, $ORIGIN, etc. is supported. All fields of the returned
|
||||
// RR are set, except RR.Header().Rdlength which is set to 0.
|
||||
func NewRR(s string) (RR, error) {
|
||||
if len(s) > 0 && s[len(s)-1] != '\n' { // We need a closing newline
|
||||
return ReadRR(strings.NewReader(s+"\n"), "")
|
||||
}
|
||||
return ReadRR(strings.NewReader(s), "")
|
||||
}
|
||||
|
||||
// ReadRR reads the RR contained in q.
|
||||
// See NewRR for more documentation.
|
||||
func ReadRR(q io.Reader, filename string) (RR, error) {
|
||||
r := <-parseZoneHelper(q, ".", filename, 1)
|
||||
if r == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if r.Error != nil {
|
||||
return nil, r.Error
|
||||
}
|
||||
return r.RR, nil
|
||||
}
|
||||
|
||||
// ParseZone reads a RFC 1035 style zonefile from r. It returns *Tokens on the
|
||||
// returned channel, which consist out the parsed RR, a potential comment or an error.
|
||||
// If there is an error the RR is nil. The string file is only used
|
||||
// in error reporting. The string origin is used as the initial origin, as
|
||||
// if the file would start with: $ORIGIN origin .
|
||||
// The directives $INCLUDE, $ORIGIN, $TTL and $GENERATE are supported.
|
||||
// The channel t is closed by ParseZone when the end of r is reached.
|
||||
//
|
||||
// Basic usage pattern when reading from a string (z) containing the
|
||||
// zone data:
|
||||
//
|
||||
// for x := range dns.ParseZone(strings.NewReader(z), "", "") {
|
||||
// if x.Error != nil {
|
||||
// // log.Println(x.Error)
|
||||
// } else {
|
||||
// // Do something with x.RR
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Comments specified after an RR (and on the same line!) are returned too:
|
||||
//
|
||||
// foo. IN A 10.0.0.1 ; this is a comment
|
||||
//
|
||||
// The text "; this is comment" is returned in Token.Comment. Comments inside the
|
||||
// RR are discarded. Comments on a line by themselves are discarded too.
|
||||
func ParseZone(r io.Reader, origin, file string) chan *Token {
|
||||
return parseZoneHelper(r, origin, file, 10000)
|
||||
}
|
||||
|
||||
func parseZoneHelper(r io.Reader, origin, file string, chansize int) chan *Token {
|
||||
t := make(chan *Token, chansize)
|
||||
go parseZone(r, origin, file, t, 0)
|
||||
return t
|
||||
}
|
||||
|
||||
func parseZone(r io.Reader, origin, f string, t chan *Token, include int) {
|
||||
defer func() {
|
||||
if include == 0 {
|
||||
close(t)
|
||||
}
|
||||
}()
|
||||
s := scanInit(r)
|
||||
c := make(chan lex)
|
||||
// Start the lexer
|
||||
go zlexer(s, c)
|
||||
// 6 possible beginnings of a line, _ is a space
|
||||
// 0. zRRTYPE -> all omitted until the rrtype
|
||||
// 1. zOwner _ zRrtype -> class/ttl omitted
|
||||
// 2. zOwner _ zString _ zRrtype -> class omitted
|
||||
// 3. zOwner _ zString _ zClass _ zRrtype -> ttl/class
|
||||
// 4. zOwner _ zClass _ zRrtype -> ttl omitted
|
||||
// 5. zOwner _ zClass _ zString _ zRrtype -> class/ttl (reversed)
|
||||
// After detecting these, we know the zRrtype so we can jump to functions
|
||||
// handling the rdata for each of these types.
|
||||
|
||||
if origin == "" {
|
||||
origin = "."
|
||||
}
|
||||
origin = Fqdn(origin)
|
||||
if _, ok := IsDomainName(origin); !ok {
|
||||
t <- &Token{Error: &ParseError{f, "bad initial origin name", lex{}}}
|
||||
return
|
||||
}
|
||||
|
||||
st := zExpectOwnerDir // initial state
|
||||
var h RR_Header
|
||||
var defttl uint32 = defaultTtl
|
||||
var prevName string
|
||||
for l := range c {
|
||||
// Lexer spotted an error already
|
||||
if l.err == true {
|
||||
t <- &Token{Error: &ParseError{f, l.token, l}}
|
||||
return
|
||||
|
||||
}
|
||||
switch st {
|
||||
case zExpectOwnerDir:
|
||||
// We can also expect a directive, like $TTL or $ORIGIN
|
||||
h.Ttl = defttl
|
||||
h.Class = ClassINET
|
||||
switch l.value {
|
||||
case zNewline:
|
||||
st = zExpectOwnerDir
|
||||
case zOwner:
|
||||
h.Name = l.token
|
||||
if l.token[0] == '@' {
|
||||
h.Name = origin
|
||||
prevName = h.Name
|
||||
st = zExpectOwnerBl
|
||||
break
|
||||
}
|
||||
if h.Name[l.length-1] != '.' {
|
||||
h.Name = appendOrigin(h.Name, origin)
|
||||
}
|
||||
_, ok := IsDomainName(l.token)
|
||||
if !ok {
|
||||
t <- &Token{Error: &ParseError{f, "bad owner name", l}}
|
||||
return
|
||||
}
|
||||
prevName = h.Name
|
||||
st = zExpectOwnerBl
|
||||
case zDirTtl:
|
||||
st = zExpectDirTtlBl
|
||||
case zDirOrigin:
|
||||
st = zExpectDirOriginBl
|
||||
case zDirInclude:
|
||||
st = zExpectDirIncludeBl
|
||||
case zDirGenerate:
|
||||
st = zExpectDirGenerateBl
|
||||
case zRrtpe:
|
||||
h.Name = prevName
|
||||
h.Rrtype = l.torc
|
||||
st = zExpectRdata
|
||||
case zClass:
|
||||
h.Name = prevName
|
||||
h.Class = l.torc
|
||||
st = zExpectAnyNoClassBl
|
||||
case zBlank:
|
||||
// Discard, can happen when there is nothing on the
|
||||
// line except the RR type
|
||||
case zString:
|
||||
ttl, ok := stringToTtl(l.token)
|
||||
if !ok {
|
||||
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
|
||||
return
|
||||
}
|
||||
h.Ttl = ttl
|
||||
// Don't about the defttl, we should take the $TTL value
|
||||
// defttl = ttl
|
||||
st = zExpectAnyNoTtlBl
|
||||
|
||||
default:
|
||||
t <- &Token{Error: &ParseError{f, "syntax error at beginning", l}}
|
||||
return
|
||||
}
|
||||
case zExpectDirIncludeBl:
|
||||
if l.value != zBlank {
|
||||
t <- &Token{Error: &ParseError{f, "no blank after $INCLUDE-directive", l}}
|
||||
return
|
||||
}
|
||||
st = zExpectDirInclude
|
||||
case zExpectDirInclude:
|
||||
if l.value != zString {
|
||||
t <- &Token{Error: &ParseError{f, "expecting $INCLUDE value, not this...", l}}
|
||||
return
|
||||
}
|
||||
neworigin := origin // There may be optionally a new origin set after the filename, if not use current one
|
||||
l := <-c
|
||||
switch l.value {
|
||||
case zBlank:
|
||||
l := <-c
|
||||
if l.value == zString {
|
||||
if _, ok := IsDomainName(l.token); !ok || l.length == 0 || l.err {
|
||||
t <- &Token{Error: &ParseError{f, "bad origin name", l}}
|
||||
return
|
||||
}
|
||||
// a new origin is specified.
|
||||
if l.token[l.length-1] != '.' {
|
||||
if origin != "." { // Prevent .. endings
|
||||
neworigin = l.token + "." + origin
|
||||
} else {
|
||||
neworigin = l.token + origin
|
||||
}
|
||||
} else {
|
||||
neworigin = l.token
|
||||
}
|
||||
}
|
||||
case zNewline, zEOF:
|
||||
// Ok
|
||||
default:
|
||||
t <- &Token{Error: &ParseError{f, "garbage after $INCLUDE", l}}
|
||||
return
|
||||
}
|
||||
// Start with the new file
|
||||
r1, e1 := os.Open(l.token)
|
||||
if e1 != nil {
|
||||
t <- &Token{Error: &ParseError{f, "failed to open `" + l.token + "'", l}}
|
||||
return
|
||||
}
|
||||
if include+1 > 7 {
|
||||
t <- &Token{Error: &ParseError{f, "too deeply nested $INCLUDE", l}}
|
||||
return
|
||||
}
|
||||
parseZone(r1, l.token, neworigin, t, include+1)
|
||||
st = zExpectOwnerDir
|
||||
case zExpectDirTtlBl:
|
||||
if l.value != zBlank {
|
||||
t <- &Token{Error: &ParseError{f, "no blank after $TTL-directive", l}}
|
||||
return
|
||||
}
|
||||
st = zExpectDirTtl
|
||||
case zExpectDirTtl:
|
||||
if l.value != zString {
|
||||
t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
|
||||
return
|
||||
}
|
||||
if e, _ := slurpRemainder(c, f); e != nil {
|
||||
t <- &Token{Error: e}
|
||||
return
|
||||
}
|
||||
ttl, ok := stringToTtl(l.token)
|
||||
if !ok {
|
||||
t <- &Token{Error: &ParseError{f, "expecting $TTL value, not this...", l}}
|
||||
return
|
||||
}
|
||||
defttl = ttl
|
||||
st = zExpectOwnerDir
|
||||
case zExpectDirOriginBl:
|
||||
if l.value != zBlank {
|
||||
t <- &Token{Error: &ParseError{f, "no blank after $ORIGIN-directive", l}}
|
||||
return
|
||||
}
|
||||
st = zExpectDirOrigin
|
||||
case zExpectDirOrigin:
|
||||
if l.value != zString {
|
||||
t <- &Token{Error: &ParseError{f, "expecting $ORIGIN value, not this...", l}}
|
||||
return
|
||||
}
|
||||
if e, _ := slurpRemainder(c, f); e != nil {
|
||||
t <- &Token{Error: e}
|
||||
}
|
||||
if _, ok := IsDomainName(l.token); !ok {
|
||||
t <- &Token{Error: &ParseError{f, "bad origin name", l}}
|
||||
return
|
||||
}
|
||||
if l.token[l.length-1] != '.' {
|
||||
if origin != "." { // Prevent .. endings
|
||||
origin = l.token + "." + origin
|
||||
} else {
|
||||
origin = l.token + origin
|
||||
}
|
||||
} else {
|
||||
origin = l.token
|
||||
}
|
||||
st = zExpectOwnerDir
|
||||
case zExpectDirGenerateBl:
|
||||
if l.value != zBlank {
|
||||
t <- &Token{Error: &ParseError{f, "no blank after $GENERATE-directive", l}}
|
||||
return
|
||||
}
|
||||
st = zExpectDirGenerate
|
||||
case zExpectDirGenerate:
|
||||
if l.value != zString {
|
||||
t <- &Token{Error: &ParseError{f, "expecting $GENERATE value, not this...", l}}
|
||||
return
|
||||
}
|
||||
if e := generate(l, c, t, origin); e != "" {
|
||||
t <- &Token{Error: &ParseError{f, e, l}}
|
||||
return
|
||||
}
|
||||
st = zExpectOwnerDir
|
||||
case zExpectOwnerBl:
|
||||
if l.value != zBlank {
|
||||
t <- &Token{Error: &ParseError{f, "no blank after owner", l}}
|
||||
return
|
||||
}
|
||||
st = zExpectAny
|
||||
case zExpectAny:
|
||||
switch l.value {
|
||||
case zRrtpe:
|
||||
h.Rrtype = l.torc
|
||||
st = zExpectRdata
|
||||
case zClass:
|
||||
h.Class = l.torc
|
||||
st = zExpectAnyNoClassBl
|
||||
case zString:
|
||||
ttl, ok := stringToTtl(l.token)
|
||||
if !ok {
|
||||
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
|
||||
return
|
||||
}
|
||||
h.Ttl = ttl
|
||||
// defttl = ttl // don't set the defttl here
|
||||
st = zExpectAnyNoTtlBl
|
||||
default:
|
||||
t <- &Token{Error: &ParseError{f, "expecting RR type, TTL or class, not this...", l}}
|
||||
return
|
||||
}
|
||||
case zExpectAnyNoClassBl:
|
||||
if l.value != zBlank {
|
||||
t <- &Token{Error: &ParseError{f, "no blank before class", l}}
|
||||
return
|
||||
}
|
||||
st = zExpectAnyNoClass
|
||||
case zExpectAnyNoTtlBl:
|
||||
if l.value != zBlank {
|
||||
t <- &Token{Error: &ParseError{f, "no blank before TTL", l}}
|
||||
return
|
||||
}
|
||||
st = zExpectAnyNoTtl
|
||||
case zExpectAnyNoTtl:
|
||||
switch l.value {
|
||||
case zClass:
|
||||
h.Class = l.torc
|
||||
st = zExpectRrtypeBl
|
||||
case zRrtpe:
|
||||
h.Rrtype = l.torc
|
||||
st = zExpectRdata
|
||||
default:
|
||||
t <- &Token{Error: &ParseError{f, "expecting RR type or class, not this...", l}}
|
||||
return
|
||||
}
|
||||
case zExpectAnyNoClass:
|
||||
switch l.value {
|
||||
case zString:
|
||||
ttl, ok := stringToTtl(l.token)
|
||||
if !ok {
|
||||
t <- &Token{Error: &ParseError{f, "not a TTL", l}}
|
||||
return
|
||||
}
|
||||
h.Ttl = ttl
|
||||
// defttl = ttl // don't set the def ttl anymore
|
||||
st = zExpectRrtypeBl
|
||||
case zRrtpe:
|
||||
h.Rrtype = l.torc
|
||||
st = zExpectRdata
|
||||
default:
|
||||
t <- &Token{Error: &ParseError{f, "expecting RR type or TTL, not this...", l}}
|
||||
return
|
||||
}
|
||||
case zExpectRrtypeBl:
|
||||
if l.value != zBlank {
|
||||
t <- &Token{Error: &ParseError{f, "no blank before RR type", l}}
|
||||
return
|
||||
}
|
||||
st = zExpectRrtype
|
||||
case zExpectRrtype:
|
||||
if l.value != zRrtpe {
|
||||
t <- &Token{Error: &ParseError{f, "unknown RR type", l}}
|
||||
return
|
||||
}
|
||||
h.Rrtype = l.torc
|
||||
st = zExpectRdata
|
||||
case zExpectRdata:
|
||||
r, e, c1 := setRR(h, c, origin, f)
|
||||
if e != nil {
|
||||
// If e.lex is nil than we have encounter a unknown RR type
|
||||
// in that case we substitute our current lex token
|
||||
if e.lex.token == "" && e.lex.value == 0 {
|
||||
e.lex = l // Uh, dirty
|
||||
}
|
||||
t <- &Token{Error: e}
|
||||
return
|
||||
}
|
||||
t <- &Token{RR: r, Comment: c1}
|
||||
st = zExpectOwnerDir
|
||||
}
|
||||
}
|
||||
// If we get here, we and the h.Rrtype is still zero, we haven't parsed anything, this
|
||||
// is not an error, because an empty zone file is still a zone file.
|
||||
}
|
||||
|
||||
// zlexer scans the sourcefile and returns tokens on the channel c.
|
||||
func zlexer(s *scan, c chan lex) {
|
||||
var l lex
|
||||
str := make([]byte, maxTok) // Should be enough for any token
|
||||
stri := 0 // Offset in str (0 means empty)
|
||||
com := make([]byte, maxTok) // Hold comment text
|
||||
comi := 0
|
||||
quote := false
|
||||
escape := false
|
||||
space := false
|
||||
commt := false
|
||||
rrtype := false
|
||||
owner := true
|
||||
brace := 0
|
||||
x, err := s.tokenText()
|
||||
defer close(c)
|
||||
for err == nil {
|
||||
l.column = s.position.Column
|
||||
l.line = s.position.Line
|
||||
if stri >= maxTok {
|
||||
l.token = "token length insufficient for parsing"
|
||||
l.err = true
|
||||
debug.Printf("[%+v]", l.token)
|
||||
c <- l
|
||||
return
|
||||
}
|
||||
if comi >= maxTok {
|
||||
l.token = "comment length insufficient for parsing"
|
||||
l.err = true
|
||||
debug.Printf("[%+v]", l.token)
|
||||
c <- l
|
||||
return
|
||||
}
|
||||
|
||||
switch x {
|
||||
case ' ', '\t':
|
||||
if escape {
|
||||
escape = false
|
||||
str[stri] = x
|
||||
stri++
|
||||
break
|
||||
}
|
||||
if quote {
|
||||
// Inside quotes this is legal
|
||||
str[stri] = x
|
||||
stri++
|
||||
break
|
||||
}
|
||||
if commt {
|
||||
com[comi] = x
|
||||
comi++
|
||||
break
|
||||
}
|
||||
if stri == 0 {
|
||||
// Space directly in the beginning, handled in the grammar
|
||||
} else if owner {
|
||||
// If we have a string and its the first, make it an owner
|
||||
l.value = zOwner
|
||||
l.token = string(str[:stri])
|
||||
l.tokenUpper = strings.ToUpper(l.token)
|
||||
l.length = stri
|
||||
// escape $... start with a \ not a $, so this will work
|
||||
switch l.tokenUpper {
|
||||
case "$TTL":
|
||||
l.value = zDirTtl
|
||||
case "$ORIGIN":
|
||||
l.value = zDirOrigin
|
||||
case "$INCLUDE":
|
||||
l.value = zDirInclude
|
||||
case "$GENERATE":
|
||||
l.value = zDirGenerate
|
||||
}
|
||||
debug.Printf("[7 %+v]", l.token)
|
||||
c <- l
|
||||
} else {
|
||||
l.value = zString
|
||||
l.token = string(str[:stri])
|
||||
l.tokenUpper = strings.ToUpper(l.token)
|
||||
l.length = stri
|
||||
if !rrtype {
|
||||
if t, ok := StringToType[l.tokenUpper]; ok {
|
||||
l.value = zRrtpe
|
||||
l.torc = t
|
||||
rrtype = true
|
||||
} else {
|
||||
if strings.HasPrefix(l.tokenUpper, "TYPE") {
|
||||
t, ok := typeToInt(l.token)
|
||||
if !ok {
|
||||
l.token = "unknown RR type"
|
||||
l.err = true
|
||||
c <- l
|
||||
return
|
||||
}
|
||||
l.value = zRrtpe
|
||||
l.torc = t
|
||||
}
|
||||
}
|
||||
if t, ok := StringToClass[l.tokenUpper]; ok {
|
||||
l.value = zClass
|
||||
l.torc = t
|
||||
} else {
|
||||
if strings.HasPrefix(l.tokenUpper, "CLASS") {
|
||||
t, ok := classToInt(l.token)
|
||||
if !ok {
|
||||
l.token = "unknown class"
|
||||
l.err = true
|
||||
c <- l
|
||||
return
|
||||
}
|
||||
l.value = zClass
|
||||
l.torc = t
|
||||
}
|
||||
}
|
||||
}
|
||||
debug.Printf("[6 %+v]", l.token)
|
||||
c <- l
|
||||
}
|
||||
stri = 0
|
||||
// I reverse space stuff here
|
||||
if !space && !commt {
|
||||
l.value = zBlank
|
||||
l.token = " "
|
||||
l.length = 1
|
||||
debug.Printf("[5 %+v]", l.token)
|
||||
c <- l
|
||||
}
|
||||
owner = false
|
||||
space = true
|
||||
case ';':
|
||||
if escape {
|
||||
escape = false
|
||||
str[stri] = x
|
||||
stri++
|
||||
break
|
||||
}
|
||||
if quote {
|
||||
// Inside quotes this is legal
|
||||
str[stri] = x
|
||||
stri++
|
||||
break
|
||||
}
|
||||
if stri > 0 {
|
||||
l.value = zString
|
||||
l.token = string(str[:stri])
|
||||
l.length = stri
|
||||
debug.Printf("[4 %+v]", l.token)
|
||||
c <- l
|
||||
stri = 0
|
||||
}
|
||||
commt = true
|
||||
com[comi] = ';'
|
||||
comi++
|
||||
case '\r':
|
||||
escape = false
|
||||
if quote {
|
||||
str[stri] = x
|
||||
stri++
|
||||
break
|
||||
}
|
||||
// discard if outside of quotes
|
||||
case '\n':
|
||||
escape = false
|
||||
// Escaped newline
|
||||
if quote {
|
||||
str[stri] = x
|
||||
stri++
|
||||
break
|
||||
}
|
||||
// inside quotes this is legal
|
||||
if commt {
|
||||
// Reset a comment
|
||||
commt = false
|
||||
rrtype = false
|
||||
stri = 0
|
||||
// If not in a brace this ends the comment AND the RR
|
||||
if brace == 0 {
|
||||
owner = true
|
||||
owner = true
|
||||
l.value = zNewline
|
||||
l.token = "\n"
|
||||
l.length = 1
|
||||
l.comment = string(com[:comi])
|
||||
debug.Printf("[3 %+v %+v]", l.token, l.comment)
|
||||
c <- l
|
||||
l.comment = ""
|
||||
comi = 0
|
||||
break
|
||||
}
|
||||
com[comi] = ' ' // convert newline to space
|
||||
comi++
|
||||
break
|
||||
}
|
||||
|
||||
if brace == 0 {
|
||||
// If there is previous text, we should output it here
|
||||
if stri != 0 {
|
||||
l.value = zString
|
||||
l.token = string(str[:stri])
|
||||
l.tokenUpper = strings.ToUpper(l.token)
|
||||
|
||||
l.length = stri
|
||||
if !rrtype {
|
||||
if t, ok := StringToType[l.tokenUpper]; ok {
|
||||
l.value = zRrtpe
|
||||
l.torc = t
|
||||
rrtype = true
|
||||
}
|
||||
}
|
||||
debug.Printf("[2 %+v]", l.token)
|
||||
c <- l
|
||||
}
|
||||
l.value = zNewline
|
||||
l.token = "\n"
|
||||
l.length = 1
|
||||
debug.Printf("[1 %+v]", l.token)
|
||||
c <- l
|
||||
stri = 0
|
||||
commt = false
|
||||
rrtype = false
|
||||
owner = true
|
||||
comi = 0
|
||||
}
|
||||
case '\\':
|
||||
// comments do not get escaped chars, everything is copied
|
||||
if commt {
|
||||
com[comi] = x
|
||||
comi++
|
||||
break
|
||||
}
|
||||
// something already escaped must be in string
|
||||
if escape {
|
||||
str[stri] = x
|
||||
stri++
|
||||
escape = false
|
||||
break
|
||||
}
|
||||
// something escaped outside of string gets added to string
|
||||
str[stri] = x
|
||||
stri++
|
||||
escape = true
|
||||
case '"':
|
||||
if commt {
|
||||
com[comi] = x
|
||||
comi++
|
||||
break
|
||||
}
|
||||
if escape {
|
||||
str[stri] = x
|
||||
stri++
|
||||
escape = false
|
||||
break
|
||||
}
|
||||
space = false
|
||||
// send previous gathered text and the quote
|
||||
if stri != 0 {
|
||||
l.value = zString
|
||||
l.token = string(str[:stri])
|
||||
l.length = stri
|
||||
|
||||
debug.Printf("[%+v]", l.token)
|
||||
c <- l
|
||||
stri = 0
|
||||
}
|
||||
|
||||
// send quote itself as separate token
|
||||
l.value = zQuote
|
||||
l.token = "\""
|
||||
l.length = 1
|
||||
c <- l
|
||||
quote = !quote
|
||||
case '(', ')':
|
||||
if commt {
|
||||
com[comi] = x
|
||||
comi++
|
||||
break
|
||||
}
|
||||
if escape {
|
||||
str[stri] = x
|
||||
stri++
|
||||
escape = false
|
||||
break
|
||||
}
|
||||
if quote {
|
||||
str[stri] = x
|
||||
stri++
|
||||
break
|
||||
}
|
||||
switch x {
|
||||
case ')':
|
||||
brace--
|
||||
if brace < 0 {
|
||||
l.token = "extra closing brace"
|
||||
l.err = true
|
||||
debug.Printf("[%+v]", l.token)
|
||||
c <- l
|
||||
return
|
||||
}
|
||||
case '(':
|
||||
brace++
|
||||
}
|
||||
default:
|
||||
escape = false
|
||||
if commt {
|
||||
com[comi] = x
|
||||
comi++
|
||||
break
|
||||
}
|
||||
str[stri] = x
|
||||
stri++
|
||||
space = false
|
||||
}
|
||||
x, err = s.tokenText()
|
||||
}
|
||||
if stri > 0 {
|
||||
// Send remainder
|
||||
l.token = string(str[:stri])
|
||||
l.length = stri
|
||||
l.value = zString
|
||||
debug.Printf("[%+v]", l.token)
|
||||
c <- l
|
||||
}
|
||||
}
|
||||
|
||||
// Extract the class number from CLASSxx
|
||||
func classToInt(token string) (uint16, bool) {
|
||||
offset := 5
|
||||
if len(token) < offset+1 {
|
||||
return 0, false
|
||||
}
|
||||
class, ok := strconv.Atoi(token[offset:])
|
||||
if ok != nil || class > maxUint16 {
|
||||
return 0, false
|
||||
}
|
||||
return uint16(class), true
|
||||
}
|
||||
|
||||
// Extract the rr number from TYPExxx
|
||||
func typeToInt(token string) (uint16, bool) {
|
||||
offset := 4
|
||||
if len(token) < offset+1 {
|
||||
return 0, false
|
||||
}
|
||||
typ, ok := strconv.Atoi(token[offset:])
|
||||
if ok != nil || typ > maxUint16 {
|
||||
return 0, false
|
||||
}
|
||||
return uint16(typ), true
|
||||
}
|
||||
|
||||
// Parse things like 2w, 2m, etc, Return the time in seconds.
|
||||
func stringToTtl(token string) (uint32, bool) {
|
||||
s := uint32(0)
|
||||
i := uint32(0)
|
||||
for _, c := range token {
|
||||
switch c {
|
||||
case 's', 'S':
|
||||
s += i
|
||||
i = 0
|
||||
case 'm', 'M':
|
||||
s += i * 60
|
||||
i = 0
|
||||
case 'h', 'H':
|
||||
s += i * 60 * 60
|
||||
i = 0
|
||||
case 'd', 'D':
|
||||
s += i * 60 * 60 * 24
|
||||
i = 0
|
||||
case 'w', 'W':
|
||||
s += i * 60 * 60 * 24 * 7
|
||||
i = 0
|
||||
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
|
||||
i *= 10
|
||||
i += uint32(c) - '0'
|
||||
default:
|
||||
return 0, false
|
||||
}
|
||||
}
|
||||
return s + i, true
|
||||
}
|
||||
|
||||
// Parse LOC records' <digits>[.<digits>][mM] into a
|
||||
// mantissa exponent format. Token should contain the entire
|
||||
// string (i.e. no spaces allowed)
|
||||
func stringToCm(token string) (e, m uint8, ok bool) {
|
||||
if token[len(token)-1] == 'M' || token[len(token)-1] == 'm' {
|
||||
token = token[0 : len(token)-1]
|
||||
}
|
||||
s := strings.SplitN(token, ".", 2)
|
||||
var meters, cmeters, val int
|
||||
var err error
|
||||
switch len(s) {
|
||||
case 2:
|
||||
if cmeters, err = strconv.Atoi(s[1]); err != nil {
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 1:
|
||||
if meters, err = strconv.Atoi(s[0]); err != nil {
|
||||
return
|
||||
}
|
||||
case 0:
|
||||
// huh?
|
||||
return 0, 0, false
|
||||
}
|
||||
ok = true
|
||||
if meters > 0 {
|
||||
e = 2
|
||||
val = meters
|
||||
} else {
|
||||
e = 0
|
||||
val = cmeters
|
||||
}
|
||||
for val > 10 {
|
||||
e++
|
||||
val /= 10
|
||||
}
|
||||
if e > 9 {
|
||||
ok = false
|
||||
}
|
||||
m = uint8(val)
|
||||
return
|
||||
}
|
||||
|
||||
func appendOrigin(name, origin string) string {
|
||||
if origin == "." {
|
||||
return name + origin
|
||||
}
|
||||
return name + "." + origin
|
||||
}
|
||||
|
||||
// LOC record helper function
|
||||
func locCheckNorth(token string, latitude uint32) (uint32, bool) {
|
||||
switch token {
|
||||
case "n", "N":
|
||||
return LOC_EQUATOR + latitude, true
|
||||
case "s", "S":
|
||||
return LOC_EQUATOR - latitude, true
|
||||
}
|
||||
return latitude, false
|
||||
}
|
||||
|
||||
// LOC record helper function
|
||||
func locCheckEast(token string, longitude uint32) (uint32, bool) {
|
||||
switch token {
|
||||
case "e", "E":
|
||||
return LOC_EQUATOR + longitude, true
|
||||
case "w", "W":
|
||||
return LOC_EQUATOR - longitude, true
|
||||
}
|
||||
return longitude, false
|
||||
}
|
||||
|
||||
// "Eat" the rest of the "line". Return potential comments
|
||||
func slurpRemainder(c chan lex, f string) (*ParseError, string) {
|
||||
l := <-c
|
||||
com := ""
|
||||
switch l.value {
|
||||
case zBlank:
|
||||
l = <-c
|
||||
com = l.comment
|
||||
if l.value != zNewline && l.value != zEOF {
|
||||
return &ParseError{f, "garbage after rdata", l}, ""
|
||||
}
|
||||
case zNewline:
|
||||
com = l.comment
|
||||
case zEOF:
|
||||
default:
|
||||
return &ParseError{f, "garbage after rdata", l}, ""
|
||||
}
|
||||
return nil, com
|
||||
}
|
||||
|
||||
// Parse a 64 bit-like ipv6 address: "0014:4fff:ff20:ee64"
|
||||
// Used for NID and L64 record.
|
||||
func stringToNodeID(l lex) (uint64, *ParseError) {
|
||||
if len(l.token) < 19 {
|
||||
return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l}
|
||||
}
|
||||
// There must be three colons at fixes postitions, if not its a parse error
|
||||
if l.token[4] != ':' && l.token[9] != ':' && l.token[14] != ':' {
|
||||
return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l}
|
||||
}
|
||||
s := l.token[0:4] + l.token[5:9] + l.token[10:14] + l.token[15:19]
|
||||
u, e := strconv.ParseUint(s, 16, 64)
|
||||
if e != nil {
|
||||
return 0, &ParseError{l.token, "bad NID/L64 NodeID/Locator64", l}
|
||||
}
|
||||
return u, nil
|
||||
}
|
2270
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/zscan_rr.go
generated
vendored
Normal file
2270
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/zscan_rr.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
842
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/ztypes.go
generated
vendored
Normal file
842
libnetwork/Godeps/_workspace/src/github.com/miekg/dns/ztypes.go
generated
vendored
Normal file
|
@ -0,0 +1,842 @@
|
|||
// *** DO NOT MODIFY ***
|
||||
// AUTOGENERATED BY go generate
|
||||
|
||||
package dns
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"net"
|
||||
)
|
||||
|
||||
// TypeToRR is a map of constructors for each RR type.
|
||||
var TypeToRR = map[uint16]func() RR{
|
||||
TypeA: func() RR { return new(A) },
|
||||
TypeAAAA: func() RR { return new(AAAA) },
|
||||
TypeAFSDB: func() RR { return new(AFSDB) },
|
||||
TypeANY: func() RR { return new(ANY) },
|
||||
TypeCAA: func() RR { return new(CAA) },
|
||||
TypeCDNSKEY: func() RR { return new(CDNSKEY) },
|
||||
TypeCDS: func() RR { return new(CDS) },
|
||||
TypeCERT: func() RR { return new(CERT) },
|
||||
TypeCNAME: func() RR { return new(CNAME) },
|
||||
TypeDHCID: func() RR { return new(DHCID) },
|
||||
TypeDLV: func() RR { return new(DLV) },
|
||||
TypeDNAME: func() RR { return new(DNAME) },
|
||||
TypeDNSKEY: func() RR { return new(DNSKEY) },
|
||||
TypeDS: func() RR { return new(DS) },
|
||||
TypeEID: func() RR { return new(EID) },
|
||||
TypeEUI48: func() RR { return new(EUI48) },
|
||||
TypeEUI64: func() RR { return new(EUI64) },
|
||||
TypeGID: func() RR { return new(GID) },
|
||||
TypeGPOS: func() RR { return new(GPOS) },
|
||||
TypeHINFO: func() RR { return new(HINFO) },
|
||||
TypeHIP: func() RR { return new(HIP) },
|
||||
TypeIPSECKEY: func() RR { return new(IPSECKEY) },
|
||||
TypeKEY: func() RR { return new(KEY) },
|
||||
TypeKX: func() RR { return new(KX) },
|
||||
TypeL32: func() RR { return new(L32) },
|
||||
TypeL64: func() RR { return new(L64) },
|
||||
TypeLOC: func() RR { return new(LOC) },
|
||||
TypeLP: func() RR { return new(LP) },
|
||||
TypeMB: func() RR { return new(MB) },
|
||||
TypeMD: func() RR { return new(MD) },
|
||||
TypeMF: func() RR { return new(MF) },
|
||||
TypeMG: func() RR { return new(MG) },
|
||||
TypeMINFO: func() RR { return new(MINFO) },
|
||||
TypeMR: func() RR { return new(MR) },
|
||||
TypeMX: func() RR { return new(MX) },
|
||||
TypeNAPTR: func() RR { return new(NAPTR) },
|
||||
TypeNID: func() RR { return new(NID) },
|
||||
TypeNIMLOC: func() RR { return new(NIMLOC) },
|
||||
TypeNINFO: func() RR { return new(NINFO) },
|
||||
TypeNS: func() RR { return new(NS) },
|
||||
TypeNSAPPTR: func() RR { return new(NSAPPTR) },
|
||||
TypeNSEC: func() RR { return new(NSEC) },
|
||||
TypeNSEC3: func() RR { return new(NSEC3) },
|
||||
TypeNSEC3PARAM: func() RR { return new(NSEC3PARAM) },
|
||||
TypeOPENPGPKEY: func() RR { return new(OPENPGPKEY) },
|
||||
TypeOPT: func() RR { return new(OPT) },
|
||||
TypePTR: func() RR { return new(PTR) },
|
||||
TypePX: func() RR { return new(PX) },
|
||||
TypeRKEY: func() RR { return new(RKEY) },
|
||||
TypeRP: func() RR { return new(RP) },
|
||||
TypeRRSIG: func() RR { return new(RRSIG) },
|
||||
TypeRT: func() RR { return new(RT) },
|
||||
TypeSIG: func() RR { return new(SIG) },
|
||||
TypeSOA: func() RR { return new(SOA) },
|
||||
TypeSPF: func() RR { return new(SPF) },
|
||||
TypeSRV: func() RR { return new(SRV) },
|
||||
TypeSSHFP: func() RR { return new(SSHFP) },
|
||||
TypeTA: func() RR { return new(TA) },
|
||||
TypeTALINK: func() RR { return new(TALINK) },
|
||||
TypeTKEY: func() RR { return new(TKEY) },
|
||||
TypeTLSA: func() RR { return new(TLSA) },
|
||||
TypeTSIG: func() RR { return new(TSIG) },
|
||||
TypeTXT: func() RR { return new(TXT) },
|
||||
TypeUID: func() RR { return new(UID) },
|
||||
TypeUINFO: func() RR { return new(UINFO) },
|
||||
TypeURI: func() RR { return new(URI) },
|
||||
TypeWKS: func() RR { return new(WKS) },
|
||||
TypeX25: func() RR { return new(X25) },
|
||||
}
|
||||
|
||||
// TypeToString is a map of strings for each RR type.
|
||||
var TypeToString = map[uint16]string{
|
||||
TypeA: "A",
|
||||
TypeAAAA: "AAAA",
|
||||
TypeAFSDB: "AFSDB",
|
||||
TypeANY: "ANY",
|
||||
TypeATMA: "ATMA",
|
||||
TypeAXFR: "AXFR",
|
||||
TypeCAA: "CAA",
|
||||
TypeCDNSKEY: "CDNSKEY",
|
||||
TypeCDS: "CDS",
|
||||
TypeCERT: "CERT",
|
||||
TypeCNAME: "CNAME",
|
||||
TypeDHCID: "DHCID",
|
||||
TypeDLV: "DLV",
|
||||
TypeDNAME: "DNAME",
|
||||
TypeDNSKEY: "DNSKEY",
|
||||
TypeDS: "DS",
|
||||
TypeEID: "EID",
|
||||
TypeEUI48: "EUI48",
|
||||
TypeEUI64: "EUI64",
|
||||
TypeGID: "GID",
|
||||
TypeGPOS: "GPOS",
|
||||
TypeHINFO: "HINFO",
|
||||
TypeHIP: "HIP",
|
||||
TypeIPSECKEY: "IPSECKEY",
|
||||
TypeISDN: "ISDN",
|
||||
TypeIXFR: "IXFR",
|
||||
TypeKEY: "KEY",
|
||||
TypeKX: "KX",
|
||||
TypeL32: "L32",
|
||||
TypeL64: "L64",
|
||||
TypeLOC: "LOC",
|
||||
TypeLP: "LP",
|
||||
TypeMAILA: "MAILA",
|
||||
TypeMAILB: "MAILB",
|
||||
TypeMB: "MB",
|
||||
TypeMD: "MD",
|
||||
TypeMF: "MF",
|
||||
TypeMG: "MG",
|
||||
TypeMINFO: "MINFO",
|
||||
TypeMR: "MR",
|
||||
TypeMX: "MX",
|
||||
TypeNAPTR: "NAPTR",
|
||||
TypeNID: "NID",
|
||||
TypeNIMLOC: "NIMLOC",
|
||||
TypeNINFO: "NINFO",
|
||||
TypeNS: "NS",
|
||||
TypeNSEC: "NSEC",
|
||||
TypeNSEC3: "NSEC3",
|
||||
TypeNSEC3PARAM: "NSEC3PARAM",
|
||||
TypeNULL: "NULL",
|
||||
TypeNXT: "NXT",
|
||||
TypeNone: "None",
|
||||
TypeOPENPGPKEY: "OPENPGPKEY",
|
||||
TypeOPT: "OPT",
|
||||
TypePTR: "PTR",
|
||||
TypePX: "PX",
|
||||
TypeRKEY: "RKEY",
|
||||
TypeRP: "RP",
|
||||
TypeRRSIG: "RRSIG",
|
||||
TypeRT: "RT",
|
||||
TypeReserved: "Reserved",
|
||||
TypeSIG: "SIG",
|
||||
TypeSOA: "SOA",
|
||||
TypeSPF: "SPF",
|
||||
TypeSRV: "SRV",
|
||||
TypeSSHFP: "SSHFP",
|
||||
TypeTA: "TA",
|
||||
TypeTALINK: "TALINK",
|
||||
TypeTKEY: "TKEY",
|
||||
TypeTLSA: "TLSA",
|
||||
TypeTSIG: "TSIG",
|
||||
TypeTXT: "TXT",
|
||||
TypeUID: "UID",
|
||||
TypeUINFO: "UINFO",
|
||||
TypeUNSPEC: "UNSPEC",
|
||||
TypeURI: "URI",
|
||||
TypeWKS: "WKS",
|
||||
TypeX25: "X25",
|
||||
TypeNSAPPTR: "NSAP-PTR",
|
||||
}
|
||||
|
||||
// Header() functions
|
||||
func (rr *A) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *AAAA) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *AFSDB) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *ANY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *CAA) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *CDNSKEY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *CDS) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *CERT) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *CNAME) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *DHCID) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *DLV) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *DNAME) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *DNSKEY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *DS) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *EID) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *EUI48) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *EUI64) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *GID) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *GPOS) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *HINFO) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *HIP) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *IPSECKEY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *KEY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *KX) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *L32) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *L64) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *LOC) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *LP) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *MB) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *MD) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *MF) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *MG) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *MINFO) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *MR) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *MX) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NAPTR) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NID) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NIMLOC) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NINFO) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NS) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NSAPPTR) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NSEC) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NSEC3) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *NSEC3PARAM) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *OPENPGPKEY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *OPT) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *PTR) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *PX) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *RFC3597) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *RKEY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *RP) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *RRSIG) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *RT) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *SIG) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *SOA) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *SPF) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *SRV) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *SSHFP) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *TA) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *TALINK) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *TKEY) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *TLSA) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *TSIG) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *TXT) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *UID) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *UINFO) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *URI) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *WKS) Header() *RR_Header { return &rr.Hdr }
|
||||
func (rr *X25) Header() *RR_Header { return &rr.Hdr }
|
||||
|
||||
// len() functions
|
||||
func (rr *A) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += net.IPv4len // A
|
||||
return l
|
||||
}
|
||||
func (rr *AAAA) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += net.IPv6len // AAAA
|
||||
return l
|
||||
}
|
||||
func (rr *AFSDB) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Subtype
|
||||
l += len(rr.Hostname) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *ANY) len() int {
|
||||
l := rr.Hdr.len()
|
||||
return l
|
||||
}
|
||||
func (rr *CAA) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 1 // Flag
|
||||
l += len(rr.Tag) + 1
|
||||
l += len(rr.Value)
|
||||
return l
|
||||
}
|
||||
func (rr *CERT) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Type
|
||||
l += 2 // KeyTag
|
||||
l += 1 // Algorithm
|
||||
l += base64.StdEncoding.DecodedLen(len(rr.Certificate))
|
||||
return l
|
||||
}
|
||||
func (rr *CNAME) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Target) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *DHCID) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += base64.StdEncoding.DecodedLen(len(rr.Digest))
|
||||
return l
|
||||
}
|
||||
func (rr *DNAME) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Target) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *DNSKEY) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Flags
|
||||
l += 1 // Protocol
|
||||
l += 1 // Algorithm
|
||||
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||
return l
|
||||
}
|
||||
func (rr *DS) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // KeyTag
|
||||
l += 1 // Algorithm
|
||||
l += 1 // DigestType
|
||||
l += len(rr.Digest)/2 + 1
|
||||
return l
|
||||
}
|
||||
func (rr *EID) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Endpoint)/2 + 1
|
||||
return l
|
||||
}
|
||||
func (rr *EUI48) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 6 // Address
|
||||
return l
|
||||
}
|
||||
func (rr *EUI64) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 8 // Address
|
||||
return l
|
||||
}
|
||||
func (rr *GID) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 4 // Gid
|
||||
return l
|
||||
}
|
||||
func (rr *GPOS) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Longitude) + 1
|
||||
l += len(rr.Latitude) + 1
|
||||
l += len(rr.Altitude) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *HINFO) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Cpu) + 1
|
||||
l += len(rr.Os) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *HIP) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 1 // HitLength
|
||||
l += 1 // PublicKeyAlgorithm
|
||||
l += 2 // PublicKeyLength
|
||||
l += len(rr.Hit)/2 + 1
|
||||
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||
for _, x := range rr.RendezvousServers {
|
||||
l += len(x) + 1
|
||||
}
|
||||
return l
|
||||
}
|
||||
func (rr *KX) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Preference
|
||||
l += len(rr.Exchanger) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *L32) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Preference
|
||||
l += net.IPv4len // Locator32
|
||||
return l
|
||||
}
|
||||
func (rr *L64) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Preference
|
||||
l += 8 // Locator64
|
||||
return l
|
||||
}
|
||||
func (rr *LOC) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 1 // Version
|
||||
l += 1 // Size
|
||||
l += 1 // HorizPre
|
||||
l += 1 // VertPre
|
||||
l += 4 // Latitude
|
||||
l += 4 // Longitude
|
||||
l += 4 // Altitude
|
||||
return l
|
||||
}
|
||||
func (rr *LP) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Preference
|
||||
l += len(rr.Fqdn) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *MB) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Mb) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *MD) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Md) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *MF) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Mf) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *MG) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Mg) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *MINFO) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Rmail) + 1
|
||||
l += len(rr.Email) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *MR) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Mr) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *MX) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Preference
|
||||
l += len(rr.Mx) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *NAPTR) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Order
|
||||
l += 2 // Preference
|
||||
l += len(rr.Flags) + 1
|
||||
l += len(rr.Service) + 1
|
||||
l += len(rr.Regexp) + 1
|
||||
l += len(rr.Replacement) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *NID) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Preference
|
||||
l += 8 // NodeID
|
||||
return l
|
||||
}
|
||||
func (rr *NIMLOC) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Locator)/2 + 1
|
||||
return l
|
||||
}
|
||||
func (rr *NINFO) len() int {
|
||||
l := rr.Hdr.len()
|
||||
for _, x := range rr.ZSData {
|
||||
l += len(x) + 1
|
||||
}
|
||||
return l
|
||||
}
|
||||
func (rr *NS) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Ns) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *NSAPPTR) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Ptr) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *NSEC3PARAM) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 1 // Hash
|
||||
l += 1 // Flags
|
||||
l += 2 // Iterations
|
||||
l += 1 // SaltLength
|
||||
l += len(rr.Salt)/2 + 1
|
||||
return l
|
||||
}
|
||||
func (rr *OPENPGPKEY) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||
return l
|
||||
}
|
||||
func (rr *PTR) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Ptr) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *PX) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Preference
|
||||
l += len(rr.Map822) + 1
|
||||
l += len(rr.Mapx400) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *RFC3597) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Rdata)/2 + 1
|
||||
return l
|
||||
}
|
||||
func (rr *RKEY) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Flags
|
||||
l += 1 // Protocol
|
||||
l += 1 // Algorithm
|
||||
l += base64.StdEncoding.DecodedLen(len(rr.PublicKey))
|
||||
return l
|
||||
}
|
||||
func (rr *RP) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Mbox) + 1
|
||||
l += len(rr.Txt) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *RRSIG) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // TypeCovered
|
||||
l += 1 // Algorithm
|
||||
l += 1 // Labels
|
||||
l += 4 // OrigTtl
|
||||
l += 4 // Expiration
|
||||
l += 4 // Inception
|
||||
l += 2 // KeyTag
|
||||
l += len(rr.SignerName) + 1
|
||||
l += base64.StdEncoding.DecodedLen(len(rr.Signature))
|
||||
return l
|
||||
}
|
||||
func (rr *RT) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Preference
|
||||
l += len(rr.Host) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *SOA) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Ns) + 1
|
||||
l += len(rr.Mbox) + 1
|
||||
l += 4 // Serial
|
||||
l += 4 // Refresh
|
||||
l += 4 // Retry
|
||||
l += 4 // Expire
|
||||
l += 4 // Minttl
|
||||
return l
|
||||
}
|
||||
func (rr *SPF) len() int {
|
||||
l := rr.Hdr.len()
|
||||
for _, x := range rr.Txt {
|
||||
l += len(x) + 1
|
||||
}
|
||||
return l
|
||||
}
|
||||
func (rr *SRV) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Priority
|
||||
l += 2 // Weight
|
||||
l += 2 // Port
|
||||
l += len(rr.Target) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *SSHFP) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 1 // Algorithm
|
||||
l += 1 // Type
|
||||
l += len(rr.FingerPrint)/2 + 1
|
||||
return l
|
||||
}
|
||||
func (rr *TA) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // KeyTag
|
||||
l += 1 // Algorithm
|
||||
l += 1 // DigestType
|
||||
l += len(rr.Digest)/2 + 1
|
||||
return l
|
||||
}
|
||||
func (rr *TALINK) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.PreviousName) + 1
|
||||
l += len(rr.NextName) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *TKEY) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Algorithm) + 1
|
||||
l += 4 // Inception
|
||||
l += 4 // Expiration
|
||||
l += 2 // Mode
|
||||
l += 2 // Error
|
||||
l += 2 // KeySize
|
||||
l += len(rr.Key) + 1
|
||||
l += 2 // OtherLen
|
||||
l += len(rr.OtherData) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *TLSA) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 1 // Usage
|
||||
l += 1 // Selector
|
||||
l += 1 // MatchingType
|
||||
l += len(rr.Certificate)/2 + 1
|
||||
return l
|
||||
}
|
||||
func (rr *TSIG) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Algorithm) + 1
|
||||
l += 6 // TimeSigned
|
||||
l += 2 // Fudge
|
||||
l += 2 // MACSize
|
||||
l += len(rr.MAC)/2 + 1
|
||||
l += 2 // OrigId
|
||||
l += 2 // Error
|
||||
l += 2 // OtherLen
|
||||
l += len(rr.OtherData)/2 + 1
|
||||
return l
|
||||
}
|
||||
func (rr *TXT) len() int {
|
||||
l := rr.Hdr.len()
|
||||
for _, x := range rr.Txt {
|
||||
l += len(x) + 1
|
||||
}
|
||||
return l
|
||||
}
|
||||
func (rr *UID) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 4 // Uid
|
||||
return l
|
||||
}
|
||||
func (rr *UINFO) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.Uinfo) + 1
|
||||
return l
|
||||
}
|
||||
func (rr *URI) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += 2 // Priority
|
||||
l += 2 // Weight
|
||||
l += len(rr.Target)
|
||||
return l
|
||||
}
|
||||
func (rr *X25) len() int {
|
||||
l := rr.Hdr.len()
|
||||
l += len(rr.PSDNAddress) + 1
|
||||
return l
|
||||
}
|
||||
|
||||
// copy() functions
|
||||
func (rr *A) copy() RR {
|
||||
return &A{*rr.Hdr.copyHeader(), copyIP(rr.A)}
|
||||
}
|
||||
func (rr *AAAA) copy() RR {
|
||||
return &AAAA{*rr.Hdr.copyHeader(), copyIP(rr.AAAA)}
|
||||
}
|
||||
func (rr *AFSDB) copy() RR {
|
||||
return &AFSDB{*rr.Hdr.copyHeader(), rr.Subtype, rr.Hostname}
|
||||
}
|
||||
func (rr *ANY) copy() RR {
|
||||
return &ANY{*rr.Hdr.copyHeader()}
|
||||
}
|
||||
func (rr *CAA) copy() RR {
|
||||
return &CAA{*rr.Hdr.copyHeader(), rr.Flag, rr.Tag, rr.Value}
|
||||
}
|
||||
func (rr *CERT) copy() RR {
|
||||
return &CERT{*rr.Hdr.copyHeader(), rr.Type, rr.KeyTag, rr.Algorithm, rr.Certificate}
|
||||
}
|
||||
func (rr *CNAME) copy() RR {
|
||||
return &CNAME{*rr.Hdr.copyHeader(), rr.Target}
|
||||
}
|
||||
func (rr *DHCID) copy() RR {
|
||||
return &DHCID{*rr.Hdr.copyHeader(), rr.Digest}
|
||||
}
|
||||
func (rr *DNAME) copy() RR {
|
||||
return &DNAME{*rr.Hdr.copyHeader(), rr.Target}
|
||||
}
|
||||
func (rr *DNSKEY) copy() RR {
|
||||
return &DNSKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
|
||||
}
|
||||
func (rr *DS) copy() RR {
|
||||
return &DS{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
|
||||
}
|
||||
func (rr *EID) copy() RR {
|
||||
return &EID{*rr.Hdr.copyHeader(), rr.Endpoint}
|
||||
}
|
||||
func (rr *EUI48) copy() RR {
|
||||
return &EUI48{*rr.Hdr.copyHeader(), rr.Address}
|
||||
}
|
||||
func (rr *EUI64) copy() RR {
|
||||
return &EUI64{*rr.Hdr.copyHeader(), rr.Address}
|
||||
}
|
||||
func (rr *GID) copy() RR {
|
||||
return &GID{*rr.Hdr.copyHeader(), rr.Gid}
|
||||
}
|
||||
func (rr *GPOS) copy() RR {
|
||||
return &GPOS{*rr.Hdr.copyHeader(), rr.Longitude, rr.Latitude, rr.Altitude}
|
||||
}
|
||||
func (rr *HINFO) copy() RR {
|
||||
return &HINFO{*rr.Hdr.copyHeader(), rr.Cpu, rr.Os}
|
||||
}
|
||||
func (rr *HIP) copy() RR {
|
||||
RendezvousServers := make([]string, len(rr.RendezvousServers))
|
||||
copy(RendezvousServers, rr.RendezvousServers)
|
||||
return &HIP{*rr.Hdr.copyHeader(), rr.HitLength, rr.PublicKeyAlgorithm, rr.PublicKeyLength, rr.Hit, rr.PublicKey, RendezvousServers}
|
||||
}
|
||||
func (rr *IPSECKEY) copy() RR {
|
||||
return &IPSECKEY{*rr.Hdr.copyHeader(), rr.Precedence, rr.GatewayType, rr.Algorithm, copyIP(rr.GatewayA), copyIP(rr.GatewayAAAA), rr.GatewayName, rr.PublicKey}
|
||||
}
|
||||
func (rr *KX) copy() RR {
|
||||
return &KX{*rr.Hdr.copyHeader(), rr.Preference, rr.Exchanger}
|
||||
}
|
||||
func (rr *L32) copy() RR {
|
||||
return &L32{*rr.Hdr.copyHeader(), rr.Preference, copyIP(rr.Locator32)}
|
||||
}
|
||||
func (rr *L64) copy() RR {
|
||||
return &L64{*rr.Hdr.copyHeader(), rr.Preference, rr.Locator64}
|
||||
}
|
||||
func (rr *LOC) copy() RR {
|
||||
return &LOC{*rr.Hdr.copyHeader(), rr.Version, rr.Size, rr.HorizPre, rr.VertPre, rr.Latitude, rr.Longitude, rr.Altitude}
|
||||
}
|
||||
func (rr *LP) copy() RR {
|
||||
return &LP{*rr.Hdr.copyHeader(), rr.Preference, rr.Fqdn}
|
||||
}
|
||||
func (rr *MB) copy() RR {
|
||||
return &MB{*rr.Hdr.copyHeader(), rr.Mb}
|
||||
}
|
||||
func (rr *MD) copy() RR {
|
||||
return &MD{*rr.Hdr.copyHeader(), rr.Md}
|
||||
}
|
||||
func (rr *MF) copy() RR {
|
||||
return &MF{*rr.Hdr.copyHeader(), rr.Mf}
|
||||
}
|
||||
func (rr *MG) copy() RR {
|
||||
return &MG{*rr.Hdr.copyHeader(), rr.Mg}
|
||||
}
|
||||
func (rr *MINFO) copy() RR {
|
||||
return &MINFO{*rr.Hdr.copyHeader(), rr.Rmail, rr.Email}
|
||||
}
|
||||
func (rr *MR) copy() RR {
|
||||
return &MR{*rr.Hdr.copyHeader(), rr.Mr}
|
||||
}
|
||||
func (rr *MX) copy() RR {
|
||||
return &MX{*rr.Hdr.copyHeader(), rr.Preference, rr.Mx}
|
||||
}
|
||||
func (rr *NAPTR) copy() RR {
|
||||
return &NAPTR{*rr.Hdr.copyHeader(), rr.Order, rr.Preference, rr.Flags, rr.Service, rr.Regexp, rr.Replacement}
|
||||
}
|
||||
func (rr *NID) copy() RR {
|
||||
return &NID{*rr.Hdr.copyHeader(), rr.Preference, rr.NodeID}
|
||||
}
|
||||
func (rr *NIMLOC) copy() RR {
|
||||
return &NIMLOC{*rr.Hdr.copyHeader(), rr.Locator}
|
||||
}
|
||||
func (rr *NINFO) copy() RR {
|
||||
ZSData := make([]string, len(rr.ZSData))
|
||||
copy(ZSData, rr.ZSData)
|
||||
return &NINFO{*rr.Hdr.copyHeader(), ZSData}
|
||||
}
|
||||
func (rr *NS) copy() RR {
|
||||
return &NS{*rr.Hdr.copyHeader(), rr.Ns}
|
||||
}
|
||||
func (rr *NSAPPTR) copy() RR {
|
||||
return &NSAPPTR{*rr.Hdr.copyHeader(), rr.Ptr}
|
||||
}
|
||||
func (rr *NSEC) copy() RR {
|
||||
TypeBitMap := make([]uint16, len(rr.TypeBitMap))
|
||||
copy(TypeBitMap, rr.TypeBitMap)
|
||||
return &NSEC{*rr.Hdr.copyHeader(), rr.NextDomain, TypeBitMap}
|
||||
}
|
||||
func (rr *NSEC3) copy() RR {
|
||||
TypeBitMap := make([]uint16, len(rr.TypeBitMap))
|
||||
copy(TypeBitMap, rr.TypeBitMap)
|
||||
return &NSEC3{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt, rr.HashLength, rr.NextDomain, TypeBitMap}
|
||||
}
|
||||
func (rr *NSEC3PARAM) copy() RR {
|
||||
return &NSEC3PARAM{*rr.Hdr.copyHeader(), rr.Hash, rr.Flags, rr.Iterations, rr.SaltLength, rr.Salt}
|
||||
}
|
||||
func (rr *OPENPGPKEY) copy() RR {
|
||||
return &OPENPGPKEY{*rr.Hdr.copyHeader(), rr.PublicKey}
|
||||
}
|
||||
func (rr *OPT) copy() RR {
|
||||
Option := make([]EDNS0, len(rr.Option))
|
||||
copy(Option, rr.Option)
|
||||
return &OPT{*rr.Hdr.copyHeader(), Option}
|
||||
}
|
||||
func (rr *PTR) copy() RR {
|
||||
return &PTR{*rr.Hdr.copyHeader(), rr.Ptr}
|
||||
}
|
||||
func (rr *PX) copy() RR {
|
||||
return &PX{*rr.Hdr.copyHeader(), rr.Preference, rr.Map822, rr.Mapx400}
|
||||
}
|
||||
func (rr *RFC3597) copy() RR {
|
||||
return &RFC3597{*rr.Hdr.copyHeader(), rr.Rdata}
|
||||
}
|
||||
func (rr *RKEY) copy() RR {
|
||||
return &RKEY{*rr.Hdr.copyHeader(), rr.Flags, rr.Protocol, rr.Algorithm, rr.PublicKey}
|
||||
}
|
||||
func (rr *RP) copy() RR {
|
||||
return &RP{*rr.Hdr.copyHeader(), rr.Mbox, rr.Txt}
|
||||
}
|
||||
func (rr *RRSIG) copy() RR {
|
||||
return &RRSIG{*rr.Hdr.copyHeader(), rr.TypeCovered, rr.Algorithm, rr.Labels, rr.OrigTtl, rr.Expiration, rr.Inception, rr.KeyTag, rr.SignerName, rr.Signature}
|
||||
}
|
||||
func (rr *RT) copy() RR {
|
||||
return &RT{*rr.Hdr.copyHeader(), rr.Preference, rr.Host}
|
||||
}
|
||||
func (rr *SOA) copy() RR {
|
||||
return &SOA{*rr.Hdr.copyHeader(), rr.Ns, rr.Mbox, rr.Serial, rr.Refresh, rr.Retry, rr.Expire, rr.Minttl}
|
||||
}
|
||||
func (rr *SPF) copy() RR {
|
||||
Txt := make([]string, len(rr.Txt))
|
||||
copy(Txt, rr.Txt)
|
||||
return &SPF{*rr.Hdr.copyHeader(), Txt}
|
||||
}
|
||||
func (rr *SRV) copy() RR {
|
||||
return &SRV{*rr.Hdr.copyHeader(), rr.Priority, rr.Weight, rr.Port, rr.Target}
|
||||
}
|
||||
func (rr *SSHFP) copy() RR {
|
||||
return &SSHFP{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Type, rr.FingerPrint}
|
||||
}
|
||||
func (rr *TA) copy() RR {
|
||||
return &TA{*rr.Hdr.copyHeader(), rr.KeyTag, rr.Algorithm, rr.DigestType, rr.Digest}
|
||||
}
|
||||
func (rr *TALINK) copy() RR {
|
||||
return &TALINK{*rr.Hdr.copyHeader(), rr.PreviousName, rr.NextName}
|
||||
}
|
||||
func (rr *TKEY) copy() RR {
|
||||
return &TKEY{*rr.Hdr.copyHeader(), rr.Algorithm, rr.Inception, rr.Expiration, rr.Mode, rr.Error, rr.KeySize, rr.Key, rr.OtherLen, rr.OtherData}
|
||||
}
|
||||
func (rr *TLSA) copy() RR {
|
||||
return &TLSA{*rr.Hdr.copyHeader(), rr.Usage, rr.Selector, rr.MatchingType, rr.Certificate}
|
||||
}
|
||||
func (rr *TSIG) copy() RR {
|
||||
return &TSIG{*rr.Hdr.copyHeader(), rr.Algorithm, rr.TimeSigned, rr.Fudge, rr.MACSize, rr.MAC, rr.OrigId, rr.Error, rr.OtherLen, rr.OtherData}
|
||||
}
|
||||
func (rr *TXT) copy() RR {
|
||||
Txt := make([]string, len(rr.Txt))
|
||||
copy(Txt, rr.Txt)
|
||||
return &TXT{*rr.Hdr.copyHeader(), Txt}
|
||||
}
|
||||
func (rr *UID) copy() RR {
|
||||
return &UID{*rr.Hdr.copyHeader(), rr.Uid}
|
||||
}
|
||||
func (rr *UINFO) copy() RR {
|
||||
return &UINFO{*rr.Hdr.copyHeader(), rr.Uinfo}
|
||||
}
|
||||
func (rr *URI) copy() RR {
|
||||
return &URI{*rr.Hdr.copyHeader(), rr.Priority, rr.Weight, rr.Target}
|
||||
}
|
||||
func (rr *WKS) copy() RR {
|
||||
BitMap := make([]uint16, len(rr.BitMap))
|
||||
copy(BitMap, rr.BitMap)
|
||||
return &WKS{*rr.Hdr.copyHeader(), copyIP(rr.Address), rr.Protocol, BitMap}
|
||||
}
|
||||
func (rr *X25) copy() RR {
|
||||
return &X25{*rr.Hdr.copyHeader(), rr.PSDNAddress}
|
||||
}
|
22
libnetwork/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/LICENSE
generated
vendored
Normal file
22
libnetwork/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
Copyright (c) 2015 Matthew Heon <mheon@redhat.com>
|
||||
Copyright (c) 2015 Paul Moore <pmoore@redhat.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
- Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
- Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
26
libnetwork/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/README
generated
vendored
Normal file
26
libnetwork/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/README
generated
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
libseccomp-golang: Go Language Bindings for the libseccomp Project
|
||||
===============================================================================
|
||||
https://github.com/seccomp/libseccomp-golang
|
||||
https://github.com/seccomp/libseccomp
|
||||
|
||||
The libseccomp library provides an easy to use, platform independent, interface
|
||||
to the Linux Kernel's syscall filtering mechanism. The libseccomp API is
|
||||
designed to abstract away the underlying BPF based syscall filter language and
|
||||
present a more conventional function-call based filtering interface that should
|
||||
be familiar to, and easily adopted by, application developers.
|
||||
|
||||
The libseccomp-golang library provides a Go based interface to the libseccomp
|
||||
library.
|
||||
|
||||
* Online Resources
|
||||
|
||||
The library source repository currently lives on GitHub at the following URLs:
|
||||
|
||||
-> https://github.com/seccomp/libseccomp-golang
|
||||
-> https://github.com/seccomp/libseccomp
|
||||
|
||||
The project mailing list is currently hosted on Google Groups at the URL below,
|
||||
please note that a Google account is not required to subscribe to the mailing
|
||||
list.
|
||||
|
||||
-> https://groups.google.com/d/forum/libseccomp
|
827
libnetwork/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/seccomp.go
generated
vendored
Normal file
827
libnetwork/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/seccomp.go
generated
vendored
Normal file
|
@ -0,0 +1,827 @@
|
|||
// +build linux
|
||||
|
||||
// Public API specification for libseccomp Go bindings
|
||||
// Contains public API for the bindings
|
||||
|
||||
// Package seccomp rovides bindings for libseccomp, a library wrapping the Linux
|
||||
// seccomp syscall. Seccomp enables an application to restrict system call use
|
||||
// for itself and its children.
|
||||
package seccomp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// C wrapping code
|
||||
|
||||
// #cgo LDFLAGS: -lseccomp
|
||||
// #include <stdlib.h>
|
||||
// #include <seccomp.h>
|
||||
import "C"
|
||||
|
||||
// Exported types
|
||||
|
||||
// ScmpArch represents a CPU architecture. Seccomp can restrict syscalls on a
|
||||
// per-architecture basis.
|
||||
type ScmpArch uint
|
||||
|
||||
// ScmpAction represents an action to be taken on a filter rule match in
|
||||
// libseccomp
|
||||
type ScmpAction uint
|
||||
|
||||
// ScmpCompareOp represents a comparison operator which can be used in a filter
|
||||
// rule
|
||||
type ScmpCompareOp uint
|
||||
|
||||
// ScmpCondition represents a rule in a libseccomp filter context
|
||||
type ScmpCondition struct {
|
||||
Argument uint `json:"argument,omitempty"`
|
||||
Op ScmpCompareOp `json:"operator,omitempty"`
|
||||
Operand1 uint64 `json:"operand_one,omitempty"`
|
||||
Operand2 uint64 `json:"operand_two,omitempty"`
|
||||
}
|
||||
|
||||
// ScmpSyscall represents a Linux System Call
|
||||
type ScmpSyscall int32
|
||||
|
||||
// Exported Constants
|
||||
|
||||
const (
|
||||
// Valid architectures recognized by libseccomp
|
||||
// ARM64 and all MIPS architectures are unsupported by versions of the
|
||||
// library before v2.2 and will return errors if used
|
||||
|
||||
// ArchInvalid is a placeholder to ensure uninitialized ScmpArch
|
||||
// variables are invalid
|
||||
ArchInvalid ScmpArch = iota
|
||||
// ArchNative is the native architecture of the kernel
|
||||
ArchNative ScmpArch = iota
|
||||
// ArchX86 represents 32-bit x86 syscalls
|
||||
ArchX86 ScmpArch = iota
|
||||
// ArchAMD64 represents 64-bit x86-64 syscalls
|
||||
ArchAMD64 ScmpArch = iota
|
||||
// ArchX32 represents 64-bit x86-64 syscalls (32-bit pointers)
|
||||
ArchX32 ScmpArch = iota
|
||||
// ArchARM represents 32-bit ARM syscalls
|
||||
ArchARM ScmpArch = iota
|
||||
// ArchARM64 represents 64-bit ARM syscalls
|
||||
ArchARM64 ScmpArch = iota
|
||||
// ArchMIPS represents 32-bit MIPS syscalls
|
||||
ArchMIPS ScmpArch = iota
|
||||
// ArchMIPS64 represents 64-bit MIPS syscalls
|
||||
ArchMIPS64 ScmpArch = iota
|
||||
// ArchMIPS64N32 represents 64-bit MIPS syscalls (32-bit pointers)
|
||||
ArchMIPS64N32 ScmpArch = iota
|
||||
// ArchMIPSEL represents 32-bit MIPS syscalls (little endian)
|
||||
ArchMIPSEL ScmpArch = iota
|
||||
// ArchMIPSEL64 represents 64-bit MIPS syscalls (little endian)
|
||||
ArchMIPSEL64 ScmpArch = iota
|
||||
// ArchMIPSEL64N32 represents 64-bit MIPS syscalls (little endian,
|
||||
// 32-bit pointers)
|
||||
ArchMIPSEL64N32 ScmpArch = iota
|
||||
)
|
||||
|
||||
const (
|
||||
// Supported actions on filter match
|
||||
|
||||
// ActInvalid is a placeholder to ensure uninitialized ScmpAction
|
||||
// variables are invalid
|
||||
ActInvalid ScmpAction = iota
|
||||
// ActKill kills the process
|
||||
ActKill ScmpAction = iota
|
||||
// ActTrap throws SIGSYS
|
||||
ActTrap ScmpAction = iota
|
||||
// ActErrno causes the syscall to return a negative error code. This
|
||||
// code can be set with the SetReturnCode method
|
||||
ActErrno ScmpAction = iota
|
||||
// ActTrace causes the syscall to notify tracing processes with the
|
||||
// given error code. This code can be set with the SetReturnCode method
|
||||
ActTrace ScmpAction = iota
|
||||
// ActAllow permits the syscall to continue execution
|
||||
ActAllow ScmpAction = iota
|
||||
)
|
||||
|
||||
const (
|
||||
// These are comparison operators used in conditional seccomp rules
|
||||
// They are used to compare the value of a single argument of a syscall
|
||||
// against a user-defined constant
|
||||
|
||||
// CompareInvalid is a placeholder to ensure uninitialized ScmpCompareOp
|
||||
// variables are invalid
|
||||
CompareInvalid ScmpCompareOp = iota
|
||||
// CompareNotEqual returns true if the argument is not equal to the
|
||||
// given value
|
||||
CompareNotEqual ScmpCompareOp = iota
|
||||
// CompareLess returns true if the argument is less than the given value
|
||||
CompareLess ScmpCompareOp = iota
|
||||
// CompareLessOrEqual returns true if the argument is less than or equal
|
||||
// to the given value
|
||||
CompareLessOrEqual ScmpCompareOp = iota
|
||||
// CompareEqual returns true if the argument is equal to the given value
|
||||
CompareEqual ScmpCompareOp = iota
|
||||
// CompareGreaterEqual returns true if the argument is greater than or
|
||||
// equal to the given value
|
||||
CompareGreaterEqual ScmpCompareOp = iota
|
||||
// CompareGreater returns true if the argument is greater than the given
|
||||
// value
|
||||
CompareGreater ScmpCompareOp = iota
|
||||
// CompareMaskedEqual returns true if the argument is equal to the given
|
||||
// value, when masked (bitwise &) against the second given value
|
||||
CompareMaskedEqual ScmpCompareOp = iota
|
||||
)
|
||||
|
||||
// Helpers for types
|
||||
|
||||
// GetArchFromString returns an ScmpArch constant from a string representing an
|
||||
// architecture
|
||||
func GetArchFromString(arch string) (ScmpArch, error) {
|
||||
switch strings.ToLower(arch) {
|
||||
case "x86":
|
||||
return ArchX86, nil
|
||||
case "amd64", "x86-64", "x86_64", "x64":
|
||||
return ArchAMD64, nil
|
||||
case "x32":
|
||||
return ArchX32, nil
|
||||
case "arm":
|
||||
return ArchARM, nil
|
||||
case "arm64", "aarch64":
|
||||
return ArchARM64, nil
|
||||
case "mips":
|
||||
return ArchMIPS, nil
|
||||
case "mips64":
|
||||
return ArchMIPS64, nil
|
||||
case "mips64n32":
|
||||
return ArchMIPS64N32, nil
|
||||
case "mipsel":
|
||||
return ArchMIPSEL, nil
|
||||
case "mipsel64":
|
||||
return ArchMIPSEL64, nil
|
||||
case "mipsel64n32":
|
||||
return ArchMIPSEL64N32, nil
|
||||
default:
|
||||
return ArchInvalid, fmt.Errorf("cannot convert unrecognized string %s", arch)
|
||||
}
|
||||
}
|
||||
|
||||
// String returns a string representation of an architecture constant
|
||||
func (a ScmpArch) String() string {
|
||||
switch a {
|
||||
case ArchX86:
|
||||
return "x86"
|
||||
case ArchAMD64:
|
||||
return "amd64"
|
||||
case ArchX32:
|
||||
return "x32"
|
||||
case ArchARM:
|
||||
return "arm"
|
||||
case ArchARM64:
|
||||
return "arm64"
|
||||
case ArchMIPS:
|
||||
return "mips"
|
||||
case ArchMIPS64:
|
||||
return "mips64"
|
||||
case ArchMIPS64N32:
|
||||
return "mips64n32"
|
||||
case ArchMIPSEL:
|
||||
return "mipsel"
|
||||
case ArchMIPSEL64:
|
||||
return "mipsel64"
|
||||
case ArchMIPSEL64N32:
|
||||
return "mipsel64n32"
|
||||
case ArchNative:
|
||||
return "native"
|
||||
case ArchInvalid:
|
||||
return "Invalid architecture"
|
||||
default:
|
||||
return "Unknown architecture"
|
||||
}
|
||||
}
|
||||
|
||||
// String returns a string representation of a comparison operator constant
|
||||
func (a ScmpCompareOp) String() string {
|
||||
switch a {
|
||||
case CompareNotEqual:
|
||||
return "Not equal"
|
||||
case CompareLess:
|
||||
return "Less than"
|
||||
case CompareLessOrEqual:
|
||||
return "Less than or equal to"
|
||||
case CompareEqual:
|
||||
return "Equal"
|
||||
case CompareGreaterEqual:
|
||||
return "Greater than or equal to"
|
||||
case CompareGreater:
|
||||
return "Greater than"
|
||||
case CompareMaskedEqual:
|
||||
return "Masked equality"
|
||||
case CompareInvalid:
|
||||
return "Invalid comparison operator"
|
||||
default:
|
||||
return "Unrecognized comparison operator"
|
||||
}
|
||||
}
|
||||
|
||||
// String returns a string representation of a seccomp match action
|
||||
func (a ScmpAction) String() string {
|
||||
switch a & 0xFFFF {
|
||||
case ActKill:
|
||||
return "Action: Kill Process"
|
||||
case ActTrap:
|
||||
return "Action: Send SIGSYS"
|
||||
case ActErrno:
|
||||
return fmt.Sprintf("Action: Return error code %d", (a >> 16))
|
||||
case ActTrace:
|
||||
return fmt.Sprintf("Action: Notify tracing processes with code %d",
|
||||
(a >> 16))
|
||||
case ActAllow:
|
||||
return "Action: Allow system call"
|
||||
default:
|
||||
return "Unrecognized Action"
|
||||
}
|
||||
}
|
||||
|
||||
// SetReturnCode adds a return code to a supporting ScmpAction, clearing any
|
||||
// existing code Only valid on ActErrno and ActTrace. Takes no action otherwise.
|
||||
// Accepts 16-bit return code as argument.
|
||||
// Returns a valid ScmpAction of the original type with the new error code set.
|
||||
func (a ScmpAction) SetReturnCode(code int16) ScmpAction {
|
||||
aTmp := a & 0x0000FFFF
|
||||
if aTmp == ActErrno || aTmp == ActTrace {
|
||||
return (aTmp | (ScmpAction(code)&0xFFFF)<<16)
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
// GetReturnCode returns the return code of an ScmpAction
|
||||
func (a ScmpAction) GetReturnCode() int16 {
|
||||
return int16(a >> 16)
|
||||
}
|
||||
|
||||
// General utility functions
|
||||
|
||||
// GetLibraryVersion returns the version of the library the bindings are built
|
||||
// against.
|
||||
// The version is formatted as follows: Major.Minor.Micro
|
||||
func GetLibraryVersion() (major, minor, micro int) {
|
||||
return verMajor, verMinor, verMicro
|
||||
}
|
||||
|
||||
// Syscall functions
|
||||
|
||||
// GetName retrieves the name of a syscall from its number.
|
||||
// Acts on any syscall number.
|
||||
// Returns either a string containing the name of the syscall, or an error.
|
||||
func (s ScmpSyscall) GetName() (string, error) {
|
||||
return s.GetNameByArch(ArchNative)
|
||||
}
|
||||
|
||||
// GetNameByArch retrieves the name of a syscall from its number for a given
|
||||
// architecture.
|
||||
// Acts on any syscall number.
|
||||
// Accepts a valid architecture constant.
|
||||
// Returns either a string containing the name of the syscall, or an error.
|
||||
// if the syscall is unrecognized or an issue occurred.
|
||||
func (s ScmpSyscall) GetNameByArch(arch ScmpArch) (string, error) {
|
||||
if err := sanitizeArch(arch); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cString := C.seccomp_syscall_resolve_num_arch(arch.toNative(), C.int(s))
|
||||
if cString == nil {
|
||||
return "", fmt.Errorf("could not resolve syscall name")
|
||||
}
|
||||
defer C.free(unsafe.Pointer(cString))
|
||||
|
||||
finalStr := C.GoString(cString)
|
||||
return finalStr, nil
|
||||
}
|
||||
|
||||
// GetSyscallFromName returns the number of a syscall by name on the kernel's
|
||||
// native architecture.
|
||||
// Accepts a string containing the name of a syscall.
|
||||
// Returns the number of the syscall, or an error if no syscall with that name
|
||||
// was found.
|
||||
func GetSyscallFromName(name string) (ScmpSyscall, error) {
|
||||
cString := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cString))
|
||||
|
||||
result := C.seccomp_syscall_resolve_name(cString)
|
||||
if result == scmpError {
|
||||
return 0, fmt.Errorf("could not resolve name to syscall")
|
||||
}
|
||||
|
||||
return ScmpSyscall(result), nil
|
||||
}
|
||||
|
||||
// GetSyscallFromNameByArch returns the number of a syscall by name for a given
|
||||
// architecture's ABI.
|
||||
// Accepts the name of a syscall and an architecture constant.
|
||||
// Returns the number of the syscall, or an error if an invalid architecture is
|
||||
// passed or a syscall with that name was not found.
|
||||
func GetSyscallFromNameByArch(name string, arch ScmpArch) (ScmpSyscall, error) {
|
||||
if err := sanitizeArch(arch); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
cString := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cString))
|
||||
|
||||
result := C.seccomp_syscall_resolve_name_arch(arch.toNative(), cString)
|
||||
if result == scmpError {
|
||||
return 0, fmt.Errorf("could not resolve name to syscall")
|
||||
}
|
||||
|
||||
return ScmpSyscall(result), nil
|
||||
}
|
||||
|
||||
// MakeCondition creates and returns a new condition to attach to a filter rule.
|
||||
// Associated rules will only match if this condition is true.
|
||||
// Accepts the number the argument we are checking, and a comparison operator
|
||||
// and value to compare to.
|
||||
// The rule will match if argument $arg (zero-indexed) of the syscall is
|
||||
// $COMPARE_OP the provided comparison value.
|
||||
// Some comparison operators accept two values. Masked equals, for example,
|
||||
// will mask $arg of the syscall with the second value provided (via bitwise
|
||||
// AND) and then compare against the first value provided.
|
||||
// For example, in the less than or equal case, if the syscall argument was
|
||||
// 0 and the value provided was 1, the condition would match, as 0 is less
|
||||
// than or equal to 1.
|
||||
// Return either an error on bad argument or a valid ScmpCondition struct.
|
||||
func MakeCondition(arg uint, comparison ScmpCompareOp, values ...uint64) (ScmpCondition, error) {
|
||||
var condStruct ScmpCondition
|
||||
|
||||
if comparison == CompareInvalid {
|
||||
return condStruct, fmt.Errorf("invalid comparison operator")
|
||||
} else if arg > 5 {
|
||||
return condStruct, fmt.Errorf("syscalls only have up to 6 arguments")
|
||||
} else if len(values) > 2 {
|
||||
return condStruct, fmt.Errorf("conditions can have at most 2 arguments")
|
||||
} else if len(values) == 0 {
|
||||
return condStruct, fmt.Errorf("must provide at least one value to compare against")
|
||||
}
|
||||
|
||||
condStruct.Argument = arg
|
||||
condStruct.Op = comparison
|
||||
condStruct.Operand1 = values[0]
|
||||
if len(values) == 2 {
|
||||
condStruct.Operand2 = values[1]
|
||||
} else {
|
||||
condStruct.Operand2 = 0 // Unused
|
||||
}
|
||||
|
||||
return condStruct, nil
|
||||
}
|
||||
|
||||
// Utility Functions
|
||||
|
||||
// GetNativeArch returns architecture token representing the native kernel
|
||||
// architecture
|
||||
func GetNativeArch() (ScmpArch, error) {
|
||||
arch := C.seccomp_arch_native()
|
||||
|
||||
return archFromNative(arch)
|
||||
}
|
||||
|
||||
// Public Filter API
|
||||
|
||||
// ScmpFilter represents a filter context in libseccomp.
|
||||
// A filter context is initially empty. Rules can be added to it, and it can
|
||||
// then be loaded into the kernel.
|
||||
type ScmpFilter struct {
|
||||
filterCtx C.scmp_filter_ctx
|
||||
valid bool
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
// NewFilter creates and returns a new filter context.
|
||||
// Accepts a default action to be taken for syscalls which match no rules in
|
||||
// the filter.
|
||||
// Returns a reference to a valid filter context, or nil and an error if the
|
||||
// filter context could not be created or an invalid default action was given.
|
||||
func NewFilter(defaultAction ScmpAction) (*ScmpFilter, error) {
|
||||
if err := sanitizeAction(defaultAction); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fPtr := C.seccomp_init(defaultAction.toNative())
|
||||
if fPtr == nil {
|
||||
return nil, fmt.Errorf("could not create filter")
|
||||
}
|
||||
|
||||
filter := new(ScmpFilter)
|
||||
filter.filterCtx = fPtr
|
||||
filter.valid = true
|
||||
runtime.SetFinalizer(filter, filterFinalizer)
|
||||
|
||||
return filter, nil
|
||||
}
|
||||
|
||||
// IsValid determines whether a filter context is valid to use.
|
||||
// Some operations (Release and Merge) render filter contexts invalid and
|
||||
// consequently prevent further use.
|
||||
func (f *ScmpFilter) IsValid() bool {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
return f.valid
|
||||
}
|
||||
|
||||
// Reset resets a filter context, removing all its existing state.
|
||||
// Accepts a new default action to be taken for syscalls which do not match.
|
||||
// Returns an error if the filter or action provided are invalid.
|
||||
func (f *ScmpFilter) Reset(defaultAction ScmpAction) error {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
if err := sanitizeAction(defaultAction); err != nil {
|
||||
return err
|
||||
} else if !f.valid {
|
||||
return errBadFilter
|
||||
}
|
||||
|
||||
retCode := C.seccomp_reset(f.filterCtx, defaultAction.toNative())
|
||||
if retCode != 0 {
|
||||
return syscall.Errno(-1 * retCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Release releases a filter context, freeing its memory. Should be called after
|
||||
// loading into the kernel, when the filter is no longer needed.
|
||||
// After calling this function, the given filter is no longer valid and cannot
|
||||
// be used.
|
||||
// Release() will be invoked automatically when a filter context is garbage
|
||||
// collected, but can also be called manually to free memory.
|
||||
func (f *ScmpFilter) Release() {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
if !f.valid {
|
||||
return
|
||||
}
|
||||
|
||||
f.valid = false
|
||||
C.seccomp_release(f.filterCtx)
|
||||
}
|
||||
|
||||
// Merge merges two filter contexts.
|
||||
// The source filter src will be released as part of the process, and will no
|
||||
// longer be usable or valid after this call.
|
||||
// To be merged, filters must NOT share any architectures, and all their
|
||||
// attributes (Default Action, Bad Arch Action, No New Privs and TSync bools)
|
||||
// must match.
|
||||
// The filter src will be merged into the filter this is called on.
|
||||
// The architectures of the src filter not present in the destination, and all
|
||||
// associated rules, will be added to the destination.
|
||||
// Returns an error if merging the filters failed.
|
||||
func (f *ScmpFilter) Merge(src *ScmpFilter) error {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
src.lock.Lock()
|
||||
defer src.lock.Unlock()
|
||||
|
||||
if !src.valid || !f.valid {
|
||||
return fmt.Errorf("one or more of the filter contexts is invalid or uninitialized")
|
||||
}
|
||||
|
||||
// Merge the filters
|
||||
retCode := C.seccomp_merge(f.filterCtx, src.filterCtx)
|
||||
if syscall.Errno(-1*retCode) == syscall.EINVAL {
|
||||
return fmt.Errorf("filters could not be merged due to a mismatch in attributes or invalid filter")
|
||||
} else if retCode != 0 {
|
||||
return syscall.Errno(-1 * retCode)
|
||||
}
|
||||
|
||||
src.valid = false
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsArchPresent checks if an architecture is present in a filter.
|
||||
// If a filter contains an architecture, it uses its default action for
|
||||
// syscalls which do not match rules in it, and its rules can match syscalls
|
||||
// for that ABI.
|
||||
// If a filter does not contain an architecture, all syscalls made to that
|
||||
// kernel ABI will fail with the filter's default Bad Architecture Action
|
||||
// (by default, killing the process).
|
||||
// Accepts an architecture constant.
|
||||
// Returns true if the architecture is present in the filter, false otherwise,
|
||||
// and an error on an invalid filter context, architecture constant, or an
|
||||
// issue with the call to libseccomp.
|
||||
func (f *ScmpFilter) IsArchPresent(arch ScmpArch) (bool, error) {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
if err := sanitizeArch(arch); err != nil {
|
||||
return false, err
|
||||
} else if !f.valid {
|
||||
return false, errBadFilter
|
||||
}
|
||||
|
||||
retCode := C.seccomp_arch_exist(f.filterCtx, arch.toNative())
|
||||
if syscall.Errno(-1*retCode) == syscall.EEXIST {
|
||||
// -EEXIST is "arch not present"
|
||||
return false, nil
|
||||
} else if retCode != 0 {
|
||||
return false, syscall.Errno(-1 * retCode)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// AddArch adds an architecture to the filter.
|
||||
// Accepts an architecture constant.
|
||||
// Returns an error on invalid filter context or architecture token, or an
|
||||
// issue with the call to libseccomp.
|
||||
func (f *ScmpFilter) AddArch(arch ScmpArch) error {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
if err := sanitizeArch(arch); err != nil {
|
||||
return err
|
||||
} else if !f.valid {
|
||||
return errBadFilter
|
||||
}
|
||||
|
||||
// Libseccomp returns -EEXIST if the specified architecture is already
|
||||
// present. Succeed silently in this case, as it's not fatal, and the
|
||||
// architecture is present already.
|
||||
retCode := C.seccomp_arch_add(f.filterCtx, arch.toNative())
|
||||
if retCode != 0 && syscall.Errno(-1*retCode) != syscall.EEXIST {
|
||||
return syscall.Errno(-1 * retCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveArch removes an architecture from the filter.
|
||||
// Accepts an architecture constant.
|
||||
// Returns an error on invalid filter context or architecture token, or an
|
||||
// issue with the call to libseccomp.
|
||||
func (f *ScmpFilter) RemoveArch(arch ScmpArch) error {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
if err := sanitizeArch(arch); err != nil {
|
||||
return err
|
||||
} else if !f.valid {
|
||||
return errBadFilter
|
||||
}
|
||||
|
||||
// Similar to AddArch, -EEXIST is returned if the arch is not present
|
||||
// Succeed silently in that case, this is not fatal and the architecture
|
||||
// is not present in the filter after RemoveArch
|
||||
retCode := C.seccomp_arch_remove(f.filterCtx, arch.toNative())
|
||||
if retCode != 0 && syscall.Errno(-1*retCode) != syscall.EEXIST {
|
||||
return syscall.Errno(-1 * retCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Load loads a filter context into the kernel.
|
||||
// Returns an error if the filter context is invalid or the syscall failed.
|
||||
func (f *ScmpFilter) Load() error {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
if !f.valid {
|
||||
return errBadFilter
|
||||
}
|
||||
|
||||
if retCode := C.seccomp_load(f.filterCtx); retCode != 0 {
|
||||
return syscall.Errno(-1 * retCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetDefaultAction returns the default action taken on a syscall which does not
|
||||
// match a rule in the filter, or an error if an issue was encountered
|
||||
// retrieving the value.
|
||||
func (f *ScmpFilter) GetDefaultAction() (ScmpAction, error) {
|
||||
action, err := f.getFilterAttr(filterAttrActDefault)
|
||||
if err != nil {
|
||||
return 0x0, err
|
||||
}
|
||||
|
||||
return actionFromNative(action)
|
||||
}
|
||||
|
||||
// GetBadArchAction returns the default action taken on a syscall for an
|
||||
// architecture not in the filter, or an error if an issue was encountered
|
||||
// retrieving the value.
|
||||
func (f *ScmpFilter) GetBadArchAction() (ScmpAction, error) {
|
||||
action, err := f.getFilterAttr(filterAttrActBadArch)
|
||||
if err != nil {
|
||||
return 0x0, err
|
||||
}
|
||||
|
||||
return actionFromNative(action)
|
||||
}
|
||||
|
||||
// GetNoNewPrivsBit returns the current state the No New Privileges bit will be set
|
||||
// to on the filter being loaded, or an error if an issue was encountered
|
||||
// retrieving the value.
|
||||
// The No New Privileges bit tells the kernel that new processes run with exec()
|
||||
// cannot gain more privileges than the process that ran exec().
|
||||
// For example, a process with No New Privileges set would be unable to exec
|
||||
// setuid/setgid executables.
|
||||
func (f *ScmpFilter) GetNoNewPrivsBit() (bool, error) {
|
||||
noNewPrivs, err := f.getFilterAttr(filterAttrNNP)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if noNewPrivs == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// GetTsyncBit returns whether Thread Synchronization will be enabled on the
|
||||
// filter being loaded, or an error if an issue was encountered retrieving the
|
||||
// value.
|
||||
// Thread Sync ensures that all members of the thread group of the calling
|
||||
// process will share the same Seccomp filter set.
|
||||
// Tsync is a fairly recent addition to the Linux kernel and older kernels
|
||||
// lack support. If the running kernel does not support Tsync and it is
|
||||
// requested in a filter, Libseccomp will not enable TSync support and will
|
||||
// proceed as normal.
|
||||
// This function is unavailable before v2.2 of libseccomp and will return an
|
||||
// error.
|
||||
func (f *ScmpFilter) GetTsyncBit() (bool, error) {
|
||||
tSync, err := f.getFilterAttr(filterAttrTsync)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if tSync == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// SetBadArchAction sets the default action taken on a syscall for an
|
||||
// architecture not in the filter, or an error if an issue was encountered
|
||||
// setting the value.
|
||||
func (f *ScmpFilter) SetBadArchAction(action ScmpAction) error {
|
||||
if err := sanitizeAction(action); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return f.setFilterAttr(filterAttrActBadArch, action.toNative())
|
||||
}
|
||||
|
||||
// SetNoNewPrivsBit sets the state of the No New Privileges bit, which will be
|
||||
// applied on filter load, or an error if an issue was encountered setting the
|
||||
// value.
|
||||
// Filters with No New Privileges set to 0 can only be loaded if the process
|
||||
// has the CAP_SYS_ADMIN capability.
|
||||
func (f *ScmpFilter) SetNoNewPrivsBit(state bool) error {
|
||||
var toSet C.uint32_t = 0x0
|
||||
|
||||
if state {
|
||||
toSet = 0x1
|
||||
}
|
||||
|
||||
return f.setFilterAttr(filterAttrNNP, toSet)
|
||||
}
|
||||
|
||||
// SetTsync sets whether Thread Synchronization will be enabled on the filter
|
||||
// being loaded. Returns an error if setting Tsync failed, or the filter is
|
||||
// invalid.
|
||||
// Thread Sync ensures that all members of the thread group of the calling
|
||||
// process will share the same Seccomp filter set.
|
||||
// Tsync is a fairly recent addition to the Linux kernel and older kernels
|
||||
// lack support. If the running kernel does not support Tsync and it is
|
||||
// requested in a filter, Libseccomp will not enable TSync support and will
|
||||
// proceed as normal.
|
||||
// This function is unavailable before v2.2 of libseccomp and will return an
|
||||
// error.
|
||||
func (f *ScmpFilter) SetTsync(enable bool) error {
|
||||
var toSet C.uint32_t = 0x0
|
||||
|
||||
if enable {
|
||||
toSet = 0x1
|
||||
}
|
||||
|
||||
return f.setFilterAttr(filterAttrTsync, toSet)
|
||||
}
|
||||
|
||||
// SetSyscallPriority sets a syscall's priority.
|
||||
// This provides a hint to the filter generator in libseccomp about the
|
||||
// importance of this syscall. High-priority syscalls are placed
|
||||
// first in the filter code, and incur less overhead (at the expense of
|
||||
// lower-priority syscalls).
|
||||
func (f *ScmpFilter) SetSyscallPriority(call ScmpSyscall, priority uint8) error {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
if !f.valid {
|
||||
return errBadFilter
|
||||
}
|
||||
|
||||
if retCode := C.seccomp_syscall_priority(f.filterCtx, C.int(call),
|
||||
C.uint8_t(priority)); retCode != 0 {
|
||||
return syscall.Errno(-1 * retCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddRule adds a single rule for an unconditional action on a syscall.
|
||||
// Accepts the number of the syscall and the action to be taken on the call
|
||||
// being made.
|
||||
// Returns an error if an issue was encountered adding the rule.
|
||||
func (f *ScmpFilter) AddRule(call ScmpSyscall, action ScmpAction) error {
|
||||
return f.addRuleGeneric(call, action, false, nil)
|
||||
}
|
||||
|
||||
// AddRuleExact adds a single rule for an unconditional action on a syscall.
|
||||
// Accepts the number of the syscall and the action to be taken on the call
|
||||
// being made.
|
||||
// No modifications will be made to the rule, and it will fail to add if it
|
||||
// cannot be applied to the current architecture without modification.
|
||||
// The rule will function exactly as described, but it may not function identically
|
||||
// (or be able to be applied to) all architectures.
|
||||
// Returns an error if an issue was encountered adding the rule.
|
||||
func (f *ScmpFilter) AddRuleExact(call ScmpSyscall, action ScmpAction) error {
|
||||
return f.addRuleGeneric(call, action, true, nil)
|
||||
}
|
||||
|
||||
// AddRuleConditional adds a single rule for a conditional action on a syscall.
|
||||
// Returns an error if an issue was encountered adding the rule.
|
||||
// All conditions must match for the rule to match.
|
||||
// There is a bug in library versions below v2.2.1 which can, in some cases,
|
||||
// cause conditions to be lost when more than one are used. Consequently,
|
||||
// AddRuleConditional is disabled on library versions lower than v2.2.1
|
||||
func (f *ScmpFilter) AddRuleConditional(call ScmpSyscall, action ScmpAction, conds []ScmpCondition) error {
|
||||
return f.addRuleGeneric(call, action, false, conds)
|
||||
}
|
||||
|
||||
// AddRuleConditionalExact adds a single rule for a conditional action on a
|
||||
// syscall.
|
||||
// No modifications will be made to the rule, and it will fail to add if it
|
||||
// cannot be applied to the current architecture without modification.
|
||||
// The rule will function exactly as described, but it may not function identically
|
||||
// (or be able to be applied to) all architectures.
|
||||
// Returns an error if an issue was encountered adding the rule.
|
||||
// There is a bug in library versions below v2.2.1 which can, in some cases,
|
||||
// cause conditions to be lost when more than one are used. Consequently,
|
||||
// AddRuleConditionalExact is disabled on library versions lower than v2.2.1
|
||||
func (f *ScmpFilter) AddRuleConditionalExact(call ScmpSyscall, action ScmpAction, conds []ScmpCondition) error {
|
||||
return f.addRuleGeneric(call, action, true, conds)
|
||||
}
|
||||
|
||||
// ExportPFC output PFC-formatted, human-readable dump of a filter context's
|
||||
// rules to a file.
|
||||
// Accepts file to write to (must be open for writing).
|
||||
// Returns an error if writing to the file fails.
|
||||
func (f *ScmpFilter) ExportPFC(file *os.File) error {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
fd := file.Fd()
|
||||
|
||||
if !f.valid {
|
||||
return errBadFilter
|
||||
}
|
||||
|
||||
if retCode := C.seccomp_export_pfc(f.filterCtx, C.int(fd)); retCode != 0 {
|
||||
return syscall.Errno(-1 * retCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExportBPF outputs Berkeley Packet Filter-formatted, kernel-readable dump of a
|
||||
// filter context's rules to a file.
|
||||
// Accepts file to write to (must be open for writing).
|
||||
// Returns an error if writing to the file fails.
|
||||
func (f *ScmpFilter) ExportBPF(file *os.File) error {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
fd := file.Fd()
|
||||
|
||||
if !f.valid {
|
||||
return errBadFilter
|
||||
}
|
||||
|
||||
if retCode := C.seccomp_export_bpf(f.filterCtx, C.int(fd)); retCode != 0 {
|
||||
return syscall.Errno(-1 * retCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
461
libnetwork/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/seccomp_internal.go
generated
vendored
Normal file
461
libnetwork/Godeps/_workspace/src/github.com/seccomp/libseccomp-golang/seccomp_internal.go
generated
vendored
Normal file
|
@ -0,0 +1,461 @@
|
|||
// +build linux
|
||||
|
||||
// Internal functions for libseccomp Go bindings
|
||||
// No exported functions
|
||||
|
||||
package seccomp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Unexported C wrapping code - provides the C-Golang interface
|
||||
// Get the seccomp header in scope
|
||||
// Need stdlib.h for free() on cstrings
|
||||
|
||||
// #cgo LDFLAGS: -lseccomp
|
||||
/*
|
||||
#include <stdlib.h>
|
||||
#include <seccomp.h>
|
||||
|
||||
#if SCMP_VER_MAJOR < 2
|
||||
#error Minimum supported version of Libseccomp is v2.1.0
|
||||
#elif SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 1
|
||||
#error Minimum supported version of Libseccomp is v2.1.0
|
||||
#endif
|
||||
|
||||
#define ARCH_BAD ~0
|
||||
|
||||
const uint32_t C_ARCH_BAD = ARCH_BAD;
|
||||
|
||||
#ifndef SCMP_ARCH_AARCH64
|
||||
#define SCMP_ARCH_AARCH64 ARCH_BAD
|
||||
#endif
|
||||
|
||||
#ifndef SCMP_ARCH_MIPS
|
||||
#define SCMP_ARCH_MIPS ARCH_BAD
|
||||
#endif
|
||||
|
||||
#ifndef SCMP_ARCH_MIPS64
|
||||
#define SCMP_ARCH_MIPS64 ARCH_BAD
|
||||
#endif
|
||||
|
||||
#ifndef SCMP_ARCH_MIPS64N32
|
||||
#define SCMP_ARCH_MIPS64N32 ARCH_BAD
|
||||
#endif
|
||||
|
||||
#ifndef SCMP_ARCH_MIPSEL
|
||||
#define SCMP_ARCH_MIPSEL ARCH_BAD
|
||||
#endif
|
||||
|
||||
#ifndef SCMP_ARCH_MIPSEL64
|
||||
#define SCMP_ARCH_MIPSEL64 ARCH_BAD
|
||||
#endif
|
||||
|
||||
#ifndef SCMP_ARCH_MIPSEL64N32
|
||||
#define SCMP_ARCH_MIPSEL64N32 ARCH_BAD
|
||||
#endif
|
||||
|
||||
const uint32_t C_ARCH_NATIVE = SCMP_ARCH_NATIVE;
|
||||
const uint32_t C_ARCH_X86 = SCMP_ARCH_X86;
|
||||
const uint32_t C_ARCH_X86_64 = SCMP_ARCH_X86_64;
|
||||
const uint32_t C_ARCH_X32 = SCMP_ARCH_X32;
|
||||
const uint32_t C_ARCH_ARM = SCMP_ARCH_ARM;
|
||||
const uint32_t C_ARCH_AARCH64 = SCMP_ARCH_AARCH64;
|
||||
const uint32_t C_ARCH_MIPS = SCMP_ARCH_MIPS;
|
||||
const uint32_t C_ARCH_MIPS64 = SCMP_ARCH_MIPS64;
|
||||
const uint32_t C_ARCH_MIPS64N32 = SCMP_ARCH_MIPS64N32;
|
||||
const uint32_t C_ARCH_MIPSEL = SCMP_ARCH_MIPSEL;
|
||||
const uint32_t C_ARCH_MIPSEL64 = SCMP_ARCH_MIPSEL64;
|
||||
const uint32_t C_ARCH_MIPSEL64N32 = SCMP_ARCH_MIPSEL64N32;
|
||||
|
||||
const uint32_t C_ACT_KILL = SCMP_ACT_KILL;
|
||||
const uint32_t C_ACT_TRAP = SCMP_ACT_TRAP;
|
||||
const uint32_t C_ACT_ERRNO = SCMP_ACT_ERRNO(0);
|
||||
const uint32_t C_ACT_TRACE = SCMP_ACT_TRACE(0);
|
||||
const uint32_t C_ACT_ALLOW = SCMP_ACT_ALLOW;
|
||||
|
||||
// If TSync is not supported, make sure it doesn't map to a supported filter attribute
|
||||
// Don't worry about major version < 2, the minimum version checks should catch that case
|
||||
#if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 2
|
||||
#define SCMP_FLTATR_CTL_TSYNC _SCMP_CMP_MIN
|
||||
#endif
|
||||
|
||||
const uint32_t C_ATTRIBUTE_DEFAULT = (uint32_t)SCMP_FLTATR_ACT_DEFAULT;
|
||||
const uint32_t C_ATTRIBUTE_BADARCH = (uint32_t)SCMP_FLTATR_ACT_BADARCH;
|
||||
const uint32_t C_ATTRIBUTE_NNP = (uint32_t)SCMP_FLTATR_CTL_NNP;
|
||||
const uint32_t C_ATTRIBUTE_TSYNC = (uint32_t)SCMP_FLTATR_CTL_TSYNC;
|
||||
|
||||
const int C_CMP_NE = (int)SCMP_CMP_NE;
|
||||
const int C_CMP_LT = (int)SCMP_CMP_LT;
|
||||
const int C_CMP_LE = (int)SCMP_CMP_LE;
|
||||
const int C_CMP_EQ = (int)SCMP_CMP_EQ;
|
||||
const int C_CMP_GE = (int)SCMP_CMP_GE;
|
||||
const int C_CMP_GT = (int)SCMP_CMP_GT;
|
||||
const int C_CMP_MASKED_EQ = (int)SCMP_CMP_MASKED_EQ;
|
||||
|
||||
const int C_VERSION_MAJOR = SCMP_VER_MAJOR;
|
||||
const int C_VERSION_MINOR = SCMP_VER_MINOR;
|
||||
const int C_VERSION_MICRO = SCMP_VER_MICRO;
|
||||
|
||||
typedef struct scmp_arg_cmp* scmp_cast_t;
|
||||
|
||||
// Wrapper to create an scmp_arg_cmp struct
|
||||
void*
|
||||
make_struct_arg_cmp(
|
||||
unsigned int arg,
|
||||
int compare,
|
||||
uint64_t a,
|
||||
uint64_t b
|
||||
)
|
||||
{
|
||||
struct scmp_arg_cmp *s = malloc(sizeof(struct scmp_arg_cmp));
|
||||
|
||||
s->arg = arg;
|
||||
s->op = compare;
|
||||
s->datum_a = a;
|
||||
s->datum_b = b;
|
||||
|
||||
return s;
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// Nonexported types
|
||||
type scmpFilterAttr uint32
|
||||
|
||||
// Nonexported constants
|
||||
|
||||
const (
|
||||
filterAttrActDefault scmpFilterAttr = iota
|
||||
filterAttrActBadArch scmpFilterAttr = iota
|
||||
filterAttrNNP scmpFilterAttr = iota
|
||||
filterAttrTsync scmpFilterAttr = iota
|
||||
)
|
||||
|
||||
const (
|
||||
// An error return from certain libseccomp functions
|
||||
scmpError C.int = -1
|
||||
// Comparison boundaries to check for architecture validity
|
||||
archStart ScmpArch = ArchNative
|
||||
archEnd ScmpArch = ArchMIPSEL64N32
|
||||
// Comparison boundaries to check for action validity
|
||||
actionStart ScmpAction = ActKill
|
||||
actionEnd ScmpAction = ActAllow
|
||||
// Comparison boundaries to check for comparison operator validity
|
||||
compareOpStart ScmpCompareOp = CompareNotEqual
|
||||
compareOpEnd ScmpCompareOp = CompareMaskedEqual
|
||||
)
|
||||
|
||||
var (
|
||||
// Error thrown on bad filter context
|
||||
errBadFilter = fmt.Errorf("filter is invalid or uninitialized")
|
||||
// Constants representing library major, minor, and micro versions
|
||||
verMajor = int(C.C_VERSION_MAJOR)
|
||||
verMinor = int(C.C_VERSION_MINOR)
|
||||
verMicro = int(C.C_VERSION_MICRO)
|
||||
)
|
||||
|
||||
// Nonexported functions
|
||||
|
||||
// Check if library version is greater than or equal to the given one
|
||||
func checkVersionAbove(major, minor, micro int) bool {
|
||||
return (verMajor > major) ||
|
||||
(verMajor == major && verMinor > minor) ||
|
||||
(verMajor == major && verMinor == minor && verMicro >= micro)
|
||||
}
|
||||
|
||||
// Init function: Verify library version is appropriate
|
||||
func init() {
|
||||
if !checkVersionAbove(2, 1, 0) {
|
||||
fmt.Fprintf(os.Stderr, "Libseccomp version too low: minimum supported is 2.1.0, detected %d.%d.%d", C.C_VERSION_MAJOR, C.C_VERSION_MINOR, C.C_VERSION_MICRO)
|
||||
os.Exit(-1)
|
||||
}
|
||||
}
|
||||
|
||||
// Filter helpers
|
||||
|
||||
// Filter finalizer - ensure that kernel context for filters is freed
|
||||
func filterFinalizer(f *ScmpFilter) {
|
||||
f.Release()
|
||||
}
|
||||
|
||||
// Get a raw filter attribute
|
||||
func (f *ScmpFilter) getFilterAttr(attr scmpFilterAttr) (C.uint32_t, error) {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
if !f.valid {
|
||||
return 0x0, errBadFilter
|
||||
}
|
||||
|
||||
if !checkVersionAbove(2, 2, 0) && attr == filterAttrTsync {
|
||||
return 0x0, fmt.Errorf("the thread synchronization attribute is not supported in this version of the library")
|
||||
}
|
||||
|
||||
var attribute C.uint32_t
|
||||
|
||||
retCode := C.seccomp_attr_get(f.filterCtx, attr.toNative(), &attribute)
|
||||
if retCode != 0 {
|
||||
return 0x0, syscall.Errno(-1 * retCode)
|
||||
}
|
||||
|
||||
return attribute, nil
|
||||
}
|
||||
|
||||
// Set a raw filter attribute
|
||||
func (f *ScmpFilter) setFilterAttr(attr scmpFilterAttr, value C.uint32_t) error {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
if !f.valid {
|
||||
return errBadFilter
|
||||
}
|
||||
|
||||
if !checkVersionAbove(2, 2, 0) && attr == filterAttrTsync {
|
||||
return fmt.Errorf("the thread synchronization attribute is not supported in this version of the library")
|
||||
}
|
||||
|
||||
retCode := C.seccomp_attr_set(f.filterCtx, attr.toNative(), value)
|
||||
if retCode != 0 {
|
||||
return syscall.Errno(-1 * retCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DOES NOT LOCK OR CHECK VALIDITY
|
||||
// Assumes caller has already done this
|
||||
// Wrapper for seccomp_rule_add_... functions
|
||||
func (f *ScmpFilter) addRuleWrapper(call ScmpSyscall, action ScmpAction, exact bool, cond C.scmp_cast_t) error {
|
||||
var length C.uint
|
||||
if cond != nil {
|
||||
length = 1
|
||||
} else {
|
||||
length = 0
|
||||
}
|
||||
|
||||
var retCode C.int
|
||||
if exact {
|
||||
retCode = C.seccomp_rule_add_exact_array(f.filterCtx, action.toNative(), C.int(call), length, cond)
|
||||
} else {
|
||||
retCode = C.seccomp_rule_add_array(f.filterCtx, action.toNative(), C.int(call), length, cond)
|
||||
}
|
||||
|
||||
if syscall.Errno(-1*retCode) == syscall.EFAULT {
|
||||
return fmt.Errorf("unrecognized syscall")
|
||||
} else if syscall.Errno(-1*retCode) == syscall.EPERM {
|
||||
return fmt.Errorf("requested action matches default action of filter")
|
||||
} else if retCode != 0 {
|
||||
return syscall.Errno(-1 * retCode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Generic add function for filter rules
|
||||
func (f *ScmpFilter) addRuleGeneric(call ScmpSyscall, action ScmpAction, exact bool, conds []ScmpCondition) error {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
if !f.valid {
|
||||
return errBadFilter
|
||||
}
|
||||
|
||||
if len(conds) == 0 {
|
||||
if err := f.addRuleWrapper(call, action, exact, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// We don't support conditional filtering in library version v2.1
|
||||
if !checkVersionAbove(2, 2, 1) {
|
||||
return fmt.Errorf("conditional filtering requires libseccomp version >= 2.2.1")
|
||||
}
|
||||
|
||||
for _, cond := range conds {
|
||||
cmpStruct := C.make_struct_arg_cmp(C.uint(cond.Argument), cond.Op.toNative(), C.uint64_t(cond.Operand1), C.uint64_t(cond.Operand2))
|
||||
defer C.free(cmpStruct)
|
||||
|
||||
if err := f.addRuleWrapper(call, action, exact, C.scmp_cast_t(cmpStruct)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Generic Helpers
|
||||
|
||||
// Helper - Sanitize Arch token input
|
||||
func sanitizeArch(in ScmpArch) error {
|
||||
if in < archStart || in > archEnd {
|
||||
return fmt.Errorf("unrecognized architecture")
|
||||
}
|
||||
|
||||
if in.toNative() == C.C_ARCH_BAD {
|
||||
return fmt.Errorf("architecture is not supported on this version of the library")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func sanitizeAction(in ScmpAction) error {
|
||||
inTmp := in & 0x0000FFFF
|
||||
if inTmp < actionStart || inTmp > actionEnd {
|
||||
return fmt.Errorf("unrecognized action")
|
||||
}
|
||||
|
||||
if inTmp != ActTrace && inTmp != ActErrno && (in&0xFFFF0000) != 0 {
|
||||
return fmt.Errorf("highest 16 bits must be zeroed except for Trace and Errno")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func sanitizeCompareOp(in ScmpCompareOp) error {
|
||||
if in < compareOpStart || in > compareOpEnd {
|
||||
return fmt.Errorf("unrecognized comparison operator")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func archFromNative(a C.uint32_t) (ScmpArch, error) {
|
||||
switch a {
|
||||
case C.C_ARCH_X86:
|
||||
return ArchX86, nil
|
||||
case C.C_ARCH_X86_64:
|
||||
return ArchAMD64, nil
|
||||
case C.C_ARCH_X32:
|
||||
return ArchX32, nil
|
||||
case C.C_ARCH_ARM:
|
||||
return ArchARM, nil
|
||||
case C.C_ARCH_NATIVE:
|
||||
return ArchNative, nil
|
||||
case C.C_ARCH_AARCH64:
|
||||
return ArchARM64, nil
|
||||
case C.C_ARCH_MIPS:
|
||||
return ArchMIPS, nil
|
||||
case C.C_ARCH_MIPS64:
|
||||
return ArchMIPS64, nil
|
||||
case C.C_ARCH_MIPS64N32:
|
||||
return ArchMIPS64N32, nil
|
||||
case C.C_ARCH_MIPSEL:
|
||||
return ArchMIPSEL, nil
|
||||
case C.C_ARCH_MIPSEL64:
|
||||
return ArchMIPSEL64, nil
|
||||
case C.C_ARCH_MIPSEL64N32:
|
||||
return ArchMIPSEL64N32, nil
|
||||
default:
|
||||
return 0x0, fmt.Errorf("unrecognized architecture")
|
||||
}
|
||||
}
|
||||
|
||||
// Only use with sanitized arches, no error handling
|
||||
func (a ScmpArch) toNative() C.uint32_t {
|
||||
switch a {
|
||||
case ArchX86:
|
||||
return C.C_ARCH_X86
|
||||
case ArchAMD64:
|
||||
return C.C_ARCH_X86_64
|
||||
case ArchX32:
|
||||
return C.C_ARCH_X32
|
||||
case ArchARM:
|
||||
return C.C_ARCH_ARM
|
||||
case ArchARM64:
|
||||
return C.C_ARCH_AARCH64
|
||||
case ArchMIPS:
|
||||
return C.C_ARCH_MIPS
|
||||
case ArchMIPS64:
|
||||
return C.C_ARCH_MIPS64
|
||||
case ArchMIPS64N32:
|
||||
return C.C_ARCH_MIPS64N32
|
||||
case ArchMIPSEL:
|
||||
return C.C_ARCH_MIPSEL
|
||||
case ArchMIPSEL64:
|
||||
return C.C_ARCH_MIPSEL64
|
||||
case ArchMIPSEL64N32:
|
||||
return C.C_ARCH_MIPSEL64N32
|
||||
case ArchNative:
|
||||
return C.C_ARCH_NATIVE
|
||||
default:
|
||||
return 0x0
|
||||
}
|
||||
}
|
||||
|
||||
// Only use with sanitized ops, no error handling
|
||||
func (a ScmpCompareOp) toNative() C.int {
|
||||
switch a {
|
||||
case CompareNotEqual:
|
||||
return C.C_CMP_NE
|
||||
case CompareLess:
|
||||
return C.C_CMP_LT
|
||||
case CompareLessOrEqual:
|
||||
return C.C_CMP_LE
|
||||
case CompareEqual:
|
||||
return C.C_CMP_EQ
|
||||
case CompareGreaterEqual:
|
||||
return C.C_CMP_GE
|
||||
case CompareGreater:
|
||||
return C.C_CMP_GT
|
||||
case CompareMaskedEqual:
|
||||
return C.C_CMP_MASKED_EQ
|
||||
default:
|
||||
return 0x0
|
||||
}
|
||||
}
|
||||
|
||||
func actionFromNative(a C.uint32_t) (ScmpAction, error) {
|
||||
aTmp := a & 0xFFFF
|
||||
switch a & 0xFFFF0000 {
|
||||
case C.C_ACT_KILL:
|
||||
return ActKill, nil
|
||||
case C.C_ACT_TRAP:
|
||||
return ActTrap, nil
|
||||
case C.C_ACT_ERRNO:
|
||||
return ActErrno.SetReturnCode(int16(aTmp)), nil
|
||||
case C.C_ACT_TRACE:
|
||||
return ActTrace.SetReturnCode(int16(aTmp)), nil
|
||||
case C.C_ACT_ALLOW:
|
||||
return ActAllow, nil
|
||||
default:
|
||||
return 0x0, fmt.Errorf("unrecognized action")
|
||||
}
|
||||
}
|
||||
|
||||
// Only use with sanitized actions, no error handling
|
||||
func (a ScmpAction) toNative() C.uint32_t {
|
||||
switch a & 0xFFFF {
|
||||
case ActKill:
|
||||
return C.C_ACT_KILL
|
||||
case ActTrap:
|
||||
return C.C_ACT_TRAP
|
||||
case ActErrno:
|
||||
return C.C_ACT_ERRNO | (C.uint32_t(a) >> 16)
|
||||
case ActTrace:
|
||||
return C.C_ACT_TRACE | (C.uint32_t(a) >> 16)
|
||||
case ActAllow:
|
||||
return C.C_ACT_ALLOW
|
||||
default:
|
||||
return 0x0
|
||||
}
|
||||
}
|
||||
|
||||
// Internal only, assumes safe attribute
|
||||
func (a scmpFilterAttr) toNative() uint32 {
|
||||
switch a {
|
||||
case filterAttrActDefault:
|
||||
return uint32(C.C_ATTRIBUTE_DEFAULT)
|
||||
case filterAttrActBadArch:
|
||||
return uint32(C.C_ATTRIBUTE_BADARCH)
|
||||
case filterAttrNNP:
|
||||
return uint32(C.C_ATTRIBUTE_NNP)
|
||||
case filterAttrTsync:
|
||||
return uint32(C.C_ATTRIBUTE_TSYNC)
|
||||
default:
|
||||
return 0x0
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue