Module: Xlat::Protocols::Ip::Ipv6

Extended by:
Common
Defined in:
lib/xlat/protocols/ip/ipv6.rb

Constant Summary collapse

EXTENSIONS =
Ractor.make_shareable([0, 43, 60, 135, 139, 140, 253, 254].to_h { |id| [id, true] })

Class Method Summary collapse

Methods included from Common

sum16be

Class Method Details

.apply(bytes, offset, _cs_delta, icmp_payload) ⇒ Object



116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/xlat/protocols/ip/ipv6.rb', line 116

def self.apply(bytes, offset, _cs_delta, icmp_payload)
  # decrement hop limit
  unless icmp_payload
    hop_limit = bytes.get_value(:U8, offset + 7)
    if hop_limit > 0
      hop_limit -= 1
      bytes.set_value(:U8, offset + 7, hop_limit)
    end
  end

  # IPv6 has no checksum
end

.icmp_cs_delta(packet) ⇒ Object



51
52
53
54
# File 'lib/xlat/protocols/ip/ipv6.rb', line 51

def self.icmp_cs_delta(packet)
  upper_layer_packet_length = packet.l4_bytes.size - packet.l4_bytes_offset
  Common.sum16be(tuple) + upper_layer_packet_length + packet.proto
end

.icmp_protocol_idObject



47
48
49
# File 'lib/xlat/protocols/ip/ipv6.rb', line 47

def self.icmp_protocol_id
  Icmp::Base::V6_PROTOCOL_ID
end

.new_icmp(packet, type) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/xlat/protocols/ip/ipv6.rb', line 56

def self.new_icmp(packet, type)
  case type
  when Icmp::Echo::V6_TYPE_REQUEST
    Icmp::Echo.new(packet, true)
  when Icmp::Echo::V6_TYPE_REPLY
    Icmp::Echo.new(packet, true)
  when Icmp::Error::V6_TYPE_DEST_UNREACH, Icmp::Error::V6_TYPE_PACKET_TOO_BIG, Icmp::Error::V6_TYPE_TIME_EXCEEDED, Icmp::Error::V6_TYPE_PARAMETER_PROBLEM
    Icmp::Error.new(packet)
  else
    Icmp::Base.new(packet)
  end
end

.parse(packet, _b0) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/xlat/protocols/ip/ipv6.rb', line 69

def self.parse(packet, _b0)
  bytes = packet.bytes
  bytes_length = packet.bytes_length
  offset = packet.bytes_offset

  return false if bytes_length < 40

  payload_length = bytes.get_value(:U16, offset + 4)
  proto = bytes.get_value(:U8, offset + 6)

  # [draft-ietf-6man-eh-limits-19] Section 4 suggests IPv6 nodes
  # to process at least 64 bytes long chain of EHs.
  extensions_length_limit = [payload_length, 64].min
  extensions_length = 0

  while EXTENSIONS[proto]
    extension_start = 40 + extensions_length
    return false if extension_start + 8 > bytes_length  # EH is at least 8 byte long

    proto = bytes.get_value(:U8, offset + extension_start)
    length = bytes.get_value(:U8, offset + extension_start + 1) * 8 + 8

    extensions_length += length
    return false if extensions_length > extensions_length_limit

    # TODO: Routing header
  end

  if proto == 51  # AH
    # AH has a non-standard EH format. It doesn't work with NAT anyway.
    return false
  end

  # We assume Fragment is at the last of EH chain.
  if proto == 44  # Fragment
    # TODO: handle fragmentation
    return false
  end

  # ESP is handled as L4 protocol

  return false unless packet.set_l4_region(40 + extensions_length, payload_length - extensions_length)
  packet.proto = proto

  true
end

.to_iObject



39
40
41
# File 'lib/xlat/protocols/ip/ipv6.rb', line 39

def self.to_i
  6
end

.tuple(bytes, offset) ⇒ Object



43
44
45
# File 'lib/xlat/protocols/ip/ipv6.rb', line 43

def self.tuple(bytes, offset)
  bytes.slice(offset + 8, 32)
end