github.com/Andyfoo/golang/x/net@v0.0.0-20190901054642-57c1bf301704/icmp/ipv4.go (about)

     1  // Copyright 2014 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package icmp
     6  
     7  import (
     8  	"encoding/binary"
     9  	"net"
    10  	"runtime"
    11  
    12  	"github.com/Andyfoo/golang/x/net/internal/socket"
    13  	"github.com/Andyfoo/golang/x/net/ipv4"
    14  )
    15  
    16  // freebsdVersion is set in sys_freebsd.go.
    17  // See http://www.freebsd.org/doc/en/books/porters-handbook/freebsd-versions.html.
    18  var freebsdVersion uint32
    19  
    20  // ParseIPv4Header returns the IPv4 header of the IPv4 packet that
    21  // triggered an ICMP error message.
    22  // This is found in the Data field of the ICMP error message body.
    23  //
    24  // The provided b must be in the format used by a raw ICMP socket on
    25  // the local system.
    26  // This may differ from the wire format, and the format used by a raw
    27  // IP socket, depending on the system.
    28  //
    29  // To parse an IPv6 header, use ipv6.ParseHeader.
    30  func ParseIPv4Header(b []byte) (*ipv4.Header, error) {
    31  	if len(b) < ipv4.HeaderLen {
    32  		return nil, errHeaderTooShort
    33  	}
    34  	hdrlen := int(b[0]&0x0f) << 2
    35  	if hdrlen > len(b) {
    36  		return nil, errBufferTooShort
    37  	}
    38  	h := &ipv4.Header{
    39  		Version:  int(b[0] >> 4),
    40  		Len:      hdrlen,
    41  		TOS:      int(b[1]),
    42  		ID:       int(binary.BigEndian.Uint16(b[4:6])),
    43  		FragOff:  int(binary.BigEndian.Uint16(b[6:8])),
    44  		TTL:      int(b[8]),
    45  		Protocol: int(b[9]),
    46  		Checksum: int(binary.BigEndian.Uint16(b[10:12])),
    47  		Src:      net.IPv4(b[12], b[13], b[14], b[15]),
    48  		Dst:      net.IPv4(b[16], b[17], b[18], b[19]),
    49  	}
    50  	switch runtime.GOOS {
    51  	case "darwin":
    52  		h.TotalLen = int(socket.NativeEndian.Uint16(b[2:4]))
    53  	case "freebsd":
    54  		if freebsdVersion >= 1000000 {
    55  			h.TotalLen = int(binary.BigEndian.Uint16(b[2:4]))
    56  		} else {
    57  			h.TotalLen = int(socket.NativeEndian.Uint16(b[2:4]))
    58  		}
    59  	default:
    60  		h.TotalLen = int(binary.BigEndian.Uint16(b[2:4]))
    61  	}
    62  	h.Flags = ipv4.HeaderFlags(h.FragOff&0xe000) >> 13
    63  	h.FragOff = h.FragOff & 0x1fff
    64  	if hdrlen-ipv4.HeaderLen > 0 {
    65  		h.Options = make([]byte, hdrlen-ipv4.HeaderLen)
    66  		copy(h.Options, b[ipv4.HeaderLen:])
    67  	}
    68  	return h, nil
    69  }