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 }