Class: Xlat::Protocols::Ip

Inherits:
Object
  • Object
show all
Defined in:
lib/xlat/protocols/ip.rb,
lib/xlat/protocols/ip/ipv4.rb,
lib/xlat/protocols/ip/ipv6.rb

Defined Under Namespace

Modules: Ipv4, Ipv6

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(icmp_payload: false) ⇒ Ip

Returns a new instance of Ip.



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

def initialize(icmp_payload: false)
  @icmp_payload = icmp_payload
  @_tcp = Tcp.new(self, icmp_payload:)
  @_udp = Udp.new(self, icmp_payload:)
end

Instance Attribute Details

#bytesObject

IO::Buffer containing L3 header



29
30
31
# File 'lib/xlat/protocols/ip.rb', line 29

def bytes
  @bytes
end

#bytes_lengthObject

Length of L3 datagram within ‘bytes`



31
32
33
# File 'lib/xlat/protocols/ip.rb', line 31

def bytes_length
  @bytes_length
end

#bytes_offsetObject

Offset where L3 header begins within ‘bytes`



30
31
32
# File 'lib/xlat/protocols/ip.rb', line 30

def bytes_offset
  @bytes_offset
end

#cs_deltaObject

Accumulated changes to be applied to L4 checksum



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

def cs_delta
  @cs_delta
end

#l4Object

Returns the value of attribute l4.



35
36
37
# File 'lib/xlat/protocols/ip.rb', line 35

def l4
  @l4
end

#l4_bytesObject

IO::Buffer containing L4 packet



36
37
38
# File 'lib/xlat/protocols/ip.rb', line 36

def l4_bytes
  @l4_bytes
end

#l4_bytes_lengthObject

Length of L4 datagram within ‘l4_bytes`, possibly truncated



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

def l4_bytes_length
  @l4_bytes_length
end

#l4_bytes_offsetObject

Offset where L4 header begins within ‘l4_bytes`



37
38
39
# File 'lib/xlat/protocols/ip.rb', line 37

def l4_bytes_offset
  @l4_bytes_offset
end

#l4_lengthObject

Length of L4 packet, as specified in L3 header



34
35
36
# File 'lib/xlat/protocols/ip.rb', line 34

def l4_length
  @l4_length
end

#l4_startObject

L3 header length



33
34
35
# File 'lib/xlat/protocols/ip.rb', line 33

def l4_start
  @l4_start
end

#protoObject

L4 protocol ID



32
33
34
# File 'lib/xlat/protocols/ip.rb', line 32

def proto
  @proto
end

#versionObject (readonly)

Returns the value of attribute version.



41
42
43
# File 'lib/xlat/protocols/ip.rb', line 41

def version
  @version
end

Class Method Details

.addr_to_s(addr) ⇒ Object



190
191
192
193
194
195
196
197
198
199
# File 'lib/xlat/protocols/ip.rb', line 190

def self.addr_to_s(addr)
  case addr.length
  when 4
    addr.unpack('C4').join('.')
  when 16
    addr.unpack('n8').map { |f| format '%x', f }.join(':').gsub(/(:0)+(?=:)/, ':')
  else
    raise "unexpected address length of #{addr.length}"
  end
end

.checksum(bytes, from = nil, len = nil) ⇒ Object



150
151
152
153
154
155
156
157
158
159
# File 'lib/xlat/protocols/ip.rb', line 150

def self.checksum(bytes, from = nil, len = nil)
  from = 0 if from.nil?
  len = bytes.size - from if len.nil?
  to = from + len - 1

  sum = Common.sum16be(bytes.slice(from, len))
  sum += bytes.get_value(:U8, to) * 256 if len.odd?
  sum = (sum & 0xffff) + (sum >> 16) while sum > 65535
  ~sum & 0xffff
end

.checksum_adjust(checksum, delta) ⇒ Object

this function assumes 0 <= sum <= 65534



182
183
184
185
186
187
188
# File 'lib/xlat/protocols/ip.rb', line 182

def self.checksum_adjust(checksum, delta)
  delta %= 65535

  mod65535 = 65534 - checksum
  mod65535 = (mod65535 + delta) % 65535
  65534 - mod65535
end

.checksum_list(buffers) ⇒ Object



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/xlat/protocols/ip.rb', line 161

