github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/icmp/echo.go (about)

     1  // Copyright 2012 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package icmp
     6  
     7  import (
     8  	"encoding/binary"
     9  
    10  	"github.com/Andyfoo/golang/x/net/internal/iana"
    11  	"github.com/Andyfoo/golang/x/net/ipv4"
    12  	"github.com/Andyfoo/golang/x/net/ipv6"
    13  )
    14  
    15  // An Echo represents an ICMP echo request or reply message body.
    16  type Echo struct {
    17  	ID   int    // identifier
    18  	Seq  int    // sequence number
    19  	Data []byte // data
    20  }
    21  
    22  // Len implements the Len method of MessageBody interface.
    23  func (p *Echo) Len(proto int) int {
    24  	if p == nil {
    25  		return 0
    26  	}
    27  	return 4 + len(p.Data)
    28  }
    29  
    30  // Marshal implements the Marshal method of MessageBody interface.
    31  func (p *Echo) Marshal(proto int) ([]byte, error) {
    32  	b := make([]byte, 4+len(p.Data))
    33  	binary.BigEndian.PutUint16(b[:2], uint16(p.ID))
    34  	binary.BigEndian.PutUint16(b[2:4], uint16(p.Seq))
    35  	copy(b[4:], p.Data)
    36  	return b, nil
    37  }
    38  
    39  // parseEcho parses b as an ICMP echo request or reply message body.
    40  func parseEcho(proto int, _ Type, b []byte) (MessageBody, error) {
    41  	bodyLen := len(b)
    42  	if bodyLen < 4 {
    43  		return nil, errMessageTooShort
    44  	}
    45  	p := &Echo{ID: int(binary.BigEndian.Uint16(b[:2])), Seq: int(binary.BigEndian.Uint16(b[2:4]))}
    46  	if bodyLen > 4 {
    47  		p.Data = make([]byte, bodyLen-4)
    48  		copy(p.Data, b[4:])
    49  	}
    50  	return p, nil
    51  }
    52  
    53  // An ExtendedEchoRequest represents an ICMP extended echo request
    54  // message body.
    55  type ExtendedEchoRequest struct {
    56  	ID         int         // identifier
    57  	Seq        int         // sequence number
    58  	Local      bool        // must be true when identifying by name or index
    59  	Extensions []Extension // extensions
    60  }
    61  
    62  // Len implements the Len method of MessageBody interface.
    63  func (p *ExtendedEchoRequest) Len(proto int) int {
    64  	if p == nil {
    65  		return 0
    66  	}
    67  	l, _ := multipartMessageBodyDataLen(proto, false, nil, p.Extensions)
    68  	return l
    69  }
    70  
    71  // Marshal implements the Marshal method of MessageBody interface.
    72  func (p *ExtendedEchoRequest) Marshal(proto int) ([]byte, error) {
    73  	var typ Type
    74  	switch proto {
    75  	case iana.ProtocolICMP:
    76  		typ = ipv4.ICMPTypeExtendedEchoRequest
    77  	case iana.ProtocolIPv6ICMP:
    78  		typ = ipv6.ICMPTypeExtendedEchoRequest
    79  	default:
    80  		return nil, errInvalidProtocol
    81  	}
    82  	if !validExtensions(typ, p.Extensions) {
    83  		return nil, errInvalidExtension
    84  	}
    85  	b, err := marshalMultipartMessageBody(proto, false, nil, p.Extensions)
    86  	if err != nil {
    87  		return nil, err
    88  	}
    89  	binary.BigEndian.PutUint16(b[:2], uint16(p.ID))
    90  	b[2] = byte(p.Seq)
    91  	if p.Local {
    92  		b[3] |= 0x01
    93  	}
    94  	return b, nil
    95  }
    96  
    97  // parseExtendedEchoRequest parses b as an ICMP extended echo request
    98  // message body.
    99  func parseExtendedEchoRequest(proto int, typ Type, b []byte) (MessageBody, error) {
   100  	if len(b) < 4 {
   101  		return nil, errMessageTooShort
   102  	}
   103  	p := &ExtendedEchoRequest{ID: int(binary.BigEndian.Uint16(b[:2])), Seq: int(b[2])}
   104  	if b[3]&0x01 != 0 {
   105  		p.Local = true
   106  	}
   107  	var err error
   108  	_, p.Extensions, err = parseMultipartMessageBody(proto, typ, b)
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  	return p, nil
   113  }
   114  
   115  // An ExtendedEchoReply represents an ICMP extended echo reply message
   116  // body.
   117  type ExtendedEchoReply struct {
   118  	ID     int  // identifier
   119  	Seq    int  // sequence number
   120  	State  int  // 3-bit state working together with Message.Code
   121  	Active bool // probed interface is active
   122  	IPv4   bool // probed interface runs IPv4
   123  	IPv6   bool // probed interface runs IPv6
   124  }
   125  
   126  // Len implements the Len method of MessageBody interface.
   127  func (p *ExtendedEchoReply) Len(proto int) int {
   128  	if p == nil {
   129  		return 0
   130  	}
   131  	return 4
   132  }
   133  
   134  // Marshal implements the Marshal method of MessageBody interface.
   135  func (p *ExtendedEchoReply) Marshal(proto int) ([]byte, error) {
   136  	b := make([]byte, 4)
   137  	binary.BigEndian.PutUint16(b[:2], uint16(p.ID))
   138  	b[2] = byte(p.Seq)
   139  	b[3] = byte(p.State<<5) & 0xe0
   140  	if p.Active {
   141  		b[3] |= 0x04
   142  	}
   143  	if p.IPv4 {
   144  		b[3] |= 0x02
   145  	}
   146  	if p.IPv6 {
   147  		b[3] |= 0x01
   148  	}
   149  	return b, nil
   150  }
   151  
   152  // parseExtendedEchoReply parses b as an ICMP extended echo reply
   153  // message body.
   154  func parseExtendedEchoReply(proto int, _ Type, b []byte) (MessageBody, error) {
   155  	if len(b) < 4 {
   156  		return nil, errMessageTooShort
   157  	}
   158  	p := &ExtendedEchoReply{
   159  		ID:    int(binary.BigEndian.Uint16(b[:2])),
   160  		Seq:   int(b[2]),
   161  		State: int(b[3]) >> 5,
   162  	}
   163  	if b[3]&0x04 != 0 {
   164  		p.Active = true
   165  	}
   166  	if b[3]&0x02 != 0 {
   167  		p.IPv4 = true
   168  	}
   169  	if b[3]&0x01 != 0 {
   170  		p.IPv6 = true
   171  	}
   172  	return p, nil
   173  }