Commit da09de30 authored by Mikio Hara's avatar Mikio Hara

go.net/ipv6: add ICMP checksum test

This CL enables testing raw ICMP packets with and without a setting of
ICMP checksum field.

Actually it's just for Linux because almost all BSD variants never
allow us to touch the checksum field of ICMP but Linux does when we use
the value 255 for the socket level.

R=golang-dev, dave
CC=golang-dev
https://golang.org/cl/15020047
parent a62ee055
...@@ -7,8 +7,22 @@ package ipv6_test ...@@ -7,8 +7,22 @@ package ipv6_test
import ( import (
"code.google.com/p/go.net/ipv6" "code.google.com/p/go.net/ipv6"
"errors" "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. // icmpMessage represents an ICMP message.
type icmpMessage struct { type icmpMessage struct {
Type ipv6.ICMPType // type Type ipv6.ICMPType // type
...@@ -25,8 +39,11 @@ type icmpMessageBody interface { ...@@ -25,8 +39,11 @@ type icmpMessageBody interface {
// Marshal returns the binary enconding of the ICMP echo request or // Marshal returns the binary enconding of the ICMP echo request or
// reply message m. // reply message m.
func (m *icmpMessage) Marshal() ([]byte, error) { func (m *icmpMessage) Marshal(psh []byte) ([]byte, error) {
b := []byte{byte(m.Type), byte(m.Code), 0, 0} 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 { if m.Body != nil && m.Body.Len() != 0 {
mb, err := m.Body.Marshal() mb, err := m.Body.Marshal()
if err != nil { if err != nil {
...@@ -34,10 +51,11 @@ func (m *icmpMessage) Marshal() ([]byte, error) { ...@@ -34,10 +51,11 @@ func (m *icmpMessage) Marshal() ([]byte, error) {
} }
b = append(b, mb...) b = append(b, mb...)
} }
switch m.Type { if psh == nil {
case ipv6.ICMPTypeEchoRequest, ipv6.ICMPTypeEchoReply:
return b, 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 csumcv := len(b) - 1 // checksum coverage
s := uint32(0) s := uint32(0)
for i := 0; i < csumcv; i += 2 { for i := 0; i < csumcv; i += 2 {
...@@ -50,9 +68,9 @@ func (m *icmpMessage) Marshal() ([]byte, error) { ...@@ -50,9 +68,9 @@ func (m *icmpMessage) Marshal() ([]byte, error) {
s = s + s>>16 s = s + s>>16
// Place checksum back in header; using ^= avoids the // Place checksum back in header; using ^= avoids the
// assumption the checksum bytes are zero. // assumption the checksum bytes are zero.
b[2] ^= byte(^s) b[len(psh)+2] ^= byte(^s)
b[3] ^= byte(^s >> 8) b[len(psh)+3] ^= byte(^s >> 8)
return b, nil return b[len(psh):], nil
} }
// parseICMPMessage parses b as an ICMP message. // parseICMPMessage parses b as an ICMP message.
......
...@@ -104,6 +104,7 @@ func TestPacketConnReadWriteMulticastICMP(t *testing.T) { ...@@ -104,6 +104,7 @@ func TestPacketConnReadWriteMulticastICMP(t *testing.T) {
t.Fatalf("net.ResolveIPAddr failed: %v", err) t.Fatalf("net.ResolveIPAddr failed: %v", err)
} }
pshicmp := ipv6PseudoHeader(c.LocalAddr().(*net.IPAddr).IP, dst.IP, ianaProtocolIPv6ICMP)
p := ipv6.NewPacketConn(c) p := ipv6.NewPacketConn(c)
if err := p.JoinGroup(ifi, dst); err != nil { if err := p.JoinGroup(ifi, dst); err != nil {
t.Fatalf("ipv6.PacketConn.JoinGroup on %v failed: %v", ifi, err) t.Fatalf("ipv6.PacketConn.JoinGroup on %v failed: %v", ifi, err)
...@@ -128,14 +129,26 @@ func TestPacketConnReadWriteMulticastICMP(t *testing.T) { ...@@ -128,14 +129,26 @@ func TestPacketConnReadWriteMulticastICMP(t *testing.T) {
t.Fatalf("ipv6.PacketConn.SetICMPFilter failed: %v", err) t.Fatalf("ipv6.PacketConn.SetICMPFilter failed: %v", err)
} }
var psh []byte
for i, toggle := range []bool{true, false, true} { for i, toggle := range []bool{true, false, true} {
if toggle {
psh = nil
if err := p.SetChecksum(true, 2); err != nil {
t.Fatalf("ipv6.PacketConn.SetChecksum failed: %v", err)
}
} else {
psh = pshicmp
// Some platforms never allow to disable the
// kernel checksum processing.
p.SetChecksum(false, -1)
}
wb, err := (&icmpMessage{ wb, err := (&icmpMessage{
Type: ipv6.ICMPTypeEchoRequest, Code: 0, Type: ipv6.ICMPTypeEchoRequest, Code: 0,
Body: &icmpEcho{ Body: &icmpEcho{
ID: os.Getpid() & 0xffff, Seq: i + 1, ID: os.Getpid() & 0xffff, Seq: i + 1,
Data: []byte("HELLO-R-U-THERE"), Data: []byte("HELLO-R-U-THERE"),
}, },
}).Marshal() }).Marshal(psh)
if err != nil { if err != nil {
t.Fatalf("icmpMessage.Marshal failed: %v", err) t.Fatalf("icmpMessage.Marshal failed: %v", err)
} }
......
...@@ -155,6 +155,7 @@ func TestPacketConnReadWriteUnicastICMP(t *testing.T) { ...@@ -155,6 +155,7 @@ func TestPacketConnReadWriteUnicastICMP(t *testing.T) {
t.Fatalf("net.ResolveIPAddr failed: %v", err) t.Fatalf("net.ResolveIPAddr failed: %v", err)
} }
pshicmp := ipv6PseudoHeader(c.LocalAddr().(*net.IPAddr).IP, dst.IP, ianaProtocolIPv6ICMP)
p := ipv6.NewPacketConn(c) p := ipv6.NewPacketConn(c)
cm := ipv6.ControlMessage{TrafficClass: DiffServAF11 | CongestionExperienced} cm := ipv6.ControlMessage{TrafficClass: DiffServAF11 | CongestionExperienced}
cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagInterface | ipv6.FlagPathMTU cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagInterface | ipv6.FlagPathMTU
...@@ -170,14 +171,26 @@ func TestPacketConnReadWriteUnicastICMP(t *testing.T) { ...@@ -170,14 +171,26 @@ func TestPacketConnReadWriteUnicastICMP(t *testing.T) {
t.Fatalf("ipv6.PacketConn.SetICMPFilter failed: %v", err) t.Fatalf("ipv6.PacketConn.SetICMPFilter failed: %v", err)
} }
var psh []byte
for i, toggle := range []bool{true, false, true} { for i, toggle := range []bool{true, false, true} {
if toggle {
psh = nil
if err := p.SetChecksum(true, 2); err != nil {
t.Fatalf("ipv6.PacketConn.SetChecksum failed: %v", err)
}
} else {
psh = pshicmp
// Some platforms never allow to disable the
// kernel checksum processing.
p.SetChecksum(false, -1)
}
wb, err := (&icmpMessage{ wb, err := (&icmpMessage{
Type: ipv6.ICMPTypeEchoRequest, Code: 0, Type: ipv6.ICMPTypeEchoRequest, Code: 0,
Body: &icmpEcho{ Body: &icmpEcho{
ID: os.Getpid() & 0xffff, Seq: i + 1, ID: os.Getpid() & 0xffff, Seq: i + 1,
Data: []byte("HELLO-R-U-THERE"), Data: []byte("HELLO-R-U-THERE"),
}, },
}).Marshal() }).Marshal(psh)
if err != nil { if err != nil {
t.Fatalf("icmpMessage.Marshal failed: %v", err) t.Fatalf("icmpMessage.Marshal failed: %v", err)
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment