github.com/contiv/libOpenflow@v0.0.0-20210609050114-d967b14cc688/protocol/ip.go (about)

     1  package protocol
     2  
     3  import (
     4  	"encoding/binary"
     5  	"errors"
     6  	"net"
     7  
     8  	"github.com/contiv/libOpenflow/util"
     9  )
    10  
    11  const (
    12  	Type_ICMP     = 0x01
    13  	Type_TCP      = 0x06
    14  	Type_UDP      = 0x11
    15  	Type_IPv6     = 0x29
    16  	Type_IPv6ICMP = 0x3a
    17  )
    18  
    19  type IPv4 struct {
    20  	Version        uint8 //4-bits
    21  	IHL            uint8 //4-bits
    22  	DSCP           uint8 //6-bits
    23  	ECN            uint8 //2-bits
    24  	Length         uint16
    25  	Id             uint16
    26  	Flags          uint16 //3-bits
    27  	FragmentOffset uint16 //13-bits
    28  	TTL            uint8
    29  	Protocol       uint8
    30  	Checksum       uint16
    31  	NWSrc          net.IP
    32  	NWDst          net.IP
    33  	Options        util.Buffer
    34  	Data           util.Message
    35  }
    36  
    37  func NewIPv4() *IPv4 {
    38  	ip := new(IPv4)
    39  	ip.NWSrc = make([]byte, 4)
    40  	ip.NWDst = make([]byte, 4)
    41  	ip.Options = *new(util.Buffer)
    42  	return ip
    43  }
    44  
    45  func (i *IPv4) Len() (n uint16) {
    46  	i.IHL = 5
    47  	if i.Data != nil {
    48  		return uint16(i.IHL*4) + i.Data.Len()
    49  	}
    50  	return uint16(i.IHL * 4)
    51  }
    52  
    53  func (i *IPv4) MarshalBinary() (data []byte, err error) {
    54  	data = make([]byte, int(i.Len()))
    55  	b := make([]byte, 0)
    56  	n := 0
    57  
    58  	var ihl uint8 = (i.Version << 4) + i.IHL
    59  	data[n] = ihl
    60  	n += 1
    61  	var ecn uint8 = (i.DSCP << 2) + i.ECN
    62  	data[n] = ecn
    63  	n += 1
    64  	binary.BigEndian.PutUint16(data[n:], i.Length)
    65  	n += 2
    66  	binary.BigEndian.PutUint16(data[n:], i.Id)
    67  	n += 2
    68  	var flg uint16 = (i.Flags << 13) + i.FragmentOffset
    69  	binary.BigEndian.PutUint16(data[n:], flg)
    70  	n += 2
    71  	data[n] = i.TTL
    72  	n += 1
    73  	data[n] = i.Protocol
    74  	n += 1
    75  	binary.BigEndian.PutUint16(data[n:], i.Checksum)
    76  	n += 2
    77  
    78  	copy(data[n:], i.NWSrc.To4())
    79  	n += 4 // Underlying rep can be 16 bytes.
    80  	copy(data[n:], i.NWDst.To4())
    81  	n += 4 // Underlying rep can be 16 bytes.
    82  
    83  	b, err = i.Options.MarshalBinary()
    84  	copy(data[n:], b)
    85  	n += len(b)
    86  
    87  	if i.Data != nil {
    88  		b, err = i.Data.MarshalBinary()
    89  		if err != nil {
    90  			return
    91  		}
    92  		copy(data[n:], b)
    93  		n += len(b)
    94  	}
    95  	return
    96  }
    97  
    98  func (i *IPv4) UnmarshalBinary(data []byte) error {
    99  	if len(data) < 20 {
   100  		return errors.New("The []byte is too short to unmarshal a full IPv4 message.")
   101  	}
   102  	n := 0
   103  
   104  	var ihl uint8
   105  	ihl = data[n]
   106  	i.Version = ihl >> 4
   107  	i.IHL = ihl & 0x0f
   108  	n += 1
   109  
   110  	var ecn uint8
   111  	ecn = data[n]
   112  	i.DSCP = ecn >> 2
   113  	i.ECN = ecn & 0x03
   114  	n += 1
   115  
   116  	i.Length = binary.BigEndian.Uint16(data[n:])
   117  	n += 2
   118  	i.Id = binary.BigEndian.Uint16(data[n:])
   119  	n += 2
   120  
   121  	var flg uint16
   122  	flg = binary.BigEndian.Uint16(data[n:])
   123  	i.Flags = flg >> 13
   124  	i.FragmentOffset = flg & 0x1fff
   125  	n += 2
   126  
   127  	i.TTL = data[n]
   128  	n += 1
   129  	i.Protocol = data[n]
   130  	n += 1
   131  	i.Checksum = binary.BigEndian.Uint16(data[n:])
   132  	n += 2
   133  	i.NWSrc = data[n : n+4]
   134  	n += 4
   135  	i.NWDst = data[n : n+4]
   136  	n += 4
   137  
   138  	err := i.Options.UnmarshalBinary(data[n:int(i.IHL*4)])
   139  	if err != nil {
   140  		return err
   141  	}
   142  	n += int(i.IHL*4) - n
   143  
   144  	switch i.Protocol {
   145  	case Type_ICMP:
   146  		i.Data = NewICMP()
   147  	case Type_UDP:
   148  		i.Data = NewUDP()
   149  	default:
   150  		i.Data = new(util.Buffer)
   151  	}
   152  	return i.Data.UnmarshalBinary(data[n:])
   153  }