gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

header.go (5085B)


      1 // Copyright 2012 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 ipv4
      6 
      7 import (
      8 	"encoding/binary"
      9 	"fmt"
     10 	"net"
     11 	"runtime"
     12 
     13 	"golang.org/x/net/internal/socket"
     14 )
     15 
     16 const (
     17 	Version   = 4  // protocol version
     18 	HeaderLen = 20 // header length without extension headers
     19 )
     20 
     21 type HeaderFlags int
     22 
     23 const (
     24 	MoreFragments HeaderFlags = 1 << iota // more fragments flag
     25 	DontFragment                          // don't fragment flag
     26 )
     27 
     28 // A Header represents an IPv4 header.
     29 type Header struct {
     30 	Version  int         // protocol version
     31 	Len      int         // header length
     32 	TOS      int         // type-of-service
     33 	TotalLen int         // packet total length
     34 	ID       int         // identification
     35 	Flags    HeaderFlags // flags
     36 	FragOff  int         // fragment offset
     37 	TTL      int         // time-to-live
     38 	Protocol int         // next protocol
     39 	Checksum int         // checksum
     40 	Src      net.IP      // source address
     41 	Dst      net.IP      // destination address
     42 	Options  []byte      // options, extension headers
     43 }
     44 
     45 func (h *Header) String() string {
     46 	if h == nil {
     47 		return "<nil>"
     48 	}
     49 	return fmt.Sprintf("ver=%d hdrlen=%d tos=%#x totallen=%d id=%#x flags=%#x fragoff=%#x ttl=%d proto=%d cksum=%#x src=%v dst=%v", h.Version, h.Len, h.TOS, h.TotalLen, h.ID, h.Flags, h.FragOff, h.TTL, h.Protocol, h.Checksum, h.Src, h.Dst)
     50 }
     51 
     52 // Marshal returns the binary encoding of h.
     53 //
     54 // The returned slice is in the format used by a raw IP socket on the
     55 // local system.
     56 // This may differ from the wire format, depending on the system.
     57 func (h *Header) Marshal() ([]byte, error) {
     58 	if h == nil {
     59 		return nil, errNilHeader
     60 	}
     61 	if h.Len < HeaderLen {
     62 		return nil, errHeaderTooShort
     63 	}
     64 	hdrlen := HeaderLen + len(h.Options)
     65 	b := make([]byte, hdrlen)
     66 	b[0] = byte(Version<<4 | (hdrlen >> 2 & 0x0f))
     67 	b[1] = byte(h.TOS)
     68 	flagsAndFragOff := (h.FragOff & 0x1fff) | int(h.Flags<<13)
     69 	switch runtime.GOOS {
     70 	case "darwin", "ios", "dragonfly", "netbsd":
     71 		socket.NativeEndian.PutUint16(b[2:4], uint16(h.TotalLen))
     72 		socket.NativeEndian.PutUint16(b[6:8], uint16(flagsAndFragOff))
     73 	case "freebsd":
     74 		if freebsdVersion < 1100000 {
     75 			socket.NativeEndian.PutUint16(b[2:4], uint16(h.TotalLen))
     76 			socket.NativeEndian.PutUint16(b[6:8], uint16(flagsAndFragOff))
     77 		} else {
     78 			binary.BigEndian.PutUint16(b[2:4], uint16(h.TotalLen))
     79 			binary.BigEndian.PutUint16(b[6:8], uint16(flagsAndFragOff))
     80 		}
     81 	default:
     82 		binary.BigEndian.PutUint16(b[2:4], uint16(h.TotalLen))
     83 		binary.BigEndian.PutUint16(b[6:8], uint16(flagsAndFragOff))
     84 	}
     85 	binary.BigEndian.PutUint16(b[4:6], uint16(h.ID))
     86 	b[8] = byte(h.TTL)
     87 	b[9] = byte(h.Protocol)
     88 	binary.BigEndian.PutUint16(b[10:12], uint16(h.Checksum))
     89 	if ip := h.Src.To4(); ip != nil {
     90 		copy(b[12:16], ip[:net.IPv4len])
     91 	}
     92 	if ip := h.Dst.To4(); ip != nil {
     93 		copy(b[16:20], ip[:net.IPv4len])
     94 	} else {
     95 		return nil, errMissingAddress
     96 	}
     97 	if len(h.Options) > 0 {
     98 		copy(b[HeaderLen:], h.Options)
     99 	}
    100 	return b, nil
    101 }
    102 
    103 // Parse parses b as an IPv4 header and stores the result in h.
    104 //
    105 // The provided b must be in the format used by a raw IP socket on the
    106 // local system.
    107 // This may differ from the wire format, depending on the system.
    108 func (h *Header) Parse(b []byte) error {
    109 	if h == nil || b == nil {
    110 		return errNilHeader
    111 	}
    112 	if len(b) < HeaderLen {
    113 		return errHeaderTooShort
    114 	}
    115 	hdrlen := int(b[0]&0x0f) << 2
    116 	if len(b) < hdrlen {
    117 		return errExtHeaderTooShort
    118 	}
    119 	h.Version = int(b[0] >> 4)
    120 	h.Len = hdrlen
    121 	h.TOS = int(b[1])
    122 	h.ID = int(binary.BigEndian.Uint16(b[4:6]))
    123 	h.TTL = int(b[8])
    124 	h.Protocol = int(b[9])
    125 	h.Checksum = int(binary.BigEndian.Uint16(b[10:12]))
    126 	h.Src = net.IPv4(b[12], b[13], b[14], b[15])
    127 	h.Dst = net.IPv4(b[16], b[17], b[18], b[19])
    128 	switch runtime.GOOS {
    129 	case "darwin", "ios", "dragonfly", "netbsd":
    130 		h.TotalLen = int(socket.NativeEndian.Uint16(b[2:4])) + hdrlen
    131 		h.FragOff = int(socket.NativeEndian.Uint16(b[6:8]))
    132 	case "freebsd":
    133 		if freebsdVersion < 1100000 {
    134 			h.TotalLen = int(socket.NativeEndian.Uint16(b[2:4]))
    135 			if freebsdVersion < 1000000 {
    136 				h.TotalLen += hdrlen
    137 			}
    138 			h.FragOff = int(socket.NativeEndian.Uint16(b[6:8]))
    139 		} else {
    140 			h.TotalLen = int(binary.BigEndian.Uint16(b[2:4]))
    141 			h.FragOff = int(binary.BigEndian.Uint16(b[6:8]))
    142 		}
    143 	default:
    144 		h.TotalLen = int(binary.BigEndian.Uint16(b[2:4]))
    145 		h.FragOff = int(binary.BigEndian.Uint16(b[6:8]))
    146 	}
    147 	h.Flags = HeaderFlags(h.FragOff&0xe000) >> 13
    148 	h.FragOff = h.FragOff & 0x1fff
    149 	optlen := hdrlen - HeaderLen
    150 	if optlen > 0 && len(b) >= hdrlen {
    151 		if cap(h.Options) < optlen {
    152 			h.Options = make([]byte, optlen)
    153 		} else {
    154 			h.Options = h.Options[:optlen]
    155 		}
    156 		copy(h.Options, b[HeaderLen:hdrlen])
    157 	}
    158 	return nil
    159 }
    160 
    161 // ParseHeader parses b as an IPv4 header.
    162 //
    163 // The provided b must be in the format used by a raw IP socket on the
    164 // local system.
    165 // This may differ from the wire format, depending on the system.
    166 func ParseHeader(b []byte) (*Header, error) {
    167 	h := new(Header)
    168 	if err := h.Parse(b); err != nil {
    169 		return nil, err
    170 	}
    171 	return h, nil
    172 }