mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
131 lines
3.1 KiB
Go
131 lines
3.1 KiB
Go
// Copyright 2013 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package ipv6_test
|
|
|
|
import (
|
|
"code.google.com/p/go.net/ipv6"
|
|
"errors"
|
|
"net"
|
|
)
|
|
|
|
const (
|
|
ipv6PseudoHeaderLen = 2*net.IPv6len + 8
|
|
ianaProtocolIPv6ICMP = 58
|
|
)
|
|
|
|
func ipv6PseudoHeader(src, dst net.IP, nextHeader int) []byte {
|
|
b := make([]byte, ipv6PseudoHeaderLen)
|
|
copy(b[:net.IPv6len], src)
|
|
copy(b[net.IPv6len:], dst)
|
|
b[len(b)-1] = byte(nextHeader)
|
|
return b
|
|
}
|
|
|
|
// icmpMessage represents an ICMP message.
|
|
type icmpMessage struct {
|
|
Type ipv6.ICMPType // type
|
|
Code int // code
|
|
Checksum int // checksum
|
|
Body icmpMessageBody // body
|
|
}
|
|
|
|
// icmpMessageBody represents an ICMP message body.
|
|
type icmpMessageBody interface {
|
|
Len() int
|
|
Marshal() ([]byte, error)
|
|
}
|
|
|
|
// Marshal returns the binary enconding of the ICMP echo request or
|
|
// reply message m.
|
|
func (m *icmpMessage) Marshal(psh []byte) ([]byte, error) {
|
|
b := []byte{byte(m.Type), byte(m.Code), 0, 0}
|
|
if psh != nil {
|
|
b = append(psh, b...)
|
|
}
|
|
if m.Body != nil && m.Body.Len() != 0 {
|
|
mb, err := m.Body.Marshal()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
b = append(b, mb...)
|
|
}
|
|
if psh == nil {
|
|
return b, nil
|
|
}
|
|
off, l := 2*net.IPv6len, len(b)-len(psh)
|
|
b[off], b[off+1], b[off+2], b[off+3] = byte(l>>24), byte(l>>16), byte(l>>8), byte(l)
|
|
csumcv := len(b) - 1 // checksum coverage
|
|
s := uint32(0)
|
|
for i := 0; i < csumcv; i += 2 {
|
|
s += uint32(b[i+1])<<8 | uint32(b[i])
|
|
}
|
|
if csumcv&1 == 0 {
|
|
s += uint32(b[csumcv])
|
|
}
|
|
s = s>>16 + s&0xffff
|
|
s = s + s>>16
|
|
// Place checksum back in header; using ^= avoids the
|
|
// assumption the checksum bytes are zero.
|
|
b[len(psh)+2] ^= byte(^s)
|
|
b[len(psh)+3] ^= byte(^s >> 8)
|
|
return b[len(psh):], nil
|
|
}
|
|
|
|
// parseICMPMessage parses b as an ICMP message.
|
|
func parseICMPMessage(b []byte) (*icmpMessage, error) {
|
|
msglen := len(b)
|
|
if msglen < 4 {
|
|
return nil, errors.New("message too short")
|
|
}
|
|
m := &icmpMessage{Type: ipv6.ICMPType(b[0]), Code: int(b[1]), Checksum: int(b[2])<<8 | int(b[3])}
|
|
if msglen > 4 {
|
|
var err error
|
|
switch m.Type {
|
|
case ipv6.ICMPTypeEchoRequest, ipv6.ICMPTypeEchoReply:
|
|
m.Body, err = parseICMPEcho(b[4:])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
}
|
|
return m, nil
|
|
}
|
|
|
|
// imcpEcho represenets an ICMP echo request or reply message body.
|
|
type icmpEcho struct {
|
|
ID int // identifier
|
|
Seq int // sequence number
|
|
Data []byte // data
|
|
}
|
|
|
|
func (p *icmpEcho) Len() int {
|
|
if p == nil {
|
|
return 0
|
|
}
|
|
return 4 + len(p.Data)
|
|
}
|
|
|
|
// Marshal returns the binary enconding of the ICMP echo request or
|
|
// reply message body p.
|
|
func (p *icmpEcho) Marshal() ([]byte, error) {
|
|
b := make([]byte, 4+len(p.Data))
|
|
b[0], b[1] = byte(p.ID>>8), byte(p.ID)
|
|
b[2], b[3] = byte(p.Seq>>8), byte(p.Seq)
|
|
copy(b[4:], p.Data)
|
|
return b, nil
|
|
}
|
|
|
|
// parseICMPEcho parses b as an ICMP echo request or reply message
|
|
// body.
|
|
func parseICMPEcho(b []byte) (*icmpEcho, error) {
|
|
bodylen := len(b)
|
|
p := &icmpEcho{ID: int(b[0])<<8 | int(b[1]), Seq: int(b[2])<<8 | int(b[3])}
|
|
if bodylen > 4 {
|
|
p.Data = make([]byte, bodylen-4)
|
|
copy(p.Data, b[4:])
|
|
}
|
|
return p, nil
|
|
}
|