| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- // 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 ipv4_test
- import (
- "code.google.com/p/go.net/ipv4"
- "errors"
- "flag"
- )
- var testExternal = flag.Bool("external", true, "allow use of external networks during long test")
- // icmpMessage represents an ICMP message.
- type icmpMessage struct {
- Type ipv4.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() ([]byte, error) {
- b := []byte{byte(m.Type), byte(m.Code), 0, 0}
- if m.Body != nil && m.Body.Len() != 0 {
- mb, err := m.Body.Marshal()
- if err != nil {
- return nil, err
- }
- b = append(b, mb...)
- }
- 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[2] ^= byte(^s & 0xff)
- b[3] ^= byte(^s >> 8)
- return b, 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: ipv4.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 ipv4.ICMPTypeEcho, ipv4.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&0xff)
- b[2], b[3] = byte(p.Seq>>8), byte(p.Seq&0xff)
- 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
- }
|