Browse Source

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
Mikio Hara 12 years ago
parent
commit
da09de3034
3 changed files with 52 additions and 8 deletions
  1. 24 6
      ipv6/mockicmp_test.go
  2. 14 1
      ipv6/multicast_test.go
  3. 14 1
      ipv6/unicast_test.go

+ 24 - 6
ipv6/mockicmp_test.go

@@ -7,8 +7,22 @@ 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
@@ -25,8 +39,11 @@ type icmpMessageBody interface {
 
 // Marshal returns the binary enconding of the ICMP echo request or
 // 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}
+	if psh != nil {
+		b = append(psh, b...)
+	}
 	if m.Body != nil && m.Body.Len() != 0 {
 		mb, err := m.Body.Marshal()
 		if err != nil {
@@ -34,10 +51,11 @@ func (m *icmpMessage) Marshal() ([]byte, error) {
 		}
 		b = append(b, mb...)
 	}
-	switch m.Type {
-	case ipv6.ICMPTypeEchoRequest, ipv6.ICMPTypeEchoReply:
+	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 {
@@ -50,9 +68,9 @@ func (m *icmpMessage) Marshal() ([]byte, error) {
 	s = s + s>>16
 	// Place checksum back in header; using ^= avoids the
 	// assumption the checksum bytes are zero.
-	b[2] ^= byte(^s)
-	b[3] ^= byte(^s >> 8)
-	return b, nil
+	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.

+ 14 - 1
ipv6/multicast_test.go

@@ -104,6 +104,7 @@ func TestPacketConnReadWriteMulticastICMP(t *testing.T) {
 		t.Fatalf("net.ResolveIPAddr failed: %v", err)
 	}
 
+	pshicmp := ipv6PseudoHeader(c.LocalAddr().(*net.IPAddr).IP, dst.IP, ianaProtocolIPv6ICMP)
 	p := ipv6.NewPacketConn(c)
 	if err := p.JoinGroup(ifi, dst); err != nil {
 		t.Fatalf("ipv6.PacketConn.JoinGroup on %v failed: %v", ifi, err)
@@ -128,14 +129,26 @@ func TestPacketConnReadWriteMulticastICMP(t *testing.T) {
 		t.Fatalf("ipv6.PacketConn.SetICMPFilter failed: %v", err)
 	}
 
+	var psh []byte
 	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{
 			Type: ipv6.ICMPTypeEchoRequest, Code: 0,
 			Body: &icmpEcho{
 				ID: os.Getpid() & 0xffff, Seq: i + 1,
 				Data: []byte("HELLO-R-U-THERE"),
 			},
-		}).Marshal()
+		}).Marshal(psh)
 		if err != nil {
 			t.Fatalf("icmpMessage.Marshal failed: %v", err)
 		}

+ 14 - 1
ipv6/unicast_test.go

@@ -155,6 +155,7 @@ func TestPacketConnReadWriteUnicastICMP(t *testing.T) {
 		t.Fatalf("net.ResolveIPAddr failed: %v", err)
 	}
 
+	pshicmp := ipv6PseudoHeader(c.LocalAddr().(*net.IPAddr).IP, dst.IP, ianaProtocolIPv6ICMP)
 	p := ipv6.NewPacketConn(c)
 	cm := ipv6.ControlMessage{TrafficClass: DiffServAF11 | CongestionExperienced}
 	cf := ipv6.FlagTrafficClass | ipv6.FlagHopLimit | ipv6.FlagInterface | ipv6.FlagPathMTU
@@ -170,14 +171,26 @@ func TestPacketConnReadWriteUnicastICMP(t *testing.T) {
 		t.Fatalf("ipv6.PacketConn.SetICMPFilter failed: %v", err)
 	}
 
+	var psh []byte
 	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{
 			Type: ipv6.ICMPTypeEchoRequest, Code: 0,
 			Body: &icmpEcho{
 				ID: os.Getpid() & 0xffff, Seq: i + 1,
 				Data: []byte("HELLO-R-U-THERE"),
 			},
-		}).Marshal()
+		}).Marshal(psh)
 		if err != nil {
 			t.Fatalf("icmpMessage.Marshal failed: %v", err)
 		}