123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- // Copyright 2015 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package icmp
- import (
- "encoding/binary"
- "golang.org/x/net/ipv4"
- "golang.org/x/net/ipv6"
- )
- // An Extension represents an ICMP extension.
- type Extension interface {
- // Len returns the length of ICMP extension.
- // The provided proto must be either the ICMPv4 or ICMPv6
- // protocol number.
- Len(proto int) int
- // Marshal returns the binary encoding of ICMP extension.
- // The provided proto must be either the ICMPv4 or ICMPv6
- // protocol number.
- Marshal(proto int) ([]byte, error)
- }
- const extensionVersion = 2
- func validExtensionHeader(b []byte) bool {
- v := int(b[0]&0xf0) >> 4
- s := binary.BigEndian.Uint16(b[2:4])
- if s != 0 {
- s = checksum(b)
- }
- if v != extensionVersion || s != 0 {
- return false
- }
- return true
- }
- // parseExtensions parses b as a list of ICMP extensions.
- // The length attribute l must be the length attribute field in
- // received icmp messages.
- //
- // 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(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.
- //
- // A minimal extension at least requires 8 octets; 4 octets
- // for an extension header, and 4 octets for a single object
- // header.
- //
- // See RFC 4884 for further information.
- switch typ {
- case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest:
- if len(b) < 8 || !validExtensionHeader(b) {
- return nil, -1, errNoExtension
- }
- 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; {
- ol := int(binary.BigEndian.Uint16(b[:2]))
- if 4 > ol || ol > len(b) {
- break
- }
- switch b[2] {
- case classMPLSLabelStack:
- ext, err := parseMPLSLabelStack(b[:ol])
- if err != nil {
- return nil, -1, err
- }
- exts = append(exts, ext)
- case classInterfaceInfo:
- ext, err := parseInterfaceInfo(b[:ol])
- if err != nil {
- 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)
- default:
- ext := &RawExtension{Data: make([]byte, ol)}
- copy(ext.Data, b[:ol])
- exts = append(exts, ext)
- }
- b = b[ol:]
- }
- return exts, l, nil
- }
- func validExtensions(typ Type, exts []Extension) bool {
- switch typ {
- case ipv4.ICMPTypeDestinationUnreachable, ipv4.ICMPTypeTimeExceeded, ipv4.ICMPTypeParameterProblem,
- ipv6.ICMPTypeDestinationUnreachable, ipv6.ICMPTypeTimeExceeded:
- for i := range exts {
- switch exts[i].(type) {
- case *MPLSLabelStack, *InterfaceInfo, *RawExtension:
- default:
- return false
- }
- }
- return true
- case ipv4.ICMPTypeExtendedEchoRequest, ipv6.ICMPTypeExtendedEchoRequest:
- var n int
- for i := range exts {
- switch exts[i].(type) {
- case *InterfaceIdent:
- n++
- case *RawExtension:
- default:
- return false
- }
- }
- // Not a single InterfaceIdent object or a combo of
- // RawExtension and InterfaceIdent objects is not
- // allowed.
- if n == 1 && len(exts) > 1 {
- return false
- }
- return true
- default:
- return false
- }
- }
- // A RawExtension represents a raw extension.
- //
- // A raw extension is excluded from message processing and can be used
- // to construct applications such as protocol conformance testing.
- type RawExtension struct {
- Data []byte // data
- }
- // Len implements the Len method of Extension interface.
- func (p *RawExtension) Len(proto int) int {
- if p == nil {
- return 0
- }
- return len(p.Data)
- }
- // Marshal implements the Marshal method of Extension interface.
- func (p *RawExtension) Marshal(proto int) ([]byte, error) {
- return p.Data, nil
- }
|