Browse Source

go.net/ipv4: handle total length field correctly on FreeBSD 10

FreeBSD 10 kernel has changed its incoming IPv4 packet handling
to stop trimming some IPv4 header fields on raw socket IO. This CL
just adapts package's IPv4 header representation to look the same
even on FreeBSD 10 kernel.

For further information:
http://svnweb.freebsd.org/base/head/?view=log&pathrev=226105
http://svnweb.freebsd.org/base/head/?view=log&pathrev=241913
http://svnweb.freebsd.org/base/head/?view=log&pathrev=241923

LGTM=iant
R=golang-codereviews, gobot, dave, iant
CC=golang-codereviews
https://golang.org/cl/53030043
Mikio Hara 12 years ago
parent
commit
28a4bd90d0
3 changed files with 43 additions and 19 deletions
  1. 6 1
      ipv4/header.go
  2. 26 18
      ipv4/header_test.go
  3. 11 0
      ipv4/sys_freebsd.go

+ 6 - 1
ipv4/header.go

@@ -121,6 +121,9 @@ func (h *Header) Marshal() ([]byte, error) {
 	return b, nil
 }
 
+// See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html.
+var freebsdVersion uint32
+
 // ParseHeader parses b as an IPv4 header.
 func ParseHeader(b []byte) (*Header, error) {
 	if len(b) < HeaderLen {
@@ -139,7 +142,9 @@ func ParseHeader(b []byte) (*Header, error) {
 		h.FragOff = int(b[posFragOff])<<8 | int(b[posFragOff+1])
 	} else {
 		h.TotalLen = int(*(*uint16)(unsafe.Pointer(&b[posTotalLen : posTotalLen+1][0])))
-		h.TotalLen += hdrlen
+		if runtime.GOOS != "freebsd" || freebsdVersion < 1000000 {
+			h.TotalLen += hdrlen
+		}
 		h.FragOff = int(*(*uint16)(unsafe.Pointer(&b[posFragOff : posFragOff+1][0])))
 	}
 	h.Flags = HeaderFlags(h.FragOff&0xe000) >> 13

+ 26 - 18
ipv4/header_test.go

@@ -2,11 +2,10 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package ipv4_test
+package ipv4
 
 import (
 	"bytes"
-	"code.google.com/p/go.net/ipv4"
 	"net"
 	"reflect"
 	"runtime"
@@ -14,28 +13,35 @@ import (
 )
 
 var (
-	wireHeaderFromKernel = [ipv4.HeaderLen]byte{
+	wireHeaderFromKernel = [HeaderLen]byte{
 		0x45, 0x01, 0xbe, 0xef,
 		0xca, 0xfe, 0x45, 0xdc,
 		0xff, 0x01, 0xde, 0xad,
 		172, 16, 254, 254,
 		192, 168, 0, 1,
 	}
-	wireHeaderToKernel = [ipv4.HeaderLen]byte{
+	wireHeaderToKernel = [HeaderLen]byte{
 		0x45, 0x01, 0xbe, 0xef,
 		0xca, 0xfe, 0x45, 0xdc,
 		0xff, 0x01, 0xde, 0xad,
 		172, 16, 254, 254,
 		192, 168, 0, 1,
 	}
-	wireHeaderFromTradBSDKernel = [ipv4.HeaderLen]byte{
+	wireHeaderFromTradBSDKernel = [HeaderLen]byte{
 		0x45, 0x01, 0xdb, 0xbe,
 		0xca, 0xfe, 0xdc, 0x45,
 		0xff, 0x01, 0xde, 0xad,
 		172, 16, 254, 254,
 		192, 168, 0, 1,
 	}
-	wireHeaderToTradBSDKernel = [ipv4.HeaderLen]byte{
+	wireHeaderFromFreeBSD10Kernel = [HeaderLen]byte{
+		0x45, 0x01, 0xef, 0xbe,
+		0xca, 0xfe, 0xdc, 0x45,
+		0xff, 0x01, 0xde, 0xad,
+		172, 16, 254, 254,
+		192, 168, 0, 1,
+	}
+	wireHeaderToTradBSDKernel = [HeaderLen]byte{
 		0x45, 0x01, 0xef, 0xbe,
 		0xca, 0xfe, 0xdc, 0x45,
 		0xff, 0x01, 0xde, 0xad,
@@ -45,13 +51,13 @@ var (
 	// TODO(mikio): Add platform dependent wire header formats when
 	// we support new platforms.
 
-	testHeader = &ipv4.Header{
-		Version:  ipv4.Version,
-		Len:      ipv4.HeaderLen,
+	testHeader = &Header{
+		Version:  Version,
+		Len:      HeaderLen,
 		TOS:      1,
 		TotalLen: 0xbeef,
 		ID:       0xcafe,
-		Flags:    ipv4.DontFragment,
+		Flags:    DontFragment,
 		FragOff:  1500,
 		TTL:      255,
 		Protocol: 1,
@@ -67,10 +73,9 @@ func TestMarshalHeader(t *testing.T) {
 		t.Fatalf("ipv4.Header.Marshal failed: %v", err)
 	}
 	var wh []byte
-	switch runtime.GOOS {
-	case "linux", "openbsd":
+	if supportsNewIPInput {
 		wh = wireHeaderToKernel[:]
-	default:
+	} else {
 		wh = wireHeaderToTradBSDKernel[:]
 	}
 	if !bytes.Equal(b, wh) {
@@ -80,13 +85,16 @@ func TestMarshalHeader(t *testing.T) {
 
 func TestParseHeader(t *testing.T) {
 	var wh []byte
-	switch runtime.GOOS {
-	case "linux", "openbsd":
+	if supportsNewIPInput {
 		wh = wireHeaderFromKernel[:]
-	default:
-		wh = wireHeaderFromTradBSDKernel[:]
+	} else {
+		if runtime.GOOS == "freebsd" && freebsdVersion >= 1000000 {
+			wh = wireHeaderFromFreeBSD10Kernel[:]
+		} else {
+			wh = wireHeaderFromTradBSDKernel[:]
+		}
 	}
-	h, err := ipv4.ParseHeader(wh)
+	h, err := ParseHeader(wh)
 	if err != nil {
 		t.Fatalf("ipv4.ParseHeader failed: %v", err)
 	}

+ 11 - 0
ipv4/sys_freebsd.go

@@ -0,0 +1,11 @@
+// Copyright 2014 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
+
+import "syscall"
+
+func init() {
+	freebsdVersion, _ = syscall.SysctlUint32("kern.osreldate")
+}