echo.go 3.92 KB
Newer Older
zhangweiwei's avatar
init  
zhangweiwei committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
// Copyright 2012 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"

// An Echo represents an ICMP echo request or reply message body.
type Echo struct {
	ID   int    // identifier
	Seq  int    // sequence number
	Data []byte // data
}

// Len implements the Len method of MessageBody interface.
func (p *Echo) Len(proto int) int {
	if p == nil {
		return 0
	}
	return 4 + len(p.Data)
}

// Marshal implements the Marshal method of MessageBody interface.
func (p *Echo) Marshal(proto int) ([]byte, error) {
	b := make([]byte, 4+len(p.Data))
	binary.BigEndian.PutUint16(b[:2], uint16(p.ID))
	binary.BigEndian.PutUint16(b[2:4], uint16(p.Seq))
	copy(b[4:], p.Data)
	return b, nil
}

// parseEcho parses b as an ICMP echo request or reply message body.
func parseEcho(proto int, _ Type, b []byte) (MessageBody, error) {
	bodyLen := len(b)
	if bodyLen < 4 {
		return nil, errMessageTooShort
	}
	p := &Echo{ID: int(binary.BigEndian.Uint16(b[:2])), Seq: int(binary.BigEndian.Uint16(b[2:4]))}
	if bodyLen > 4 {
		p.Data = make([]byte, bodyLen-4)
		copy(p.Data, b[4:])
	}
	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
}