1
0
Fork 0
mirror of https://github.com/miniflux/v2.git synced 2025-09-15 18:57:04 +00:00

Update vendor dependencies

This commit is contained in:
Frédéric Guillot 2018-07-06 21:18:14 -07:00
parent 34a3fe426b
commit 459bb4531f
747 changed files with 89857 additions and 39711 deletions

View file

@ -4,16 +4,15 @@ Go is an open source project.
It is the work of hundreds of contributors. We appreciate your help!
## Filing issues
When [filing an issue](https://golang.org/issue/new), make sure to answer these five questions:
1. What version of Go are you using (`go version`)?
2. What operating system and processor architecture are you using?
3. What did you do?
4. What did you expect to see?
5. What did you see instead?
1. What version of Go are you using (`go version`)?
2. What operating system and processor architecture are you using?
3. What did you do?
4. What did you expect to see?
5. What did you see instead?
General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker.
The gophers there will answer or ask you to file an issue if you've tripped over a bug.
@ -23,9 +22,5 @@ The gophers there will answer or ask you to file an issue if you've tripped over
Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html)
before sending patches.
**We do not accept GitHub pull requests**
(we use [Gerrit](https://code.google.com/p/gerrit/) instead for code review).
Unless otherwise noted, the Go source files are distributed under
the BSD-style license found in the LICENSE file.

View file

@ -198,7 +198,7 @@ func (a LoadConstant) Assemble() (RawInstruction, error) {
return assembleLoad(a.Dst, 4, opAddrModeImmediate, a.Val)
}
// String returns the the instruction in assembler notation.
// String returns the instruction in assembler notation.
func (a LoadConstant) String() string {
switch a.Dst {
case RegA:
@ -224,7 +224,7 @@ func (a LoadScratch) Assemble() (RawInstruction, error) {
return assembleLoad(a.Dst, 4, opAddrModeScratch, uint32(a.N))
}
// String returns the the instruction in assembler notation.
// String returns the instruction in assembler notation.
func (a LoadScratch) String() string {
switch a.Dst {
case RegA:
@ -248,7 +248,7 @@ func (a LoadAbsolute) Assemble() (RawInstruction, error) {
return assembleLoad(RegA, a.Size, opAddrModeAbsolute, a.Off)
}
// String returns the the instruction in assembler notation.
// String returns the instruction in assembler notation.
func (a LoadAbsolute) String() string {
switch a.Size {
case 1: // byte
@ -277,7 +277,7 @@ func (a LoadIndirect) Assemble() (RawInstruction, error) {
return assembleLoad(RegA, a.Size, opAddrModeIndirect, a.Off)
}
// String returns the the instruction in assembler notation.
// String returns the instruction in assembler notation.
func (a LoadIndirect) String() string {
switch a.Size {
case 1: // byte
@ -306,7 +306,7 @@ func (a LoadMemShift) Assemble() (RawInstruction, error) {
return assembleLoad(RegX, 1, opAddrModeMemShift, a.Off)
}
// String returns the the instruction in assembler notation.
// String returns the instruction in assembler notation.
func (a LoadMemShift) String() string {
return fmt.Sprintf("ldx 4*([%d]&0xf)", a.Off)
}
@ -325,7 +325,7 @@ func (a LoadExtension) Assemble() (RawInstruction, error) {
return assembleLoad(RegA, 4, opAddrModeAbsolute, uint32(extOffset+a.Num))
}
// String returns the the instruction in assembler notation.
// String returns the instruction in assembler notation.
func (a LoadExtension) String() string {
switch a.Num {
case ExtLen:
@ -392,7 +392,7 @@ func (a StoreScratch) Assemble() (RawInstruction, error) {
}, nil
}
// String returns the the instruction in assembler notation.
// String returns the instruction in assembler notation.
func (a StoreScratch) String() string {
switch a.Src {
case RegA:
@ -418,7 +418,7 @@ func (a ALUOpConstant) Assemble() (RawInstruction, error) {
}, nil
}
// String returns the the instruction in assembler notation.
// String returns the instruction in assembler notation.
func (a ALUOpConstant) String() string {
switch a.Op {
case ALUOpAdd:
@ -458,7 +458,7 @@ func (a ALUOpX) Assemble() (RawInstruction, error) {
}, nil
}
// String returns the the instruction in assembler notation.
// String returns the instruction in assembler notation.
func (a ALUOpX) String() string {
switch a.Op {
case ALUOpAdd:
@ -496,7 +496,7 @@ func (a NegateA) Assemble() (RawInstruction, error) {
}, nil
}
// String returns the the instruction in assembler notation.
// String returns the instruction in assembler notation.
func (a NegateA) String() string {
return fmt.Sprintf("neg")
}
@ -514,7 +514,7 @@ func (a Jump) Assemble() (RawInstruction, error) {
}, nil
}
// String returns the the instruction in assembler notation.
// String returns the instruction in assembler notation.
func (a Jump) String() string {
return fmt.Sprintf("ja %d", a.Skip)
}
@ -566,7 +566,7 @@ func (a JumpIf) Assemble() (RawInstruction, error) {
}, nil
}
// String returns the the instruction in assembler notation.
// String returns the instruction in assembler notation.
func (a JumpIf) String() string {
switch a.Cond {
// K == A
@ -621,7 +621,7 @@ func (a RetA) Assemble() (RawInstruction, error) {
}, nil
}
// String returns the the instruction in assembler notation.
// String returns the instruction in assembler notation.
func (a RetA) String() string {
return fmt.Sprintf("ret a")
}
@ -639,7 +639,7 @@ func (a RetConstant) Assemble() (RawInstruction, error) {
}, nil
}
// String returns the the instruction in assembler notation.
// String returns the instruction in assembler notation.
func (a RetConstant) String() string {
return fmt.Sprintf("ret #%d", a.Val)
}
@ -654,7 +654,7 @@ func (a TXA) Assemble() (RawInstruction, error) {
}, nil
}
// String returns the the instruction in assembler notation.
// String returns the instruction in assembler notation.
func (a TXA) String() string {
return fmt.Sprintf("txa")
}
@ -669,7 +669,7 @@ func (a TAX) Assemble() (RawInstruction, error) {
}, nil
}
// String returns the the instruction in assembler notation.
// String returns the instruction in assembler notation.
func (a TAX) String() string {
return fmt.Sprintf("tax")
}

View file

@ -37,20 +37,20 @@ func ExampleParser() {
},
Answers: []dnsmessage.Resource{
{
dnsmessage.ResourceHeader{
Header: dnsmessage.ResourceHeader{
Name: mustNewName("foo.bar.example.com."),
Type: dnsmessage.TypeA,
Class: dnsmessage.ClassINET,
},
&dnsmessage.AResource{[4]byte{127, 0, 0, 1}},
Body: &dnsmessage.AResource{A: [4]byte{127, 0, 0, 1}},
},
{
dnsmessage.ResourceHeader{
Header: dnsmessage.ResourceHeader{
Name: mustNewName("bar.example.com."),
Type: dnsmessage.TypeA,
Class: dnsmessage.ClassINET,
},
&dnsmessage.AResource{[4]byte{127, 0, 0, 2}},
Body: &dnsmessage.AResource{A: [4]byte{127, 0, 0, 2}},
},
},
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -306,7 +306,7 @@ func (t *table) push(i uint32, depth int) bool {
// The lists of element names and attribute keys were taken from
// https://html.spec.whatwg.org/multipage/indices.html#index
// as of the "HTML Living Standard - Last Updated 18 September 2017" version.
// as of the "HTML Living Standard - Last Updated 16 April 2018" version.
// "command", "keygen" and "menuitem" have been removed from the spec,
// but are kept here for backwards compatibility.
@ -665,6 +665,7 @@ var eventHandlers = []string{
// extra are ad-hoc values not covered by any of the lists above.
var extra = []string{
"acronym",
"align",
"annotation",
"annotation-xml",
@ -700,6 +701,8 @@ var extra = []string{
"plaintext",
"prompt",
"public",
"rb",
"rtc",
"spacer",
"strike",
"svg",

File diff suppressed because it is too large Load diff

View file

@ -10,6 +10,7 @@ var testAtomList = []string{
"accept",
"accept-charset",
"accesskey",
"acronym",
"action",
"address",
"align",
@ -295,6 +296,7 @@ var testAtomList = []string{
"public",
"q",
"radiogroup",
"rb",
"readonly",
"referrerpolicy",
"rel",
@ -304,6 +306,7 @@ var testAtomList = []string{
"rowspan",
"rp",
"rt",
"rtc",
"ruby",
"s",
"samp",

View file

@ -4,7 +4,7 @@
package html
// Section 12.2.3.2 of the HTML5 specification says "The following elements
// Section 12.2.4.2 of the HTML5 specification says "The following elements
// have varying levels of special parsing rules".
// https://html.spec.whatwg.org/multipage/syntax.html#the-stack-of-open-elements
var isSpecialElementMap = map[string]bool{

4154
vendor/golang.org/x/net/html/entity.go generated vendored

File diff suppressed because it is too large Load diff

View file

@ -67,7 +67,7 @@ func mathMLTextIntegrationPoint(n *Node) bool {
return false
}
// Section 12.2.5.5.
// Section 12.2.6.5.
var breakout = map[string]bool{
"b": true,
"big": true,
@ -115,7 +115,7 @@ var breakout = map[string]bool{
"var": true,
}
// Section 12.2.5.5.
// Section 12.2.6.5.
var svgTagNameAdjustments = map[string]string{
"altglyph": "altGlyph",
"altglyphdef": "altGlyphDef",
@ -155,7 +155,7 @@ var svgTagNameAdjustments = map[string]string{
"textpath": "textPath",
}
// Section 12.2.5.1
// Section 12.2.6.1
var mathMLAttributeAdjustments = map[string]string{
"definitionurl": "definitionURL",
}

33
vendor/golang.org/x/net/html/node.go generated vendored
View file

@ -21,9 +21,10 @@ const (
scopeMarkerNode
)
// Section 12.2.3.3 says "scope markers are inserted when entering applet
// elements, buttons, object elements, marquees, table cells, and table
// captions, and are used to prevent formatting from 'leaking'".
// Section 12.2.4.3 says "The markers are inserted when entering applet,
// object, marquee, template, td, th, and caption elements, and are used
// to prevent formatting from "leaking" into applet, object, marquee,
// template, td, th, and caption elements".
var scopeMarker = Node{Type: scopeMarkerNode}
// A Node consists of a NodeType and some Data (tag name for element nodes,
@ -173,6 +174,16 @@ func (s *nodeStack) index(n *Node) int {
return -1
}
// contains returns whether a is within s.
func (s *nodeStack) contains(a atom.Atom) bool {
for _, n := range *s {
if n.DataAtom == a {
return true
}
}
return false
}
// insert inserts a node at the given index.
func (s *nodeStack) insert(i int, n *Node) {
(*s) = append(*s, nil)
@ -191,3 +202,19 @@ func (s *nodeStack) remove(n *Node) {
(*s)[j] = nil
*s = (*s)[:j]
}
type insertionModeStack []insertionMode
func (s *insertionModeStack) pop() (im insertionMode) {
i := len(*s)
im = (*s)[i-1]
*s = (*s)[:i-1]
return im
}
func (s *insertionModeStack) top() insertionMode {
if i := len(*s); i > 0 {
return (*s)[i-1]
}
return nil
}

370
vendor/golang.org/x/net/html/parse.go generated vendored
View file

@ -25,20 +25,22 @@ type parser struct {
hasSelfClosingToken bool
// doc is the document root element.
doc *Node
// The stack of open elements (section 12.2.3.2) and active formatting
// elements (section 12.2.3.3).
// The stack of open elements (section 12.2.4.2) and active formatting
// elements (section 12.2.4.3).
oe, afe nodeStack
// Element pointers (section 12.2.3.4).
// Element pointers (section 12.2.4.4).
head, form *Node
// Other parsing state flags (section 12.2.3.5).
// Other parsing state flags (section 12.2.4.5).
scripting, framesetOK bool
// The stack of template insertion modes
templateStack insertionModeStack
// im is the current insertion mode.
im insertionMode
// originalIM is the insertion mode to go back to after completing a text
// or inTableText insertion mode.
originalIM insertionMode
// fosterParenting is whether new elements should be inserted according to
// the foster parenting rules (section 12.2.5.3).
// the foster parenting rules (section 12.2.6.1).
fosterParenting bool
// quirks is whether the parser is operating in "quirks mode."
quirks bool
@ -56,7 +58,7 @@ func (p *parser) top() *Node {
return p.doc
}
// Stop tags for use in popUntil. These come from section 12.2.3.2.
// Stop tags for use in popUntil. These come from section 12.2.4.2.
var (
defaultScopeStopTags = map[string][]a.Atom{
"": {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, a.Marquee, a.Object, a.Template},
@ -79,7 +81,7 @@ const (
// popUntil pops the stack of open elements at the highest element whose tag
// is in matchTags, provided there is no higher element in the scope's stop
// tags (as defined in section 12.2.3.2). It returns whether or not there was
// tags (as defined in section 12.2.4.2). It returns whether or not there was
// such an element. If there was not, popUntil leaves the stack unchanged.
//
// For example, the set of stop tags for table scope is: "html", "table". If
@ -126,7 +128,7 @@ func (p *parser) indexOfElementInScope(s scope, matchTags ...a.Atom) int {
return -1
}
case tableScope:
if tagAtom == a.Html || tagAtom == a.Table {
if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template {
return -1
}
case selectScope:
@ -162,17 +164,17 @@ func (p *parser) clearStackToContext(s scope) {
tagAtom := p.oe[i].DataAtom
switch s {
case tableScope:
if tagAtom == a.Html || tagAtom == a.Table {
if tagAtom == a.Html || tagAtom == a.Table || tagAtom == a.Template {
p.oe = p.oe[:i+1]
return
}
case tableRowScope:
if tagAtom == a.Html || tagAtom == a.Tr {
if tagAtom == a.Html || tagAtom == a.Tr || tagAtom == a.Template {
p.oe = p.oe[:i+1]
return
}
case tableBodyScope:
if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead {
if tagAtom == a.Html || tagAtom == a.Tbody || tagAtom == a.Tfoot || tagAtom == a.Thead || tagAtom == a.Template {
p.oe = p.oe[:i+1]
return
}
@ -183,7 +185,7 @@ func (p *parser) clearStackToContext(s scope) {
}
// generateImpliedEndTags pops nodes off the stack of open elements as long as
// the top node has a tag name of dd, dt, li, option, optgroup, p, rp, or rt.
// the top node has a tag name of dd, dt, li, optgroup, option, p, rb, rp, rt or rtc.
// If exceptions are specified, nodes with that name will not be popped off.
func (p *parser) generateImpliedEndTags(exceptions ...string) {
var i int
@ -192,7 +194,7 @@ loop:
n := p.oe[i]
if n.Type == ElementNode {
switch n.DataAtom {
case a.Dd, a.Dt, a.Li, a.Option, a.Optgroup, a.P, a.Rp, a.Rt:
case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rb, a.Rp, a.Rt, a.Rtc:
for _, except := range exceptions {
if n.Data == except {
break loop
@ -207,6 +209,27 @@ loop:
p.oe = p.oe[:i+1]
}
// generateAllImpliedEndTags pops nodes off the stack of open elements as long as
// the top node has a tag name of caption, colgroup, dd, div, dt, li, optgroup, option, p, rb,
// rp, rt, rtc, span, tbody, td, tfoot, th, thead or tr.
func (p *parser) generateAllImpliedEndTags() {
var i int
for i = len(p.oe) - 1; i >= 0; i-- {
n := p.oe[i]
if n.Type == ElementNode {
switch n.DataAtom {
// TODO: remove this divergence from the HTML5 spec
case a.Caption, a.Colgroup, a.Dd, a.Div, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rb,
a.Rp, a.Rt, a.Rtc, a.Span, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
continue
}
}
break
}
p.oe = p.oe[:i+1]
}
// addChild adds a child node n to the top element, and pushes n onto the stack
// of open elements if it is an element node.
func (p *parser) addChild(n *Node) {
@ -234,9 +257,9 @@ func (p *parser) shouldFosterParent() bool {
}
// fosterParent adds a child node according to the foster parenting rules.
// Section 12.2.5.3, "foster parenting".
// Section 12.2.6.1, "foster parenting".
func (p *parser) fosterParent(n *Node) {
var table, parent, prev *Node
var table, parent, prev, template *Node
var i int
for i = len(p.oe) - 1; i >= 0; i-- {
if p.oe[i].DataAtom == a.Table {
@ -245,6 +268,19 @@ func (p *parser) fosterParent(n *Node) {
}
}
var j int
for j = len(p.oe) - 1; j >= 0; j-- {
if p.oe[j].DataAtom == a.Template {
template = p.oe[j]
break
}
}
if template != nil && (table == nil || j < i) {
template.AppendChild(n)
return
}
if table == nil {
// The foster parent is the html element.
parent = p.oe[0]
@ -304,7 +340,7 @@ func (p *parser) addElement() {
})
}
// Section 12.2.3.3.
// Section 12.2.4.3.
func (p *parser) addFormattingElement() {
tagAtom, attr := p.tok.DataAtom, p.tok.Attr
p.addElement()
@ -351,7 +387,7 @@ findIdenticalElements:
p.afe = append(p.afe, p.top())
}
// Section 12.2.3.3.
// Section 12.2.4.3.
func (p *parser) clearActiveFormattingElements() {
for {
n := p.afe.pop()
@ -361,7 +397,7 @@ func (p *parser) clearActiveFormattingElements() {
}
}
// Section 12.2.3.3.
// Section 12.2.4.3.
func (p *parser) reconstructActiveFormattingElements() {
n := p.afe.top()
if n == nil {
@ -390,12 +426,12 @@ func (p *parser) reconstructActiveFormattingElements() {
}
}
// Section 12.2.4.
// Section 12.2.5.
func (p *parser) acknowledgeSelfClosingTag() {
p.hasSelfClosingToken = false
}
// An insertion mode (section 12.2.3.1) is the state transition function from
// An insertion mode (section 12.2.4.1) is the state transition function from
// a particular state in the HTML5 parser's state machine. It updates the
// parser's fields depending on parser.tok (where ErrorToken means EOF).
// It returns whether the token was consumed.
@ -403,7 +439,7 @@ type insertionMode func(*parser) bool
// setOriginalIM sets the insertion mode to return to after completing a text or
// inTableText insertion mode.
// Section 12.2.3.1, "using the rules for".
// Section 12.2.4.1, "using the rules for".
func (p *parser) setOriginalIM() {
if p.originalIM != nil {
panic("html: bad parser state: originalIM was set twice")
@ -411,18 +447,38 @@ func (p *parser) setOriginalIM() {
p.originalIM = p.im
}
// Section 12.2.3.1, "reset the insertion mode".
// Section 12.2.4.1, "reset the insertion mode".
func (p *parser) resetInsertionMode() {
for i := len(p.oe) - 1; i >= 0; i-- {
n := p.oe[i]
if i == 0 && p.context != nil {
last := i == 0
if last && p.context != nil {
n = p.context
}
switch n.DataAtom {
case a.Select:
if !last {
for ancestor, first := n, p.oe[0]; ancestor != first; {
if ancestor == first {
break
}
ancestor = p.oe[p.oe.index(ancestor)-1]
switch ancestor.DataAtom {
case a.Template:
p.im = inSelectIM
return
case a.Table:
p.im = inSelectInTableIM
return
}
}
}
p.im = inSelectIM
case a.Td, a.Th:
// TODO: remove this divergence from the HTML5 spec.
//
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
p.im = inCellIM
case a.Tr:
p.im = inRowIM
@ -434,25 +490,37 @@ func (p *parser) resetInsertionMode() {
p.im = inColumnGroupIM
case a.Table:
p.im = inTableIM
case a.Template:
p.im = p.templateStack.top()
case a.Head:
p.im = inBodyIM
// TODO: remove this divergence from the HTML5 spec.
//
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
p.im = inHeadIM
case a.Body:
p.im = inBodyIM
case a.Frameset:
p.im = inFramesetIM
case a.Html:
p.im = beforeHeadIM
if p.head == nil {
p.im = beforeHeadIM
} else {
p.im = afterHeadIM
}
default:
if last {
p.im = inBodyIM
return
}
continue
}
return
}
p.im = inBodyIM
}
const whitespace = " \t\r\n\f"
// Section 12.2.5.4.1.
// Section 12.2.6.4.1.
func initialIM(p *parser) bool {
switch p.tok.Type {
case TextToken:
@ -479,7 +547,7 @@ func initialIM(p *parser) bool {
return false
}
// Section 12.2.5.4.2.
// Section 12.2.6.4.2.
func beforeHTMLIM(p *parser) bool {
switch p.tok.Type {
case DoctypeToken:
@ -517,7 +585,7 @@ func beforeHTMLIM(p *parser) bool {
return false
}
// Section 12.2.5.4.3.
// Section 12.2.6.4.3.
func beforeHeadIM(p *parser) bool {
switch p.tok.Type {
case TextToken:
@ -560,7 +628,7 @@ func beforeHeadIM(p *parser) bool {
return false
}
// Section 12.2.5.4.4.
// Section 12.2.6.4.4.
func inHeadIM(p *parser) bool {
switch p.tok.Type {
case TextToken:
@ -590,19 +658,36 @@ func inHeadIM(p *parser) bool {
case a.Head:
// Ignore the token.
return true
case a.Template:
p.addElement()
p.afe = append(p.afe, &scopeMarker)
p.framesetOK = false
p.im = inTemplateIM
p.templateStack = append(p.templateStack, inTemplateIM)
return true
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Head:
n := p.oe.pop()
if n.DataAtom != a.Head {
panic("html: bad parser state: <head> element not found, in the in-head insertion mode")
}
p.oe.pop()
p.im = afterHeadIM
return true
case a.Body, a.Html, a.Br:
p.parseImpliedToken(EndTagToken, a.Head, a.Head.String())
return false
case a.Template:
if !p.oe.contains(a.Template) {
return true
}
p.generateAllImpliedEndTags()
if n := p.oe.top(); n.DataAtom != a.Template {
return true
}
p.popUntil(defaultScope, a.Template)
p.clearActiveFormattingElements()
p.templateStack.pop()
p.resetInsertionMode()
return true
default:
// Ignore the token.
return true
@ -622,7 +707,7 @@ func inHeadIM(p *parser) bool {
return false
}
// Section 12.2.5.4.6.
// Section 12.2.6.4.6.
func afterHeadIM(p *parser) bool {
switch p.tok.Type {
case TextToken:
@ -648,7 +733,7 @@ func afterHeadIM(p *parser) bool {
p.addElement()
p.im = inFramesetIM
return true
case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title:
case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
p.oe = append(p.oe, p.head)
defer p.oe.remove(p.head)
return inHeadIM(p)
@ -660,6 +745,8 @@ func afterHeadIM(p *parser) bool {
switch p.tok.DataAtom {
case a.Body, a.Html, a.Br:
// Drop down to creating an implied <body> tag.
case a.Template:
return inHeadIM(p)
default:
// Ignore the token.
return true
@ -697,7 +784,7 @@ func copyAttributes(dst *Node, src Token) {
}
}
// Section 12.2.5.4.7.
// Section 12.2.6.4.7.
func inBodyIM(p *parser) bool {
switch p.tok.Type {
case TextToken:
@ -727,10 +814,16 @@ func inBodyIM(p *parser) bool {
case StartTagToken:
switch p.tok.DataAtom {
case a.Html:
if p.oe.contains(a.Template) {
return true
}
copyAttributes(p.oe[0], p.tok)
case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Title:
case a.Base, a.Basefont, a.Bgsound, a.Command, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
return inHeadIM(p)
case a.Body:
if p.oe.contains(a.Template) {
return true
}
if len(p.oe) >= 2 {
body := p.oe[1]
if body.Type == ElementNode && body.DataAtom == a.Body {
@ -767,9 +860,13 @@ func inBodyIM(p *parser) bool {
// The newline, if any, will be dealt with by the TextToken case.
p.framesetOK = false
case a.Form:
if p.form == nil {
p.popUntil(buttonScope, a.P)
p.addElement()
if p.form != nil && !p.oe.contains(a.Template) {
// Ignore the token
return true
}
p.popUntil(buttonScope, a.P)
p.addElement()
if !p.oe.contains(a.Template) {
p.form = p.top()
}
case a.Li:
@ -952,11 +1049,16 @@ func inBodyIM(p *parser) bool {
}
p.reconstructActiveFormattingElements()
p.addElement()
case a.Rp, a.Rt:
case a.Rb, a.Rtc:
if p.elementInScope(defaultScope, a.Ruby) {
p.generateImpliedEndTags()
}
p.addElement()
case a.Rp, a.Rt:
if p.elementInScope(defaultScope, a.Ruby) {
p.generateImpliedEndTags("rtc")
}
p.addElement()
case a.Math, a.Svg:
p.reconstructActiveFormattingElements()
if p.tok.DataAtom == a.Math {
@ -972,7 +1074,13 @@ func inBodyIM(p *parser) bool {
p.acknowledgeSelfClosingTag()
}
return true
case a.Caption, a.Col, a.Colgroup, a.Frame, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
case a.Frame:
// TODO: remove this divergence from the HTML5 spec.
if p.oe.contains(a.Template) {
p.addElement()
return true
}
case a.Caption, a.Col, a.Colgroup, a.Head, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
// Ignore the token.
default:
p.reconstructActiveFormattingElements()
@ -993,15 +1101,29 @@ func inBodyIM(p *parser) bool {
case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, a.Center, a.Details, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Menu, a.Nav, a.Ol, a.Pre, a.Section, a.Summary, a.Ul:
p.popUntil(defaultScope, p.tok.DataAtom)
case a.Form:
node := p.form
p.form = nil
i := p.indexOfElementInScope(defaultScope, a.Form)
if node == nil || i == -1 || p.oe[i] != node {
// Ignore the token.
return true
if p.oe.contains(a.Template) {
i := p.indexOfElementInScope(defaultScope, a.Form)
if i == -1 {
// Ignore the token.
return true
}
p.generateImpliedEndTags()
if p.oe[i].DataAtom != a.Form {
// Ignore the token.
return true
}
p.popUntil(defaultScope, a.Form)
} else {
node := p.form
p.form = nil
i := p.indexOfElementInScope(defaultScope, a.Form)
if node == nil || i == -1 || p.oe[i] != node {
// Ignore the token.
return true
}
p.generateImpliedEndTags()
p.oe.remove(node)
}
p.generateImpliedEndTags()
p.oe.remove(node)
case a.P:
if !p.elementInScope(buttonScope, a.P) {
p.parseImpliedToken(StartTagToken, a.P, a.P.String())
@ -1022,6 +1144,8 @@ func inBodyIM(p *parser) bool {
case a.Br:
p.tok.Type = StartTagToken
return false
case a.Template:
return inHeadIM(p)
default:
p.inBodyEndTagOther(p.tok.DataAtom)
}
@ -1030,6 +1154,21 @@ func inBodyIM(p *parser) bool {
Type: CommentNode,
Data: p.tok.Data,
})
case ErrorToken:
// TODO: remove this divergence from the HTML5 spec.
if len(p.templateStack) > 0 {
p.im = inTemplateIM
return false
} else {
for _, e := range p.oe {
switch e.DataAtom {
case a.Dd, a.Dt, a.Li, a.Optgroup, a.Option, a.P, a.Rb, a.Rp, a.Rt, a.Rtc, a.Tbody, a.Td, a.Tfoot, a.Th,
a.Thead, a.Tr, a.Body, a.Html:
default:
return true
}
}
}
}
return true
@ -1135,6 +1274,12 @@ func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
switch commonAncestor.DataAtom {
case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
p.fosterParent(lastNode)
case a.Template:
// TODO: remove namespace checking
if commonAncestor.Namespace == "html" {
commonAncestor = commonAncestor.LastChild
}
fallthrough
default:
commonAncestor.AppendChild(lastNode)
}
@ -1160,7 +1305,7 @@ func (p *parser) inBodyEndTagFormatting(tagAtom a.Atom) {
}
// inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM.
// "Any other end tag" handling from 12.2.5.5 The rules for parsing tokens in foreign content
// "Any other end tag" handling from 12.2.6.5 The rules for parsing tokens in foreign content
// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign
func (p *parser) inBodyEndTagOther(tagAtom a.Atom) {
for i := len(p.oe) - 1; i >= 0; i-- {
@ -1174,7 +1319,7 @@ func (p *parser) inBodyEndTagOther(tagAtom a.Atom) {
}
}
// Section 12.2.5.4.8.
// Section 12.2.6.4.8.
func textIM(p *parser) bool {
switch p.tok.Type {
case ErrorToken:
@ -1203,7 +1348,7 @@ func textIM(p *parser) bool {
return p.tok.Type == EndTagToken
}
// Section 12.2.5.4.9.
// Section 12.2.6.4.9.
func inTableIM(p *parser) bool {
switch p.tok.Type {
case ErrorToken:
@ -1249,7 +1394,7 @@ func inTableIM(p *parser) bool {
}
// Ignore the token.
return true
case a.Style, a.Script:
case a.Style, a.Script, a.Template:
return inHeadIM(p)
case a.Input:
for _, t := range p.tok.Attr {
@ -1261,7 +1406,7 @@ func inTableIM(p *parser) bool {
}
// Otherwise drop down to the default action.
case a.Form:
if p.form != nil {
if p.oe.contains(a.Template) || p.form != nil {
// Ignore the token.
return true
}
@ -1291,6 +1436,8 @@ func inTableIM(p *parser) bool {
case a.Body, a.Caption, a.Col, a.Colgroup, a.Html, a.Tbody, a.Td, a.Tfoot, a.Th, a.Thead, a.Tr:
// Ignore the token.
return true
case a.Template:
return inHeadIM(p)
}
case CommentToken:
p.addChild(&Node{
@ -1309,7 +1456,7 @@ func inTableIM(p *parser) bool {
return inBodyIM(p)
}
// Section 12.2.5.4.11.
// Section 12.2.6.4.11.
func inCaptionIM(p *parser) bool {
switch p.tok.Type {
case StartTagToken:
@ -1355,7 +1502,7 @@ func inCaptionIM(p *parser) bool {
return inBodyIM(p)
}
// Section 12.2.5.4.12.
// Section 12.2.6.4.12.
func inColumnGroupIM(p *parser) bool {
switch p.tok.Type {
case TextToken:
@ -1386,11 +1533,13 @@ func inColumnGroupIM(p *parser) bool {
p.oe.pop()
p.acknowledgeSelfClosingTag()
return true
case a.Template:
return inHeadIM(p)
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Colgroup:
if p.oe.top().DataAtom != a.Html {
if p.oe.top().DataAtom == a.Colgroup {
p.oe.pop()
p.im = inTableIM
}
@ -1398,17 +1547,19 @@ func inColumnGroupIM(p *parser) bool {
case a.Col:
// Ignore the token.
return true
case a.Template:
return inHeadIM(p)
}
}
if p.oe.top().DataAtom != a.Html {
p.oe.pop()
p.im = inTableIM
return false
if p.oe.top().DataAtom != a.Colgroup {
return true
}
return true
p.oe.pop()
p.im = inTableIM
return false
}
// Section 12.2.5.4.13.
// Section 12.2.6.4.13.
func inTableBodyIM(p *parser) bool {
switch p.tok.Type {
case StartTagToken:
@ -1460,7 +1611,7 @@ func inTableBodyIM(p *parser) bool {
return inTableIM(p)
}
// Section 12.2.5.4.14.
// Section 12.2.6.4.14.
func inRowIM(p *parser) bool {
switch p.tok.Type {
case StartTagToken:
@ -1511,7 +1662,7 @@ func inRowIM(p *parser) bool {
return inTableIM(p)
}
// Section 12.2.5.4.15.
// Section 12.2.6.4.15.
func inCellIM(p *parser) bool {
switch p.tok.Type {
case StartTagToken:
@ -1560,7 +1711,7 @@ func inCellIM(p *parser) bool {
return inBodyIM(p)
}
// Section 12.2.5.4.16.
// Section 12.2.6.4.16.
func inSelectIM(p *parser) bool {
switch p.tok.Type {
case ErrorToken:
@ -1597,7 +1748,7 @@ func inSelectIM(p *parser) bool {
p.tokenizer.NextIsNotRawText()
// Ignore the token.
return true
case a.Script:
case a.Script, a.Template:
return inHeadIM(p)
}
case EndTagToken:
@ -1618,6 +1769,8 @@ func inSelectIM(p *parser) bool {
if p.popUntil(selectScope, a.Select) {
p.resetInsertionMode()
}
case a.Template:
return inHeadIM(p)
}
case CommentToken:
p.addChild(&Node{
@ -1632,7 +1785,7 @@ func inSelectIM(p *parser) bool {
return true
}
// Section 12.2.5.4.17.
// Section 12.2.6.4.17.
func inSelectInTableIM(p *parser) bool {
switch p.tok.Type {
case StartTagToken, EndTagToken:
@ -1650,7 +1803,62 @@ func inSelectInTableIM(p *parser) bool {
return inSelectIM(p)
}
// Section 12.2.5.4.18.
// Section 12.2.6.4.18.
func inTemplateIM(p *parser) bool {
switch p.tok.Type {
case TextToken, CommentToken, DoctypeToken:
return inBodyIM(p)
case StartTagToken:
switch p.tok.DataAtom {
case a.Base, a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Script, a.Style, a.Template, a.Title:
return inHeadIM(p)
case a.Caption, a.Colgroup, a.Tbody, a.Tfoot, a.Thead:
p.templateStack.pop()
p.templateStack = append(p.templateStack, inTableIM)
p.im = inTableIM
return false
case a.Col:
p.templateStack.pop()
p.templateStack = append(p.templateStack, inColumnGroupIM)
p.im = inColumnGroupIM
return false
case a.Tr:
p.templateStack.pop()
p.templateStack = append(p.templateStack, inTableBodyIM)
p.im = inTableBodyIM
return false
case a.Td, a.Th:
p.templateStack.pop()
p.templateStack = append(p.templateStack, inRowIM)
p.im = inRowIM
return false
default:
p.templateStack.pop()
p.templateStack = append(p.templateStack, inBodyIM)
p.im = inBodyIM
return false
}
case EndTagToken:
switch p.tok.DataAtom {
case a.Template:
return inHeadIM(p)
default:
// Ignore the token.
return true
}
}
if !p.oe.contains(a.Template) {
// Ignore the token.
return true
}
p.popUntil(defaultScope, a.Template)
p.clearActiveFormattingElements()
p.templateStack.pop()
p.resetInsertionMode()
return false
}
// Section 12.2.6.4.19.
func afterBodyIM(p *parser) bool {
switch p.tok.Type {
case ErrorToken:
@ -1688,7 +1896,7 @@ func afterBodyIM(p *parser) bool {
return false
}
// Section 12.2.5.4.19.
// Section 12.2.6.4.20.
func inFramesetIM(p *parser) bool {
switch p.tok.Type {
case CommentToken:
@ -1720,6 +1928,11 @@ func inFramesetIM(p *parser) bool {
p.acknowledgeSelfClosingTag()
case a.Noframes:
return inHeadIM(p)
case a.Template:
// TODO: remove this divergence from the HTML5 spec.
//
// See https://bugs.chromium.org/p/chromium/issues/detail?id=829668
return inTemplateIM(p)
}
case EndTagToken:
switch p.tok.DataAtom {
@ -1738,7 +1951,7 @@ func inFramesetIM(p *parser) bool {
return true
}
// Section 12.2.5.4.20.
// Section 12.2.6.4.21.
func afterFramesetIM(p *parser) bool {
switch p.tok.Type {
case CommentToken:
@ -1777,7 +1990,7 @@ func afterFramesetIM(p *parser) bool {
return true
}
// Section 12.2.5.4.21.
// Section 12.2.6.4.22.
func afterAfterBodyIM(p *parser) bool {
switch p.tok.Type {
case ErrorToken:
@ -1806,7 +2019,7 @@ func afterAfterBodyIM(p *parser) bool {
return false
}
// Section 12.2.5.4.22.
// Section 12.2.6.4.23.
func afterAfterFramesetIM(p *parser) bool {
switch p.tok.Type {
case CommentToken:
@ -1844,7 +2057,7 @@ func afterAfterFramesetIM(p *parser) bool {
const whitespaceOrNUL = whitespace + "\x00"
// Section 12.2.5.5.
// Section 12.2.6.5
func parseForeignContent(p *parser) bool {
switch p.tok.Type {
case TextToken:
@ -1924,7 +2137,7 @@ func parseForeignContent(p *parser) bool {
return true
}
// Section 12.2.5.
// Section 12.2.6.
func (p *parser) inForeignContent() bool {
if len(p.oe) == 0 {
return false
@ -2064,6 +2277,9 @@ func ParseFragment(r io.Reader, context *Node) ([]*Node, error) {
}
p.doc.AppendChild(root)
p.oe = nodeStack{root}
if context != nil && context.DataAtom == a.Template {
p.templateStack = append(p.templateStack, inTemplateIM)
}
p.resetInsertionMode()
for n := context; n != nil; n = n.Parent {

View file

@ -125,6 +125,7 @@ func (a sortedAttributes) Swap(i, j int) {
func dumpLevel(w io.Writer, n *Node, level int) error {
dumpIndent(w, level)
level++
switch n.Type {
case ErrorNode:
return errors.New("unexpected ErrorNode")
@ -140,13 +141,19 @@ func dumpLevel(w io.Writer, n *Node, level int) error {
sort.Sort(attr)
for _, a := range attr {
io.WriteString(w, "\n")
dumpIndent(w, level+1)
dumpIndent(w, level)
if a.Namespace != "" {
fmt.Fprintf(w, `%s %s="%s"`, a.Namespace, a.Key, a.Val)
} else {
fmt.Fprintf(w, `%s="%s"`, a.Key, a.Val)
}
}
if n.Namespace == "" && n.DataAtom == atom.Template {
io.WriteString(w, "\n")
dumpIndent(w, level)
level++
io.WriteString(w, "content")
}
case TextNode:
fmt.Fprintf(w, `"%s"`, n.Data)
case CommentNode:
@ -176,7 +183,7 @@ func dumpLevel(w io.Writer, n *Node, level int) error {
}
io.WriteString(w, "\n")
for c := n.FirstChild; c != nil; c = c.NextSibling {
if err := dumpLevel(w, c, level+1); err != nil {
if err := dumpLevel(w, c, level); err != nil {
return err
}
}
@ -196,34 +203,36 @@ func dump(n *Node) (string, error) {
return b.String(), nil
}
const testDataDir = "testdata/webkit/"
var testDataDirs = []string{"testdata/webkit/", "testdata/go/"}
func TestParser(t *testing.T) {
testFiles, err := filepath.Glob(testDataDir + "*.dat")
if err != nil {
t.Fatal(err)
}
for _, tf := range testFiles {
f, err := os.Open(tf)
for _, testDataDir := range testDataDirs {
testFiles, err := filepath.Glob(testDataDir + "*.dat")
if err != nil {
t.Fatal(err)
}
defer f.Close()
r := bufio.NewReader(f)
for i := 0; ; i++ {
text, want, context, err := readParseTest(r)
if err == io.EOF {
break
}
for _, tf := range testFiles {
f, err := os.Open(tf)
if err != nil {
t.Fatal(err)
}
defer f.Close()
r := bufio.NewReader(f)
err = testParseCase(text, want, context)
for i := 0; ; i++ {
text, want, context, err := readParseTest(r)
if err == io.EOF {
break
}
if err != nil {
t.Fatal(err)
}
if err != nil {
t.Errorf("%s test #%d %q, %s", tf, i, text, err)
err = testParseCase(text, want, context)
if err != nil {
t.Errorf("%s test #%d %q, %s", tf, i, text, err)
}
}
}
}
@ -373,6 +382,11 @@ func TestNodeConsistency(t *testing.T) {
}
}
func TestParseFragmentWithNilContext(t *testing.T) {
// This shouldn't panic.
ParseFragment(strings.NewReader("<p>hello</p>"), nil)
}
func BenchmarkParser(b *testing.B) {
buf, err := ioutil.ReadFile("testdata/go1.html")
if err != nil {

13
vendor/golang.org/x/net/html/testdata/go/template.dat generated vendored Normal file
View file

@ -0,0 +1,13 @@
#data
<body><template><yt-icon-button></yt-icon-button><form><paper-input></paper-input></form><style></style></template>
#errors
#document
| <html>
| <head>
| <body>
| <template>
| content
| <yt-icon-button>
| <form>
| <paper-input>
| <style>

298
vendor/golang.org/x/net/html/testdata/webkit/ruby.dat generated vendored Normal file
View file

@ -0,0 +1,298 @@
#data
<html><ruby>a<rb>b<rb></ruby></html>
#errors
(1,6): expected-doctype-but-got-start-tag
#document
| <html>
| <head>
| <body>
| <ruby>
| "a"
| <rb>
| "b"
| <rb>
#data
<html><ruby>a<rb>b<rt></ruby></html>
#errors
(1,6): expected-doctype-but-got-start-tag
#document
| <html>
| <head>
| <body>
| <ruby>
| "a"
| <rb>
| "b"
| <rt>
#data
<html><ruby>a<rb>b<rtc></ruby></html>
#errors
(1,6): expected-doctype-but-got-start-tag
#document
| <html>
| <head>
| <body>
| <ruby>
| "a"
| <rb>
| "b"
| <rtc>
#data
<html><ruby>a<rb>b<rp></ruby></html>
#errors
(1,6): expected-doctype-but-got-start-tag
#document
| <html>
| <head>
| <body>
| <ruby>
| "a"
| <rb>
| "b"
| <rp>
#data
<html><ruby>a<rb>b<span></ruby></html>
#errors
(1,6): expected-doctype-but-got-start-tag
#document
| <html>
| <head>
| <body>
| <ruby>
| "a"
| <rb>
| "b"
| <span>
#data
<html><ruby>a<rt>b<rb></ruby></html>
#errors
(1,6): expected-doctype-but-got-start-tag
#document
| <html>
| <head>
| <body>
| <ruby>
| "a"
| <rt>
| "b"
| <rb>
#data
<html><ruby>a<rt>b<rt></ruby></html>
#errors
(1,6): expected-doctype-but-got-start-tag
#document
| <html>
| <head>
| <body>
| <ruby>
| "a"
| <rt>
| "b"
| <rt>
#data
<html><ruby>a<rt>b<rtc></ruby></html>
#errors
(1,6): expected-doctype-but-got-start-tag
#document
| <html>
| <head>
| <body>
| <ruby>
| "a"
| <rt>
| "b"
| <rtc>
#data
<html><ruby>a<rt>b<rp></ruby></html>
#errors
(1,6): expected-doctype-but-got-start-tag
#document
| <html>
| <head>
| <body>
| <ruby>
| "a"
| <rt>
| "b"
| <rp>
#data
<html><ruby>a<rt>b<span></ruby></html>
#errors
(1,6): expected-doctype-but-got-start-tag
#document
| <html>
| <head>
| <body>
| <ruby>
| "a"
| <rt>
| "b"
| <span>
#data
<html><ruby>a<rtc>b<rb></ruby></html>
#errors
(1,6): expected-doctype-but-got-start-tag
#document
| <html>
| <head>
| <body>
| <ruby>
| "a"
| <rtc>
| "b"
| <rb>
#data
<html><ruby>a<rtc>b<rt>c<rt>d</ruby></html>
#errors
(1,6): expected-doctype-but-got-start-tag
#document
| <html>
| <head>
| <body>
| <ruby>
| "a"
| <rtc>
| "b"
| <rt>
| "c"
| <rt>
| "d"
#data
<html><ruby>a<rtc>b<rtc></ruby></html>
#errors
(1,6): expected-doctype-but-got-start-tag
#document
| <html>
| <head>
| <body>
| <ruby>
| "a"
| <rtc>
| "b"
| <rtc>
#data
<html><ruby>a<rtc>b<rp></ruby></html>
#errors
(1,6): expected-doctype-but-got-start-tag
#document
| <html>
| <head>
| <body>
| <ruby>
| "a"
| <rtc>
| "b"
| <rp>
#data
<html><ruby>a<rtc>b<span></ruby></html>
#errors
(1,6): expected-doctype-but-got-start-tag
#document
| <html>
| <head>
| <body>
| <ruby>
| "a"
| <rtc>
| "b"
| <span>
#data
<html><ruby>a<rp>b<rb></ruby></html>
#errors
(1,6): expected-doctype-but-got-start-tag
#document
| <html>
| <head>
| <body>
| <ruby>
| "a"
| <rp>
| "b"
| <rb>
#data
<html><ruby>a<rp>b<rt></ruby></html>
#errors
(1,6): expected-doctype-but-got-start-tag
#document
| <html>
| <head>
| <body>
| <ruby>
| "a"
| <rp>
| "b"
| <rt>
#data
<html><ruby>a<rp>b<rtc></ruby></html>
#errors
(1,6): expected-doctype-but-got-start-tag
#document
| <html>
| <head>
| <body>
| <ruby>
| "a"
| <rp>
| "b"
| <rtc>
#data
<html><ruby>a<rp>b<rp></ruby></html>
#errors
(1,6): expected-doctype-but-got-start-tag
#document
| <html>
| <head>
| <body>
| <ruby>
| "a"
| <rp>
| "b"
| <rp>
#data
<html><ruby>a<rp>b<span></ruby></html>
#errors
(1,6): expected-doctype-but-got-start-tag
#document
| <html>
| <head>
| <body>
| <ruby>
| "a"
| <rp>
| "b"
| <span>
#data
<html><ruby><rtc><ruby>a<rb>b<rt></ruby></ruby></html>
#errors
(1,6): expected-doctype-but-got-start-tag
#document
| <html>
| <head>
| <body>
| <ruby>
| <rtc>
| <ruby>
| "a"
| <rb>
| "b"
| <rt>

1117
vendor/golang.org/x/net/html/testdata/webkit/template.dat generated vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -1161,8 +1161,8 @@ func (z *Tokenizer) TagAttr() (key, val []byte, moreAttr bool) {
return nil, nil, false
}
// Token returns the next Token. The result's Data and Attr values remain valid
// after subsequent Next calls.
// Token returns the current Token. The result's Data and Attr values remain
// valid after subsequent Next calls.
func (z *Tokenizer) Token() Token {
t := Token{Type: z.tt}
switch z.tt {

View file

@ -589,20 +589,20 @@ func TestConvertNewlines(t *testing.T) {
"Mac\rDOS\r\nUnix\n": "Mac\nDOS\nUnix\n",
"Unix\nMac\rDOS\r\n": "Unix\nMac\nDOS\n",
"DOS\r\nDOS\r\nDOS\r\n": "DOS\nDOS\nDOS\n",
"": "",
"\n": "\n",
"\n\r": "\n\n",
"\r": "\n",
"\r\n": "\n",
"\r\n\n": "\n\n",
"\r\n\r": "\n\n",
"\r\n\r\n": "\n\n",
"\r\r": "\n\n",
"\r\r\n": "\n\n",
"\r\r\n\n": "\n\n\n",
"\r\r\r\n": "\n\n\n",
"\r \n": "\n \n",
"xyz": "xyz",
"": "",
"\n": "\n",
"\n\r": "\n\n",
"\r": "\n",
"\r\n": "\n",
"\r\n\n": "\n\n",
"\r\n\r": "\n\n",
"\r\n\r\n": "\n\n",
"\r\r": "\n\n",
"\r\r\n": "\n\n",
"\r\r\n\n": "\n\n\n",
"\r\r\r\n": "\n\n\n",
"\r \n": "\n \n",
"xyz": "xyz",
}
for in, want := range testCases {
if got := string(convertNewlines([]byte(in))); got != want {

50
vendor/golang.org/x/net/http/httpguts/guts.go generated vendored Normal file
View file

@ -0,0 +1,50 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package httpguts provides functions implementing various details
// of the HTTP specification.
//
// This package is shared by the standard library (which vendors it)
// and x/net/http2. It comes with no API stability promise.
package httpguts
import (
"net/textproto"
"strings"
)
// ValidTrailerHeader reports whether name is a valid header field name to appear
// in trailers.
// See RFC 7230, Section 4.1.2
func ValidTrailerHeader(name string) bool {
name = textproto.CanonicalMIMEHeaderKey(name)
if strings.HasPrefix(name, "If-") || badTrailer[name] {
return false
}
return true
}
var badTrailer = map[string]bool{
"Authorization": true,
"Cache-Control": true,
"Connection": true,
"Content-Encoding": true,
"Content-Length": true,
"Content-Range": true,
"Content-Type": true,
"Expect": true,
"Host": true,
"Keep-Alive": true,
"Max-Forwards": true,
"Pragma": true,
"Proxy-Authenticate": true,
"Proxy-Authorization": true,
"Proxy-Connection": true,
"Range": true,
"Realm": true,
"Te": true,
"Trailer": true,
"Transfer-Encoding": true,
"Www-Authenticate": true,
}

View file

@ -2,12 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package httplex contains rules around lexical matters of various
// HTTP-related specifications.
//
// This package is shared by the standard library (which vendors it)
// and x/net/http2. It comes with no API stability promise.
package httplex
package httpguts
import (
"net"

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package httplex
package httpguts
import (
"testing"

View file

@ -5,7 +5,7 @@
package http2
// A list of the possible cipher suite ids. Taken from
// http://www.iana.org/assignments/tls-parameters/tls-parameters.txt
// https://www.iana.org/assignments/tls-parameters/tls-parameters.txt
const (
cipher_TLS_NULL_WITH_NULL_NULL uint16 = 0x0000

View file

@ -73,7 +73,7 @@ type noDialH2RoundTripper struct{ t *Transport }
func (rt noDialH2RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
res, err := rt.t.RoundTrip(req)
if err == ErrNoCachedConn {
if isNoCachedConnError(err) {
return nil, http.ErrSkipAltProtocol
}
return res, err

View file

@ -41,10 +41,10 @@ func (f *flow) take(n int32) {
// add adds n bytes (positive or negative) to the flow control window.
// It returns false if the sum would exceed 2^31-1.
func (f *flow) add(n int32) bool {
remain := (1<<31 - 1) - f.n
if n > remain {
return false
sum := f.n + n
if (sum > n) == (f.n > 0) {
f.n = sum
return true
}
f.n += n
return true
return false
}

View file

@ -49,5 +49,39 @@ func TestFlowAdd(t *testing.T) {
if f.add(1) {
t.Fatal("adding 1 to max shouldn't be allowed")
}
}
func TestFlowAddOverflow(t *testing.T) {
var f flow
if !f.add(0) {
t.Fatal("failed to add 0")
}
if !f.add(-1) {
t.Fatal("failed to add -1")
}
if !f.add(0) {
t.Fatal("failed to add 0")
}
if !f.add(1) {
t.Fatal("failed to add 1")
}
if !f.add(1) {
t.Fatal("failed to add 1")
}
if !f.add(0) {
t.Fatal("failed to add 0")
}
if !f.add(-3) {
t.Fatal("failed to add -3")
}
if got, want := f.available(), int32(-2); got != want {
t.Fatalf("size = %d; want %d", got, want)
}
if !f.add(1<<31 - 1) {
t.Fatal("failed to add 2^31-1")
}
if got, want := f.available(), int32(1+-3+(1<<31-1)); got != want {
t.Fatalf("size = %d; want %d", got, want)
}
}

View file

@ -14,8 +14,8 @@ import (
"strings"
"sync"
"golang.org/x/net/http/httpguts"
"golang.org/x/net/http2/hpack"
"golang.org/x/net/lex/httplex"
)
const frameHeaderLen = 9
@ -1462,7 +1462,7 @@ func (fr *Framer) readMetaFrame(hf *HeadersFrame) (*MetaHeadersFrame, error) {
if VerboseLogs && fr.logReads {
fr.debugReadLoggerf("http2: decoded hpack field %+v", hf)
}
if !httplex.ValidHeaderFieldValue(hf.Value) {
if !httpguts.ValidHeaderFieldValue(hf.Value) {
invalid = headerFieldValueError(hf.Value)
}
isPseudo := strings.HasPrefix(hf.Name, ":")

View file

@ -3,3 +3,4 @@ h2demo.linux
client-id.dat
client-secret.dat
token.dat
ca-certificates.crt

11
vendor/golang.org/x/net/http2/h2demo/Dockerfile generated vendored Normal file
View file

@ -0,0 +1,11 @@
# Copyright 2018 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.
FROM scratch
LABEL maintainer "golang-dev@googlegroups.com"
COPY ca-certificates.crt /etc/ssl/certs/
COPY h2demo /
ENTRYPOINT ["/h2demo", "-prod"]

134
vendor/golang.org/x/net/http2/h2demo/Dockerfile.0 generated vendored Normal file
View file

@ -0,0 +1,134 @@
# Copyright 2018 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.
FROM golang:1.9
LABEL maintainer "golang-dev@googlegroups.com"
ENV CGO_ENABLED=0
# BEGIN deps (run `make update-deps` to update)
# Repo cloud.google.com/go at 1d0c2da (2018-01-30)
ENV REV=1d0c2da40456a9b47f5376165f275424acc15c09
RUN go get -d cloud.google.com/go/compute/metadata `#and 6 other pkgs` &&\
(cd /go/src/cloud.google.com/go && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
# Repo github.com/golang/protobuf at 9255415 (2018-01-25)
ENV REV=925541529c1fa6821df4e44ce2723319eb2be768
RUN go get -d github.com/golang/protobuf/proto `#and 6 other pkgs` &&\
(cd /go/src/github.com/golang/protobuf && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
# Repo github.com/googleapis/gax-go at 317e000 (2017-09-15)
ENV REV=317e0006254c44a0ac427cc52a0e083ff0b9622f
RUN go get -d github.com/googleapis/gax-go &&\
(cd /go/src/github.com/googleapis/gax-go && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
# Repo go4.org at 034d17a (2017-05-25)
ENV REV=034d17a462f7b2dcd1a4a73553ec5357ff6e6c6e
RUN go get -d go4.org/syncutil/singleflight &&\
(cd /go/src/go4.org && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
# Repo golang.org/x/build at 8aa9ee0 (2018-02-01)
ENV REV=8aa9ee0e557fd49c14113e5ba106e13a5b455460
RUN go get -d golang.org/x/build/autocertcache &&\
(cd /go/src/golang.org/x/build && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
# Repo golang.org/x/crypto at 1875d0a (2018-01-27)
ENV REV=1875d0a70c90e57f11972aefd42276df65e895b9
RUN go get -d golang.org/x/crypto/acme `#and 2 other pkgs` &&\
(cd /go/src/golang.org/x/crypto && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
# Repo golang.org/x/oauth2 at 30785a2 (2018-01-04)
ENV REV=30785a2c434e431ef7c507b54617d6a951d5f2b4
RUN go get -d golang.org/x/oauth2 `#and 5 other pkgs` &&\
(cd /go/src/golang.org/x/oauth2 && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
# Repo golang.org/x/text at e19ae14 (2017-12-27)
ENV REV=e19ae1496984b1c655b8044a65c0300a3c878dd3
RUN go get -d golang.org/x/text/secure/bidirule `#and 4 other pkgs` &&\
(cd /go/src/golang.org/x/text && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
# Repo google.golang.org/api at 7d0e2d3 (2018-01-30)
ENV REV=7d0e2d350555821bef5a5b8aecf0d12cc1def633
RUN go get -d google.golang.org/api/gensupport `#and 9 other pkgs` &&\
(cd /go/src/google.golang.org/api && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
# Repo google.golang.org/genproto at 4eb30f4 (2018-01-25)
ENV REV=4eb30f4778eed4c258ba66527a0d4f9ec8a36c45
RUN go get -d google.golang.org/genproto/googleapis/api/annotations `#and 3 other pkgs` &&\
(cd /go/src/google.golang.org/genproto && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
# Repo google.golang.org/grpc at 0bd008f (2018-01-25)
ENV REV=0bd008f5fadb62d228f12b18d016709e8139a7af
RUN go get -d google.golang.org/grpc `#and 23 other pkgs` &&\
(cd /go/src/google.golang.org/grpc && (git cat-file -t $REV 2>/dev/null || git fetch -q origin $REV) && git reset --hard $REV)
# Optimization to speed up iterative development, not necessary for correctness:
RUN go install cloud.google.com/go/compute/metadata \
cloud.google.com/go/iam \
cloud.google.com/go/internal \
cloud.google.com/go/internal/optional \
cloud.google.com/go/internal/version \
cloud.google.com/go/storage \
github.com/golang/protobuf/proto \
github.com/golang/protobuf/protoc-gen-go/descriptor \
github.com/golang/protobuf/ptypes \
github.com/golang/protobuf/ptypes/any \
github.com/golang/protobuf/ptypes/duration \
github.com/golang/protobuf/ptypes/timestamp \
github.com/googleapis/gax-go \
go4.org/syncutil/singleflight \
golang.org/x/build/autocertcache \
golang.org/x/crypto/acme \
golang.org/x/crypto/acme/autocert \
golang.org/x/oauth2 \
golang.org/x/oauth2/google \
golang.org/x/oauth2/internal \
golang.org/x/oauth2/jws \
golang.org/x/oauth2/jwt \
golang.org/x/text/secure/bidirule \
golang.org/x/text/transform \
golang.org/x/text/unicode/bidi \
golang.org/x/text/unicode/norm \
google.golang.org/api/gensupport \
google.golang.org/api/googleapi \
google.golang.org/api/googleapi/internal/uritemplates \
google.golang.org/api/googleapi/transport \
google.golang.org/api/internal \
google.golang.org/api/iterator \
google.golang.org/api/option \
google.golang.org/api/storage/v1 \
google.golang.org/api/transport/http \
google.golang.org/genproto/googleapis/api/annotations \
google.golang.org/genproto/googleapis/iam/v1 \
google.golang.org/genproto/googleapis/rpc/status \
google.golang.org/grpc \
google.golang.org/grpc/balancer \
google.golang.org/grpc/balancer/base \
google.golang.org/grpc/balancer/roundrobin \
google.golang.org/grpc/codes \
google.golang.org/grpc/connectivity \
google.golang.org/grpc/credentials \
google.golang.org/grpc/encoding \
google.golang.org/grpc/encoding/proto \
google.golang.org/grpc/grpclb/grpc_lb_v1/messages \
google.golang.org/grpc/grpclog \
google.golang.org/grpc/internal \
google.golang.org/grpc/keepalive \
google.golang.org/grpc/metadata \
google.golang.org/grpc/naming \
google.golang.org/grpc/peer \
google.golang.org/grpc/resolver \
google.golang.org/grpc/resolver/dns \
google.golang.org/grpc/resolver/passthrough \
google.golang.org/grpc/stats \
google.golang.org/grpc/status \
google.golang.org/grpc/tap \
google.golang.org/grpc/transport
# END deps
COPY . /go/src/golang.org/x/net/
RUN go install -tags "h2demo netgo" -ldflags "-linkmode=external -extldflags '-static -pthread'" golang.org/x/net/http2/h2demo

View file

@ -1,8 +1,55 @@
h2demo.linux: h2demo.go
GOOS=linux go build --tags=h2demo -o h2demo.linux .
# Copyright 2018 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.
MUTABLE_VERSION ?= latest
VERSION ?= $(shell git rev-parse --short HEAD)
IMAGE_STAGING := gcr.io/go-dashboard-dev/h2demo
IMAGE_PROD := gcr.io/symbolic-datum-552/h2demo
DOCKER_IMAGE_build0=build0/h2demo:latest
DOCKER_CTR_build0=h2demo-build0
build0: *.go Dockerfile.0
docker build --force-rm -f Dockerfile.0 --tag=$(DOCKER_IMAGE_build0) ../..
h2demo: build0
docker create --name $(DOCKER_CTR_build0) $(DOCKER_IMAGE_build0)
docker cp $(DOCKER_CTR_build0):/go/bin/$@ $@
docker rm $(DOCKER_CTR_build0)
ca-certificates.crt:
docker create --name $(DOCKER_CTR_build0) $(DOCKER_IMAGE_build0)
docker cp $(DOCKER_CTR_build0):/etc/ssl/certs/$@ $@
docker rm $(DOCKER_CTR_build0)
update-deps:
go install golang.org/x/build/cmd/gitlock
gitlock --update=Dockerfile.0 --ignore=golang.org/x/net --tags=h2demo golang.org/x/net/http2/h2demo
docker-prod: Dockerfile h2demo ca-certificates.crt
docker build --force-rm --tag=$(IMAGE_PROD):$(VERSION) .
docker tag $(IMAGE_PROD):$(VERSION) $(IMAGE_PROD):$(MUTABLE_VERSION)
docker-staging: Dockerfile h2demo ca-certificates.crt
docker build --force-rm --tag=$(IMAGE_STAGING):$(VERSION) .
docker tag $(IMAGE_STAGING):$(VERSION) $(IMAGE_STAGING):$(MUTABLE_VERSION)
push-prod: docker-prod
gcloud docker -- push $(IMAGE_PROD):$(MUTABLE_VERSION)
gcloud docker -- push $(IMAGE_PROD):$(VERSION)
push-staging: docker-staging
gcloud docker -- push $(IMAGE_STAGING):$(MUTABLE_VERSION)
gcloud docker -- push $(IMAGE_STAGING):$(VERSION)
deploy-prod: push-prod
kubectl set image deployment/h2demo-deployment h2demo=$(IMAGE_PROD):$(VERSION)
deploy-staging: push-staging
kubectl set image deployment/h2demo-deployment h2demo=$(IMAGE_STAGING):$(VERSION)
.PHONY: clean
clean:
$(RM) h2demo
$(RM) ca-certificates.crt
FORCE:
upload: FORCE
go install golang.org/x/build/cmd/upload
upload --verbose --osarch=linux-amd64 --tags=h2demo --file=go:golang.org/x/net/http2/h2demo --public http2-demo-server-tls/h2demo

View file

@ -0,0 +1,28 @@
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: h2demo-deployment
spec:
replicas: 1
template:
metadata:
labels:
app: h2demo
annotations:
container.seccomp.security.alpha.kubernetes.io/h2demo: docker/default
container.apparmor.security.beta.kubernetes.io/h2demo: runtime/default
spec:
containers:
- name: h2demo
image: gcr.io/symbolic-datum-552/h2demo:latest
imagePullPolicy: Always
command: ["/h2demo", "-prod"]
ports:
- containerPort: 80
- containerPort: 443
resources:
requests:
cpu: "1"
memory: "1Gi"
limits:
memory: "2Gi"

View file

@ -8,6 +8,7 @@ package main
import (
"bytes"
"context"
"crypto/tls"
"flag"
"fmt"
@ -19,7 +20,6 @@ import (
"log"
"net"
"net/http"
"os"
"path"
"regexp"
"runtime"
@ -28,7 +28,9 @@ import (
"sync"
"time"
"cloud.google.com/go/storage"
"go4.org/syncutil/singleflight"
"golang.org/x/build/autocertcache"
"golang.org/x/crypto/acme/autocert"
"golang.org/x/net/http2"
)
@ -426,19 +428,10 @@ func httpHost() string {
}
}
func serveProdTLS() error {
const cacheDir = "/var/cache/autocert"
if err := os.MkdirAll(cacheDir, 0700); err != nil {
return err
}
m := autocert.Manager{
Cache: autocert.DirCache(cacheDir),
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist("http2.golang.org"),
}
func serveProdTLS(autocertManager *autocert.Manager) error {
srv := &http.Server{
TLSConfig: &tls.Config{
GetCertificate: m.GetCertificate,
GetCertificate: autocertManager.GetCertificate,
},
}
http2.ConfigureServer(srv, &http2.Server{
@ -468,9 +461,21 @@ func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
}
func serveProd() error {
log.Printf("running in production mode")
storageClient, err := storage.NewClient(context.Background())
if err != nil {
log.Fatalf("storage.NewClient: %v", err)
}
autocertManager := &autocert.Manager{
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist("http2.golang.org"),
Cache: autocertcache.NewGoogleCloudStorageCache(storageClient, "golang-h2demo-autocert"),
}
errc := make(chan error, 2)
go func() { errc <- http.ListenAndServe(":80", nil) }()
go func() { errc <- serveProdTLS() }()
go func() { errc <- http.ListenAndServe(":80", autocertManager.HTTPHandler(http.DefaultServeMux)) }()
go func() { errc <- serveProdTLS(autocertManager) }()
return <-errc
}

17
vendor/golang.org/x/net/http2/h2demo/service.yaml generated vendored Normal file
View file

@ -0,0 +1,17 @@
apiVersion: v1
kind: Service
metadata:
name: h2demo
spec:
externalTrafficPolicy: Local
ports:
- port: 80
targetPort: 80
name: http
- port: 443
targetPort: 443
name: https
selector:
app: h2demo
type: LoadBalancer
loadBalancerIP: 130.211.116.44

View file

@ -206,7 +206,7 @@ func appendVarInt(dst []byte, n byte, i uint64) []byte {
}
// appendHpackString appends s, as encoded in "String Literal"
// representation, to dst and returns the the extended buffer.
// representation, to dst and returns the extended buffer.
//
// s will be encoded in Huffman codes only when it produces strictly
// shorter byte string.

View file

@ -389,6 +389,12 @@ func (d *Decoder) callEmit(hf HeaderField) error {
// (same invariants and behavior as parseHeaderFieldRepr)
func (d *Decoder) parseDynamicTableSizeUpdate() error {
// RFC 7541, sec 4.2: This dynamic table size update MUST occur at the
// beginning of the first header block following the change to the dynamic table size.
if d.dynTab.size > 0 {
return DecodingError{errors.New("dynamic table size update MUST occur at the beginning of a header block")}
}
buf := d.buf
size, buf, err := readVarInt(5, buf)
if err != nil {

View file

@ -720,3 +720,22 @@ func TestSaveBufLimit(t *testing.T) {
t.Fatalf("Write error = %v; want ErrStringLength", err)
}
}
func TestDynamicSizeUpdate(t *testing.T) {
var buf bytes.Buffer
enc := NewEncoder(&buf)
enc.SetMaxDynamicTableSize(255)
enc.WriteField(HeaderField{Name: "foo", Value: "bar"})
d := NewDecoder(4096, nil)
_, err := d.DecodeFull(buf.Bytes())
if err != nil {
t.Fatalf("unexpected error: got = %v", err)
}
// must fail since the dynamic table update must be at the beginning
_, err = d.DecodeFull(buf.Bytes())
if err == nil {
t.Fatalf("dynamic table size update not at the beginning of a header block")
}
}

View file

@ -29,7 +29,7 @@ import (
"strings"
"sync"
"golang.org/x/net/lex/httplex"
"golang.org/x/net/http/httpguts"
)
var (
@ -179,7 +179,7 @@ var (
)
// validWireHeaderFieldName reports whether v is a valid header field
// name (key). See httplex.ValidHeaderName for the base rules.
// name (key). See httpguts.ValidHeaderName for the base rules.
//
// Further, http2 says:
// "Just as in HTTP/1.x, header field names are strings of ASCII
@ -191,7 +191,7 @@ func validWireHeaderFieldName(v string) bool {
return false
}
for _, r := range v {
if !httplex.IsTokenRune(r) {
if !httpguts.IsTokenRune(r) {
return false
}
if 'A' <= r && r <= 'Z' {
@ -312,7 +312,7 @@ func mustUint31(v int32) uint32 {
}
// bodyAllowedForStatus reports whether a given response status code
// permits a body. See RFC 2616, section 4.4.
// permits a body. See RFC 7230, section 3.3.
func bodyAllowedForStatus(status int) bool {
switch {
case status >= 100 && status <= 199:

View file

@ -14,6 +14,7 @@ import (
"strconv"
"strings"
"testing"
"time"
"golang.org/x/net/http2/hpack"
)
@ -197,3 +198,30 @@ func TestSorterPoolAllocs(t *testing.T) {
t.Logf("Keys allocs = %v; want <1", allocs)
}
}
// waitCondition reports whether fn eventually returned true,
// checking immediately and then every checkEvery amount,
// until waitFor has elapsed, at which point it returns false.
func waitCondition(waitFor, checkEvery time.Duration, fn func() bool) bool {
deadline := time.Now().Add(waitFor)
for time.Now().Before(deadline) {
if fn() {
return true
}
time.Sleep(checkEvery)
}
return false
}
// waitErrCondition is like waitCondition but with errors instead of bools.
func waitErrCondition(waitFor, checkEvery time.Duration, fn func() error) error {
deadline := time.Now().Add(waitFor)
var err error
for time.Now().Before(deadline) {
if err = fn(); err == nil {
return nil
}
time.Sleep(checkEvery)
}
return err
}

View file

@ -46,6 +46,7 @@ import (
"sync"
"time"
"golang.org/x/net/http/httpguts"
"golang.org/x/net/http2/hpack"
)
@ -406,7 +407,7 @@ func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
// addresses during development.
//
// TODO: optionally enforce? Or enforce at the time we receive
// a new request, and verify the the ServerName matches the :authority?
// a new request, and verify the ServerName matches the :authority?
// But that precludes proxy situations, perhaps.
//
// So for now, do nothing here again.
@ -1607,7 +1608,10 @@ func (sc *serverConn) processData(f *DataFrame) error {
// Sender sending more than they'd declared?
if st.declBodyBytes != -1 && st.bodyBytes+int64(len(data)) > st.declBodyBytes {
st.body.CloseWithError(fmt.Errorf("sender tried to send more than declared Content-Length of %d bytes", st.declBodyBytes))
return streamError(id, ErrCodeStreamClosed)
// RFC 7540, sec 8.1.2.6: A request or response is also malformed if the
// value of a content-length header field does not equal the sum of the
// DATA frame payload lengths that form the body.
return streamError(id, ErrCodeProtocol)
}
if f.Length > 0 {
// Check whether the client has flow control quota.
@ -1817,7 +1821,7 @@ func (st *stream) processTrailerHeaders(f *MetaHeadersFrame) error {
if st.trailer != nil {
for _, hf := range f.RegularFields() {
key := sc.canonicalHeader(hf.Name)
if !ValidTrailerHeader(key) {
if !httpguts.ValidTrailerHeader(key) {
// TODO: send more details to the peer somehow. But http2 has
// no way to send debug data at a stream level. Discuss with
// HTTP folk.
@ -2284,8 +2288,8 @@ func (rws *responseWriterState) hasTrailers() bool { return len(rws.trailers) !=
// written in the trailers at the end of the response.
func (rws *responseWriterState) declareTrailer(k string) {
k = http.CanonicalHeaderKey(k)
if !ValidTrailerHeader(k) {
// Forbidden by RFC 2616 14.40.
if !httpguts.ValidTrailerHeader(k) {
// Forbidden by RFC 7230, section 4.1.2.
rws.conn.logf("ignoring invalid trailer %q", k)
return
}
@ -2323,7 +2327,15 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
}
_, hasContentType := rws.snapHeader["Content-Type"]
if !hasContentType && bodyAllowedForStatus(rws.status) && len(p) > 0 {
ctype = http.DetectContentType(p)
if cto := rws.snapHeader.Get("X-Content-Type-Options"); strings.EqualFold("nosniff", cto) {
// nosniff is an explicit directive not to guess a content-type.
// Content-sniffing is no less susceptible to polyglot attacks via
// hosted content when done on the server.
ctype = "application/octet-stream"
rws.conn.logf("http2: WriteHeader called with X-Content-Type-Options:nosniff but no Content-Type")
} else {
ctype = http.DetectContentType(p)
}
}
var date string
if _, ok := rws.snapHeader["Date"]; !ok {
@ -2335,6 +2347,19 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
foreachHeaderElement(v, rws.declareTrailer)
}
// "Connection" headers aren't allowed in HTTP/2 (RFC 7540, 8.1.2.2),
// but respect "Connection" == "close" to mean sending a GOAWAY and tearing
// down the TCP connection when idle, like we do for HTTP/1.
// TODO: remove more Connection-specific header fields here, in addition
// to "Connection".
if _, ok := rws.snapHeader["Connection"]; ok {
v := rws.snapHeader.Get("Connection")
delete(rws.snapHeader, "Connection")
if v == "close" {
rws.conn.startGracefulShutdown()
}
}
endStream := (rws.handlerDone && !rws.hasTrailers() && len(p) == 0) || isHeadResp
err = rws.conn.writeHeaders(rws.stream, &writeResHeaders{
streamID: rws.stream.id,
@ -2406,7 +2431,7 @@ const TrailerPrefix = "Trailer:"
// after the header has already been flushed. Because the Go
// ResponseWriter interface has no way to set Trailers (only the
// Header), and because we didn't want to expand the ResponseWriter
// interface, and because nobody used trailers, and because RFC 2616
// interface, and because nobody used trailers, and because RFC 7230
// says you SHOULD (but not must) predeclare any trailers in the
// header, the official ResponseWriter rules said trailers in Go must
// be predeclared, and then we reuse the same ResponseWriter.Header()
@ -2509,7 +2534,6 @@ func checkWriteHeaderCode(code int) {
}
func (w *responseWriter) WriteHeader(code int) {
checkWriteHeaderCode(code)
rws := w.rws
if rws == nil {
panic("WriteHeader called after Handler finished")
@ -2519,6 +2543,7 @@ func (w *responseWriter) WriteHeader(code int) {
func (rws *responseWriterState) writeHeader(code int) {
if !rws.wroteHeader {
checkWriteHeaderCode(code)
rws.wroteHeader = true
rws.status = code
if len(rws.handlerHeader) > 0 {
@ -2790,7 +2815,7 @@ func (sc *serverConn) startPush(msg *startPushRequest) {
}
// foreachHeaderElement splits v according to the "#rule" construction
// in RFC 2616 section 2.1 and calls fn for each non-empty element.
// in RFC 7230 section 7 and calls fn for each non-empty element.
func foreachHeaderElement(v string, fn func(string)) {
v = textproto.TrimString(v)
if v == "" {
@ -2838,41 +2863,6 @@ func new400Handler(err error) http.HandlerFunc {
}
}
// ValidTrailerHeader reports whether name is a valid header field name to appear
// in trailers.
// See: http://tools.ietf.org/html/rfc7230#section-4.1.2
func ValidTrailerHeader(name string) bool {
name = http.CanonicalHeaderKey(name)
if strings.HasPrefix(name, "If-") || badTrailer[name] {
return false
}
return true
}
var badTrailer = map[string]bool{
"Authorization": true,
"Cache-Control": true,
"Connection": true,
"Content-Encoding": true,
"Content-Length": true,
"Content-Range": true,
"Content-Type": true,
"Expect": true,
"Host": true,
"Keep-Alive": true,
"Max-Forwards": true,
"Pragma": true,
"Proxy-Authenticate": true,
"Proxy-Authorization": true,
"Proxy-Connection": true,
"Range": true,
"Realm": true,
"Te": true,
"Trailer": true,
"Transfer-Encoding": true,
"Www-Authenticate": true,
}
// h1ServerKeepAlivesDisabled reports whether hs has its keep-alives
// disabled. See comments on h1ServerShutdownChan above for why
// the code is written this way.

View file

@ -1760,6 +1760,42 @@ func TestServer_Response_Data_Sniff_DoesntOverride(t *testing.T) {
})
}
func TestServer_Response_Nosniff_WithoutContentType(t *testing.T) {
const msg = "<html>this is HTML."
testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
w.Header().Set("X-Content-Type-Options", "nosniff")
w.WriteHeader(200)
io.WriteString(w, msg)
return nil
}, func(st *serverTester) {
getSlash(st)
hf := st.wantHeaders()
if hf.StreamEnded() {
t.Fatal("don't want END_STREAM, expecting data")
}
if !hf.HeadersEnded() {
t.Fatal("want END_HEADERS flag")
}
goth := st.decodeHeader(hf.HeaderBlockFragment())
wanth := [][2]string{
{":status", "200"},
{"x-content-type-options", "nosniff"},
{"content-type", "application/octet-stream"},
{"content-length", strconv.Itoa(len(msg))},
}
if !reflect.DeepEqual(goth, wanth) {
t.Errorf("Got headers %v; want %v", goth, wanth)
}
df := st.wantData()
if !df.StreamEnded() {
t.Error("expected DATA to have END_STREAM flag")
}
if got := string(df.Data()); got != msg {
t.Errorf("got DATA %q; want %q", got, msg)
}
})
}
func TestServer_Response_TransferEncoding_chunked(t *testing.T) {
const msg = "hi"
testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
@ -2877,9 +2913,9 @@ func testServerWritesTrailers(t *testing.T, withFlush bool) {
w.Header().Set("Trailer:post-header-trailer2", "hi2")
w.Header().Set("Trailer:Range", "invalid")
w.Header().Set("Trailer:Foo\x01Bogus", "invalid")
w.Header().Set("Transfer-Encoding", "should not be included; Forbidden by RFC 2616 14.40")
w.Header().Set("Content-Length", "should not be included; Forbidden by RFC 2616 14.40")
w.Header().Set("Trailer", "should not be included; Forbidden by RFC 2616 14.40")
w.Header().Set("Transfer-Encoding", "should not be included; Forbidden by RFC 7230 4.1.2")
w.Header().Set("Content-Length", "should not be included; Forbidden by RFC 7230 4.1.2")
w.Header().Set("Trailer", "should not be included; Forbidden by RFC 7230 4.1.2")
return nil
}, func(st *serverTester) {
getSlash(st)
@ -2971,7 +3007,7 @@ func BenchmarkServerGets(b *testing.B) {
defer st.Close()
st.greet()
// Give the server quota to reply. (plus it has the the 64KB)
// Give the server quota to reply. (plus it has the 64KB)
if err := st.fr.WriteWindowUpdate(0, uint32(b.N*len(msg))); err != nil {
b.Fatal(err)
}
@ -3009,7 +3045,7 @@ func BenchmarkServerPosts(b *testing.B) {
defer st.Close()
st.greet()
// Give the server quota to reply. (plus it has the the 64KB)
// Give the server quota to reply. (plus it has the 64KB)
if err := st.fr.WriteWindowUpdate(0, uint32(b.N*len(msg))); err != nil {
b.Fatal(err)
}
@ -3316,7 +3352,7 @@ func BenchmarkServer_GetRequest(b *testing.B) {
defer st.Close()
st.greet()
// Give the server quota to reply. (plus it has the the 64KB)
// Give the server quota to reply. (plus it has the 64KB)
if err := st.fr.WriteWindowUpdate(0, uint32(b.N*len(msg))); err != nil {
b.Fatal(err)
}
@ -3347,7 +3383,7 @@ func BenchmarkServer_PostRequest(b *testing.B) {
})
defer st.Close()
st.greet()
// Give the server quota to reply. (plus it has the the 64KB)
// Give the server quota to reply. (plus it has the 64KB)
if err := st.fr.WriteWindowUpdate(0, uint32(b.N*len(msg))); err != nil {
b.Fatal(err)
}
@ -3723,3 +3759,85 @@ func TestIssue20704Race(t *testing.T) {
resp.Body.Close()
}
}
func TestServer_Rejects_TooSmall(t *testing.T) {
testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
ioutil.ReadAll(r.Body)
return nil
}, func(st *serverTester) {
st.writeHeaders(HeadersFrameParam{
StreamID: 1, // clients send odd numbers
BlockFragment: st.encodeHeader(
":method", "POST",
"content-length", "4",
),
EndStream: false, // to say DATA frames are coming
EndHeaders: true,
})
st.writeData(1, true, []byte("12345"))
st.wantRSTStream(1, ErrCodeProtocol)
})
}
// Tests that a handler setting "Connection: close" results in a GOAWAY being sent,
// and the connection still completing.
func TestServerHandlerConnectionClose(t *testing.T) {
unblockHandler := make(chan bool, 1)
defer close(unblockHandler) // backup; in case of errors
testServerResponse(t, func(w http.ResponseWriter, r *http.Request) error {
w.Header().Set("Connection", "close")
w.Header().Set("Foo", "bar")
w.(http.Flusher).Flush()
<-unblockHandler
return nil
}, func(st *serverTester) {
st.writeHeaders(HeadersFrameParam{
StreamID: 1,
BlockFragment: st.encodeHeader(),
EndStream: true,
EndHeaders: true,
})
var sawGoAway bool
var sawRes bool
for {
f, err := st.readFrame()
if err == io.EOF {
break
}
if err != nil {
t.Fatal(err)
}
switch f := f.(type) {
case *GoAwayFrame:
sawGoAway = true
unblockHandler <- true
if f.LastStreamID != 1 || f.ErrCode != ErrCodeNo {
t.Errorf("unexpected GOAWAY frame: %v", summarizeFrame(f))
}
case *HeadersFrame:
goth := st.decodeHeader(f.HeaderBlockFragment())
wanth := [][2]string{
{":status", "200"},
{"foo", "bar"},
}
if !reflect.DeepEqual(goth, wanth) {
t.Errorf("got headers %v; want %v", goth, wanth)
}
sawRes = true
case *DataFrame:
if f.StreamID != 1 || !f.StreamEnded() || len(f.Data()) != 0 {
t.Errorf("unexpected DATA frame: %v", summarizeFrame(f))
}
default:
t.Logf("unexpected frame: %v", summarizeFrame(f))
}
}
if !sawGoAway {
t.Errorf("didn't see GOAWAY")
}
if !sawRes {
t.Errorf("didn't see response")
}
})
}

View file

@ -27,9 +27,9 @@ import (
"sync"
"time"
"golang.org/x/net/http/httpguts"
"golang.org/x/net/http2/hpack"
"golang.org/x/net/idna"
"golang.org/x/net/lex/httplex"
)
const (
@ -306,7 +306,26 @@ func (sew stickyErrWriter) Write(p []byte) (n int, err error) {
return
}
var ErrNoCachedConn = errors.New("http2: no cached connection was available")
// noCachedConnError is the concrete type of ErrNoCachedConn, which
// needs to be detected by net/http regardless of whether it's its
// bundled version (in h2_bundle.go with a rewritten type name) or
// from a user's x/net/http2. As such, as it has a unique method name
// (IsHTTP2NoCachedConnError) that net/http sniffs for via func
// isNoCachedConnError.
type noCachedConnError struct{}
func (noCachedConnError) IsHTTP2NoCachedConnError() {}
func (noCachedConnError) Error() string { return "http2: no cached connection was available" }
// isNoCachedConnError reports whether err is of type noCachedConnError
// or its equivalent renamed type in net/http2's h2_bundle.go. Both types
// may coexist in the same running program.
func isNoCachedConnError(err error) bool {
_, ok := err.(interface{ IsHTTP2NoCachedConnError() })
return ok
}
var ErrNoCachedConn error = noCachedConnError{}
// RoundTripOpt are options for the Transport.RoundTripOpt method.
type RoundTripOpt struct {
@ -548,6 +567,10 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro
// henc in response to SETTINGS frames?
cc.henc = hpack.NewEncoder(&cc.hbuf)
if t.AllowHTTP {
cc.nextStreamID = 3
}
if cs, ok := c.(connectionStater); ok {
state := cs.ConnectionState()
cc.tlsState = &state
@ -932,6 +955,9 @@ func (cc *ClientConn) awaitOpenSlotForRequest(req *http.Request) error {
for {
cc.lastActive = time.Now()
if cc.closed || !cc.canTakeNewRequestLocked() {
if waitingForConn != nil {
close(waitingForConn)
}
return errClientConnUnusable
}
if int64(len(cc.streams))+1 <= int64(cc.maxConcurrentStreams) {
@ -1155,7 +1181,7 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail
if host == "" {
host = req.URL.Host
}
host, err := httplex.PunycodeHostPort(host)
host, err := httpguts.PunycodeHostPort(host)
if err != nil {
return nil, err
}
@ -1180,11 +1206,11 @@ func (cc *ClientConn) encodeHeaders(req *http.Request, addGzipHeader bool, trail
// potentially pollute our hpack state. (We want to be able to
// continue to reuse the hpack encoder for future requests)
for k, vv := range req.Header {
if !httplex.ValidHeaderFieldName(k) {
if !httpguts.ValidHeaderFieldName(k) {
return nil, fmt.Errorf("invalid HTTP header name %q", k)
}
for _, v := range vv {
if !httplex.ValidHeaderFieldValue(v) {
if !httpguts.ValidHeaderFieldValue(v) {
return nil, fmt.Errorf("invalid HTTP header value %q for header %q", v, k)
}
}
@ -2225,7 +2251,7 @@ func (t *Transport) getBodyWriterState(cs *clientStream, body io.Reader) (s body
}
s.delay = t.expectContinueTimeout()
if s.delay == 0 ||
!httplex.HeaderValuesContainsToken(
!httpguts.HeaderValuesContainsToken(
cs.req.Header["Expect"],
"100-continue") {
return
@ -2280,5 +2306,5 @@ func (s bodyWriterState) scheduleBodyWrite() {
// isConnectionCloseRequest reports whether req should use its own
// connection for a single request and then close the connection.
func isConnectionCloseRequest(req *http.Request) bool {
return req.Close || httplex.HeaderValuesContainsToken(req.Header["Connection"], "close")
return req.Close || httpguts.HeaderValuesContainsToken(req.Header["Connection"], "close")
}

View file

@ -1693,7 +1693,7 @@ func TestTransportChecksResponseHeaderListSize(t *testing.T) {
ct.run()
}
// Test that the the Transport returns a typed error from Response.Body.Read calls
// Test that the Transport returns a typed error from Response.Body.Read calls
// when the server sends an error. (here we use a panic, since that should generate
// a stream error, but others like cancel should be similar)
func TestTransportBodyReadErrorType(t *testing.T) {
@ -2394,11 +2394,12 @@ func TestTransportHandlerBodyClose(t *testing.T) {
}
tr.CloseIdleConnections()
gd := runtime.NumGoroutine() - g0
if gd > numReq/2 {
if !waitCondition(5*time.Second, 100*time.Millisecond, func() bool {
gd := runtime.NumGoroutine() - g0
return gd < numReq/2
}) {
t.Errorf("appeared to leak goroutines")
}
}
// https://golang.org/issue/15930

View file

@ -11,8 +11,8 @@ import (
"net/http"
"net/url"
"golang.org/x/net/http/httpguts"
"golang.org/x/net/http2/hpack"
"golang.org/x/net/lex/httplex"
)
// writeFramer is implemented by any type that is used to write frames.
@ -350,7 +350,7 @@ func encodeHeaders(enc *hpack.Encoder, h http.Header, keys []string) {
}
isTE := k == "transfer-encoding"
for _, v := range vv {
if !httplex.ValidHeaderFieldValue(v) {
if !httpguts.ValidHeaderFieldValue(v) {
// TODO: return an error? golang.org/issue/14048
// For now just omit it.
continue

274
vendor/golang.org/x/net/icmp/diag_test.go generated vendored Normal file
View file

@ -0,0 +1,274 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package icmp_test
import (
"errors"
"fmt"
"net"
"os"
"runtime"
"sync"
"testing"
"time"
"golang.org/x/net/icmp"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/nettest"
"golang.org/x/net/ipv4"
"golang.org/x/net/ipv6"
)
type diagTest struct {
network, address string
protocol int
m icmp.Message
}
func TestDiag(t *testing.T) {
if testing.Short() {
t.Skip("avoid external network")
}
t.Run("Ping/NonPrivileged", func(t *testing.T) {
switch runtime.GOOS {
case "darwin":
case "linux":
t.Log("you may need to adjust the net.ipv4.ping_group_range kernel state")
default:
t.Logf("not supported on %s", runtime.GOOS)
return
}
for i, dt := range []diagTest{
{
"udp4", "0.0.0.0", iana.ProtocolICMP,
icmp.Message{
Type: ipv4.ICMPTypeEcho, Code: 0,
Body: &icmp.Echo{
ID: os.Getpid() & 0xffff,
Data: []byte("HELLO-R-U-THERE"),
},
},
},
{
"udp6", "::", iana.ProtocolIPv6ICMP,
icmp.Message{
Type: ipv6.ICMPTypeEchoRequest, Code: 0,
Body: &icmp.Echo{
ID: os.Getpid() & 0xffff,
Data: []byte("HELLO-R-U-THERE"),
},
},
},
} {
if err := doDiag(dt, i); err != nil {
t.Error(err)
}
}
})
t.Run("Ping/Privileged", func(t *testing.T) {
if m, ok := nettest.SupportsRawIPSocket(); !ok {
t.Skip(m)
}
for i, dt := range []diagTest{
{
"ip4:icmp", "0.0.0.0", iana.ProtocolICMP,
icmp.Message{
Type: ipv4.ICMPTypeEcho, Code: 0,
Body: &icmp.Echo{
ID: os.Getpid() & 0xffff,
Data: []byte("HELLO-R-U-THERE"),
},
},
},
{
"ip6:ipv6-icmp", "::", iana.ProtocolIPv6ICMP,
icmp.Message{
Type: ipv6.ICMPTypeEchoRequest, Code: 0,
Body: &icmp.Echo{
ID: os.Getpid() & 0xffff,
Data: []byte("HELLO-R-U-THERE"),
},
},
},
} {
if err := doDiag(dt, i); err != nil {
t.Error(err)
}
}
})
t.Run("Probe/Privileged", func(t *testing.T) {
if m, ok := nettest.SupportsRawIPSocket(); !ok {
t.Skip(m)
}
for i, dt := range []diagTest{
{
"ip4:icmp", "0.0.0.0", iana.ProtocolICMP,
icmp.Message{
Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
Body: &icmp.ExtendedEchoRequest{
ID: os.Getpid() & 0xffff,
Local: true,
Extensions: []icmp.Extension{
&icmp.InterfaceIdent{
Class: 3, Type: 1,
Name: "doesnotexist",
},
},
},
},
},
{
"ip6:ipv6-icmp", "::", iana.ProtocolIPv6ICMP,
icmp.Message{
Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
Body: &icmp.ExtendedEchoRequest{
ID: os.Getpid() & 0xffff,
Local: true,
Extensions: []icmp.Extension{
&icmp.InterfaceIdent{
Class: 3, Type: 1,
Name: "doesnotexist",
},
},
},
},
},
} {
if err := doDiag(dt, i); err != nil {
t.Error(err)
}
}
})
}
func doDiag(dt diagTest, seq int) error {
c, err := icmp.ListenPacket(dt.network, dt.address)
if err != nil {
return err
}
defer c.Close()
dst, err := googleAddr(c, dt.protocol)
if err != nil {
return err
}
if dt.network != "udp6" && dt.protocol == iana.ProtocolIPv6ICMP {
var f ipv6.ICMPFilter
f.SetAll(true)
f.Accept(ipv6.ICMPTypeDestinationUnreachable)
f.Accept(ipv6.ICMPTypePacketTooBig)
f.Accept(ipv6.ICMPTypeTimeExceeded)
f.Accept(ipv6.ICMPTypeParameterProblem)
f.Accept(ipv6.ICMPTypeEchoReply)
f.Accept(ipv6.ICMPTypeExtendedEchoReply)
if err := c.IPv6PacketConn().SetICMPFilter(&f); err != nil {
return err
}
}
switch m := dt.m.Body.(type) {
case *icmp.Echo:
m.Seq = 1 << uint(seq)
case *icmp.ExtendedEchoRequest:
m.Seq = 1 << uint(seq)
}
wb, err := dt.m.Marshal(nil)
if err != nil {
return err
}
if n, err := c.WriteTo(wb, dst); err != nil {
return err
} else if n != len(wb) {
return fmt.Errorf("got %v; want %v", n, len(wb))
}
rb := make([]byte, 1500)
if err := c.SetReadDeadline(time.Now().Add(3 * time.Second)); err != nil {
return err
}
n, peer, err := c.ReadFrom(rb)
if err != nil {
return err
}
rm, err := icmp.ParseMessage(dt.protocol, rb[:n])
if err != nil {
return err
}
switch {
case dt.m.Type == ipv4.ICMPTypeEcho && rm.Type == ipv4.ICMPTypeEchoReply:
fallthrough
case dt.m.Type == ipv6.ICMPTypeEchoRequest && rm.Type == ipv6.ICMPTypeEchoReply:
fallthrough
case dt.m.Type == ipv4.ICMPTypeExtendedEchoRequest && rm.Type == ipv4.ICMPTypeExtendedEchoReply:
fallthrough
case dt.m.Type == ipv6.ICMPTypeExtendedEchoRequest && rm.Type == ipv6.ICMPTypeExtendedEchoReply:
return nil
default:
return fmt.Errorf("got %+v from %v; want echo reply or extended echo reply", rm, peer)
}
}
func googleAddr(c *icmp.PacketConn, protocol int) (net.Addr, error) {
host := "ipv4.google.com"
if protocol == iana.ProtocolIPv6ICMP {
host = "ipv6.google.com"
}
ips, err := net.LookupIP(host)
if err != nil {
return nil, err
}
netaddr := func(ip net.IP) (net.Addr, error) {
switch c.LocalAddr().(type) {
case *net.UDPAddr:
return &net.UDPAddr{IP: ip}, nil
case *net.IPAddr:
return &net.IPAddr{IP: ip}, nil
default:
return nil, errors.New("neither UDPAddr nor IPAddr")
}
}
if len(ips) > 0 {
return netaddr(ips[0])
}
return nil, errors.New("no A or AAAA record")
}
func TestConcurrentNonPrivilegedListenPacket(t *testing.T) {
if testing.Short() {
t.Skip("avoid external network")
}
switch runtime.GOOS {
case "darwin":
case "linux":
t.Log("you may need to adjust the net.ipv4.ping_group_range kernel state")
default:
t.Skipf("not supported on %s", runtime.GOOS)
}
network, address := "udp4", "127.0.0.1"
if !nettest.SupportsIPv4() {
network, address = "udp6", "::1"
}
const N = 1000
var wg sync.WaitGroup
wg.Add(N)
for i := 0; i < N; i++ {
go func() {
defer wg.Done()
c, err := icmp.ListenPacket(network, address)
if err != nil {
t.Error(err)
return
}
c.Close()
}()
}
wg.Wait()
}

View file

@ -16,24 +16,24 @@ func (p *DstUnreach) Len(proto int) int {
if p == nil {
return 0
}
l, _ := multipartMessageBodyDataLen(proto, p.Data, p.Extensions)
l, _ := multipartMessageBodyDataLen(proto, true, p.Data, p.Extensions)
return 4 + l
}
// Marshal implements the Marshal method of MessageBody interface.
func (p *DstUnreach) Marshal(proto int) ([]byte, error) {
return marshalMultipartMessageBody(proto, p.Data, p.Extensions)
return marshalMultipartMessageBody(proto, true, p.Data, p.Extensions)
}
// parseDstUnreach parses b as an ICMP destination unreachable message
// body.
func parseDstUnreach(proto int, b []byte) (MessageBody, error) {
func parseDstUnreach(proto int, typ Type, b []byte) (MessageBody, error) {
if len(b) < 4 {
return nil, errMessageTooShort
}
p := &DstUnreach{}
var err error
p.Data, p.Extensions, err = parseMultipartMessageBody(proto, b)
p.Data, p.Extensions, err = parseMultipartMessageBody(proto, typ, b)
if err != nil {
return nil, err
}

114
vendor/golang.org/x/net/icmp/echo.go generated vendored
View file

@ -31,7 +31,7 @@ func (p *Echo) Marshal(proto int) ([]byte, error) {
}
// parseEcho parses b as an ICMP echo request or reply message body.
func parseEcho(proto int, b []byte) (MessageBody, error) {
func parseEcho(proto int, _ Type, b []byte) (MessageBody, error) {
bodyLen := len(b)
if bodyLen < 4 {
return nil, errMessageTooShort
@ -43,3 +43,115 @@ func parseEcho(proto int, b []byte) (MessageBody, error) {
}
return p, nil
}
// An ExtendedEchoRequest represents an ICMP extended echo request
// message body.
type ExtendedEchoRequest struct {
ID int // identifier
Seq int // sequence number
Local bool // must be true when identifying by name or index
Extensions []Extension // extensions
}
// Len implements the Len method of MessageBody interface.
func (p *ExtendedEchoRequest) Len(proto int) int {
if p == nil {
return 0
}
l, _ := multipartMessageBodyDataLen(proto, false, nil, p.Extensions)
return 4 + l
}
// Marshal implements the Marshal method of MessageBody interface.
func (p *ExtendedEchoRequest) Marshal(proto int) ([]byte, error) {
b, err := marshalMultipartMessageBody(proto, false, nil, p.Extensions)
if err != nil {
return nil, err
}
bb := make([]byte, 4)
binary.BigEndian.PutUint16(bb[:2], uint16(p.ID))
bb[2] = byte(p.Seq)
if p.Local {
bb[3] |= 0x01
}
bb = append(bb, b...)
return bb, nil
}
// parseExtendedEchoRequest parses b as an ICMP extended echo request
// message body.
func parseExtendedEchoRequest(proto int, typ Type, b []byte) (MessageBody, error) {
if len(b) < 4+4 {
return nil, errMessageTooShort
}
p := &ExtendedEchoRequest{ID: int(binary.BigEndian.Uint16(b[:2])), Seq: int(b[2])}
if b[3]&0x01 != 0 {
p.Local = true
}
var err error
_, p.Extensions, err = parseMultipartMessageBody(proto, typ, b[4:])
if err != nil {
return nil, err
}
return p, nil
}
// An ExtendedEchoReply represents an ICMP extended echo reply message
// body.
type ExtendedEchoReply struct {
ID int // identifier
Seq int // sequence number
State int // 3-bit state working together with Message.Code
Active bool // probed interface is active
IPv4 bool // probed interface runs IPv4
IPv6 bool // probed interface runs IPv6
}
// Len implements the Len method of MessageBody interface.
func (p *ExtendedEchoReply) Len(proto int) int {
if p == nil {
return 0
}
return 4
}
// Marshal implements the Marshal method of MessageBody interface.
func (p *ExtendedEchoReply) Marshal(proto int) ([]byte, error) {
b := make([]byte, 4)
binary.BigEndian.PutUint16(b[:2], uint16(p.ID))
b[2] = byte(p.Seq)
b[3] = byte(p.State<<5) & 0xe0
if p.Active {
b[3] |= 0x04
}
if p.IPv4 {
b[3] |= 0x02
}
if p.IPv6 {
b[3] |= 0x01
}
return b, nil
}
// parseExtendedEchoReply parses b as an ICMP extended echo reply
// message body.
func parseExtendedEchoReply(proto int, _ Type, b []byte) (MessageBody, error) {
if len(b) < 4 {
return nil, errMessageTooShort
}
p := &ExtendedEchoReply{
ID: int(binary.BigEndian.Uint16(b[:2])),
Seq: int(b[2]),
State: int(b[3]) >> 5,
}
if b[3]&0x04 != 0 {
p.Active = true
}
if b[3]&0x02 != 0 {
p.IPv4 = true
}
if b[3]&0x01 != 0 {
p.IPv6 = true
}
return p, nil
}

View file

@ -7,7 +7,6 @@ package icmp
import (
"net"
"runtime"
"syscall"
"time"
"golang.org/x/net/ipv4"
@ -47,7 +46,7 @@ func (c *PacketConn) IPv6PacketConn() *ipv6.PacketConn {
// ReadFrom reads an ICMP message from the connection.
func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
if !c.ok() {
return 0, nil, syscall.EINVAL
return 0, nil, errInvalidConn
}
// Please be informed that ipv4.NewPacketConn enables
// IP_STRIPHDR option by default on Darwin.
@ -64,7 +63,7 @@ func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
// datagram-oriented ICMP endpoint. Otherwise it must be net.IPAddr.
func (c *PacketConn) WriteTo(b []byte, dst net.Addr) (int, error) {
if !c.ok() {
return 0, syscall.EINVAL
return 0, errInvalidConn
}
return c.c.WriteTo(b, dst)
}
@ -72,7 +71,7 @@ func (c *PacketConn) WriteTo(b []byte, dst net.Addr) (int, error) {
// Close closes the endpoint.
func (c *PacketConn) Close() error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
return c.c.Close()
}
@ -89,7 +88,7 @@ func (c *PacketConn) LocalAddr() net.Addr {
// endpoint.
func (c *PacketConn) SetDeadline(t time.Time) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
return c.c.SetDeadline(t)
}
@ -98,7 +97,7 @@ func (c *PacketConn) SetDeadline(t time.Time) error {
// endpoint.
func (c *PacketConn) SetReadDeadline(t time.Time) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
return c.c.SetReadDeadline(t)
}
@ -107,7 +106,7 @@ func (c *PacketConn) SetReadDeadline(t time.Time) error {
// endpoint.
func (c *PacketConn) SetWriteDeadline(t time.Time) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
return c.c.SetWriteDeadline(t)
}

View file

@ -4,7 +4,12 @@
package icmp
import "encoding/binary"
import (
"encoding/binary"
"golang.org/x/net/ipv4"
"golang.org/x/net/ipv6"
)
// An Extension represents an ICMP extension.
type Extension interface {
@ -38,7 +43,7 @@ func validExtensionHeader(b []byte) bool {
// It will return a list of ICMP extensions and an adjusted length
// attribute that represents the length of the padded original
// datagram field. Otherwise, it returns an error.
func parseExtensions(b []byte, l int) ([]Extension, int, error) {
func parseExtensions(typ Type, b []byte, l int) ([]Extension, int, error) {
// Still a lot of non-RFC 4884 compliant implementations are
// out there. Set the length attribute l to 128 when it looks
// inappropriate for backwards compatibility.
@ -48,20 +53,28 @@ func parseExtensions(b []byte, l int) ([]Extension, int, error) {
// header.
//
// See RFC 4884 for further information.
if 128 > l || l+8 > len(b) {
l = 128
}
if l+8 > len(b) {
return nil, -1, errNoExtension
}
if !validExtensionHeader(b[l:]) {
if l == 128 {
switch typ {
case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest:
if len(b) < 8 || !validExtensionHeader(b) {
return nil, -1, errNoExtension
}
l = 128
if !validExtensionHeader(b[l:]) {
l = 0
default:
if 128 > l || l+8 > len(b) {
l = 128
}
if l+8 > len(b) {
return nil, -1, errNoExtension
}
if !validExtensionHeader(b[l:]) {
if l == 128 {
return nil, -1, errNoExtension
}
l = 128
if !validExtensionHeader(b[l:]) {
return nil, -1, errNoExtension
}
}
}
var exts []Extension
for b = b[l+4:]; len(b) >= 4; {
@ -82,6 +95,12 @@ func parseExtensions(b []byte, l int) ([]Extension, int, error) {
return nil, -1, err
}
exts = append(exts, ext)
case classInterfaceIdent:
ext, err := parseInterfaceIdent(b[:ol])
if err != nil {
return nil, -1, err
}
exts = append(exts, ext)
}
b = b[ol:]
}

View file

@ -5,253 +5,327 @@
package icmp
import (
"fmt"
"net"
"reflect"
"testing"
"golang.org/x/net/internal/iana"
"golang.org/x/net/ipv4"
"golang.org/x/net/ipv6"
)
var marshalAndParseExtensionTests = []struct {
proto int
hdr []byte
obj []byte
exts []Extension
}{
// MPLS label stack with no label
{
proto: iana.ProtocolICMP,
hdr: []byte{
0x20, 0x00, 0x00, 0x00,
},
obj: []byte{
0x00, 0x04, 0x01, 0x01,
},
exts: []Extension{
&MPLSLabelStack{
Class: classMPLSLabelStack,
Type: typeIncomingMPLSLabelStack,
},
},
},
// MPLS label stack with a single label
{
proto: iana.ProtocolIPv6ICMP,
hdr: []byte{
0x20, 0x00, 0x00, 0x00,
},
obj: []byte{
0x00, 0x08, 0x01, 0x01,
0x03, 0xe8, 0xe9, 0xff,
},
exts: []Extension{
&MPLSLabelStack{
Class: classMPLSLabelStack,
Type: typeIncomingMPLSLabelStack,
Labels: []MPLSLabel{
{
Label: 16014,
TC: 0x4,
S: true,
TTL: 255,
},
},
},
},
},
// MPLS label stack with multiple labels
{
proto: iana.ProtocolICMP,
hdr: []byte{
0x20, 0x00, 0x00, 0x00,
},
obj: []byte{
0x00, 0x0c, 0x01, 0x01,
0x03, 0xe8, 0xde, 0xfe,
0x03, 0xe8, 0xe1, 0xff,
},
exts: []Extension{
&MPLSLabelStack{
Class: classMPLSLabelStack,
Type: typeIncomingMPLSLabelStack,
Labels: []MPLSLabel{
{
Label: 16013,
TC: 0x7,
S: false,
TTL: 254,
},
{
Label: 16014,
TC: 0,
S: true,
TTL: 255,
},
},
},
},
},
// Interface information with no attribute
{
proto: iana.ProtocolICMP,
hdr: []byte{
0x20, 0x00, 0x00, 0x00,
},
obj: []byte{
0x00, 0x04, 0x02, 0x00,
},
exts: []Extension{
&InterfaceInfo{
Class: classInterfaceInfo,
},
},
},
// Interface information with ifIndex and name
{
proto: iana.ProtocolICMP,
hdr: []byte{
0x20, 0x00, 0x00, 0x00,
},
obj: []byte{
0x00, 0x10, 0x02, 0x0a,
0x00, 0x00, 0x00, 0x10,
0x08, byte('e'), byte('n'), byte('1'),
byte('0'), byte('1'), 0x00, 0x00,
},
exts: []Extension{
&InterfaceInfo{
Class: classInterfaceInfo,
Type: 0x0a,
Interface: &net.Interface{
Index: 16,
Name: "en101",
},
},
},
},
// Interface information with ifIndex, IPAddr, name and MTU
{
proto: iana.ProtocolIPv6ICMP,
hdr: []byte{
0x20, 0x00, 0x00, 0x00,
},
obj: []byte{
0x00, 0x28, 0x02, 0x0f,
0x00, 0x00, 0x00, 0x0f,
0x00, 0x02, 0x00, 0x00,
0xfe, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01,
0x08, byte('e'), byte('n'), byte('1'),
byte('0'), byte('1'), 0x00, 0x00,
0x00, 0x00, 0x20, 0x00,
},
exts: []Extension{
&InterfaceInfo{
Class: classInterfaceInfo,
Type: 0x0f,
Interface: &net.Interface{
Index: 15,
Name: "en101",
MTU: 8192,
},
Addr: &net.IPAddr{
IP: net.ParseIP("fe80::1"),
Zone: "en101",
},
},
},
},
}
func TestMarshalAndParseExtension(t *testing.T) {
for i, tt := range marshalAndParseExtensionTests {
for j, ext := range tt.exts {
var err error
var b []byte
switch ext := ext.(type) {
case *MPLSLabelStack:
b, err = ext.Marshal(tt.proto)
if err != nil {
t.Errorf("#%v/%v: %v", i, j, err)
fn := func(t *testing.T, proto int, typ Type, hdr, obj []byte, te Extension) error {
b, err := te.Marshal(proto)
if err != nil {
return err
}
if !reflect.DeepEqual(b, obj) {
return fmt.Errorf("got %#v; want %#v", b, obj)
}
switch typ {
case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest:
exts, l, err := parseExtensions(typ, append(hdr, obj...), 0)
if err != nil {
return err
}
if l != 0 {
return fmt.Errorf("got %d; want 0", l)
}
if !reflect.DeepEqual(exts, []Extension{te}) {
return fmt.Errorf("got %#v; want %#v", exts[0], te)
}
default:
for i, wire := range []struct {
data []byte // original datagram
inlattr int // length of padded original datagram, a hint
outlattr int // length of padded original datagram, a want
err error
}{
{nil, 0, -1, errNoExtension},
{make([]byte, 127), 128, -1, errNoExtension},
{make([]byte, 128), 127, -1, errNoExtension},
{make([]byte, 128), 128, -1, errNoExtension},
{make([]byte, 128), 129, -1, errNoExtension},
{append(make([]byte, 128), append(hdr, obj...)...), 127, 128, nil},
{append(make([]byte, 128), append(hdr, obj...)...), 128, 128, nil},
{append(make([]byte, 128), append(hdr, obj...)...), 129, 128, nil},
{append(make([]byte, 512), append(hdr, obj...)...), 511, -1, errNoExtension},
{append(make([]byte, 512), append(hdr, obj...)...), 512, 512, nil},
{append(make([]byte, 512), append(hdr, obj...)...), 513, -1, errNoExtension},
} {
exts, l, err := parseExtensions(typ, wire.data, wire.inlattr)
if err != wire.err {
return fmt.Errorf("#%d: got %v; want %v", i, err, wire.err)
}
if wire.err != nil {
continue
}
case *InterfaceInfo:
b, err = ext.Marshal(tt.proto)
if err != nil {
t.Errorf("#%v/%v: %v", i, j, err)
continue
if l != wire.outlattr {
return fmt.Errorf("#%d: got %d; want %d", i, l, wire.outlattr)
}
if !reflect.DeepEqual(exts, []Extension{te}) {
return fmt.Errorf("#%d: got %#v; want %#v", i, exts[0], te)
}
}
if !reflect.DeepEqual(b, tt.obj) {
t.Errorf("#%v/%v: got %#v; want %#v", i, j, b, tt.obj)
continue
}
}
for j, wire := range []struct {
data []byte // original datagram
inlattr int // length of padded original datagram, a hint
outlattr int // length of padded original datagram, a want
err error
}{
{nil, 0, -1, errNoExtension},
{make([]byte, 127), 128, -1, errNoExtension},
{make([]byte, 128), 127, -1, errNoExtension},
{make([]byte, 128), 128, -1, errNoExtension},
{make([]byte, 128), 129, -1, errNoExtension},
{append(make([]byte, 128), append(tt.hdr, tt.obj...)...), 127, 128, nil},
{append(make([]byte, 128), append(tt.hdr, tt.obj...)...), 128, 128, nil},
{append(make([]byte, 128), append(tt.hdr, tt.obj...)...), 129, 128, nil},
{append(make([]byte, 512), append(tt.hdr, tt.obj...)...), 511, -1, errNoExtension},
{append(make([]byte, 512), append(tt.hdr, tt.obj...)...), 512, 512, nil},
{append(make([]byte, 512), append(tt.hdr, tt.obj...)...), 513, -1, errNoExtension},
} {
exts, l, err := parseExtensions(wire.data, wire.inlattr)
if err != wire.err {
t.Errorf("#%v/%v: got %v; want %v", i, j, err, wire.err)
continue
}
if wire.err != nil {
continue
}
if l != wire.outlattr {
t.Errorf("#%v/%v: got %v; want %v", i, j, l, wire.outlattr)
}
if !reflect.DeepEqual(exts, tt.exts) {
for j, ext := range exts {
switch ext := ext.(type) {
case *MPLSLabelStack:
want := tt.exts[j].(*MPLSLabelStack)
t.Errorf("#%v/%v: got %#v; want %#v", i, j, ext, want)
case *InterfaceInfo:
want := tt.exts[j].(*InterfaceInfo)
t.Errorf("#%v/%v: got %#v; want %#v", i, j, ext, want)
}
}
continue
}
}
return nil
}
}
var parseInterfaceNameTests = []struct {
b []byte
error
}{
{[]byte{0, 'e', 'n', '0'}, errInvalidExtension},
{[]byte{4, 'e', 'n', '0'}, nil},
{[]byte{7, 'e', 'n', '0', 0xff, 0xff, 0xff, 0xff}, errInvalidExtension},
{[]byte{8, 'e', 'n', '0', 0xff, 0xff, 0xff}, errMessageTooShort},
t.Run("MPLSLabelStack", func(t *testing.T) {
for _, et := range []struct {
proto int
typ Type
hdr []byte
obj []byte
ext Extension
}{
// MPLS label stack with no label
{
proto: iana.ProtocolICMP,
typ: ipv4.ICMPTypeDestinationUnreachable,
hdr: []byte{
0x20, 0x00, 0x00, 0x00,
},
obj: []byte{
0x00, 0x04, 0x01, 0x01,
},
ext: &MPLSLabelStack{
Class: classMPLSLabelStack,
Type: typeIncomingMPLSLabelStack,
},
},
// MPLS label stack with a single label
{
proto: iana.ProtocolIPv6ICMP,
typ: ipv6.ICMPTypeDestinationUnreachable,
hdr: []byte{
0x20, 0x00, 0x00, 0x00,
},
obj: []byte{
0x00, 0x08, 0x01, 0x01,
0x03, 0xe8, 0xe9, 0xff,
},
ext: &MPLSLabelStack{
Class: classMPLSLabelStack,
Type: typeIncomingMPLSLabelStack,
Labels: []MPLSLabel{
{
Label: 16014,
TC: 0x4,
S: true,
TTL: 255,
},
},
},
},
// MPLS label stack with multiple labels
{
proto: iana.ProtocolICMP,
typ: ipv4.ICMPTypeDestinationUnreachable,
hdr: []byte{
0x20, 0x00, 0x00, 0x00,
},
obj: []byte{
0x00, 0x0c, 0x01, 0x01,
0x03, 0xe8, 0xde, 0xfe,
0x03, 0xe8, 0xe1, 0xff,
},
ext: &MPLSLabelStack{
Class: classMPLSLabelStack,
Type: typeIncomingMPLSLabelStack,
Labels: []MPLSLabel{
{
Label: 16013,
TC: 0x7,
S: false,
TTL: 254,
},
{
Label: 16014,
TC: 0,
S: true,
TTL: 255,
},
},
},
},
} {
if err := fn(t, et.proto, et.typ, et.hdr, et.obj, et.ext); err != nil {
t.Error(err)
}
}
})
t.Run("InterfaceInfo", func(t *testing.T) {
for _, et := range []struct {
proto int
typ Type
hdr []byte
obj []byte
ext Extension
}{
// Interface information with no attribute
{
proto: iana.ProtocolICMP,
typ: ipv4.ICMPTypeDestinationUnreachable,
hdr: []byte{
0x20, 0x00, 0x00, 0x00,
},
obj: []byte{
0x00, 0x04, 0x02, 0x00,
},
ext: &InterfaceInfo{
Class: classInterfaceInfo,
},
},
// Interface information with ifIndex and name
{
proto: iana.ProtocolICMP,
typ: ipv4.ICMPTypeDestinationUnreachable,
hdr: []byte{
0x20, 0x00, 0x00, 0x00,
},
obj: []byte{
0x00, 0x10, 0x02, 0x0a,
0x00, 0x00, 0x00, 0x10,
0x08, byte('e'), byte('n'), byte('1'),
byte('0'), byte('1'), 0x00, 0x00,
},
ext: &InterfaceInfo{
Class: classInterfaceInfo,
Type: 0x0a,
Interface: &net.Interface{
Index: 16,
Name: "en101",
},
},
},
// Interface information with ifIndex, IPAddr, name and MTU
{
proto: iana.ProtocolIPv6ICMP,
typ: ipv6.ICMPTypeDestinationUnreachable,
hdr: []byte{
0x20, 0x00, 0x00, 0x00,
},
obj: []byte{
0x00, 0x28, 0x02, 0x0f,
0x00, 0x00, 0x00, 0x0f,
0x00, 0x02, 0x00, 0x00,
0xfe, 0x80, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01,
0x08, byte('e'), byte('n'), byte('1'),
byte('0'), byte('1'), 0x00, 0x00,
0x00, 0x00, 0x20, 0x00,
},
ext: &InterfaceInfo{
Class: classInterfaceInfo,
Type: 0x0f,
Interface: &net.Interface{
Index: 15,
Name: "en101",
MTU: 8192,
},
Addr: &net.IPAddr{
IP: net.ParseIP("fe80::1"),
Zone: "en101",
},
},
},
} {
if err := fn(t, et.proto, et.typ, et.hdr, et.obj, et.ext); err != nil {
t.Error(err)
}
}
})
t.Run("InterfaceIdent", func(t *testing.T) {
for _, et := range []struct {
proto int
typ Type
hdr []byte
obj []byte
ext Extension
}{
// Interface identification by name
{
proto: iana.ProtocolICMP,
typ: ipv4.ICMPTypeExtendedEchoRequest,
hdr: []byte{
0x20, 0x00, 0x00, 0x00,
},
obj: []byte{
0x00, 0x0c, 0x03, 0x01,
byte('e'), byte('n'), byte('1'), byte('0'),
byte('1'), 0x00, 0x00, 0x00,
},
ext: &InterfaceIdent{
Class: classInterfaceIdent,
Type: typeInterfaceByName,
Name: "en101",
},
},
// Interface identification by index
{
proto: iana.ProtocolIPv6ICMP,
typ: ipv6.ICMPTypeExtendedEchoRequest,
hdr: []byte{
0x20, 0x00, 0x00, 0x00,
},
obj: []byte{
0x00, 0x0c, 0x03, 0x02,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x03, 0x8f,
},
ext: &InterfaceIdent{
Class: classInterfaceIdent,
Type: typeInterfaceByIndex,
Index: 911,
},
},
// Interface identification by address
{
proto: iana.ProtocolICMP,
typ: ipv4.ICMPTypeExtendedEchoRequest,
hdr: []byte{
0x20, 0x00, 0x00, 0x00,
},
obj: []byte{
0x00, 0x10, 0x03, 0x03,
byte(iana.AddrFamily48bitMAC >> 8), byte(iana.AddrFamily48bitMAC & 0x0f), 0x06, 0x00,
0x01, 0x23, 0x45, 0x67,
0x89, 0xab, 0x00, 0x00,
},
ext: &InterfaceIdent{
Class: classInterfaceIdent,
Type: typeInterfaceByAddress,
AFI: iana.AddrFamily48bitMAC,
Addr: []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab},
},
},
} {
if err := fn(t, et.proto, et.typ, et.hdr, et.obj, et.ext); err != nil {
t.Error(err)
}
}
})
}
func TestParseInterfaceName(t *testing.T) {
ifi := InterfaceInfo{Interface: &net.Interface{}}
for i, tt := range parseInterfaceNameTests {
for i, tt := range []struct {
b []byte
error
}{
{[]byte{0, 'e', 'n', '0'}, errInvalidExtension},
{[]byte{4, 'e', 'n', '0'}, nil},
{[]byte{7, 'e', 'n', '0', 0xff, 0xff, 0xff, 0xff}, errInvalidExtension},
{[]byte{8, 'e', 'n', '0', 0xff, 0xff, 0xff}, errMessageTooShort},
} {
if _, err := ifi.parseName(tt.b); err != tt.error {
t.Errorf("#%d: got %v; want %v", i, err, tt.error)
}

View file

@ -14,9 +14,6 @@ import (
const (
classInterfaceInfo = 2
afiIPv4 = 1
afiIPv6 = 2
)
const (
@ -127,11 +124,11 @@ func (ifi *InterfaceInfo) parseIfIndex(b []byte) ([]byte, error) {
func (ifi *InterfaceInfo) marshalIPAddr(proto int, b []byte) []byte {
switch proto {
case iana.ProtocolICMP:
binary.BigEndian.PutUint16(b[:2], uint16(afiIPv4))
binary.BigEndian.PutUint16(b[:2], uint16(iana.AddrFamilyIPv4))
copy(b[4:4+net.IPv4len], ifi.Addr.IP.To4())
b = b[4+net.IPv4len:]
case iana.ProtocolIPv6ICMP:
binary.BigEndian.PutUint16(b[:2], uint16(afiIPv6))
binary.BigEndian.PutUint16(b[:2], uint16(iana.AddrFamilyIPv6))
copy(b[4:4+net.IPv6len], ifi.Addr.IP.To16())
b = b[4+net.IPv6len:]
}
@ -145,14 +142,14 @@ func (ifi *InterfaceInfo) parseIPAddr(b []byte) ([]byte, error) {
afi := int(binary.BigEndian.Uint16(b[:2]))
b = b[4:]
switch afi {
case afiIPv4:
case iana.AddrFamilyIPv4:
if len(b) < net.IPv4len {
return nil, errMessageTooShort
}
ifi.Addr.IP = make(net.IP, net.IPv4len)
copy(ifi.Addr.IP, b[:net.IPv4len])
b = b[net.IPv4len:]
case afiIPv6:
case iana.AddrFamilyIPv6:
if len(b) < net.IPv6len {
return nil, errMessageTooShort
}
@ -234,3 +231,92 @@ func parseInterfaceInfo(b []byte) (Extension, error) {
}
return ifi, nil
}
const (
classInterfaceIdent = 3
typeInterfaceByName = 1
typeInterfaceByIndex = 2
typeInterfaceByAddress = 3
)
// An InterfaceIdent represents interface identification.
type InterfaceIdent struct {
Class int // extension object class number
Type int // extension object sub-type
Name string // interface name
Index int // interface index
AFI int // address family identifier; see address family numbers in IANA registry
Addr []byte // address
}
// Len implements the Len method of Extension interface.
func (ifi *InterfaceIdent) Len(_ int) int {
switch ifi.Type {
case typeInterfaceByName:
l := len(ifi.Name)
if l > 255 {
l = 255
}
return 4 + (l+3)&^3
case typeInterfaceByIndex:
return 4 + 8
case typeInterfaceByAddress:
return 4 + 4 + (len(ifi.Addr)+3)&^3
default:
return 4
}
}
// Marshal implements the Marshal method of Extension interface.
func (ifi *InterfaceIdent) Marshal(proto int) ([]byte, error) {
b := make([]byte, ifi.Len(proto))
if err := ifi.marshal(proto, b); err != nil {
return nil, err
}
return b, nil
}
func (ifi *InterfaceIdent) marshal(proto int, b []byte) error {
l := ifi.Len(proto)
binary.BigEndian.PutUint16(b[:2], uint16(l))
b[2], b[3] = classInterfaceIdent, byte(ifi.Type)
switch ifi.Type {
case typeInterfaceByName:
copy(b[4:], ifi.Name)
case typeInterfaceByIndex:
binary.BigEndian.PutUint64(b[4:4+8], uint64(ifi.Index))
case typeInterfaceByAddress:
binary.BigEndian.PutUint16(b[4:4+2], uint16(ifi.AFI))
b[4+2] = byte(len(ifi.Addr))
copy(b[4+4:], ifi.Addr)
}
return nil
}
func parseInterfaceIdent(b []byte) (Extension, error) {
ifi := &InterfaceIdent{
Class: int(b[2]),
Type: int(b[3]),
}
switch ifi.Type {
case typeInterfaceByName:
ifi.Name = strings.Trim(string(b[4:]), string(0))
case typeInterfaceByIndex:
if len(b[4:]) < 8 {
return nil, errInvalidExtension
}
ifi.Index = int(binary.BigEndian.Uint64(b[4 : 4+8]))
case typeInterfaceByAddress:
if len(b[4:]) < 4 {
return nil, errInvalidExtension
}
ifi.AFI = int(binary.BigEndian.Uint16(b[4 : 4+2]))
l := int(b[4+2])
if len(b[4+4:]) < l {
return nil, errInvalidExtension
}
ifi.Addr = make([]byte, l)
copy(ifi.Addr, b[4+4:])
}
return ifi, nil
}

View file

@ -15,69 +15,61 @@ import (
"golang.org/x/net/ipv4"
)
type ipv4HeaderTest struct {
wireHeaderFromKernel [ipv4.HeaderLen]byte
wireHeaderFromTradBSDKernel [ipv4.HeaderLen]byte
Header *ipv4.Header
}
var ipv4HeaderLittleEndianTest = ipv4HeaderTest{
// TODO(mikio): Add platform dependent wire header formats when
// we support new platforms.
wireHeaderFromKernel: [ipv4.HeaderLen]byte{
0x45, 0x01, 0xbe, 0xef,
0xca, 0xfe, 0x45, 0xdc,
0xff, 0x01, 0xde, 0xad,
172, 16, 254, 254,
192, 168, 0, 1,
},
wireHeaderFromTradBSDKernel: [ipv4.HeaderLen]byte{
0x45, 0x01, 0xef, 0xbe,
0xca, 0xfe, 0x45, 0xdc,
0xff, 0x01, 0xde, 0xad,
172, 16, 254, 254,
192, 168, 0, 1,
},
Header: &ipv4.Header{
Version: ipv4.Version,
Len: ipv4.HeaderLen,
TOS: 1,
TotalLen: 0xbeef,
ID: 0xcafe,
Flags: ipv4.DontFragment,
FragOff: 1500,
TTL: 255,
Protocol: 1,
Checksum: 0xdead,
Src: net.IPv4(172, 16, 254, 254),
Dst: net.IPv4(192, 168, 0, 1),
},
}
func TestParseIPv4Header(t *testing.T) {
tt := &ipv4HeaderLittleEndianTest
if socket.NativeEndian != binary.LittleEndian {
t.Skip("no test for non-little endian machine yet")
}
var wh []byte
switch runtime.GOOS {
case "darwin":
wh = tt.wireHeaderFromTradBSDKernel[:]
case "freebsd":
if freebsdVersion >= 1000000 {
wh = tt.wireHeaderFromKernel[:]
} else {
wh = tt.wireHeaderFromTradBSDKernel[:]
}
default:
wh = tt.wireHeaderFromKernel[:]
}
h, err := ParseIPv4Header(wh)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(h, tt.Header) {
t.Fatalf("got %#v; want %#v", h, tt.Header)
switch socket.NativeEndian {
case binary.LittleEndian:
t.Run("LittleEndian", func(t *testing.T) {
// TODO(mikio): Add platform dependent wire
// header formats when we support new
// platforms.
wireHeaderFromKernel := [ipv4.HeaderLen]byte{
0x45, 0x01, 0xbe, 0xef,
0xca, 0xfe, 0x45, 0xdc,
0xff, 0x01, 0xde, 0xad,
172, 16, 254, 254,
192, 168, 0, 1,
}
wireHeaderFromTradBSDKernel := [ipv4.HeaderLen]byte{
0x45, 0x01, 0xef, 0xbe,
0xca, 0xfe, 0x45, 0xdc,
0xff, 0x01, 0xde, 0xad,
172, 16, 254, 254,
192, 168, 0, 1,
}
th := &ipv4.Header{
Version: ipv4.Version,
Len: ipv4.HeaderLen,
TOS: 1,
TotalLen: 0xbeef,
ID: 0xcafe,
Flags: ipv4.DontFragment,
FragOff: 1500,
TTL: 255,
Protocol: 1,
Checksum: 0xdead,
Src: net.IPv4(172, 16, 254, 254),
Dst: net.IPv4(192, 168, 0, 1),
}
var wh []byte
switch runtime.GOOS {
case "darwin":
wh = wireHeaderFromTradBSDKernel[:]
case "freebsd":
if freebsdVersion >= 1000000 {
wh = wireHeaderFromKernel[:]
} else {
wh = wireHeaderFromTradBSDKernel[:]
}
default:
wh = wireHeaderFromKernel[:]
}
h, err := ParseIPv4Header(wh)
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(h, th) {
t.Fatalf("got %#v; want %#v", h, th)
}
})
}
}

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build nacl plan9
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!windows
package icmp

View file

@ -11,22 +11,23 @@
// ICMP extensions for MPLS are defined in RFC 4950.
// ICMP extensions for interface and next-hop identification are
// defined in RFC 5837.
// PROBE: A utility for probing interfaces is defined in RFC 8335.
package icmp // import "golang.org/x/net/icmp"
import (
"encoding/binary"
"errors"
"net"
"syscall"
"golang.org/x/net/internal/iana"
"golang.org/x/net/ipv4"
"golang.org/x/net/ipv6"
)
// BUG(mikio): This package is not implemented on NaCl and Plan 9.
// BUG(mikio): This package is not implemented on JS, NaCl and Plan 9.
var (
errInvalidConn = errors.New("invalid connection")
errMessageTooShort = errors.New("message too short")
errHeaderTooShort = errors.New("header too short")
errBufferTooShort = errors.New("buffer too short")
@ -79,7 +80,7 @@ func (m *Message) Marshal(psh []byte) ([]byte, error) {
case ipv6.ICMPType:
mtype = int(typ)
default:
return nil, syscall.EINVAL
return nil, errInvalidConn
}
b := []byte{byte(mtype), byte(m.Code), 0, 0}
if m.Type.Protocol() == iana.ProtocolIPv6ICMP && psh != nil {
@ -107,21 +108,25 @@ func (m *Message) Marshal(psh []byte) ([]byte, error) {
return b[len(psh):], nil
}
var parseFns = map[Type]func(int, []byte) (MessageBody, error){
var parseFns = map[Type]func(int, Type, []byte) (MessageBody, error){
ipv4.ICMPTypeDestinationUnreachable: parseDstUnreach,
ipv4.ICMPTypeTimeExceeded: parseTimeExceeded,
ipv4.ICMPTypeParameterProblem: parseParamProb,
ipv4.ICMPTypeEcho: parseEcho,
ipv4.ICMPTypeEchoReply: parseEcho,
ipv4.ICMPTypeEcho: parseEcho,
ipv4.ICMPTypeEchoReply: parseEcho,
ipv4.ICMPTypeExtendedEchoRequest: parseExtendedEchoRequest,
ipv4.ICMPTypeExtendedEchoReply: parseExtendedEchoReply,
ipv6.ICMPTypeDestinationUnreachable: parseDstUnreach,
ipv6.ICMPTypePacketTooBig: parsePacketTooBig,
ipv6.ICMPTypeTimeExceeded: parseTimeExceeded,
ipv6.ICMPTypeParameterProblem: parseParamProb,
ipv6.ICMPTypeEchoRequest: parseEcho,
ipv6.ICMPTypeEchoReply: parseEcho,
ipv6.ICMPTypeEchoRequest: parseEcho,
ipv6.ICMPTypeEchoReply: parseEcho,
ipv6.ICMPTypeExtendedEchoRequest: parseExtendedEchoRequest,
ipv6.ICMPTypeExtendedEchoReply: parseExtendedEchoReply,
}
// ParseMessage parses b as an ICMP message.
@ -138,12 +143,12 @@ func ParseMessage(proto int, b []byte) (*Message, error) {
case iana.ProtocolIPv6ICMP:
m.Type = ipv6.ICMPType(b[0])
default:
return nil, syscall.EINVAL
return nil, errInvalidConn
}
if fn, ok := parseFns[m.Type]; !ok {
m.Body, err = parseDefaultMessageBody(proto, b[4:])
} else {
m.Body, err = fn(proto, b[4:])
m.Body, err = fn(proto, m.Type, b[4:])
}
if err != nil {
return nil, err

View file

@ -15,120 +15,141 @@ import (
"golang.org/x/net/ipv6"
)
var marshalAndParseMessageForIPv4Tests = []icmp.Message{
{
Type: ipv4.ICMPTypeDestinationUnreachable, Code: 15,
Body: &icmp.DstUnreach{
Data: []byte("ERROR-INVOKING-PACKET"),
},
},
{
Type: ipv4.ICMPTypeTimeExceeded, Code: 1,
Body: &icmp.TimeExceeded{
Data: []byte("ERROR-INVOKING-PACKET"),
},
},
{
Type: ipv4.ICMPTypeParameterProblem, Code: 2,
Body: &icmp.ParamProb{
Pointer: 8,
Data: []byte("ERROR-INVOKING-PACKET"),
},
},
{
Type: ipv4.ICMPTypeEcho, Code: 0,
Body: &icmp.Echo{
ID: 1, Seq: 2,
Data: []byte("HELLO-R-U-THERE"),
},
},
{
Type: ipv4.ICMPTypePhoturis,
Body: &icmp.DefaultMessageBody{
Data: []byte{0x80, 0x40, 0x20, 0x10},
},
},
}
func TestMarshalAndParseMessageForIPv4(t *testing.T) {
for i, tt := range marshalAndParseMessageForIPv4Tests {
b, err := tt.Marshal(nil)
if err != nil {
t.Fatal(err)
}
m, err := icmp.ParseMessage(iana.ProtocolICMP, b)
if err != nil {
t.Fatal(err)
}
if m.Type != tt.Type || m.Code != tt.Code {
t.Errorf("#%v: got %v; want %v", i, m, &tt)
}
if !reflect.DeepEqual(m.Body, tt.Body) {
t.Errorf("#%v: got %v; want %v", i, m.Body, tt.Body)
}
}
}
var marshalAndParseMessageForIPv6Tests = []icmp.Message{
{
Type: ipv6.ICMPTypeDestinationUnreachable, Code: 6,
Body: &icmp.DstUnreach{
Data: []byte("ERROR-INVOKING-PACKET"),
},
},
{
Type: ipv6.ICMPTypePacketTooBig, Code: 0,
Body: &icmp.PacketTooBig{
MTU: 1<<16 - 1,
Data: []byte("ERROR-INVOKING-PACKET"),
},
},
{
Type: ipv6.ICMPTypeTimeExceeded, Code: 1,
Body: &icmp.TimeExceeded{
Data: []byte("ERROR-INVOKING-PACKET"),
},
},
{
Type: ipv6.ICMPTypeParameterProblem, Code: 2,
Body: &icmp.ParamProb{
Pointer: 8,
Data: []byte("ERROR-INVOKING-PACKET"),
},
},
{
Type: ipv6.ICMPTypeEchoRequest, Code: 0,
Body: &icmp.Echo{
ID: 1, Seq: 2,
Data: []byte("HELLO-R-U-THERE"),
},
},
{
Type: ipv6.ICMPTypeDuplicateAddressConfirmation,
Body: &icmp.DefaultMessageBody{
Data: []byte{0x80, 0x40, 0x20, 0x10},
},
},
}
func TestMarshalAndParseMessageForIPv6(t *testing.T) {
pshicmp := icmp.IPv6PseudoHeader(net.ParseIP("fe80::1"), net.ParseIP("ff02::1"))
for i, tt := range marshalAndParseMessageForIPv6Tests {
for _, psh := range [][]byte{pshicmp, nil} {
b, err := tt.Marshal(psh)
if err != nil {
t.Fatal(err)
func TestMarshalAndParseMessage(t *testing.T) {
fn := func(t *testing.T, proto int, tms []icmp.Message) {
var pshs [][]byte
switch proto {
case iana.ProtocolICMP:
pshs = [][]byte{nil}
case iana.ProtocolIPv6ICMP:
pshs = [][]byte{
icmp.IPv6PseudoHeader(net.ParseIP("fe80::1"), net.ParseIP("ff02::1")),
nil,
}
m, err := icmp.ParseMessage(iana.ProtocolIPv6ICMP, b)
if err != nil {
t.Fatal(err)
}
if m.Type != tt.Type || m.Code != tt.Code {
t.Errorf("#%v: got %v; want %v", i, m, &tt)
}
if !reflect.DeepEqual(m.Body, tt.Body) {
t.Errorf("#%v: got %v; want %v", i, m.Body, tt.Body)
}
for i, tm := range tms {
for _, psh := range pshs {
b, err := tm.Marshal(psh)
if err != nil {
t.Fatal(err)
}
m, err := icmp.ParseMessage(proto, b)
if err != nil {
t.Fatal(err)
}
if m.Type != tm.Type || m.Code != tm.Code {
t.Errorf("#%d: got %#v; want %#v", i, m, &tm)
}
if !reflect.DeepEqual(m.Body, tm.Body) {
t.Errorf("#%d: got %#v; want %#v", i, m.Body, tm.Body)
}
}
}
}
t.Run("IPv4", func(t *testing.T) {
fn(t, iana.ProtocolICMP,
[]icmp.Message{
{
Type: ipv4.ICMPTypeDestinationUnreachable, Code: 15,
Body: &icmp.DstUnreach{
Data: []byte("ERROR-INVOKING-PACKET"),
},
},
{
Type: ipv4.ICMPTypeTimeExceeded, Code: 1,
Body: &icmp.TimeExceeded{
Data: []byte("ERROR-INVOKING-PACKET"),
},
},
{
Type: ipv4.ICMPTypeParameterProblem, Code: 2,
Body: &icmp.ParamProb{
Pointer: 8,
Data: []byte("ERROR-INVOKING-PACKET"),
},
},
{
Type: ipv4.ICMPTypeEcho, Code: 0,
Body: &icmp.Echo{
ID: 1, Seq: 2,
Data: []byte("HELLO-R-U-THERE"),
},
},
{
Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
Body: &icmp.ExtendedEchoRequest{
ID: 1, Seq: 2,
},
},
{
Type: ipv4.ICMPTypeExtendedEchoReply, Code: 0,
Body: &icmp.ExtendedEchoReply{
State: 4 /* Delay */, Active: true, IPv4: true,
},
},
{
Type: ipv4.ICMPTypePhoturis,
Body: &icmp.DefaultMessageBody{
Data: []byte{0x80, 0x40, 0x20, 0x10},
},
},
})
})
t.Run("IPv6", func(t *testing.T) {
fn(t, iana.ProtocolIPv6ICMP,
[]icmp.Message{
{
Type: ipv6.ICMPTypeDestinationUnreachable, Code: 6,
Body: &icmp.DstUnreach{
Data: []byte("ERROR-INVOKING-PACKET"),
},
},
{
Type: ipv6.ICMPTypePacketTooBig, Code: 0,
Body: &icmp.PacketTooBig{
MTU: 1<<16 - 1,
Data: []byte("ERROR-INVOKING-PACKET"),
},
},
{
Type: ipv6.ICMPTypeTimeExceeded, Code: 1,
Body: &icmp.TimeExceeded{
Data: []byte("ERROR-INVOKING-PACKET"),
},
},
{
Type: ipv6.ICMPTypeParameterProblem, Code: 2,
Body: &icmp.ParamProb{
Pointer: 8,
Data: []byte("ERROR-INVOKING-PACKET"),
},
},
{
Type: ipv6.ICMPTypeEchoRequest, Code: 0,
Body: &icmp.Echo{
ID: 1, Seq: 2,
Data: []byte("HELLO-R-U-THERE"),
},
},
{
Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
Body: &icmp.ExtendedEchoRequest{
ID: 1, Seq: 2,
},
},
{
Type: ipv6.ICMPTypeExtendedEchoReply, Code: 0,
Body: &icmp.ExtendedEchoReply{
State: 5 /* Probe */, Active: true, IPv6: true,
},
},
{
Type: ipv6.ICMPTypeDuplicateAddressConfirmation,
Body: &icmp.DefaultMessageBody{
Data: []byte{0x80, 0x40, 0x20, 0x10},
},
},
})
})
}

View file

@ -6,7 +6,7 @@ package icmp
import "encoding/binary"
// A MPLSLabel represents a MPLS label stack entry.
// MPLSLabel represents an MPLS label stack entry.
type MPLSLabel struct {
Label int // label value
TC int // traffic class; formerly experimental use
@ -19,7 +19,7 @@ const (
typeIncomingMPLSLabelStack = 1
)
// A MPLSLabelStack represents a MPLS label stack.
// MPLSLabelStack represents an MPLS label stack.
type MPLSLabelStack struct {
Class int // extension object class number
Type int // extension object sub-type

View file

@ -10,12 +10,14 @@ import "golang.org/x/net/internal/iana"
// exts as extensions, and returns a required length for message body
// and a required length for a padded original datagram in wire
// format.
func multipartMessageBodyDataLen(proto int, b []byte, exts []Extension) (bodyLen, dataLen int) {
func multipartMessageBodyDataLen(proto int, withOrigDgram bool, b []byte, exts []Extension) (bodyLen, dataLen int) {
for _, ext := range exts {
bodyLen += ext.Len(proto)
}
if bodyLen > 0 {
dataLen = multipartMessageOrigDatagramLen(proto, b)
if withOrigDgram {
dataLen = multipartMessageOrigDatagramLen(proto, b)
}
bodyLen += 4 // length of extension header
} else {
dataLen = len(b)
@ -50,8 +52,8 @@ func multipartMessageOrigDatagramLen(proto int, b []byte) int {
// marshalMultipartMessageBody takes data as an original datagram and
// exts as extesnsions, and returns a binary encoding of message body.
// It can be used for non-multipart message bodies when exts is nil.
func marshalMultipartMessageBody(proto int, data []byte, exts []Extension) ([]byte, error) {
bodyLen, dataLen := multipartMessageBodyDataLen(proto, data, exts)
func marshalMultipartMessageBody(proto int, withOrigDgram bool, data []byte, exts []Extension) ([]byte, error) {
bodyLen, dataLen := multipartMessageBodyDataLen(proto, withOrigDgram, data, exts)
b := make([]byte, 4+bodyLen)
copy(b[4:], data)
off := dataLen + 4
@ -71,16 +73,23 @@ func marshalMultipartMessageBody(proto int, data []byte, exts []Extension) ([]by
return nil, err
}
off += ext.Len(proto)
case *InterfaceIdent:
if err := ext.marshal(proto, b[off:]); err != nil {
return nil, err
}
off += ext.Len(proto)
}
}
s := checksum(b[dataLen+4:])
b[dataLen+4+2] ^= byte(s)
b[dataLen+4+3] ^= byte(s >> 8)
switch proto {
case iana.ProtocolICMP:
b[1] = byte(dataLen / 4)
case iana.ProtocolIPv6ICMP:
b[0] = byte(dataLen / 8)
if withOrigDgram {
switch proto {
case iana.ProtocolICMP:
b[1] = byte(dataLen / 4)
case iana.ProtocolIPv6ICMP:
b[0] = byte(dataLen / 8)
}
}
}
return b, nil
@ -88,7 +97,7 @@ func marshalMultipartMessageBody(proto int, data []byte, exts []Extension) ([]by
// parseMultipartMessageBody parses b as either a non-multipart
// message body or a multipart message body.
func parseMultipartMessageBody(proto int, b []byte) ([]byte, []Extension, error) {
func parseMultipartMessageBody(proto int, typ Type, b []byte) ([]byte, []Extension, error) {
var l int
switch proto {
case iana.ProtocolICMP:
@ -99,11 +108,14 @@ func parseMultipartMessageBody(proto int, b []byte) ([]byte, []Extension, error)
if len(b) == 4 {
return nil, nil, nil
}
exts, l, err := parseExtensions(b[4:], l)
exts, l, err := parseExtensions(typ, b[4:], l)
if err != nil {
l = len(b) - 4
}
data := make([]byte, l)
copy(data, b[4:])
var data []byte
if l > 0 {
data = make([]byte, l)
copy(data, b[4:])
}
return data, exts, nil
}

View file

@ -5,6 +5,7 @@
package icmp_test
import (
"errors"
"fmt"
"net"
"reflect"
@ -16,425 +17,557 @@ import (
"golang.org/x/net/ipv6"
)
var marshalAndParseMultipartMessageForIPv4Tests = []icmp.Message{
{
Type: ipv4.ICMPTypeDestinationUnreachable, Code: 15,
Body: &icmp.DstUnreach{
Data: []byte("ERROR-INVOKING-PACKET"),
Extensions: []icmp.Extension{
&icmp.MPLSLabelStack{
Class: 1,
Type: 1,
Labels: []icmp.MPLSLabel{
{
Label: 16014,
TC: 0x4,
S: true,
TTL: 255,
},
},
},
&icmp.InterfaceInfo{
Class: 2,
Type: 0x0f,
Interface: &net.Interface{
Index: 15,
Name: "en101",
MTU: 8192,
},
Addr: &net.IPAddr{
IP: net.IPv4(192, 168, 0, 1).To4(),
},
},
},
},
},
{
Type: ipv4.ICMPTypeTimeExceeded, Code: 1,
Body: &icmp.TimeExceeded{
Data: []byte("ERROR-INVOKING-PACKET"),
Extensions: []icmp.Extension{
&icmp.InterfaceInfo{
Class: 2,
Type: 0x0f,
Interface: &net.Interface{
Index: 15,
Name: "en101",
MTU: 8192,
},
Addr: &net.IPAddr{
IP: net.IPv4(192, 168, 0, 1).To4(),
},
},
&icmp.MPLSLabelStack{
Class: 1,
Type: 1,
Labels: []icmp.MPLSLabel{
{
Label: 16014,
TC: 0x4,
S: true,
TTL: 255,
},
},
},
},
},
},
{
Type: ipv4.ICMPTypeParameterProblem, Code: 2,
Body: &icmp.ParamProb{
Pointer: 8,
Data: []byte("ERROR-INVOKING-PACKET"),
Extensions: []icmp.Extension{
&icmp.MPLSLabelStack{
Class: 1,
Type: 1,
Labels: []icmp.MPLSLabel{
{
Label: 16014,
TC: 0x4,
S: true,
TTL: 255,
},
},
},
&icmp.InterfaceInfo{
Class: 2,
Type: 0x0f,
Interface: &net.Interface{
Index: 15,
Name: "en101",
MTU: 8192,
},
Addr: &net.IPAddr{
IP: net.IPv4(192, 168, 0, 1).To4(),
},
},
&icmp.InterfaceInfo{
Class: 2,
Type: 0x2f,
Interface: &net.Interface{
Index: 16,
Name: "en102",
MTU: 8192,
},
Addr: &net.IPAddr{
IP: net.IPv4(192, 168, 0, 2).To4(),
},
},
},
},
},
}
func TestMarshalAndParseMultipartMessageForIPv4(t *testing.T) {
for i, tt := range marshalAndParseMultipartMessageForIPv4Tests {
b, err := tt.Marshal(nil)
func TestMarshalAndParseMultipartMessage(t *testing.T) {
fn := func(t *testing.T, proto int, tm icmp.Message) error {
b, err := tm.Marshal(nil)
if err != nil {
t.Fatal(err)
return err
}
if b[5] != 32 {
t.Errorf("#%v: got %v; want 32", i, b[5])
switch tm.Type {
case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest:
default:
switch proto {
case iana.ProtocolICMP:
if b[5] != 32 {
return fmt.Errorf("got %d; want 32", b[5])
}
case iana.ProtocolIPv6ICMP:
if b[4] != 16 {
return fmt.Errorf("got %d; want 16", b[4])
}
default:
return fmt.Errorf("unknown protocol: %d", proto)
}
}
m, err := icmp.ParseMessage(iana.ProtocolICMP, b)
m, err := icmp.ParseMessage(proto, b)
if err != nil {
t.Fatal(err)
return err
}
if m.Type != tt.Type || m.Code != tt.Code {
t.Errorf("#%v: got %v; want %v", i, m, &tt)
if m.Type != tm.Type || m.Code != tm.Code {
return fmt.Errorf("got %v; want %v", m, &tm)
}
switch m.Type {
case ipv4.ICMPTypeDestinationUnreachable:
got, want := m.Body.(*icmp.DstUnreach), tt.Body.(*icmp.DstUnreach)
case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest:
got, want := m.Body.(*icmp.ExtendedEchoRequest), tm.Body.(*icmp.ExtendedEchoRequest)
if !reflect.DeepEqual(got.Extensions, want.Extensions) {
t.Error(dumpExtensions(i, got.Extensions, want.Extensions))
return errors.New(dumpExtensions(got.Extensions, want.Extensions))
}
case ipv4.ICMPTypeDestinationUnreachable:
got, want := m.Body.(*icmp.DstUnreach), tm.Body.(*icmp.DstUnreach)
if !reflect.DeepEqual(got.Extensions, want.Extensions) {
return errors.New(dumpExtensions(got.Extensions, want.Extensions))
}
if len(got.Data) != 128 {
t.Errorf("#%v: got %v; want 128", i, len(got.Data))
return fmt.Errorf("got %d; want 128", len(got.Data))
}
case ipv4.ICMPTypeTimeExceeded:
got, want := m.Body.(*icmp.TimeExceeded), tt.Body.(*icmp.TimeExceeded)
got, want := m.Body.(*icmp.TimeExceeded), tm.Body.(*icmp.TimeExceeded)
if !reflect.DeepEqual(got.Extensions, want.Extensions) {
t.Error(dumpExtensions(i, got.Extensions, want.Extensions))
return errors.New(dumpExtensions(got.Extensions, want.Extensions))
}
if len(got.Data) != 128 {
t.Errorf("#%v: got %v; want 128", i, len(got.Data))
return fmt.Errorf("got %d; want 128", len(got.Data))
}
case ipv4.ICMPTypeParameterProblem:
got, want := m.Body.(*icmp.ParamProb), tt.Body.(*icmp.ParamProb)
got, want := m.Body.(*icmp.ParamProb), tm.Body.(*icmp.ParamProb)
if !reflect.DeepEqual(got.Extensions, want.Extensions) {
t.Error(dumpExtensions(i, got.Extensions, want.Extensions))
return errors.New(dumpExtensions(got.Extensions, want.Extensions))
}
if len(got.Data) != 128 {
t.Errorf("#%v: got %v; want 128", i, len(got.Data))
return fmt.Errorf("got %d; want 128", len(got.Data))
}
case ipv6.ICMPTypeDestinationUnreachable:
got, want := m.Body.(*icmp.DstUnreach), tm.Body.(*icmp.DstUnreach)
if !reflect.DeepEqual(got.Extensions, want.Extensions) {
return errors.New(dumpExtensions(got.Extensions, want.Extensions))
}
if len(got.Data) != 128 {
return fmt.Errorf("got %d; want 128", len(got.Data))
}
case ipv6.ICMPTypeTimeExceeded:
got, want := m.Body.(*icmp.TimeExceeded), tm.Body.(*icmp.TimeExceeded)
if !reflect.DeepEqual(got.Extensions, want.Extensions) {
return errors.New(dumpExtensions(got.Extensions, want.Extensions))
}
if len(got.Data) != 128 {
return fmt.Errorf("got %d; want 128", len(got.Data))
}
default:
return fmt.Errorf("unknown message type: %v", m.Type)
}
return nil
}
}
var marshalAndParseMultipartMessageForIPv6Tests = []icmp.Message{
{
Type: ipv6.ICMPTypeDestinationUnreachable, Code: 6,
Body: &icmp.DstUnreach{
Data: []byte("ERROR-INVOKING-PACKET"),
Extensions: []icmp.Extension{
&icmp.MPLSLabelStack{
Class: 1,
Type: 1,
Labels: []icmp.MPLSLabel{
{
Label: 16014,
TC: 0x4,
S: true,
TTL: 255,
t.Run("IPv4", func(t *testing.T) {
for i, tm := range []icmp.Message{
{
Type: ipv4.ICMPTypeDestinationUnreachable, Code: 15,
Body: &icmp.DstUnreach{
Data: []byte("ERROR-INVOKING-PACKET"),
Extensions: []icmp.Extension{
&icmp.MPLSLabelStack{
Class: 1,
Type: 1,
Labels: []icmp.MPLSLabel{
{
Label: 16014,
TC: 0x4,
S: true,
TTL: 255,
},
},
},
&icmp.InterfaceInfo{
Class: 2,
Type: 0x0f,
Interface: &net.Interface{
Index: 15,
Name: "en101",
MTU: 8192,
},
Addr: &net.IPAddr{
IP: net.IPv4(192, 168, 0, 1).To4(),
},
},
},
},
&icmp.InterfaceInfo{
Class: 2,
Type: 0x0f,
Interface: &net.Interface{
Index: 15,
Name: "en101",
MTU: 8192,
},
Addr: &net.IPAddr{
IP: net.ParseIP("fe80::1"),
Zone: "en101",
},
},
},
},
},
{
Type: ipv6.ICMPTypeTimeExceeded, Code: 1,
Body: &icmp.TimeExceeded{
Data: []byte("ERROR-INVOKING-PACKET"),
Extensions: []icmp.Extension{
&icmp.InterfaceInfo{
Class: 2,
Type: 0x0f,
Interface: &net.Interface{
Index: 15,
Name: "en101",
MTU: 8192,
},
Addr: &net.IPAddr{
IP: net.ParseIP("fe80::1"),
Zone: "en101",
},
},
&icmp.MPLSLabelStack{
Class: 1,
Type: 1,
Labels: []icmp.MPLSLabel{
{
Label: 16014,
TC: 0x4,
S: true,
TTL: 255,
{
Type: ipv4.ICMPTypeTimeExceeded, Code: 1,
Body: &icmp.TimeExceeded{
Data: []byte("ERROR-INVOKING-PACKET"),
Extensions: []icmp.Extension{
&icmp.InterfaceInfo{
Class: 2,
Type: 0x0f,
Interface: &net.Interface{
Index: 15,
Name: "en101",
MTU: 8192,
},
Addr: &net.IPAddr{
IP: net.IPv4(192, 168, 0, 1).To4(),
},
},
&icmp.MPLSLabelStack{
Class: 1,
Type: 1,
Labels: []icmp.MPLSLabel{
{
Label: 16014,
TC: 0x4,
S: true,
TTL: 255,
},
},
},
},
},
&icmp.InterfaceInfo{
Class: 2,
Type: 0x2f,
Interface: &net.Interface{
Index: 16,
Name: "en102",
MTU: 8192,
},
Addr: &net.IPAddr{
IP: net.ParseIP("fe80::1"),
Zone: "en102",
},
{
Type: ipv4.ICMPTypeParameterProblem, Code: 2,
Body: &icmp.ParamProb{
Pointer: 8,
Data: []byte("ERROR-INVOKING-PACKET"),
Extensions: []icmp.Extension{
&icmp.MPLSLabelStack{
Class: 1,
Type: 1,
Labels: []icmp.MPLSLabel{
{
Label: 16014,
TC: 0x4,
S: true,
TTL: 255,
},
},
},
&icmp.InterfaceInfo{
Class: 2,
Type: 0x0f,
Interface: &net.Interface{
Index: 15,
Name: "en101",
MTU: 8192,
},
Addr: &net.IPAddr{
IP: net.IPv4(192, 168, 0, 1).To4(),
},
},
&icmp.InterfaceInfo{
Class: 2,
Type: 0x2f,
Interface: &net.Interface{
Index: 16,
Name: "en102",
MTU: 8192,
},
Addr: &net.IPAddr{
IP: net.IPv4(192, 168, 0, 2).To4(),
},
},
},
},
},
},
},
}
func TestMarshalAndParseMultipartMessageForIPv6(t *testing.T) {
pshicmp := icmp.IPv6PseudoHeader(net.ParseIP("fe80::1"), net.ParseIP("ff02::1"))
for i, tt := range marshalAndParseMultipartMessageForIPv6Tests {
for _, psh := range [][]byte{pshicmp, nil} {
b, err := tt.Marshal(psh)
if err != nil {
t.Fatal(err)
}
if b[4] != 16 {
t.Errorf("#%v: got %v; want 16", i, b[4])
}
m, err := icmp.ParseMessage(iana.ProtocolIPv6ICMP, b)
if err != nil {
t.Fatal(err)
}
if m.Type != tt.Type || m.Code != tt.Code {
t.Errorf("#%v: got %v; want %v", i, m, &tt)
}
switch m.Type {
case ipv6.ICMPTypeDestinationUnreachable:
got, want := m.Body.(*icmp.DstUnreach), tt.Body.(*icmp.DstUnreach)
if !reflect.DeepEqual(got.Extensions, want.Extensions) {
t.Error(dumpExtensions(i, got.Extensions, want.Extensions))
}
if len(got.Data) != 128 {
t.Errorf("#%v: got %v; want 128", i, len(got.Data))
}
case ipv6.ICMPTypeTimeExceeded:
got, want := m.Body.(*icmp.TimeExceeded), tt.Body.(*icmp.TimeExceeded)
if !reflect.DeepEqual(got.Extensions, want.Extensions) {
t.Error(dumpExtensions(i, got.Extensions, want.Extensions))
}
if len(got.Data) != 128 {
t.Errorf("#%v: got %v; want 128", i, len(got.Data))
}
{
Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
Body: &icmp.ExtendedEchoRequest{
ID: 1, Seq: 2, Local: true,
Extensions: []icmp.Extension{
&icmp.InterfaceIdent{
Class: 3,
Type: 1,
Name: "en101",
},
},
},
},
{
Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
Body: &icmp.ExtendedEchoRequest{
ID: 1, Seq: 2, Local: true,
Extensions: []icmp.Extension{
&icmp.InterfaceIdent{
Class: 3,
Type: 2,
Index: 911,
},
&icmp.InterfaceIdent{
Class: 3,
Type: 1,
Name: "en101",
},
},
},
},
{
Type: ipv4.ICMPTypeExtendedEchoRequest, Code: 0,
Body: &icmp.ExtendedEchoRequest{
ID: 1, Seq: 2,
Extensions: []icmp.Extension{
&icmp.InterfaceIdent{
Class: 3,
Type: 3,
AFI: iana.AddrFamily48bitMAC,
Addr: []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab},
},
},
},
},
} {
if err := fn(t, iana.ProtocolICMP, tm); err != nil {
t.Errorf("#%d: %v", i, err)
}
}
}
})
t.Run("IPv6", func(t *testing.T) {
for i, tm := range []icmp.Message{
{
Type: ipv6.ICMPTypeDestinationUnreachable, Code: 6,
Body: &icmp.DstUnreach{
Data: []byte("ERROR-INVOKING-PACKET"),
Extensions: []icmp.Extension{
&icmp.MPLSLabelStack{
Class: 1,
Type: 1,
Labels: []icmp.MPLSLabel{
{
Label: 16014,
TC: 0x4,
S: true,
TTL: 255,
},
},
},
&icmp.InterfaceInfo{
Class: 2,
Type: 0x0f,
Interface: &net.Interface{
Index: 15,
Name: "en101",
MTU: 8192,
},
Addr: &net.IPAddr{
IP: net.ParseIP("fe80::1"),
Zone: "en101",
},
},
},
},
},
{
Type: ipv6.ICMPTypeTimeExceeded, Code: 1,
Body: &icmp.TimeExceeded{
Data: []byte("ERROR-INVOKING-PACKET"),
Extensions: []icmp.Extension{
&icmp.InterfaceInfo{
Class: 2,
Type: 0x0f,
Interface: &net.Interface{
Index: 15,
Name: "en101",
MTU: 8192,
},
Addr: &net.IPAddr{
IP: net.ParseIP("fe80::1"),
Zone: "en101",
},
},
&icmp.MPLSLabelStack{
Class: 1,
Type: 1,
Labels: []icmp.MPLSLabel{
{
Label: 16014,
TC: 0x4,
S: true,
TTL: 255,
},
},
},
&icmp.InterfaceInfo{
Class: 2,
Type: 0x2f,
Interface: &net.Interface{
Index: 16,
Name: "en102",
MTU: 8192,
},
Addr: &net.IPAddr{
IP: net.ParseIP("fe80::1"),
Zone: "en102",
},
},
},
},
},
{
Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
Body: &icmp.ExtendedEchoRequest{
ID: 1, Seq: 2, Local: true,
Extensions: []icmp.Extension{
&icmp.InterfaceIdent{
Class: 3,
Type: 1,
Name: "en101",
},
},
},
},
{
Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
Body: &icmp.ExtendedEchoRequest{
ID: 1, Seq: 2, Local: true,
Extensions: []icmp.Extension{
&icmp.InterfaceIdent{
Class: 3,
Type: 1,
Name: "en101",
},
&icmp.InterfaceIdent{
Class: 3,
Type: 2,
Index: 911,
},
},
},
},
{
Type: ipv6.ICMPTypeExtendedEchoRequest, Code: 0,
Body: &icmp.ExtendedEchoRequest{
ID: 1, Seq: 2,
Extensions: []icmp.Extension{
&icmp.InterfaceIdent{
Class: 3,
Type: 3,
AFI: iana.AddrFamilyIPv4,
Addr: []byte{192, 0, 2, 1},
},
},
},
},
} {
if err := fn(t, iana.ProtocolIPv6ICMP, tm); err != nil {
t.Errorf("#%d: %v", i, err)
}
}
})
}
func dumpExtensions(i int, gotExts, wantExts []icmp.Extension) string {
func dumpExtensions(gotExts, wantExts []icmp.Extension) string {
var s string
for j, got := range gotExts {
for i, got := range gotExts {
switch got := got.(type) {
case *icmp.MPLSLabelStack:
want := wantExts[j].(*icmp.MPLSLabelStack)
want := wantExts[i].(*icmp.MPLSLabelStack)
if !reflect.DeepEqual(got, want) {
s += fmt.Sprintf("#%v/%v: got %#v; want %#v\n", i, j, got, want)
s += fmt.Sprintf("#%d: got %#v; want %#v\n", i, got, want)
}
case *icmp.InterfaceInfo:
want := wantExts[j].(*icmp.InterfaceInfo)
want := wantExts[i].(*icmp.InterfaceInfo)
if !reflect.DeepEqual(got, want) {
s += fmt.Sprintf("#%v/%v: got %#v, %#v, %#v; want %#v, %#v, %#v\n", i, j, got, got.Interface, got.Addr, want, want.Interface, want.Addr)
s += fmt.Sprintf("#%d: got %#v, %#v, %#v; want %#v, %#v, %#v\n", i, got, got.Interface, got.Addr, want, want.Interface, want.Addr)
}
case *icmp.InterfaceIdent:
want := wantExts[i].(*icmp.InterfaceIdent)
if !reflect.DeepEqual(got, want) {
s += fmt.Sprintf("#%d: got %#v; want %#v\n", i, got, want)
}
}
}
if len(s) == 0 {
return "<nil>"
}
return s[:len(s)-1]
}
var multipartMessageBodyLenTests = []struct {
proto int
in icmp.MessageBody
out int
}{
{
iana.ProtocolICMP,
&icmp.DstUnreach{
Data: make([]byte, ipv4.HeaderLen),
},
4 + ipv4.HeaderLen, // unused and original datagram
},
{
iana.ProtocolICMP,
&icmp.TimeExceeded{
Data: make([]byte, ipv4.HeaderLen),
},
4 + ipv4.HeaderLen, // unused and original datagram
},
{
iana.ProtocolICMP,
&icmp.ParamProb{
Data: make([]byte, ipv4.HeaderLen),
},
4 + ipv4.HeaderLen, // [pointer, unused] and original datagram
},
{
iana.ProtocolICMP,
&icmp.ParamProb{
Data: make([]byte, ipv4.HeaderLen),
Extensions: []icmp.Extension{
&icmp.MPLSLabelStack{},
},
},
4 + 4 + 4 + 0 + 128, // [pointer, length, unused], extension header, object header, object payload, original datagram
},
{
iana.ProtocolICMP,
&icmp.ParamProb{
Data: make([]byte, 128),
Extensions: []icmp.Extension{
&icmp.MPLSLabelStack{},
},
},
4 + 4 + 4 + 0 + 128, // [pointer, length, unused], extension header, object header, object payload and original datagram
},
{
iana.ProtocolICMP,
&icmp.ParamProb{
Data: make([]byte, 129),
Extensions: []icmp.Extension{
&icmp.MPLSLabelStack{},
},
},
4 + 4 + 4 + 0 + 132, // [pointer, length, unused], extension header, object header, object payload and original datagram
},
{
iana.ProtocolIPv6ICMP,
&icmp.DstUnreach{
Data: make([]byte, ipv6.HeaderLen),
},
4 + ipv6.HeaderLen, // unused and original datagram
},
{
iana.ProtocolIPv6ICMP,
&icmp.PacketTooBig{
Data: make([]byte, ipv6.HeaderLen),
},
4 + ipv6.HeaderLen, // mtu and original datagram
},
{
iana.ProtocolIPv6ICMP,
&icmp.TimeExceeded{
Data: make([]byte, ipv6.HeaderLen),
},
4 + ipv6.HeaderLen, // unused and original datagram
},
{
iana.ProtocolIPv6ICMP,
&icmp.ParamProb{
Data: make([]byte, ipv6.HeaderLen),
},
4 + ipv6.HeaderLen, // pointer and original datagram
},
{
iana.ProtocolIPv6ICMP,
&icmp.DstUnreach{
Data: make([]byte, 127),
Extensions: []icmp.Extension{
&icmp.MPLSLabelStack{},
},
},
4 + 4 + 4 + 0 + 128, // [length, unused], extension header, object header, object payload and original datagram
},
{
iana.ProtocolIPv6ICMP,
&icmp.DstUnreach{
Data: make([]byte, 128),
Extensions: []icmp.Extension{
&icmp.MPLSLabelStack{},
},
},
4 + 4 + 4 + 0 + 128, // [length, unused], extension header, object header, object payload and original datagram
},
{
iana.ProtocolIPv6ICMP,
&icmp.DstUnreach{
Data: make([]byte, 129),
Extensions: []icmp.Extension{
&icmp.MPLSLabelStack{},
},
},
4 + 4 + 4 + 0 + 136, // [length, unused], extension header, object header, object payload and original datagram
},
}
func TestMultipartMessageBodyLen(t *testing.T) {
for i, tt := range multipartMessageBodyLenTests {
for i, tt := range []struct {
proto int
in icmp.MessageBody
out int
}{
{
iana.ProtocolICMP,
&icmp.DstUnreach{
Data: make([]byte, ipv4.HeaderLen),
},
4 + ipv4.HeaderLen, // unused and original datagram
},
{
iana.ProtocolICMP,
&icmp.TimeExceeded{
Data: make([]byte, ipv4.HeaderLen),
},
4 + ipv4.HeaderLen, // unused and original datagram
},
{
iana.ProtocolICMP,
&icmp.ParamProb{
Data: make([]byte, ipv4.HeaderLen),
},
4 + ipv4.HeaderLen, // [pointer, unused] and original datagram
},
{
iana.ProtocolICMP,
&icmp.ParamProb{
Data: make([]byte, ipv4.HeaderLen),
Extensions: []icmp.Extension{
&icmp.MPLSLabelStack{},
},
},
4 + 4 + 4 + 0 + 128, // [pointer, length, unused], extension header, object header, object payload, original datagram
},
{
iana.ProtocolICMP,
&icmp.ParamProb{
Data: make([]byte, 128),
Extensions: []icmp.Extension{
&icmp.MPLSLabelStack{},
},
},
4 + 4 + 4 + 0 + 128, // [pointer, length, unused], extension header, object header, object payload and original datagram
},
{
iana.ProtocolICMP,
&icmp.ParamProb{
Data: make([]byte, 129),
Extensions: []icmp.Extension{
&icmp.MPLSLabelStack{},
},
},
4 + 4 + 4 + 0 + 132, // [pointer, length, unused], extension header, object header, object payload and original datagram
},
{
iana.ProtocolIPv6ICMP,
&icmp.DstUnreach{
Data: make([]byte, ipv6.HeaderLen),
},
4 + ipv6.HeaderLen, // unused and original datagram
},
{
iana.ProtocolIPv6ICMP,
&icmp.PacketTooBig{
Data: make([]byte, ipv6.HeaderLen),
},
4 + ipv6.HeaderLen, // mtu and original datagram
},
{
iana.ProtocolIPv6ICMP,
&icmp.TimeExceeded{
Data: make([]byte, ipv6.HeaderLen),
},
4 + ipv6.HeaderLen, // unused and original datagram
},
{
iana.ProtocolIPv6ICMP,
&icmp.ParamProb{
Data: make([]byte, ipv6.HeaderLen),
},
4 + ipv6.HeaderLen, // pointer and original datagram
},
{
iana.ProtocolIPv6ICMP,
&icmp.DstUnreach{
Data: make([]byte, 127),
Extensions: []icmp.Extension{
&icmp.MPLSLabelStack{},
},
},
4 + 4 + 4 + 0 + 128, // [length, unused], extension header, object header, object payload and original datagram
},
{
iana.ProtocolIPv6ICMP,
&icmp.DstUnreach{
Data: make([]byte, 128),
Extensions: []icmp.Extension{
&icmp.MPLSLabelStack{},
},
},
4 + 4 + 4 + 0 + 128, // [length, unused], extension header, object header, object payload and original datagram
},
{
iana.ProtocolIPv6ICMP,
&icmp.DstUnreach{
Data: make([]byte, 129),
Extensions: []icmp.Extension{
&icmp.MPLSLabelStack{},
},
},
4 + 4 + 4 + 0 + 136, // [length, unused], extension header, object header, object payload and original datagram
},
{
iana.ProtocolICMP,
&icmp.ExtendedEchoRequest{},
4, // [id, seq, l-bit]
},
{
iana.ProtocolICMP,
&icmp.ExtendedEchoRequest{
Extensions: []icmp.Extension{
&icmp.InterfaceIdent{},
},
},
4 + 4 + 4, // [id, seq, l-bit], extension header, object header
},
{
iana.ProtocolIPv6ICMP,
&icmp.ExtendedEchoRequest{
Extensions: []icmp.Extension{
&icmp.InterfaceIdent{
Type: 3,
AFI: iana.AddrFamilyNSAP,
Addr: []byte{0x49, 0x00, 0x01, 0xaa, 0xaa, 0xbb, 0xbb, 0xcc, 0xcc, 0x00},
},
},
},
4 + 4 + 4 + 16, // [id, seq, l-bit], extension header, object header, object payload
},
} {
if out := tt.in.Len(tt.proto); out != tt.out {
t.Errorf("#%d: got %d; want %d", i, out, tt.out)
}

View file

@ -29,7 +29,7 @@ func (p *PacketTooBig) Marshal(proto int) ([]byte, error) {
}
// parsePacketTooBig parses b as an ICMP packet too big message body.
func parsePacketTooBig(proto int, b []byte) (MessageBody, error) {
func parsePacketTooBig(proto int, _ Type, b []byte) (MessageBody, error) {
bodyLen := len(b)
if bodyLen < 4 {
return nil, errMessageTooShort

View file

@ -21,7 +21,7 @@ func (p *ParamProb) Len(proto int) int {
if p == nil {
return 0
}
l, _ := multipartMessageBodyDataLen(proto, p.Data, p.Extensions)
l, _ := multipartMessageBodyDataLen(proto, true, p.Data, p.Extensions)
return 4 + l
}
@ -33,7 +33,7 @@ func (p *ParamProb) Marshal(proto int) ([]byte, error) {
copy(b[4:], p.Data)
return b, nil
}
b, err := marshalMultipartMessageBody(proto, p.Data, p.Extensions)
b, err := marshalMultipartMessageBody(proto, true, p.Data, p.Extensions)
if err != nil {
return nil, err
}
@ -42,7 +42,7 @@ func (p *ParamProb) Marshal(proto int) ([]byte, error) {
}
// parseParamProb parses b as an ICMP parameter problem message body.
func parseParamProb(proto int, b []byte) (MessageBody, error) {
func parseParamProb(proto int, typ Type, b []byte) (MessageBody, error) {
if len(b) < 4 {
return nil, errMessageTooShort
}
@ -55,7 +55,7 @@ func parseParamProb(proto int, b []byte) (MessageBody, error) {
}
p.Pointer = uintptr(b[0])
var err error
p.Data, p.Extensions, err = parseMultipartMessageBody(proto, b)
p.Data, p.Extensions, err = parseMultipartMessageBody(proto, typ, b)
if err != nil {
return nil, err
}

View file

@ -1,200 +0,0 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package icmp_test
import (
"errors"
"fmt"
"net"
"os"
"runtime"
"sync"
"testing"
"time"
"golang.org/x/net/icmp"
"golang.org/x/net/internal/iana"
"golang.org/x/net/internal/nettest"
"golang.org/x/net/ipv4"
"golang.org/x/net/ipv6"
)
func googleAddr(c *icmp.PacketConn, protocol int) (net.Addr, error) {
const host = "www.google.com"
ips, err := net.LookupIP(host)
if err != nil {
return nil, err
}
netaddr := func(ip net.IP) (net.Addr, error) {
switch c.LocalAddr().(type) {
case *net.UDPAddr:
return &net.UDPAddr{IP: ip}, nil
case *net.IPAddr:
return &net.IPAddr{IP: ip}, nil
default:
return nil, errors.New("neither UDPAddr nor IPAddr")
}
}
for _, ip := range ips {
switch protocol {
case iana.ProtocolICMP:
if ip.To4() != nil {
return netaddr(ip)
}
case iana.ProtocolIPv6ICMP:
if ip.To16() != nil && ip.To4() == nil {
return netaddr(ip)
}
}
}
return nil, errors.New("no A or AAAA record")
}
type pingTest struct {
network, address string
protocol int
mtype icmp.Type
}
var nonPrivilegedPingTests = []pingTest{
{"udp4", "0.0.0.0", iana.ProtocolICMP, ipv4.ICMPTypeEcho},
{"udp6", "::", iana.ProtocolIPv6ICMP, ipv6.ICMPTypeEchoRequest},
}
func TestNonPrivilegedPing(t *testing.T) {
if testing.Short() {
t.Skip("avoid external network")
}
switch runtime.GOOS {
case "darwin":
case "linux":
t.Log("you may need to adjust the net.ipv4.ping_group_range kernel state")
default:
t.Skipf("not supported on %s", runtime.GOOS)
}
for i, tt := range nonPrivilegedPingTests {
if err := doPing(tt, i); err != nil {
t.Error(err)
}
}
}
var privilegedPingTests = []pingTest{
{"ip4:icmp", "0.0.0.0", iana.ProtocolICMP, ipv4.ICMPTypeEcho},
{"ip6:ipv6-icmp", "::", iana.ProtocolIPv6ICMP, ipv6.ICMPTypeEchoRequest},
}
func TestPrivilegedPing(t *testing.T) {
if testing.Short() {
t.Skip("avoid external network")
}
if m, ok := nettest.SupportsRawIPSocket(); !ok {
t.Skip(m)
}
for i, tt := range privilegedPingTests {
if err := doPing(tt, i); err != nil {
t.Error(err)
}
}
}
func doPing(tt pingTest, seq int) error {
c, err := icmp.ListenPacket(tt.network, tt.address)
if err != nil {
return err
}
defer c.Close()
dst, err := googleAddr(c, tt.protocol)
if err != nil {
return err
}
if tt.network != "udp6" && tt.protocol == iana.ProtocolIPv6ICMP {
var f ipv6.ICMPFilter
f.SetAll(true)
f.Accept(ipv6.ICMPTypeDestinationUnreachable)
f.Accept(ipv6.ICMPTypePacketTooBig)
f.Accept(ipv6.ICMPTypeTimeExceeded)
f.Accept(ipv6.ICMPTypeParameterProblem)
f.Accept(ipv6.ICMPTypeEchoReply)
if err := c.IPv6PacketConn().SetICMPFilter(&f); err != nil {
return err
}
}
wm := icmp.Message{
Type: tt.mtype, Code: 0,
Body: &icmp.Echo{
ID: os.Getpid() & 0xffff, Seq: 1 << uint(seq),
Data: []byte("HELLO-R-U-THERE"),
},
}
wb, err := wm.Marshal(nil)
if err != nil {
return err
}
if n, err := c.WriteTo(wb, dst); err != nil {
return err
} else if n != len(wb) {
return fmt.Errorf("got %v; want %v", n, len(wb))
}
rb := make([]byte, 1500)
if err := c.SetReadDeadline(time.Now().Add(3 * time.Second)); err != nil {
return err
}
n, peer, err := c.ReadFrom(rb)
if err != nil {
return err
}
rm, err := icmp.ParseMessage(tt.protocol, rb[:n])
if err != nil {
return err
}
switch rm.Type {
case ipv4.ICMPTypeEchoReply, ipv6.ICMPTypeEchoReply:
return nil
default:
return fmt.Errorf("got %+v from %v; want echo reply", rm, peer)
}
}
func TestConcurrentNonPrivilegedListenPacket(t *testing.T) {
if testing.Short() {
t.Skip("avoid external network")
}
switch runtime.GOOS {
case "darwin":
case "linux":
t.Log("you may need to adjust the net.ipv4.ping_group_range kernel state")
default:
t.Skipf("not supported on %s", runtime.GOOS)
}
network, address := "udp4", "127.0.0.1"
if !nettest.SupportsIPv4() {
network, address = "udp6", "::1"
}
const N = 1000
var wg sync.WaitGroup
wg.Add(N)
for i := 0; i < N; i++ {
go func() {
defer wg.Done()
c, err := icmp.ListenPacket(network, address)
if err != nil {
t.Error(err)
return
}
c.Close()
}()
}
wg.Wait()
}

View file

@ -15,23 +15,23 @@ func (p *TimeExceeded) Len(proto int) int {
if p == nil {
return 0
}
l, _ := multipartMessageBodyDataLen(proto, p.Data, p.Extensions)
l, _ := multipartMessageBodyDataLen(proto, true, p.Data, p.Extensions)
return 4 + l
}
// Marshal implements the Marshal method of MessageBody interface.
func (p *TimeExceeded) Marshal(proto int) ([]byte, error) {
return marshalMultipartMessageBody(proto, p.Data, p.Extensions)
return marshalMultipartMessageBody(proto, true, p.Data, p.Extensions)
}
// parseTimeExceeded parses b as an ICMP time exceeded message body.
func parseTimeExceeded(proto int, b []byte) (MessageBody, error) {
func parseTimeExceeded(proto int, typ Type, b []byte) (MessageBody, error) {
if len(b) < 4 {
return nil, errMessageTooShort
}
p := &TimeExceeded{}
var err error
p.Data, p.Extensions, err = parseMultipartMessageBody(proto, b)
p.Data, p.Extensions, err = parseMultipartMessageBody(proto, typ, b)
if err != nil {
return nil, err
}

View file

@ -1,44 +1,40 @@
// go generate gen.go
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
// Code generated by the command above; DO NOT EDIT.
// Package iana provides protocol number resources managed by the Internet Assigned Numbers Authority (IANA).
package iana // import "golang.org/x/net/internal/iana"
// Differentiated Services Field Codepoints (DSCP), Updated: 2017-05-12
// Differentiated Services Field Codepoints (DSCP), Updated: 2018-05-04
const (
DiffServCS0 = 0x0 // CS0
DiffServCS1 = 0x20 // CS1
DiffServCS2 = 0x40 // CS2
DiffServCS3 = 0x60 // CS3
DiffServCS4 = 0x80 // CS4
DiffServCS5 = 0xa0 // CS5
DiffServCS6 = 0xc0 // CS6
DiffServCS7 = 0xe0 // CS7
DiffServAF11 = 0x28 // AF11
DiffServAF12 = 0x30 // AF12
DiffServAF13 = 0x38 // AF13
DiffServAF21 = 0x48 // AF21
DiffServAF22 = 0x50 // AF22
DiffServAF23 = 0x58 // AF23
DiffServAF31 = 0x68 // AF31
DiffServAF32 = 0x70 // AF32
DiffServAF33 = 0x78 // AF33
DiffServAF41 = 0x88 // AF41
DiffServAF42 = 0x90 // AF42
DiffServAF43 = 0x98 // AF43
DiffServEF = 0xb8 // EF
DiffServVOICEADMIT = 0xb0 // VOICE-ADMIT
DiffServCS0 = 0x00 // CS0
DiffServCS1 = 0x20 // CS1
DiffServCS2 = 0x40 // CS2
DiffServCS3 = 0x60 // CS3
DiffServCS4 = 0x80 // CS4
DiffServCS5 = 0xa0 // CS5
DiffServCS6 = 0xc0 // CS6
DiffServCS7 = 0xe0 // CS7
DiffServAF11 = 0x28 // AF11
DiffServAF12 = 0x30 // AF12
DiffServAF13 = 0x38 // AF13
DiffServAF21 = 0x48 // AF21
DiffServAF22 = 0x50 // AF22
DiffServAF23 = 0x58 // AF23
DiffServAF31 = 0x68 // AF31
DiffServAF32 = 0x70 // AF32
DiffServAF33 = 0x78 // AF33
DiffServAF41 = 0x88 // AF41
DiffServAF42 = 0x90 // AF42
DiffServAF43 = 0x98 // AF43
DiffServEF = 0xb8 // EF
DiffServVOICEADMIT = 0xb0 // VOICE-ADMIT
NotECNTransport = 0x00 // Not-ECT (Not ECN-Capable Transport)
ECNTransport1 = 0x01 // ECT(1) (ECN-Capable Transport(1))
ECNTransport0 = 0x02 // ECT(0) (ECN-Capable Transport(0))
CongestionExperienced = 0x03 // CE (Congestion Experienced)
)
// IPv4 TOS Byte and IPv6 Traffic Class Octet, Updated: 2001-09-06
const (
NotECNTransport = 0x0 // Not-ECT (Not ECN-Capable Transport)
ECNTransport1 = 0x1 // ECT(1) (ECN-Capable Transport(1))
ECNTransport0 = 0x2 // ECT(0) (ECN-Capable Transport(0))
CongestionExperienced = 0x3 // CE (Congestion Experienced)
)
// Protocol Numbers, Updated: 2016-06-22
// Protocol Numbers, Updated: 2017-10-13
const (
ProtocolIP = 0 // IPv4 encapsulation, pseudo protocol number
ProtocolHOPOPT = 0 // IPv6 Hop-by-Hop Option
@ -178,3 +174,50 @@ const (
ProtocolROHC = 142 // Robust Header Compression
ProtocolReserved = 255 // Reserved
)
// Address Family Numbers, Updated: 2018-04-02
const (
AddrFamilyIPv4 = 1 // IP (IP version 4)
AddrFamilyIPv6 = 2 // IP6 (IP version 6)
AddrFamilyNSAP = 3 // NSAP
AddrFamilyHDLC = 4 // HDLC (8-bit multidrop)
AddrFamilyBBN1822 = 5 // BBN 1822
AddrFamily802 = 6 // 802 (includes all 802 media plus Ethernet "canonical format")
AddrFamilyE163 = 7 // E.163
AddrFamilyE164 = 8 // E.164 (SMDS, Frame Relay, ATM)
AddrFamilyF69 = 9 // F.69 (Telex)
AddrFamilyX121 = 10 // X.121 (X.25, Frame Relay)
AddrFamilyIPX = 11 // IPX
AddrFamilyAppletalk = 12 // Appletalk
AddrFamilyDecnetIV = 13 // Decnet IV
AddrFamilyBanyanVines = 14 // Banyan Vines
AddrFamilyE164withSubaddress = 15 // E.164 with NSAP format subaddress
AddrFamilyDNS = 16 // DNS (Domain Name System)
AddrFamilyDistinguishedName = 17 // Distinguished Name
AddrFamilyASNumber = 18 // AS Number
AddrFamilyXTPoverIPv4 = 19 // XTP over IP version 4
AddrFamilyXTPoverIPv6 = 20 // XTP over IP version 6
AddrFamilyXTPnativemodeXTP = 21 // XTP native mode XTP
AddrFamilyFibreChannelWorldWidePortName = 22 // Fibre Channel World-Wide Port Name
AddrFamilyFibreChannelWorldWideNodeName = 23 // Fibre Channel World-Wide Node Name
AddrFamilyGWID = 24 // GWID
AddrFamilyL2VPN = 25 // AFI for L2VPN information
AddrFamilyMPLSTPSectionEndpointID = 26 // MPLS-TP Section Endpoint Identifier
AddrFamilyMPLSTPLSPEndpointID = 27 // MPLS-TP LSP Endpoint Identifier
AddrFamilyMPLSTPPseudowireEndpointID = 28 // MPLS-TP Pseudowire Endpoint Identifier
AddrFamilyMTIPv4 = 29 // MT IP: Multi-Topology IP version 4
AddrFamilyMTIPv6 = 30 // MT IPv6: Multi-Topology IP version 6
AddrFamilyEIGRPCommonServiceFamily = 16384 // EIGRP Common Service Family
AddrFamilyEIGRPIPv4ServiceFamily = 16385 // EIGRP IPv4 Service Family
AddrFamilyEIGRPIPv6ServiceFamily = 16386 // EIGRP IPv6 Service Family
AddrFamilyLISPCanonicalAddressFormat = 16387 // LISP Canonical Address Format (LCAF)
AddrFamilyBGPLS = 16388 // BGP-LS
AddrFamily48bitMAC = 16389 // 48-bit MAC
AddrFamily64bitMAC = 16390 // 64-bit MAC
AddrFamilyOUI = 16391 // OUI
AddrFamilyMACFinal24bits = 16392 // MAC/24
AddrFamilyMACFinal40bits = 16393 // MAC/40
AddrFamilyIPv6Initial64bits = 16394 // IPv6/64
AddrFamilyRBridgePortID = 16395 // RBridge Port ID
AddrFamilyTRILLNickname = 16396 // TRILL Nickname
)

View file

@ -28,23 +28,23 @@ var registries = []struct {
parse func(io.Writer, io.Reader) error
}{
{
"http://www.iana.org/assignments/dscp-registry/dscp-registry.xml",
"https://www.iana.org/assignments/dscp-registry/dscp-registry.xml",
parseDSCPRegistry,
},
{
"http://www.iana.org/assignments/ipv4-tos-byte/ipv4-tos-byte.xml",
parseTOSTCByte,
"https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml",
parseProtocolNumbers,
},
{
"http://www.iana.org/assignments/protocol-numbers/protocol-numbers.xml",
parseProtocolNumbers,
"https://www.iana.org/assignments/address-family-numbers/address-family-numbers.xml",
parseAddrFamilyNumbers,
},
}
func main() {
var bb bytes.Buffer
fmt.Fprintf(&bb, "// go generate gen.go\n")
fmt.Fprintf(&bb, "// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n")
fmt.Fprintf(&bb, "// Code generated by the command above; DO NOT EDIT.\n\n")
fmt.Fprintf(&bb, "// Package iana provides protocol number resources managed by the Internet Assigned Numbers Authority (IANA).\n")
fmt.Fprintf(&bb, `package iana // import "golang.org/x/net/internal/iana"`+"\n\n")
for _, r := range registries {
@ -81,31 +81,39 @@ func parseDSCPRegistry(w io.Writer, r io.Reader) error {
if err := dec.Decode(&dr); err != nil {
return err
}
drs := dr.escape()
fmt.Fprintf(w, "// %s, Updated: %s\n", dr.Title, dr.Updated)
fmt.Fprintf(w, "const (\n")
for _, dr := range drs {
fmt.Fprintf(w, "DiffServ%s = %#x", dr.Name, dr.Value)
for _, dr := range dr.escapeDSCP() {
fmt.Fprintf(w, "DiffServ%s = %#02x", dr.Name, dr.Value)
fmt.Fprintf(w, "// %s\n", dr.OrigName)
}
for _, er := range dr.escapeECN() {
fmt.Fprintf(w, "%s = %#02x", er.Descr, er.Value)
fmt.Fprintf(w, "// %s\n", er.OrigDescr)
}
fmt.Fprintf(w, ")\n")
return nil
}
type dscpRegistry struct {
XMLName xml.Name `xml:"registry"`
Title string `xml:"title"`
Updated string `xml:"updated"`
Note string `xml:"note"`
RegTitle string `xml:"registry>title"`
PoolRecords []struct {
Name string `xml:"name"`
Space string `xml:"space"`
} `xml:"registry>record"`
Records []struct {
Name string `xml:"name"`
Space string `xml:"space"`
} `xml:"registry>registry>record"`
XMLName xml.Name `xml:"registry"`
Title string `xml:"title"`
Updated string `xml:"updated"`
Note string `xml:"note"`
Registries []struct {
Title string `xml:"title"`
Registries []struct {
Title string `xml:"title"`
Records []struct {
Name string `xml:"name"`
Space string `xml:"space"`
} `xml:"record"`
} `xml:"registry"`
Records []struct {
Value string `xml:"value"`
Descr string `xml:"description"`
} `xml:"record"`
} `xml:"registry"`
}
type canonDSCPRecord struct {
@ -114,92 +122,84 @@ type canonDSCPRecord struct {
Value int
}
func (drr *dscpRegistry) escape() []canonDSCPRecord {
drs := make([]canonDSCPRecord, len(drr.Records))
sr := strings.NewReplacer(
"+", "",
"-", "",
"/", "",
".", "",
" ", "",
)
for i, dr := range drr.Records {
s := strings.TrimSpace(dr.Name)
drs[i].OrigName = s
drs[i].Name = sr.Replace(s)
n, err := strconv.ParseUint(dr.Space, 2, 8)
if err != nil {
func (drr *dscpRegistry) escapeDSCP() []canonDSCPRecord {
var drs []canonDSCPRecord
for _, preg := range drr.Registries {
if !strings.Contains(preg.Title, "Differentiated Services Field Codepoints") {
continue
}
drs[i].Value = int(n) << 2
for _, reg := range preg.Registries {
if !strings.Contains(reg.Title, "Pool 1 Codepoints") {
continue
}
drs = make([]canonDSCPRecord, len(reg.Records))
sr := strings.NewReplacer(
"+", "",
"-", "",
"/", "",
".", "",
" ", "",
)
for i, dr := range reg.Records {
s := strings.TrimSpace(dr.Name)
drs[i].OrigName = s
drs[i].Name = sr.Replace(s)
n, err := strconv.ParseUint(dr.Space, 2, 8)
if err != nil {
continue
}
drs[i].Value = int(n) << 2
}
}
}
return drs
}
func parseTOSTCByte(w io.Writer, r io.Reader) error {
dec := xml.NewDecoder(r)
var ttb tosTCByte
if err := dec.Decode(&ttb); err != nil {
return err
}
trs := ttb.escape()
fmt.Fprintf(w, "// %s, Updated: %s\n", ttb.Title, ttb.Updated)
fmt.Fprintf(w, "const (\n")
for _, tr := range trs {
fmt.Fprintf(w, "%s = %#x", tr.Keyword, tr.Value)
fmt.Fprintf(w, "// %s\n", tr.OrigKeyword)
}
fmt.Fprintf(w, ")\n")
return nil
type canonECNRecord struct {
OrigDescr string
Descr string
Value int
}
type tosTCByte struct {
XMLName xml.Name `xml:"registry"`
Title string `xml:"title"`
Updated string `xml:"updated"`
Note string `xml:"note"`
RegTitle string `xml:"registry>title"`
Records []struct {
Binary string `xml:"binary"`
Keyword string `xml:"keyword"`
} `xml:"registry>record"`
}
type canonTOSTCByteRecord struct {
OrigKeyword string
Keyword string
Value int
}
func (ttb *tosTCByte) escape() []canonTOSTCByteRecord {
trs := make([]canonTOSTCByteRecord, len(ttb.Records))
sr := strings.NewReplacer(
"Capable", "",
"(", "",
")", "",
"+", "",
"-", "",
"/", "",
".", "",
" ", "",
)
for i, tr := range ttb.Records {
s := strings.TrimSpace(tr.Keyword)
trs[i].OrigKeyword = s
ss := strings.Split(s, " ")
if len(ss) > 1 {
trs[i].Keyword = strings.Join(ss[1:], " ")
} else {
trs[i].Keyword = ss[0]
}
trs[i].Keyword = sr.Replace(trs[i].Keyword)
n, err := strconv.ParseUint(tr.Binary, 2, 8)
if err != nil {
func (drr *dscpRegistry) escapeECN() []canonECNRecord {
var ers []canonECNRecord
for _, reg := range drr.Registries {
if !strings.Contains(reg.Title, "ECN Field") {
continue
}
trs[i].Value = int(n)
ers = make([]canonECNRecord, len(reg.Records))
sr := strings.NewReplacer(
"Capable", "",
"Not-ECT", "",
"ECT(1)", "",
"ECT(0)", "",
"CE", "",
"(", "",
")", "",
"+", "",
"-", "",
"/", "",
".", "",
" ", "",
)
for i, er := range reg.Records {
s := strings.TrimSpace(er.Descr)
ers[i].OrigDescr = s
ss := strings.Split(s, " ")
if len(ss) > 1 {
ers[i].Descr = strings.Join(ss[1:], " ")
} else {
ers[i].Descr = ss[0]
}
ers[i].Descr = sr.Replace(er.Descr)
n, err := strconv.ParseUint(er.Value, 2, 8)
if err != nil {
continue
}
ers[i].Value = int(n)
}
}
return trs
return ers
}
func parseProtocolNumbers(w io.Writer, r io.Reader) error {
@ -291,3 +291,93 @@ func (pn *protocolNumbers) escape() []canonProtocolRecord {
}
return prs
}
func parseAddrFamilyNumbers(w io.Writer, r io.Reader) error {
dec := xml.NewDecoder(r)
var afn addrFamilylNumbers
if err := dec.Decode(&afn); err != nil {
return err
}
afrs := afn.escape()
fmt.Fprintf(w, "// %s, Updated: %s\n", afn.Title, afn.Updated)
fmt.Fprintf(w, "const (\n")
for _, afr := range afrs {
if afr.Name == "" {
continue
}
fmt.Fprintf(w, "AddrFamily%s = %d", afr.Name, afr.Value)
fmt.Fprintf(w, "// %s\n", afr.Descr)
}
fmt.Fprintf(w, ")\n")
return nil
}
type addrFamilylNumbers struct {
XMLName xml.Name `xml:"registry"`
Title string `xml:"title"`
Updated string `xml:"updated"`
RegTitle string `xml:"registry>title"`
Note string `xml:"registry>note"`
Records []struct {
Value string `xml:"value"`
Descr string `xml:"description"`
} `xml:"registry>record"`
}
type canonAddrFamilyRecord struct {
Name string
Descr string
Value int
}
func (afn *addrFamilylNumbers) escape() []canonAddrFamilyRecord {
afrs := make([]canonAddrFamilyRecord, len(afn.Records))
sr := strings.NewReplacer(
"IP version 4", "IPv4",
"IP version 6", "IPv6",
"Identifier", "ID",
"-", "",
"-", "",
"/", "",
".", "",
" ", "",
)
for i, afr := range afn.Records {
if strings.Contains(afr.Descr, "Unassigned") ||
strings.Contains(afr.Descr, "Reserved") {
continue
}
afrs[i].Descr = afr.Descr
s := strings.TrimSpace(afr.Descr)
switch s {
case "IP (IP version 4)":
afrs[i].Name = "IPv4"
case "IP6 (IP version 6)":
afrs[i].Name = "IPv6"
case "AFI for L2VPN information":
afrs[i].Name = "L2VPN"
case "E.164 with NSAP format subaddress":
afrs[i].Name = "E164withSubaddress"
case "MT IP: Multi-Topology IP version 4":
afrs[i].Name = "MTIPv4"
case "MAC/24":
afrs[i].Name = "MACFinal24bits"
case "MAC/40":
afrs[i].Name = "MACFinal40bits"
case "IPv6/64":
afrs[i].Name = "IPv6Initial64bits"
default:
n := strings.Index(s, "(")
if n > 0 {
s = s[:n]
}
n = strings.Index(s, ":")
if n > 0 {
s = s[:n]
}
afrs[i].Name = sr.Replace(s)
}
afrs[i].Value, _ = strconv.Atoi(afr.Value)
}
return afrs
}

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build nacl plan9
// +build js,wasm nacl plan9
package nettest

View file

@ -64,7 +64,7 @@ func TestableNetwork(network string) bool {
switch network {
case "unix", "unixgram":
switch runtime.GOOS {
case "android", "nacl", "plan9", "windows":
case "android", "js", "nacl", "plan9", "windows":
return false
}
if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
@ -72,7 +72,7 @@ func TestableNetwork(network string) bool {
}
case "unixpacket":
switch runtime.GOOS {
case "android", "darwin", "freebsd", "nacl", "plan9", "windows":
case "android", "darwin", "freebsd", "js", "nacl", "plan9", "windows":
return false
case "netbsd":
// It passes on amd64 at least. 386 fails (Issue 22927). arm is unknown.

View file

@ -26,6 +26,11 @@ type msghdr struct {
Flags int32
}
type mmsghdr struct {
Hdr msghdr
Len uint32
}
type cmsghdr struct {
Len uint32
Level int32
@ -52,6 +57,7 @@ type sockaddrInet6 struct {
const (
sizeofIovec = 0x8
sizeofMsghdr = 0x1c
sizeofMmsghdr = 0x20
sizeofCmsghdr = 0xc
sizeofSockaddrInet = 0x10

168
vendor/golang.org/x/net/internal/socks/client.go generated vendored Normal file
View file

@ -0,0 +1,168 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package socks
import (
"context"
"errors"
"io"
"net"
"strconv"
"time"
)
var (
noDeadline = time.Time{}
aLongTimeAgo = time.Unix(1, 0)
)
func (d *Dialer) connect(ctx context.Context, c net.Conn, address string) (_ net.Addr, ctxErr error) {
host, port, err := splitHostPort(address)
if err != nil {
return nil, err
}
if deadline, ok := ctx.Deadline(); ok && !deadline.IsZero() {
c.SetDeadline(deadline)
defer c.SetDeadline(noDeadline)
}
if ctx != context.Background() {
errCh := make(chan error, 1)
done := make(chan struct{})
defer func() {
close(done)
if ctxErr == nil {
ctxErr = <-errCh
}
}()
go func() {
select {
case <-ctx.Done():
c.SetDeadline(aLongTimeAgo)
errCh <- ctx.Err()
case <-done:
errCh <- nil
}
}()
}
b := make([]byte, 0, 6+len(host)) // the size here is just an estimate
b = append(b, Version5)
if len(d.AuthMethods) == 0 || d.Authenticate == nil {
b = append(b, 1, byte(AuthMethodNotRequired))
} else {
ams := d.AuthMethods
if len(ams) > 255 {
return nil, errors.New("too many authentication methods")
}
b = append(b, byte(len(ams)))
for _, am := range ams {
b = append(b, byte(am))
}
}
if _, ctxErr = c.Write(b); ctxErr != nil {
return
}
if _, ctxErr = io.ReadFull(c, b[:2]); ctxErr != nil {
return
}
if b[0] != Version5 {
return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0])))
}
am := AuthMethod(b[1])
if am == AuthMethodNoAcceptableMethods {
return nil, errors.New("no acceptable authentication methods")
}
if d.Authenticate != nil {
if ctxErr = d.Authenticate(ctx, c, am); ctxErr != nil {
return
}
}
b = b[:0]
b = append(b, Version5, byte(d.cmd), 0)
if ip := net.ParseIP(host); ip != nil {
if ip4 := ip.To4(); ip4 != nil {
b = append(b, AddrTypeIPv4)
b = append(b, ip4...)
} else if ip6 := ip.To16(); ip6 != nil {
b = append(b, AddrTypeIPv6)
b = append(b, ip6...)
} else {
return nil, errors.New("unknown address type")
}
} else {
if len(host) > 255 {
return nil, errors.New("FQDN too long")
}
b = append(b, AddrTypeFQDN)
b = append(b, byte(len(host)))
b = append(b, host...)
}
b = append(b, byte(port>>8), byte(port))
if _, ctxErr = c.Write(b); ctxErr != nil {
return
}
if _, ctxErr = io.ReadFull(c, b[:4]); ctxErr != nil {
return
}
if b[0] != Version5 {
return nil, errors.New("unexpected protocol version " + strconv.Itoa(int(b[0])))
}
if cmdErr := Reply(b[1]); cmdErr != StatusSucceeded {
return nil, errors.New("unknown error " + cmdErr.String())
}
if b[2] != 0 {
return nil, errors.New("non-zero reserved field")
}
l := 2
var a Addr
switch b[3] {
case AddrTypeIPv4:
l += net.IPv4len
a.IP = make(net.IP, net.IPv4len)
case AddrTypeIPv6:
l += net.IPv6len
a.IP = make(net.IP, net.IPv6len)
case AddrTypeFQDN:
if _, err := io.ReadFull(c, b[:1]); err != nil {
return nil, err
}
l += int(b[0])
default:
return nil, errors.New("unknown address type " + strconv.Itoa(int(b[3])))
}
if cap(b) < l {
b = make([]byte, l)
} else {
b = b[:l]
}
if _, ctxErr = io.ReadFull(c, b); ctxErr != nil {
return
}
if a.IP != nil {
copy(a.IP, b)
} else {
a.Name = string(b[:len(b)-2])
}
a.Port = int(b[len(b)-2])<<8 | int(b[len(b)-1])
return &a, nil
}
func splitHostPort(address string) (string, int, error) {
host, port, err := net.SplitHostPort(address)
if err != nil {
return "", 0, err
}
portnum, err := strconv.Atoi(port)
if err != nil {
return "", 0, err
}
if 1 > portnum || portnum > 0xffff {
return "", 0, errors.New("port number out of range " + port)
}
return host, portnum, nil
}

170
vendor/golang.org/x/net/internal/socks/dial_test.go generated vendored Normal file
View file

@ -0,0 +1,170 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package socks_test
import (
"context"
"io"
"math/rand"
"net"
"os"
"testing"
"time"
"golang.org/x/net/internal/socks"
"golang.org/x/net/internal/sockstest"
)
func TestDial(t *testing.T) {
t.Run("Connect", func(t *testing.T) {
ss, err := sockstest.NewServer(sockstest.NoAuthRequired, sockstest.NoProxyRequired)
if err != nil {
t.Fatal(err)
}
defer ss.Close()
d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String())
d.AuthMethods = []socks.AuthMethod{
socks.AuthMethodNotRequired,
socks.AuthMethodUsernamePassword,
}
d.Authenticate = (&socks.UsernamePassword{
Username: "username",
Password: "password",
}).Authenticate
c, err := d.DialContext(context.Background(), ss.TargetAddr().Network(), ss.TargetAddr().String())
if err != nil {
t.Fatal(err)
}
c.(*socks.Conn).BoundAddr()
c.Close()
})
t.Run("ConnectWithConn", func(t *testing.T) {
ss, err := sockstest.NewServer(sockstest.NoAuthRequired, sockstest.NoProxyRequired)
if err != nil {
t.Fatal(err)
}
defer ss.Close()
c, err := net.Dial(ss.Addr().Network(), ss.Addr().String())
if err != nil {
t.Fatal(err)
}
defer c.Close()
d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String())
d.AuthMethods = []socks.AuthMethod{
socks.AuthMethodNotRequired,
socks.AuthMethodUsernamePassword,
}
d.Authenticate = (&socks.UsernamePassword{
Username: "username",
Password: "password",
}).Authenticate
a, err := d.DialWithConn(context.Background(), c, ss.TargetAddr().Network(), ss.TargetAddr().String())
if err != nil {
t.Fatal(err)
}
if _, ok := a.(*socks.Addr); !ok {
t.Fatalf("got %+v; want socks.Addr", a)
}
})
t.Run("Cancel", func(t *testing.T) {
ss, err := sockstest.NewServer(sockstest.NoAuthRequired, blackholeCmdFunc)
if err != nil {
t.Fatal(err)
}
defer ss.Close()
d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String())
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
dialErr := make(chan error)
go func() {
c, err := d.DialContext(ctx, ss.TargetAddr().Network(), ss.TargetAddr().String())
if err == nil {
c.Close()
}
dialErr <- err
}()
time.Sleep(100 * time.Millisecond)
cancel()
err = <-dialErr
if perr, nerr := parseDialError(err); perr != context.Canceled && nerr == nil {
t.Fatalf("got %v; want context.Canceled or equivalent", err)
}
})
t.Run("Deadline", func(t *testing.T) {
ss, err := sockstest.NewServer(sockstest.NoAuthRequired, blackholeCmdFunc)
if err != nil {
t.Fatal(err)
}
defer ss.Close()
d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String())
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(100*time.Millisecond))
defer cancel()
c, err := d.DialContext(ctx, ss.TargetAddr().Network(), ss.TargetAddr().String())
if err == nil {
c.Close()
}
if perr, nerr := parseDialError(err); perr != context.DeadlineExceeded && nerr == nil {
t.Fatalf("got %v; want context.DeadlineExceeded or equivalent", err)
}
})
t.Run("WithRogueServer", func(t *testing.T) {
ss, err := sockstest.NewServer(sockstest.NoAuthRequired, rogueCmdFunc)
if err != nil {
t.Fatal(err)
}
defer ss.Close()
d := socks.NewDialer(ss.Addr().Network(), ss.Addr().String())
for i := 0; i < 2*len(rogueCmdList); i++ {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(100*time.Millisecond))
defer cancel()
c, err := d.DialContext(ctx, ss.TargetAddr().Network(), ss.TargetAddr().String())
if err == nil {
t.Log(c.(*socks.Conn).BoundAddr())
c.Close()
t.Error("should fail")
}
}
})
}
func blackholeCmdFunc(rw io.ReadWriter, b []byte) error {
if _, err := sockstest.ParseCmdRequest(b); err != nil {
return err
}
var bb [1]byte
for {
if _, err := rw.Read(bb[:]); err != nil {
return err
}
}
}
func rogueCmdFunc(rw io.ReadWriter, b []byte) error {
if _, err := sockstest.ParseCmdRequest(b); err != nil {
return err
}
rw.Write(rogueCmdList[rand.Intn(len(rogueCmdList))])
return nil
}
var rogueCmdList = [][]byte{
{0x05},
{0x06, 0x00, 0x00, 0x01, 192, 0, 2, 1, 0x17, 0x4b},
{0x05, 0x00, 0xff, 0x01, 192, 0, 2, 2, 0x17, 0x4b},
{0x05, 0x00, 0x00, 0x01, 192, 0, 2, 3},
{0x05, 0x00, 0x00, 0x03, 0x04, 'F', 'Q', 'D', 'N'},
}
func parseDialError(err error) (perr, nerr error) {
if e, ok := err.(*net.OpError); ok {
err = e.Err
nerr = e
}
if e, ok := err.(*os.SyscallError); ok {
err = e.Err
}
perr = err
return
}

316
vendor/golang.org/x/net/internal/socks/socks.go generated vendored Normal file
View file

@ -0,0 +1,316 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package socks provides a SOCKS version 5 client implementation.
//
// SOCKS protocol version 5 is defined in RFC 1928.
// Username/Password authentication for SOCKS version 5 is defined in
// RFC 1929.
package socks
import (
"context"
"errors"
"io"
"net"
"strconv"
)
// A Command represents a SOCKS command.
type Command int
func (cmd Command) String() string {
switch cmd {
case CmdConnect:
return "socks connect"
case cmdBind:
return "socks bind"
default:
return "socks " + strconv.Itoa(int(cmd))
}
}
// An AuthMethod represents a SOCKS authentication method.
type AuthMethod int
// A Reply represents a SOCKS command reply code.
type Reply int
func (code Reply) String() string {
switch code {
case StatusSucceeded:
return "succeeded"
case 0x01:
return "general SOCKS server failure"
case 0x02:
return "connection not allowed by ruleset"
case 0x03:
return "network unreachable"
case 0x04:
return "host unreachable"
case 0x05:
return "connection refused"
case 0x06:
return "TTL expired"
case 0x07:
return "command not supported"
case 0x08:
return "address type not supported"
default:
return "unknown code: " + strconv.Itoa(int(code))
}
}
// Wire protocol constants.
const (
Version5 = 0x05
AddrTypeIPv4 = 0x01
AddrTypeFQDN = 0x03
AddrTypeIPv6 = 0x04
CmdConnect Command = 0x01 // establishes an active-open forward proxy connection
cmdBind Command = 0x02 // establishes a passive-open forward proxy connection
AuthMethodNotRequired AuthMethod = 0x00 // no authentication required
AuthMethodUsernamePassword AuthMethod = 0x02 // use username/password
AuthMethodNoAcceptableMethods AuthMethod = 0xff // no acceptable authentication methods
StatusSucceeded Reply = 0x00
)
// An Addr represents a SOCKS-specific address.
// Either Name or IP is used exclusively.
type Addr struct {
Name string // fully-qualified domain name
IP net.IP
Port int
}
func (a *Addr) Network() string { return "socks" }
func (a *Addr) String() string {
if a == nil {
return "<nil>"
}
port := strconv.Itoa(a.Port)
if a.IP == nil {
return net.JoinHostPort(a.Name, port)
}
return net.JoinHostPort(a.IP.String(), port)
}
// A Conn represents a forward proxy connection.
type Conn struct {
net.Conn
boundAddr net.Addr
}
// BoundAddr returns the address assigned by the proxy server for
// connecting to the command target address from the proxy server.
func (c *Conn) BoundAddr() net.Addr {
if c == nil {
return nil
}
return c.boundAddr
}
// A Dialer holds SOCKS-specific options.
type Dialer struct {
cmd Command // either CmdConnect or cmdBind
proxyNetwork string // network between a proxy server and a client
proxyAddress string // proxy server address
// ProxyDial specifies the optional dial function for
// establishing the transport connection.
ProxyDial func(context.Context, string, string) (net.Conn, error)
// AuthMethods specifies the list of request authention
// methods.
// If empty, SOCKS client requests only AuthMethodNotRequired.
AuthMethods []AuthMethod
// Authenticate specifies the optional authentication
// function. It must be non-nil when AuthMethods is not empty.
// It must return an error when the authentication is failed.
Authenticate func(context.Context, io.ReadWriter, AuthMethod) error
}
// DialContext connects to the provided address on the provided
// network.
//
// The returned error value may be a net.OpError. When the Op field of
// net.OpError contains "socks", the Source field contains a proxy
// server address and the Addr field contains a command target
// address.
//
// See func Dial of the net package of standard library for a
// description of the network and address parameters.
func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
if err := d.validateTarget(network, address); err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
if ctx == nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")}
}
var err error
var c net.Conn
if d.ProxyDial != nil {
c, err = d.ProxyDial(ctx, d.proxyNetwork, d.proxyAddress)
} else {
var dd net.Dialer
c, err = dd.DialContext(ctx, d.proxyNetwork, d.proxyAddress)
}
if err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
a, err := d.connect(ctx, c, address)
if err != nil {
c.Close()
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
return &Conn{Conn: c, boundAddr: a}, nil
}
// DialWithConn initiates a connection from SOCKS server to the target
// network and address using the connection c that is already
// connected to the SOCKS server.
//
// It returns the connection's local address assigned by the SOCKS
// server.
func (d *Dialer) DialWithConn(ctx context.Context, c net.Conn, network, address string) (net.Addr, error) {
if err := d.validateTarget(network, address); err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
if ctx == nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: errors.New("nil context")}
}
a, err := d.connect(ctx, c, address)
if err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
return a, nil
}
// Dial connects to the provided address on the provided network.
//
// Unlike DialContext, it returns a raw transport connection instead
// of a forward proxy connection.
//
// Deprecated: Use DialContext or DialWithConn instead.
func (d *Dialer) Dial(network, address string) (net.Conn, error) {
if err := d.validateTarget(network, address); err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
var err error
var c net.Conn
if d.ProxyDial != nil {
c, err = d.ProxyDial(context.Background(), d.proxyNetwork, d.proxyAddress)
} else {
c, err = net.Dial(d.proxyNetwork, d.proxyAddress)
}
if err != nil {
proxy, dst, _ := d.pathAddrs(address)
return nil, &net.OpError{Op: d.cmd.String(), Net: network, Source: proxy, Addr: dst, Err: err}
}
if _, err := d.DialWithConn(context.Background(), c, network, address); err != nil {
return nil, err
}
return c, nil
}
func (d *Dialer) validateTarget(network, address string) error {
switch network {
case "tcp", "tcp6", "tcp4":
default:
return errors.New("network not implemented")
}
switch d.cmd {
case CmdConnect, cmdBind:
default:
return errors.New("command not implemented")
}
return nil
}
func (d *Dialer) pathAddrs(address string) (proxy, dst net.Addr, err error) {
for i, s := range []string{d.proxyAddress, address} {
host, port, err := splitHostPort(s)
if err != nil {
return nil, nil, err
}
a := &Addr{Port: port}
a.IP = net.ParseIP(host)
if a.IP == nil {
a.Name = host
}
if i == 0 {
proxy = a
} else {
dst = a
}
}
return
}
// NewDialer returns a new Dialer that dials through the provided
// proxy server's network and address.
func NewDialer(network, address string) *Dialer {
return &Dialer{proxyNetwork: network, proxyAddress: address, cmd: CmdConnect}
}
const (
authUsernamePasswordVersion = 0x01
authStatusSucceeded = 0x00
)
// UsernamePassword are the credentials for the username/password
// authentication method.
type UsernamePassword struct {
Username string
Password string
}
// Authenticate authenticates a pair of username and password with the
// proxy server.
func (up *UsernamePassword) Authenticate(ctx context.Context, rw io.ReadWriter, auth AuthMethod) error {
switch auth {
case AuthMethodNotRequired:
return nil
case AuthMethodUsernamePassword:
if len(up.Username) == 0 || len(up.Username) > 255 || len(up.Password) == 0 || len(up.Password) > 255 {
return errors.New("invalid username/password")
}
b := []byte{authUsernamePasswordVersion}
b = append(b, byte(len(up.Username)))
b = append(b, up.Username...)
b = append(b, byte(len(up.Password)))
b = append(b, up.Password...)
// TODO(mikio): handle IO deadlines and cancelation if
// necessary
if _, err := rw.Write(b); err != nil {
return err
}
if _, err := io.ReadFull(rw, b[:2]); err != nil {
return err
}
if b[0] != authUsernamePasswordVersion {
return errors.New("invalid username/password version")
}
if b[1] != authStatusSucceeded {
return errors.New("username/password authentication failed")
}
return nil
}
return errors.New("unsupported authentication method " + strconv.Itoa(int(auth)))
}

241
vendor/golang.org/x/net/internal/sockstest/server.go generated vendored Normal file
View file

@ -0,0 +1,241 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package sockstest provides utilities for SOCKS testing.
package sockstest
import (
"errors"
"io"
"net"
"golang.org/x/net/internal/nettest"
"golang.org/x/net/internal/socks"
)
// An AuthRequest represents an authentication request.
type AuthRequest struct {
Version int
Methods []socks.AuthMethod
}
// ParseAuthRequest parses an authentication request.
func ParseAuthRequest(b []byte) (*AuthRequest, error) {
if len(b) < 2 {
return nil, errors.New("short auth request")
}
if b[0] != socks.Version5 {
return nil, errors.New("unexpected protocol version")
}
if len(b)-2 < int(b[1]) {
return nil, errors.New("short auth request")
}
req := &AuthRequest{Version: int(b[0])}
if b[1] > 0 {
req.Methods = make([]socks.AuthMethod, b[1])
for i, m := range b[2 : 2+b[1]] {
req.Methods[i] = socks.AuthMethod(m)
}
}
return req, nil
}
// MarshalAuthReply returns an authentication reply in wire format.
func MarshalAuthReply(ver int, m socks.AuthMethod) ([]byte, error) {
return []byte{byte(ver), byte(m)}, nil
}
// A CmdRequest repesents a command request.
type CmdRequest struct {
Version int
Cmd socks.Command
Addr socks.Addr
}
// ParseCmdRequest parses a command request.
func ParseCmdRequest(b []byte) (*CmdRequest, error) {
if len(b) < 7 {
return nil, errors.New("short cmd request")
}
if b[0] != socks.Version5 {
return nil, errors.New("unexpected protocol version")
}
if socks.Command(b[1]) != socks.CmdConnect {
return nil, errors.New("unexpected command")
}
if b[2] != 0 {
return nil, errors.New("non-zero reserved field")
}
req := &CmdRequest{Version: int(b[0]), Cmd: socks.Command(b[1])}
l := 2
off := 4
switch b[3] {
case socks.AddrTypeIPv4:
l += net.IPv4len
req.Addr.IP = make(net.IP, net.IPv4len)
case socks.AddrTypeIPv6:
l += net.IPv6len
req.Addr.IP = make(net.IP, net.IPv6len)
case socks.AddrTypeFQDN:
l += int(b[4])
off = 5
default:
return nil, errors.New("unknown address type")
}
if len(b[off:]) < l {
return nil, errors.New("short cmd request")
}
if req.Addr.IP != nil {
copy(req.Addr.IP, b[off:])
} else {
req.Addr.Name = string(b[off : off+l-2])
}
req.Addr.Port = int(b[off+l-2])<<8 | int(b[off+l-1])
return req, nil
}
// MarshalCmdReply returns a command reply in wire format.
func MarshalCmdReply(ver int, reply socks.Reply, a *socks.Addr) ([]byte, error) {
b := make([]byte, 4)
b[0] = byte(ver)
b[1] = byte(reply)
if a.Name != "" {
if len(a.Name) > 255 {
return nil, errors.New("fqdn too long")
}
b[3] = socks.AddrTypeFQDN
b = append(b, byte(len(a.Name)))
b = append(b, a.Name...)
} else if ip4 := a.IP.To4(); ip4 != nil {
b[3] = socks.AddrTypeIPv4
b = append(b, ip4...)
} else if ip6 := a.IP.To16(); ip6 != nil {
b[3] = socks.AddrTypeIPv6
b = append(b, ip6...)
} else {
return nil, errors.New("unknown address type")
}
b = append(b, byte(a.Port>>8), byte(a.Port))
return b, nil
}
// A Server repesents a server for handshake testing.
type Server struct {
ln net.Listener
}
// Addr rerurns a server address.
func (s *Server) Addr() net.Addr {
return s.ln.Addr()
}
// TargetAddr returns a fake final destination address.
//
// The returned address is only valid for testing with Server.
func (s *Server) TargetAddr() net.Addr {
a := s.ln.Addr()
switch a := a.(type) {
case *net.TCPAddr:
if a.IP.To4() != nil {
return &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 5963}
}
if a.IP.To16() != nil && a.IP.To4() == nil {
return &net.TCPAddr{IP: net.IPv6loopback, Port: 5963}
}
}
return nil
}
// Close closes the server.
func (s *Server) Close() error {
return s.ln.Close()
}
func (s *Server) serve(authFunc, cmdFunc func(io.ReadWriter, []byte) error) {
c, err := s.ln.Accept()
if err != nil {
return
}
defer c.Close()
go s.serve(authFunc, cmdFunc)
b := make([]byte, 512)
n, err := c.Read(b)
if err != nil {
return
}
if err := authFunc(c, b[:n]); err != nil {
return
}
n, err = c.Read(b)
if err != nil {
return
}
if err := cmdFunc(c, b[:n]); err != nil {
return
}
}
// NewServer returns a new server.
//
// The provided authFunc and cmdFunc must parse requests and return
// appropriate replies to clients.
func NewServer(authFunc, cmdFunc func(io.ReadWriter, []byte) error) (*Server, error) {
var err error
s := new(Server)
s.ln, err = nettest.NewLocalListener("tcp")
if err != nil {
return nil, err
}
go s.serve(authFunc, cmdFunc)
return s, nil
}
// NoAuthRequired handles a no-authentication-required signaling.
func NoAuthRequired(rw io.ReadWriter, b []byte) error {
req, err := ParseAuthRequest(b)
if err != nil {
return err
}
b, err = MarshalAuthReply(req.Version, socks.AuthMethodNotRequired)
if err != nil {
return err
}
n, err := rw.Write(b)
if err != nil {
return err
}
if n != len(b) {
return errors.New("short write")
}
return nil
}
// NoProxyRequired handles a command signaling without constructing a
// proxy connection to the final destination.
func NoProxyRequired(rw io.ReadWriter, b []byte) error {
req, err := ParseCmdRequest(b)
if err != nil {
return err
}
req.Addr.Port += 1
if req.Addr.Name != "" {
req.Addr.Name = "boundaddr.doesnotexist"
} else if req.Addr.IP.To4() != nil {
req.Addr.IP = net.IPv4(127, 0, 0, 1)
} else {
req.Addr.IP = net.IPv6loopback
}
b, err = MarshalCmdReply(socks.Version5, socks.StatusSucceeded, &req.Addr)
if err != nil {
return err
}
n, err := rw.Write(b)
if err != nil {
return err
}
if n != len(b) {
return errors.New("short write")
}
return nil
}

View file

@ -0,0 +1,103 @@
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package sockstest
import (
"net"
"reflect"
"testing"
"golang.org/x/net/internal/socks"
)
func TestParseAuthRequest(t *testing.T) {
for i, tt := range []struct {
wire []byte
req *AuthRequest
}{
{
[]byte{0x05, 0x00},
&AuthRequest{
socks.Version5,
nil,
},
},
{
[]byte{0x05, 0x01, 0xff},
&AuthRequest{
socks.Version5,
[]socks.AuthMethod{
socks.AuthMethodNoAcceptableMethods,
},
},
},
{
[]byte{0x05, 0x02, 0x00, 0xff},
&AuthRequest{
socks.Version5,
[]socks.AuthMethod{
socks.AuthMethodNotRequired,
socks.AuthMethodNoAcceptableMethods,
},
},
},
// corrupted requests
{nil, nil},
{[]byte{0x00, 0x01}, nil},
{[]byte{0x06, 0x00}, nil},
{[]byte{0x05, 0x02, 0x00}, nil},
} {
req, err := ParseAuthRequest(tt.wire)
if !reflect.DeepEqual(req, tt.req) {
t.Errorf("#%d: got %v, %v; want %v", i, req, err, tt.req)
continue
}
}
}
func TestParseCmdRequest(t *testing.T) {
for i, tt := range []struct {
wire []byte
req *CmdRequest
}{
{
[]byte{0x05, 0x01, 0x00, 0x01, 192, 0, 2, 1, 0x17, 0x4b},
&CmdRequest{
socks.Version5,
socks.CmdConnect,
socks.Addr{
IP: net.IP{192, 0, 2, 1},
Port: 5963,
},
},
},
{
[]byte{0x05, 0x01, 0x00, 0x03, 0x04, 'F', 'Q', 'D', 'N', 0x17, 0x4b},
&CmdRequest{
socks.Version5,
socks.CmdConnect,
socks.Addr{
Name: "FQDN",
Port: 5963,
},
},
},
// corrupted requests
{nil, nil},
{[]byte{0x05}, nil},
{[]byte{0x06, 0x01, 0x00, 0x01, 192, 0, 2, 2, 0x17, 0x4b}, nil},
{[]byte{0x05, 0x01, 0xff, 0x01, 192, 0, 2, 3}, nil},
{[]byte{0x05, 0x01, 0x00, 0x01, 192, 0, 2, 4}, nil},
{[]byte{0x05, 0x01, 0x00, 0x03, 0x04, 'F', 'Q', 'D', 'N'}, nil},
} {
req, err := ParseCmdRequest(tt.wire)
if !reflect.DeepEqual(req, tt.req) {
t.Errorf("#%d: got %v, %v; want %v", i, req, err, tt.req)
continue
}
}
}

View file

@ -9,7 +9,6 @@ package ipv4
import (
"net"
"runtime"
"syscall"
"golang.org/x/net/internal/socket"
)
@ -76,7 +75,7 @@ type Message = socket.Message
// headers.
func (c *payloadHandler) ReadBatch(ms []Message, flags int) (int, error) {
if !c.ok() {
return 0, syscall.EINVAL
return 0, errInvalidConn
}
switch runtime.GOOS {
case "linux":
@ -107,7 +106,7 @@ func (c *payloadHandler) ReadBatch(ms []Message, flags int) (int, error) {
// On other platforms, this method will write only a single message.
func (c *payloadHandler) WriteBatch(ms []Message, flags int) (int, error) {
if !c.ok() {
return 0, syscall.EINVAL
return 0, errInvalidConn
}
switch runtime.GOOS {
case "linux":
@ -139,7 +138,7 @@ func (c *payloadHandler) WriteBatch(ms []Message, flags int) (int, error) {
// On other platforms, this method will read only a single message.
func (c *packetHandler) ReadBatch(ms []Message, flags int) (int, error) {
if !c.ok() {
return 0, syscall.EINVAL
return 0, errInvalidConn
}
switch runtime.GOOS {
case "linux":
@ -170,7 +169,7 @@ func (c *packetHandler) ReadBatch(ms []Message, flags int) (int, error) {
// On other platforms, this method will write only a single message.
func (c *packetHandler) WriteBatch(ms []Message, flags int) (int, error) {
if !c.ok() {
return 0, syscall.EINVAL
return 0, errInvalidConn
}
switch runtime.GOOS {
case "linux":

View file

@ -6,7 +6,6 @@ package ipv4
import (
"net"
"syscall"
"golang.org/x/net/bpf"
)
@ -15,7 +14,7 @@ import (
// multicast packets.
func (c *dgramOpt) MulticastTTL() (int, error) {
if !c.ok() {
return 0, syscall.EINVAL
return 0, errInvalidConn
}
so, ok := sockOpts[ssoMulticastTTL]
if !ok {
@ -28,7 +27,7 @@ func (c *dgramOpt) MulticastTTL() (int, error) {
// outgoing multicast packets.
func (c *dgramOpt) SetMulticastTTL(ttl int) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoMulticastTTL]
if !ok {
@ -41,7 +40,7 @@ func (c *dgramOpt) SetMulticastTTL(ttl int) error {
// packet transmissions.
func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
if !c.ok() {
return nil, syscall.EINVAL
return nil, errInvalidConn
}
so, ok := sockOpts[ssoMulticastInterface]
if !ok {
@ -54,7 +53,7 @@ func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
// multicast packet transmissions.
func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoMulticastInterface]
if !ok {
@ -67,7 +66,7 @@ func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
// should be copied and send back to the originator.
func (c *dgramOpt) MulticastLoopback() (bool, error) {
if !c.ok() {
return false, syscall.EINVAL
return false, errInvalidConn
}
so, ok := sockOpts[ssoMulticastLoopback]
if !ok {
@ -84,7 +83,7 @@ func (c *dgramOpt) MulticastLoopback() (bool, error) {
// should be copied and send back to the originator.
func (c *dgramOpt) SetMulticastLoopback(on bool) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoMulticastLoopback]
if !ok {
@ -104,7 +103,7 @@ func (c *dgramOpt) SetMulticastLoopback(on bool) error {
// configuration.
func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoJoinGroup]
if !ok {
@ -122,7 +121,7 @@ func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error {
// source-specific group.
func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoLeaveGroup]
if !ok {
@ -143,7 +142,7 @@ func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
// routing configuration.
func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoJoinSourceGroup]
if !ok {
@ -164,7 +163,7 @@ func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net
// interface ifi.
func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoLeaveSourceGroup]
if !ok {
@ -186,7 +185,7 @@ func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source ne
// ifi.
func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoBlockSourceGroup]
if !ok {
@ -207,7 +206,7 @@ func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source
// group by ExcludeSourceSpecificGroup again on the interface ifi.
func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoUnblockSourceGroup]
if !ok {
@ -228,7 +227,7 @@ func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source
// Currently only Linux supports this.
func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) {
if !c.ok() {
return nil, syscall.EINVAL
return nil, errInvalidConn
}
so, ok := sockOpts[ssoICMPFilter]
if !ok {
@ -241,7 +240,7 @@ func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) {
// Currently only Linux supports this.
func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoICMPFilter]
if !ok {
@ -255,7 +254,7 @@ func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error {
// Only supported on Linux.
func (c *dgramOpt) SetBPF(filter []bpf.RawInstruction) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoAttachFilter]
if !ok {

View file

@ -241,4 +241,4 @@
// IncludeSourceSpecificGroup may return an error.
package ipv4 // import "golang.org/x/net/ipv4"
// BUG(mikio): This package is not implemented on NaCl and Plan 9.
// BUG(mikio): This package is not implemented on JS, NaCl and Plan 9.

View file

@ -6,7 +6,6 @@ package ipv4
import (
"net"
"syscall"
"time"
"golang.org/x/net/internal/socket"
@ -58,7 +57,7 @@ func (c *dgramOpt) ok() bool { return c != nil && c.Conn != nil }
// SetControlMessage sets the per packet IP-level socket options.
func (c *PacketConn) SetControlMessage(cf ControlFlags, on bool) error {
if !c.payloadHandler.ok() {
return syscall.EINVAL
return errInvalidConn
}
return setControlMessage(c.dgramOpt.Conn, &c.payloadHandler.rawOpt, cf, on)
}
@ -67,7 +66,7 @@ func (c *PacketConn) SetControlMessage(cf ControlFlags, on bool) error {
// endpoint.
func (c *PacketConn) SetDeadline(t time.Time) error {
if !c.payloadHandler.ok() {
return syscall.EINVAL
return errInvalidConn
}
return c.payloadHandler.PacketConn.SetDeadline(t)
}
@ -76,7 +75,7 @@ func (c *PacketConn) SetDeadline(t time.Time) error {
// endpoint.
func (c *PacketConn) SetReadDeadline(t time.Time) error {
if !c.payloadHandler.ok() {
return syscall.EINVAL
return errInvalidConn
}
return c.payloadHandler.PacketConn.SetReadDeadline(t)
}
@ -85,7 +84,7 @@ func (c *PacketConn) SetReadDeadline(t time.Time) error {
// endpoint.
func (c *PacketConn) SetWriteDeadline(t time.Time) error {
if !c.payloadHandler.ok() {
return syscall.EINVAL
return errInvalidConn
}
return c.payloadHandler.PacketConn.SetWriteDeadline(t)
}
@ -93,7 +92,7 @@ func (c *PacketConn) SetWriteDeadline(t time.Time) error {
// Close closes the endpoint.
func (c *PacketConn) Close() error {
if !c.payloadHandler.ok() {
return syscall.EINVAL
return errInvalidConn
}
return c.payloadHandler.PacketConn.Close()
}
@ -124,7 +123,7 @@ type RawConn struct {
// SetControlMessage sets the per packet IP-level socket options.
func (c *RawConn) SetControlMessage(cf ControlFlags, on bool) error {
if !c.packetHandler.ok() {
return syscall.EINVAL
return errInvalidConn
}
return setControlMessage(c.dgramOpt.Conn, &c.packetHandler.rawOpt, cf, on)
}
@ -133,7 +132,7 @@ func (c *RawConn) SetControlMessage(cf ControlFlags, on bool) error {
// endpoint.
func (c *RawConn) SetDeadline(t time.Time) error {
if !c.packetHandler.ok() {
return syscall.EINVAL
return errInvalidConn
}
return c.packetHandler.IPConn.SetDeadline(t)
}
@ -142,7 +141,7 @@ func (c *RawConn) SetDeadline(t time.Time) error {
// endpoint.
func (c *RawConn) SetReadDeadline(t time.Time) error {
if !c.packetHandler.ok() {
return syscall.EINVAL
return errInvalidConn
}
return c.packetHandler.IPConn.SetReadDeadline(t)
}
@ -151,7 +150,7 @@ func (c *RawConn) SetReadDeadline(t time.Time) error {
// endpoint.
func (c *RawConn) SetWriteDeadline(t time.Time) error {
if !c.packetHandler.ok() {
return syscall.EINVAL
return errInvalidConn
}
return c.packetHandler.IPConn.SetWriteDeadline(t)
}
@ -159,7 +158,7 @@ func (c *RawConn) SetWriteDeadline(t time.Time) error {
// Close closes the endpoint.
func (c *RawConn) Close() error {
if !c.packetHandler.ok() {
return syscall.EINVAL
return errInvalidConn
}
return c.packetHandler.IPConn.Close()
}

View file

@ -72,7 +72,7 @@ var registries = []struct {
parse func(io.Writer, io.Reader) error
}{
{
"http://www.iana.org/assignments/icmp-parameters/icmp-parameters.xml",
"https://www.iana.org/assignments/icmp-parameters/icmp-parameters.xml",
parseICMPv4Parameters,
},
}
@ -80,7 +80,7 @@ var registries = []struct {
func geniana() error {
var bb bytes.Buffer
fmt.Fprintf(&bb, "// go generate gen.go\n")
fmt.Fprintf(&bb, "// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n")
fmt.Fprintf(&bb, "// Code generated by the command above; DO NOT EDIT.\n\n")
fmt.Fprintf(&bb, "package ipv4\n\n")
for _, r := range registries {
resp, err := http.Get(r.url)

View file

@ -4,12 +4,10 @@
package ipv4
import "syscall"
// TOS returns the type-of-service field value for outgoing packets.
func (c *genericOpt) TOS() (int, error) {
if !c.ok() {
return 0, syscall.EINVAL
return 0, errInvalidConn
}
so, ok := sockOpts[ssoTOS]
if !ok {
@ -22,7 +20,7 @@ func (c *genericOpt) TOS() (int, error) {
// packets.
func (c *genericOpt) SetTOS(tos int) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoTOS]
if !ok {
@ -34,7 +32,7 @@ func (c *genericOpt) SetTOS(tos int) error {
// TTL returns the time-to-live field value for outgoing packets.
func (c *genericOpt) TTL() (int, error) {
if !c.ok() {
return 0, syscall.EINVAL
return 0, errInvalidConn
}
so, ok := sockOpts[ssoTTL]
if !ok {
@ -47,7 +45,7 @@ func (c *genericOpt) TTL() (int, error) {
// packets.
func (c *genericOpt) SetTTL(ttl int) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoTTL]
if !ok {

View file

@ -9,7 +9,6 @@ import (
"fmt"
"net"
"runtime"
"syscall"
"golang.org/x/net/internal/socket"
)
@ -54,7 +53,7 @@ func (h *Header) String() string {
// Marshal returns the binary encoding of h.
func (h *Header) Marshal() ([]byte, error) {
if h == nil {
return nil, syscall.EINVAL
return nil, errInvalidConn
}
if h.Len < HeaderLen {
return nil, errHeaderTooShort
@ -98,7 +97,7 @@ func (h *Header) Marshal() ([]byte, error) {
return b, nil
}
// Parse parses b as an IPv4 header and sotres the result in h.
// Parse parses b as an IPv4 header and stores the result in h.
func (h *Header) Parse(b []byte) error {
if h == nil || len(b) < HeaderLen {
return errHeaderTooShort

View file

@ -10,6 +10,7 @@ import (
)
var (
errInvalidConn = errors.New("invalid connection")
errMissingAddress = errors.New("missing address")
errMissingHeader = errors.New("missing header")
errHeaderTooShort = errors.New("header too short")

10
vendor/golang.org/x/net/ipv4/iana.go generated vendored
View file

@ -1,9 +1,9 @@
// go generate gen.go
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
// Code generated by the command above; DO NOT EDIT.
package ipv4
// Internet Control Message Protocol (ICMP) Parameters, Updated: 2013-04-19
// Internet Control Message Protocol (ICMP) Parameters, Updated: 2018-02-26
const (
ICMPTypeEchoReply ICMPType = 0 // Echo Reply
ICMPTypeDestinationUnreachable ICMPType = 3 // Destination Unreachable
@ -16,9 +16,11 @@ const (
ICMPTypeTimestamp ICMPType = 13 // Timestamp
ICMPTypeTimestampReply ICMPType = 14 // Timestamp Reply
ICMPTypePhoturis ICMPType = 40 // Photuris
ICMPTypeExtendedEchoRequest ICMPType = 42 // Extended Echo Request
ICMPTypeExtendedEchoReply ICMPType = 43 // Extended Echo Reply
)
// Internet Control Message Protocol (ICMP) Parameters, Updated: 2013-04-19
// Internet Control Message Protocol (ICMP) Parameters, Updated: 2018-02-26
var icmpTypes = map[ICMPType]string{
0: "echo reply",
3: "destination unreachable",
@ -31,4 +33,6 @@ var icmpTypes = map[ICMPType]string{
13: "timestamp",
14: "timestamp reply",
40: "photuris",
42: "extended echo request",
43: "extended echo reply",
}

View file

@ -29,7 +29,7 @@ var packetConnReadWriteMulticastUDPTests = []struct {
func TestPacketConnReadWriteMulticastUDP(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris", "windows":
case "js", "nacl", "plan9", "solaris", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback)
@ -117,7 +117,7 @@ var packetConnReadWriteMulticastICMPTests = []struct {
func TestPacketConnReadWriteMulticastICMP(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "solaris", "windows":
case "js", "nacl", "plan9", "solaris", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if m, ok := nettest.SupportsRawIPSocket(); !ok {

View file

@ -21,7 +21,7 @@ var udpMultipleGroupListenerTests = []net.Addr{
func TestUDPSinglePacketConnWithMultipleGroupListeners(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "js", "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if testing.Short() {
@ -61,7 +61,7 @@ func TestUDPSinglePacketConnWithMultipleGroupListeners(t *testing.T) {
func TestUDPMultiplePacketConnWithMultipleGroupListeners(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "js", "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if testing.Short() {
@ -116,7 +116,7 @@ func TestUDPMultiplePacketConnWithMultipleGroupListeners(t *testing.T) {
func TestUDPPerInterfaceSinglePacketConnWithSingleGroupListener(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "js", "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if testing.Short() {
@ -172,7 +172,7 @@ func TestUDPPerInterfaceSinglePacketConnWithSingleGroupListener(t *testing.T) {
func TestIPSingleRawConnWithSingleGroupListener(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "js", "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if testing.Short() {
@ -217,7 +217,7 @@ func TestIPSingleRawConnWithSingleGroupListener(t *testing.T) {
func TestIPPerInterfaceSingleRawConnWithSingleGroupListener(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "js", "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if testing.Short() {

View file

@ -26,7 +26,7 @@ var packetConnMulticastSocketOptionTests = []struct {
func TestPacketConnMulticastSocketOptions(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9":
case "js", "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagMulticast|net.FlagLoopback)
@ -66,7 +66,7 @@ var rawConnMulticastSocketOptionTests = []struct {
func TestRawConnMulticastSocketOptions(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9":
case "js", "nacl", "plan9":
t.Skipf("not supported on %s", runtime.GOOS)
}
if m, ok := nettest.SupportsRawIPSocket(); !ok {

View file

@ -6,7 +6,6 @@ package ipv4
import (
"net"
"syscall"
"golang.org/x/net/internal/socket"
)
@ -28,7 +27,7 @@ func (c *packetHandler) ok() bool { return c != nil && c.IPConn != nil && c.Conn
// header h, the payload p and the control message cm.
func (c *packetHandler) ReadFrom(b []byte) (h *Header, p []byte, cm *ControlMessage, err error) {
if !c.ok() {
return nil, nil, nil, syscall.EINVAL
return nil, nil, nil, errInvalidConn
}
return c.readFrom(b)
}
@ -63,7 +62,7 @@ func slicePacket(b []byte) (h, p []byte, err error) {
// Options = optional
func (c *packetHandler) WriteTo(h *Header, p []byte, cm *ControlMessage) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
return c.writeTo(h, p, cm)
}

View file

@ -6,10 +6,7 @@
package ipv4
import (
"net"
"syscall"
)
import "net"
// ReadFrom reads a payload of the received IPv4 datagram, from the
// endpoint c, copying the payload into b. It returns the number of
@ -17,7 +14,7 @@ import (
// src of the received datagram.
func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) {
if !c.ok() {
return 0, nil, nil, syscall.EINVAL
return 0, nil, nil, errInvalidConn
}
return c.readFrom(b)
}
@ -30,7 +27,7 @@ func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.
// control of the outgoing datagram is not required.
func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) {
if !c.ok() {
return 0, syscall.EINVAL
return 0, errInvalidConn
}
return c.writeTo(b, cm, dst)
}

View file

@ -6,10 +6,7 @@
package ipv4
import (
"net"
"syscall"
)
import "net"
// ReadFrom reads a payload of the received IPv4 datagram, from the
// endpoint c, copying the payload into b. It returns the number of
@ -17,7 +14,7 @@ import (
// src of the received datagram.
func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.Addr, err error) {
if !c.ok() {
return 0, nil, nil, syscall.EINVAL
return 0, nil, nil, errInvalidConn
}
if n, src, err = c.PacketConn.ReadFrom(b); err != nil {
return 0, nil, nil, err
@ -33,7 +30,7 @@ func (c *payloadHandler) ReadFrom(b []byte) (n int, cm *ControlMessage, src net.
// control of the outgoing datagram is not required.
func (c *payloadHandler) WriteTo(b []byte, cm *ControlMessage, dst net.Addr) (n int, err error) {
if !c.ok() {
return 0, syscall.EINVAL
return 0, errInvalidConn
}
if dst == nil {
return 0, errMissingAddress

View file

@ -22,7 +22,7 @@ import (
func BenchmarkPacketConnReadWriteUnicast(b *testing.B) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "js", "nacl", "plan9", "windows":
b.Skipf("not supported on %s", runtime.GOOS)
}
@ -126,7 +126,7 @@ func BenchmarkPacketConnReadWriteUnicast(b *testing.B) {
func TestPacketConnConcurrentReadWriteUnicast(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "js", "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}

View file

@ -22,7 +22,7 @@ import (
func BenchmarkPacketConnReadWriteUnicast(b *testing.B) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "js", "nacl", "plan9", "windows":
b.Skipf("not supported on %s", runtime.GOOS)
}
@ -172,7 +172,7 @@ func BenchmarkPacketConnReadWriteUnicast(b *testing.B) {
func TestPacketConnConcurrentReadWriteUnicast(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "js", "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}

View file

@ -61,7 +61,7 @@ func BenchmarkReadWriteUnicast(b *testing.B) {
func TestPacketConnConcurrentReadWriteUnicastUDP(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "js", "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}

View file

@ -20,7 +20,7 @@ import (
func TestPacketConnReadWriteUnicastUDP(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "js", "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback)
@ -71,7 +71,7 @@ func TestPacketConnReadWriteUnicastUDP(t *testing.T) {
func TestPacketConnReadWriteUnicastICMP(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "js", "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if m, ok := nettest.SupportsRawIPSocket(); !ok {
@ -157,7 +157,7 @@ func TestPacketConnReadWriteUnicastICMP(t *testing.T) {
func TestRawConnReadWriteUnicastICMP(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "js", "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if m, ok := nettest.SupportsRawIPSocket(); !ok {

View file

@ -16,7 +16,7 @@ import (
func TestConnUnicastSocketOptions(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "js", "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback)
@ -62,7 +62,7 @@ var packetConnUnicastSocketOptionTests = []struct {
func TestPacketConnUnicastSocketOptions(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "js", "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
ifi := nettest.RoutedInterface("ip4", net.FlagUp|net.FlagLoopback)
@ -88,7 +88,7 @@ func TestPacketConnUnicastSocketOptions(t *testing.T) {
func TestRawConnUnicastSocketOptions(t *testing.T) {
switch runtime.GOOS {
case "nacl", "plan9", "windows":
case "js", "nacl", "plan9", "windows":
t.Skipf("not supported on %s", runtime.GOOS)
}
if m, ok := nettest.SupportsRawIPSocket(); !ok {

View file

@ -9,7 +9,6 @@ package ipv6
import (
"net"
"runtime"
"syscall"
"golang.org/x/net/internal/socket"
)
@ -67,7 +66,7 @@ type Message = socket.Message
// On other platforms, this method will read only a single message.
func (c *payloadHandler) ReadBatch(ms []Message, flags int) (int, error) {
if !c.ok() {
return 0, syscall.EINVAL
return 0, errInvalidConn
}
switch runtime.GOOS {
case "linux":
@ -98,7 +97,7 @@ func (c *payloadHandler) ReadBatch(ms []Message, flags int) (int, error) {
// On other platforms, this method will write only a single message.
func (c *payloadHandler) WriteBatch(ms []Message, flags int) (int, error) {
if !c.ok() {
return 0, syscall.EINVAL
return 0, errInvalidConn
}
switch runtime.GOOS {
case "linux":

View file

@ -6,7 +6,6 @@ package ipv6
import (
"net"
"syscall"
"golang.org/x/net/bpf"
)
@ -15,7 +14,7 @@ import (
// multicast packets.
func (c *dgramOpt) MulticastHopLimit() (int, error) {
if !c.ok() {
return 0, syscall.EINVAL
return 0, errInvalidConn
}
so, ok := sockOpts[ssoMulticastHopLimit]
if !ok {
@ -28,7 +27,7 @@ func (c *dgramOpt) MulticastHopLimit() (int, error) {
// outgoing multicast packets.
func (c *dgramOpt) SetMulticastHopLimit(hoplim int) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoMulticastHopLimit]
if !ok {
@ -41,7 +40,7 @@ func (c *dgramOpt) SetMulticastHopLimit(hoplim int) error {
// packet transmissions.
func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
if !c.ok() {
return nil, syscall.EINVAL
return nil, errInvalidConn
}
so, ok := sockOpts[ssoMulticastInterface]
if !ok {
@ -54,7 +53,7 @@ func (c *dgramOpt) MulticastInterface() (*net.Interface, error) {
// multicast packet transmissions.
func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoMulticastInterface]
if !ok {
@ -67,7 +66,7 @@ func (c *dgramOpt) SetMulticastInterface(ifi *net.Interface) error {
// should be copied and send back to the originator.
func (c *dgramOpt) MulticastLoopback() (bool, error) {
if !c.ok() {
return false, syscall.EINVAL
return false, errInvalidConn
}
so, ok := sockOpts[ssoMulticastLoopback]
if !ok {
@ -84,7 +83,7 @@ func (c *dgramOpt) MulticastLoopback() (bool, error) {
// should be copied and send back to the originator.
func (c *dgramOpt) SetMulticastLoopback(on bool) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoMulticastLoopback]
if !ok {
@ -104,7 +103,7 @@ func (c *dgramOpt) SetMulticastLoopback(on bool) error {
// configuration.
func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoJoinGroup]
if !ok {
@ -122,7 +121,7 @@ func (c *dgramOpt) JoinGroup(ifi *net.Interface, group net.Addr) error {
// source-specific group.
func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoLeaveGroup]
if !ok {
@ -143,7 +142,7 @@ func (c *dgramOpt) LeaveGroup(ifi *net.Interface, group net.Addr) error {
// routing configuration.
func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoJoinSourceGroup]
if !ok {
@ -164,7 +163,7 @@ func (c *dgramOpt) JoinSourceSpecificGroup(ifi *net.Interface, group, source net
// interface ifi.
func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoLeaveSourceGroup]
if !ok {
@ -186,7 +185,7 @@ func (c *dgramOpt) LeaveSourceSpecificGroup(ifi *net.Interface, group, source ne
// ifi.
func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoBlockSourceGroup]
if !ok {
@ -207,7 +206,7 @@ func (c *dgramOpt) ExcludeSourceSpecificGroup(ifi *net.Interface, group, source
// group by ExcludeSourceSpecificGroup again on the interface ifi.
func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source net.Addr) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoUnblockSourceGroup]
if !ok {
@ -230,7 +229,7 @@ func (c *dgramOpt) IncludeSourceSpecificGroup(ifi *net.Interface, group, source
// field is located.
func (c *dgramOpt) Checksum() (on bool, offset int, err error) {
if !c.ok() {
return false, 0, syscall.EINVAL
return false, 0, errInvalidConn
}
so, ok := sockOpts[ssoChecksum]
if !ok {
@ -251,7 +250,7 @@ func (c *dgramOpt) Checksum() (on bool, offset int, err error) {
// checksum field is located.
func (c *dgramOpt) SetChecksum(on bool, offset int) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoChecksum]
if !ok {
@ -266,7 +265,7 @@ func (c *dgramOpt) SetChecksum(on bool, offset int) error {
// ICMPFilter returns an ICMP filter.
func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) {
if !c.ok() {
return nil, syscall.EINVAL
return nil, errInvalidConn
}
so, ok := sockOpts[ssoICMPFilter]
if !ok {
@ -278,7 +277,7 @@ func (c *dgramOpt) ICMPFilter() (*ICMPFilter, error) {
// SetICMPFilter deploys the ICMP filter.
func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoICMPFilter]
if !ok {
@ -292,7 +291,7 @@ func (c *dgramOpt) SetICMPFilter(f *ICMPFilter) error {
// Only supported on Linux.
func (c *dgramOpt) SetBPF(filter []bpf.RawInstruction) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoAttachFilter]
if !ok {

View file

@ -240,4 +240,4 @@
// IncludeSourceSpecificGroup may return an error.
package ipv6 // import "golang.org/x/net/ipv6"
// BUG(mikio): This package is not implemented on NaCl and Plan 9.
// BUG(mikio): This package is not implemented on JS, NaCl and Plan 9.

View file

@ -6,7 +6,6 @@ package ipv6
import (
"net"
"syscall"
"time"
"golang.org/x/net/internal/socket"
@ -34,7 +33,7 @@ func (c *genericOpt) ok() bool { return c != nil && c.Conn != nil }
// with the endpoint.
func (c *Conn) PathMTU() (int, error) {
if !c.ok() {
return 0, syscall.EINVAL
return 0, errInvalidConn
}
so, ok := sockOpts[ssoPathMTU]
if !ok {
@ -76,7 +75,7 @@ func (c *dgramOpt) ok() bool { return c != nil && c.Conn != nil }
// socket options.
func (c *PacketConn) SetControlMessage(cf ControlFlags, on bool) error {
if !c.payloadHandler.ok() {
return syscall.EINVAL
return errInvalidConn
}
return setControlMessage(c.dgramOpt.Conn, &c.payloadHandler.rawOpt, cf, on)
}
@ -85,7 +84,7 @@ func (c *PacketConn) SetControlMessage(cf ControlFlags, on bool) error {
// endpoint.
func (c *PacketConn) SetDeadline(t time.Time) error {
if !c.payloadHandler.ok() {
return syscall.EINVAL
return errInvalidConn
}
return c.payloadHandler.SetDeadline(t)
}
@ -94,7 +93,7 @@ func (c *PacketConn) SetDeadline(t time.Time) error {
// endpoint.
func (c *PacketConn) SetReadDeadline(t time.Time) error {
if !c.payloadHandler.ok() {
return syscall.EINVAL
return errInvalidConn
}
return c.payloadHandler.SetReadDeadline(t)
}
@ -103,7 +102,7 @@ func (c *PacketConn) SetReadDeadline(t time.Time) error {
// endpoint.
func (c *PacketConn) SetWriteDeadline(t time.Time) error {
if !c.payloadHandler.ok() {
return syscall.EINVAL
return errInvalidConn
}
return c.payloadHandler.SetWriteDeadline(t)
}
@ -111,7 +110,7 @@ func (c *PacketConn) SetWriteDeadline(t time.Time) error {
// Close closes the endpoint.
func (c *PacketConn) Close() error {
if !c.payloadHandler.ok() {
return syscall.EINVAL
return errInvalidConn
}
return c.payloadHandler.Close()
}

View file

@ -72,7 +72,7 @@ var registries = []struct {
parse func(io.Writer, io.Reader) error
}{
{
"http://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xml",
"https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xml",
parseICMPv6Parameters,
},
}
@ -80,7 +80,7 @@ var registries = []struct {
func geniana() error {
var bb bytes.Buffer
fmt.Fprintf(&bb, "// go generate gen.go\n")
fmt.Fprintf(&bb, "// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT\n\n")
fmt.Fprintf(&bb, "// Code generated by the command above; DO NOT EDIT.\n\n")
fmt.Fprintf(&bb, "package ipv6\n\n")
for _, r := range registries {
resp, err := http.Get(r.url)

View file

@ -4,13 +4,11 @@
package ipv6
import "syscall"
// TrafficClass returns the traffic class field value for outgoing
// packets.
func (c *genericOpt) TrafficClass() (int, error) {
if !c.ok() {
return 0, syscall.EINVAL
return 0, errInvalidConn
}
so, ok := sockOpts[ssoTrafficClass]
if !ok {
@ -23,7 +21,7 @@ func (c *genericOpt) TrafficClass() (int, error) {
// outgoing packets.
func (c *genericOpt) SetTrafficClass(tclass int) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoTrafficClass]
if !ok {
@ -35,7 +33,7 @@ func (c *genericOpt) SetTrafficClass(tclass int) error {
// HopLimit returns the hop limit field value for outgoing packets.
func (c *genericOpt) HopLimit() (int, error) {
if !c.ok() {
return 0, syscall.EINVAL
return 0, errInvalidConn
}
so, ok := sockOpts[ssoHopLimit]
if !ok {
@ -48,7 +46,7 @@ func (c *genericOpt) HopLimit() (int, error) {
// packets.
func (c *genericOpt) SetHopLimit(hoplim int) error {
if !c.ok() {
return syscall.EINVAL
return errInvalidConn
}
so, ok := sockOpts[ssoHopLimit]
if !ok {

View file

@ -10,6 +10,7 @@ import (
)
var (
errInvalidConn = errors.New("invalid connection")
errMissingAddress = errors.New("missing address")
errHeaderTooShort = errors.New("header too short")
errInvalidConnType = errors.New("invalid conn type")

10
vendor/golang.org/x/net/ipv6/iana.go generated vendored
View file

@ -1,9 +1,9 @@
// go generate gen.go
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
// Code generated by the command above; DO NOT EDIT.
package ipv6
// Internet Control Message Protocol version 6 (ICMPv6) Parameters, Updated: 2015-07-07
// Internet Control Message Protocol version 6 (ICMPv6) Parameters, Updated: 2018-03-09
const (
ICMPTypeDestinationUnreachable ICMPType = 1 // Destination Unreachable
ICMPTypePacketTooBig ICMPType = 2 // Packet Too Big
@ -40,9 +40,11 @@ const (
ICMPTypeDuplicateAddressRequest ICMPType = 157 // Duplicate Address Request
ICMPTypeDuplicateAddressConfirmation ICMPType = 158 // Duplicate Address Confirmation
ICMPTypeMPLControl ICMPType = 159 // MPL Control Message
ICMPTypeExtendedEchoRequest ICMPType = 160 // Extended Echo Request
ICMPTypeExtendedEchoReply ICMPType = 161 // Extended Echo Reply
)
// Internet Control Message Protocol version 6 (ICMPv6) Parameters, Updated: 2015-07-07
// Internet Control Message Protocol version 6 (ICMPv6) Parameters, Updated: 2018-03-09
var icmpTypes = map[ICMPType]string{
1: "destination unreachable",
2: "packet too big",
@ -79,4 +81,6 @@ var icmpTypes = map[ICMPType]string{
157: "duplicate address request",
158: "duplicate address confirmation",
159: "mpl control message",
160: "extended echo request",
161: "extended echo reply",
}

Some files were not shown because too many files have changed in this diff Show more