def self.checksum_list(buffers)
  sum = 0
  offset = 0
  buffers.each do |buf|
    if offset.odd?
      sum += buf.get_value(:U8, 0)
      buf = buf.slice(1)
      offset += 1
    end
    sum += Common.sum16be(buf)
    len = buf.size
    if len.odd?
      sum += buf.get_value(:U8, len - 1) << 8
    end
    offset += len
  end
  sum = (sum & 0xffff) + (sum >> 16) while sum > 65535
  ~sum & 0xffff
end

.parse(bytes) ⇒ Object



49
50
51
# File 'lib/xlat/protocols/ip.rb', line 49

def self.parse(bytes)
  new.parse(bytes:)
end

Instance Method Details

#apply_changesObject



143
144
145
146
147
148
# File 'lib/xlat/protocols/ip.rb', line 143

def apply_changes
  cs_delta = @cs_delta
  @version.apply(@bytes, @bytes_offset, cs_delta, @icmp_payload)
  @l4&.apply(cs_delta)
  @cs_delta = 0
end

#convert_version!(version, new_header_bytes, cs_delta) ⇒ Ip

Convert this packet into different IP version using the supplied buffer as header.

Parameters:

  • version (Module)

    New version

  • new_header_bytes (IO::Buffer)

    Buffer to hold L3 header. The caller is responsible for populating the buffer with a proper content.

  • cs_delta (Integer)

    Checksum delta in the pseudo header to be cancelled with the L4 checksum.

Returns:

  • (Ip)

    self



129
130
131
132
133
134
135
136
137
# File 'lib/xlat/protocols/ip.rb', line 129

def convert_version!(version, new_header_bytes, cs_delta)
  @bytes = new_header_bytes
  @bytes_offset = 0
  @bytes_length = new_header_bytes.size
  @version = version
  @l4_start = new_header_bytes.size
  @cs_delta += cs_delta
  self
end

#parse(bytes:, bytes_offset: 0, bytes_length: bytes.size - bytes_offset, l4_bytes: nil, l4_bytes_offset: nil) ⇒ Object



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/xlat/protocols/ip.rb', line 53

def parse(bytes:, bytes_offset: 0, bytes_length: bytes.size - bytes_offset, l4_bytes: nil, l4_bytes_offset: nil)
  @bytes = bytes
  @bytes_offset = bytes_offset
  @bytes_length = bytes_length
  @proto = nil
  @version = nil
  @l4_start = nil
  @l4_length = nil
  @l4 = nil
  @l4_bytes = l4_bytes
  @l4_bytes_offset = l4_bytes_offset
  @l4_bytes_length = nil
  @cs_delta = 0

  # mimimum size for IPv4
  return nil if bytes_length < 20

  b0 = bytes.get_value(:U8, bytes_offset)
  case b0 >> 4
  when 4
    @version = Ipv4
  when 6
    @version = Ipv6
  else
    return nil
  end

  return nil unless @version.parse(self, b0)

  case @proto
  when Protocols::Udp::PROTOCOL_ID
    @l4 = @_udp.parse
  when Protocols::Tcp::PROTOCOL_ID
    @l4 = @_tcp.parse
  when @version.icmp_protocol_id
    @l4 = Protocols::Icmp.parse(self)
  end

  self
end

#set_l4_region(start, length) ⇒ true, false

Returns Whether the given range is valid.

Parameters:

  • start (Integer)

    Length of L3 header in octets

  • length (Integer)

    Length of L4 datagram in octets, as specified in L3 header

Returns:

  • (true, false)

    Whether the given range is valid



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/xlat/protocols/ip.rb', line 97

def set_l4_region(start, length)
  @l4_start = start
  @l4_length = length

  unless @l4_bytes
    @l4_bytes = @bytes
    @l4_bytes_offset = @bytes_offset + start
    @l4_bytes_length = @bytes_length - start
  end

  if @l4_bytes_length < length
    if @icmp_payload
      # allow truncation in ICMP payload
      length = @l4_bytes_length
      return false if length < 0
    else
      return false
    end
  end

  @l4_bytes_length = length

  true
end

#tupleObject



139
140
141
# File 'lib/xlat/protocols/ip.rb', line 139

def tuple
  @version.tuple(@bytes, @bytes_offset)
end