MoonGen
 All Files Functions Variables Pages
ip4.lua
Go to the documentation of this file.
1 ------------------------------------------------------------------------
2 --- @file ip4.lua
3 --- @brief Internet protocol (v4) utility.
4 --- Utility functions for the ip4_address and ip4_header structs
5 --- defined in \ref headers.lua . \n
6 --- Includes:
7 --- - IP4 constants
8 --- - IP4 address utility
9 --- - IP4 header utility
10 --- - Definition of IP4 packets
11 ------------------------------------------------------------------------
12 
13 local ffi = require "ffi"
14 local pkt = require "packet"
15 
16 require "utils"
17 require "headers"
18 
19 local ntoh, hton = ntoh, hton
20 local ntoh16, hton16 = ntoh16, hton16
21 local bswap = bswap
22 local bswap16 = bswap16
23 local bor, band, bnot, rshift, lshift= bit.bor, bit.band, bit.bnot, bit.rshift, bit.lshift
24 local istype = ffi.istype
25 local format = string.format
26 
27 ----------------------------------------------------------------------------------
28 ---- IPv4 constants
29 ----------------------------------------------------------------------------------
30 
31 --- IP4 protocol constants
32 local ip = {}
33 
34 --- Protocol field value for Icmp
35 ip.PROTO_ICMP = 0x01
36 --- Protocol field value for Tcp
37 ip.PROTO_TCP = 0x06
38 --- Protocol field value for Udp
39 ip.PROTO_UDP = 0x11
40 ip.PROTO_ESP = 0x32
41 ip.PROTO_AH = 0x33
42 
43 
44 ----------------------------------------------------------------------------------
45 ---- IPv4 addresses
46 ----------------------------------------------------------------------------------
47 
48 --- Module for ip4_address struct (see \ref headers.lua).
49 local ip4Addr = {}
50 ip4Addr.__index = ip4Addr
51 local ip4AddrType = ffi.typeof("union ip4_address")
52 
53 --- Retrieve the IPv4 address.
54 --- @return Address in uint32 format.
55 function ip4Addr:get()
56  return bswap(self.uint32)
57 end
58 
59 --- Set the IPv4 address.
60 --- @param ip Address in uint32 format.
61 function ip4Addr:set(ip)
62  self.uint32 = bswap(ip)
63 end
64 
65 --- Set the IPv4 address.
66 --- @param ip Address in string format.
67 function ip4Addr:setString(ip)
68  self:set(parseIPAddress(ip))
69 end
70 
71 --- Retrieve the string representation of the IPv4 address.
72 --- @return Address in string format.
73 function ip4Addr:getString()
74  return ("%d.%d.%d.%d"):format(self.uint8[0], self.uint8[1], self.uint8[2], self.uint8[3])
75 end
76 
77 
78 --- Test equality of two IPv4 addresses.
79 --- @param lhs Address in 'union ip4_address' format.
80 --- @param rhs Address in 'union ip4_address' format.
81 --- @return true if equal, false otherwise.
82 function ip4Addr.__eq(lhs, rhs)
83  return istype(ip4AddrType, lhs) and istype(ip4AddrType, rhs) and lhs.uint32 == rhs.uint32
84 end
85 
86 --- Add a number to an IPv4 address.
87 --- Max. 32 bit, commutative.
88 --- @param lhs Address in 'union ip4_address' format.
89 --- @param rhs Number to add (32 bit integer).
90 --- @return Resulting address in uint32 format.
91 function ip4Addr.__add(lhs, rhs)
92  -- calc ip (self) + number (val)
93  local self, val
94  if istype(ip4AddrType, lhs) then
95  self = lhs
96  val = rhs
97  else
98  -- commutative for number + ip
99  self = rhs
100  val = lhs
101  end -- TODO: ip + ip?
102 
103  return self:get() + val
104 end
105 
106 --- Add a number to an IPv4 address in-place.
107 --- Max. 32 bit.
108 --- @param val Number to add (32 bit integer).
109 function ip4Addr:add(val)
110  self:set(self:get() + val)
111 end
112 
113 --- Subtract a number from an IPv4 address.
114 --- Max. 32 bit.
115 --- @param val Number to substract (32 bit integer)
116 --- @return Resulting address in uint32 format.
117 function ip4Addr:__sub(val)
118  return self + -val
119 end
120 
121 
122 -----------------------------------------------------------------------------------
123 ---- IPv4 header
124 -----------------------------------------------------------------------------------
125 
126 --- Module for ip4_header struct (see \ref headers.lua).
127 local ip4Header = {}
128 
129 ip4Header.__index = ip4Header
130 
131 --- Set the version.
132 --- @param int IP header version as 4 bit integer. Should always be '4'.
133 function ip4Header:setVersion(int)
134  int = int or 4
135  int = band(lshift(int, 4), 0xf0) -- fill to 8 bits
136 
137  old = self.verihl
138  old = band(old, 0x0f) -- remove old value
139 
140  self.verihl = bor(old, int)
141 end
142 
143 --- Retrieve the version.
144 --- @return Version as 4 bit integer.
145 function ip4Header:getVersion()
146  return band(rshift(self.verihl, 4), 0x0f)
147 end
148 
149 --- Retrieve the version.
150 --- @return Version as string.
151 function ip4Header:getVersionString()
152  return self:getVersion()
153 end
154 
155 --- Set the header length.
156 --- @param int Length of the ip header (in multiple of 32 bits) as 4 bit integer. Should always be '5'.
157 function ip4Header:setHeaderLength(int)
158  int = int or 5
159  int = band(int, 0x0f)
160 
161  old = self.verihl
162  old = band(old, 0xf0)
163 
164  self.verihl = bor(old, int)
165 end
166 
167 --- Retrieve the header length.
168 --- @return Header length as 4 bit integer.
169 function ip4Header:getHeaderLength()
170  return band(self.verihl, 0x0f)
171 end
172 
173 --- Retrieve the header length.
174 --- @return Header length as string.
176  return self:getHeaderLength()
177 end
178 
179 --- Set the type of service (TOS).
180 --- @param int TOS of the ip header as 8 bit integer.
181 function ip4Header:setTOS(int)
182  int = int or 0
183  self.tos = int
184 end
185 
186 --- Retrieve the type of service.
187 --- @return TOS as 8 bit integer.
188 function ip4Header:getTOS()
189  return self.tos
190 end
191 
192 --- Retrieve the type of service.
193 --- @return TOS as string.
194 function ip4Header:getTOSString()
195  return self:getTOS()
196 end
197 
198 --- Set the total length.
199 --- @param int Length of the packet excluding layer 2. 16 bit integer.
200 function ip4Header:setLength(int)
201  int = int or 48 -- with eth + UDP -> minimum 64
202  self.len = hton16(int)
203 end
204 
205 --- Retrieve the length.
206 --- @return Length as 16 bit integer.
207 function ip4Header:getLength()
208  return hton16(self.len)
209 end
210 
211 --- Retrieve the length.
212 --- @return Length as string.
213 function ip4Header:getLengthString()
214  return self:getLength()
215 end
216 
217 --- Set the identification.
218 --- @param int ID of the ip header as 16 bit integer.
219 function ip4Header:setID(int)
220  int = int or 0
221  self.id = hton16(int)
222 end
223 
224 --- Retrieve the identification.
225 --- @return ID as 16 bit integer.
226 function ip4Header:getID()
227  return hton16(self.id)
228 end
229 
230 --- Retrieve the identification.
231 --- @return ID as string.
232 function ip4Header:getIDString()
233  return self:getID()
234 end
235 
236 --- Set the flags.
237 --- Bits: [ reserved (must be 0) | don't fragment | more fragments ]
238 --- @param int Flags of the ip header as 3 bit integer
239 function ip4Header:setFlags(int)
240  int = int or 0
241  int = band(lshift(int, 13), 0xe000) -- fill to 16 bits
242 
243  old = hton16(self.frag)
244  old = band(old, 0x1fff) -- remove old value
245 
246  self.frag = hton16(bor(old, int))
247 end
248 
249 --- Retrieve the flags.
250 --- @return Flags as 3 bit integer.
251 function ip4Header:getFlags()
252  return band(rshift(hton16(self.frag), 13), 0x000e)
253 end
254 
255 --- Retrieve the flags.
256 --- @return Flags as string.
257 function ip4Header:getFlagsString()
258  flags = self:getFlags()
259  --TODO show flags in a more clever manner: 1|1|1 or reserved|DF|MF
260  return flags
261 end
262 
263 --- Set the fragment.
264 --- @param int Fragment of the ip header as 13 bit integer.
265 function ip4Header:setFragment(int)
266  int = int or 0
267  int = band(int, 0x1fff)
268 
269  old = hton16(self.frag)
270  old = band(old, 0xe000)
271 
272  self.frag = hton16(bor(old, int))
273 end
274 
275 --- Retrieve the fragment.
276 --- @return Fragment as 13 bit integer.
277 function ip4Header:getFragment()
278  return band(hton16(self.frag), 0x1fff)
279 end
280 
281 --- Retrieve the fragemt.
282 --- @return Fragment as string.
283 function ip4Header:getFragmentString()
284  return self:getFragment()
285 end
286 
287 --- Set the time-to-live (TTL).
288 --- @param int TTL of the ip header as 8 bit integer.
289 function ip4Header:setTTL(int)
290  int = int or 64
291  self.ttl = int
292 end
293 
294 --- Retrieve the time-to-live.
295 --- @return TTL as 8 bit integer.
296 function ip4Header:getTTL()
297  return self.ttl
298 end
299 
300 --- Retrieve the time-to-live.
301 --- @return TTL as string.
302 function ip4Header:getTTLString()
303  return self:getTTL()
304 end
305 
306 --- Set the next layer protocol.
307 --- @param int Next layer protocol of the ip header as 8 bit integer.
308 function ip4Header:setProtocol(int)
309  int = int or ip.PROTO_UDP
310  self.protocol = int
311 end
312 
313 --- Retrieve the next layer protocol.
314 --- @return Next layer protocol as 8 bit integer.
315 function ip4Header:getProtocol()
316  return self.protocol
317 end
318 
319 --- Retrieve the next layer protocol.
320 --- @return Next layer protocol as string.
322  local proto = self:getProtocol()
323  local cleartext = ""
324 
325  if proto == ip.PROTO_ICMP then
326  cleartext = "(ICMP)"
327  elseif proto == ip.PROTO_UDP then
328  cleartext = "(UDP)"
329  elseif proto == ip.PROTO_TCP then
330  cleartext = "(TCP)"
331  elseif proto == ip.PROTO_ESP then
332  cleartext = "(ESP)"
333  elseif proto == ip.PROTO_AH then
334  cleartext = "(AH)"
335  else
336  cleartext = "(unknown)"
337  end
338 
339  return format("0x%02x %s", proto, cleartext)
340 end
341 
342 --- Set the checksum.
343 --- @param int Checksum of the ip header as 16 bit integer.
345 --- @see pkt:offloadUdpChecksum
346 function ip4Header:setChecksum(int)
347  int = int or 0
348  self.cs = hton16(int)
349 end
350 
351 --- Retrieve the checksum.
352 --- @return Checksum as 16 bit integer.
353 function ip4Header:getChecksum()
354  return hton16(self.cs)
355 end
356 
357 --- Retrieve the checksum.
358 --- @return Checksum as string.
359 function ip4Header:getChecksumString()
360  return format("0x%04x", self:getChecksum())
361 end
362 
363 --- Calculate and set the checksum.
364 --- If possible use checksum offloading instead.
365 --- @see pkt:offloadUdpChecksum
366 function ip4Header:calculateChecksum()
367  self:setChecksum() -- just to be sure (packet may be reused); must be 0
368  self:setChecksum(hton16(checksum(self, 20)))
369 end
370 
371 --- Set the destination address.
372 --- @param int Address in 'union ip4_address' format.
373 function ip4Header:setDst(int)
374  self.dst:set(int)
375 end
376 
377 --- Retrieve the destination IP address.
378 --- @return Address in 'union ip4_address' format.
379 function ip4Header:getDst()
380  return self.dst:get()
381 end
382 
383 --- Set the source address.
384 --- @param int Address in 'union ip4_address' format.
385 function ip4Header:setSrc(int)
386  self.src:set(int)
387 end
388 
389 --- Retrieve the source IP address.
390 --- @return Address in 'union ip4_address' format.
391 function ip4Header:getSrc()
392  return self.src:get()
393 end
394 
395 --- Set the destination address.
396 --- @param str Address in string format.
397 function ip4Header:setDstString(str)
398  self.dst:setString(str)
399 end
400 
401 --- Retrieve the destination IP address.
402 --- @return Address in string format.
403 function ip4Header:getDstString()
404  return self.dst:getString()
405 end
406 
407 --- Set the source address.
408 --- @param str Address in string format.
409 function ip4Header:setSrcString(str)
410  self.src:setString(str)
411 end
412 
413 --- Retrieve the source IP address.
414 --- @return Address in string format.
415 function ip4Header:getSrcString()
416  return self.src:getString()
417 end
418 
419 --- Set all members of the ip header.
420 --- Per default, all members are set to default values specified in the respective set function.
421 --- Optional named arguments can be used to set a member to a user-provided value.
422 --- @param args Table of named arguments. Available arguments: Version, HeaderLength, TOS, Length, ID, Flags, Fragment, TTL, Protocol, Checksum, Src, Dst
423 --- @param pre prefix for namedArgs. Default 'ip4'.
424 --- @code
425 --- fill() --- only default values
426 --- fill{ ipSrc="1.1.1.1", ipTTL=100 } --- all members are set to default values with the exception of ipSrc and ipTTL
427 --- @endcode
428 function ip4Header:fill(args, pre)
429  args = args or {}
430  pre = pre or "ip4"
431 
432  self:setVersion(args[pre .. "Version"])
433  self:setHeaderLength(args[pre .. "HeaderLength"])
434  self:setTOS(args[pre .. "TOS"])
435  self:setLength(args[pre .. "Length"])
436  self:setID(args[pre .. "ID"])
437  self:setFlags(args[pre .. "Flags"])
438  self:setFragment(args[pre .. "Fragment"])
439  self:setTTL(args[pre .. "TTL"])
440  self:setProtocol(args[pre .. "Protocol"])
441  self:setChecksum(args[pre .. "Checksum"])
442 
443  local src = pre .. "Src"
444  local dst = pre .. "Dst"
445  args[src] = args[src] or "192.168.1.1"
446  args[dst] = args[dst] or "192.168.1.2"
447 
448  -- if for some reason the address is in 'union ip4_address' format, cope with it
449  if type(args[src]) == "string" then
450  self:setSrcString(args[src])
451  else
452  self:setSrc(args[src])
453  end
454  if type(args[dst]) == "string" then
455  self:setDstString(args[dst])
456  else
457  self:setDst(args[dst])
458  end
459 end
460 
461 --- Retrieve the values of all members.
462 --- @param pre prefix for namedArgs. Default 'ip4'.
463 --- @return Table of named arguments. For a list of arguments see "See also".
464 --- @see ip4Header:fill
465 function ip4Header:get(pre)
466  pre = pre or "ip4"
467 
468  local args = {}
469  args[pre .. "Src"] = self:getSrcString()
470  args[pre .. "Dst"] = self:getDstString()
471  args[pre .. "Version"] = self:getVersion()
472  args[pre .. "HeaderLength"] = self:getHeaderLength()
473  args[pre .. "TOS"] = self:getTOS()
474  args[pre .. "Length"] = self:getLength()
475  args[pre .. "ID"] = self:getID()
476  args[pre .. "Flags"] = self:getFlags()
477  args[pre .. "Fragment"] = self:getFragment()
478  args[pre .. "TTL"] = self:getTTL()
479  args[pre .. "Protocol"] = self:getProtocol()
480  args[pre .. "Checksum"] = self:getChecksum()
481 
482  return args
483 end
484 
485 --- Retrieve the values of all members.
486 --- @return Values in string format.
487 function ip4Header:getString()
488  return "IP4 " .. self:getSrcString() .. " > " .. self:getDstString() .. " ver " .. self:getVersionString()
489  .. " ihl " .. self:getHeaderLengthString() .. " tos " .. self:getTOSString() .. " len " .. self:getLengthString()
490  .. " id " .. self:getIDString() .. " flags " .. self:getFlagsString() .. " frag " .. self:getFragmentString()
491  .. " ttl " .. self:getTTLString() .. " proto " .. self:getProtocolString() .. " cksum " .. self:getChecksumString()
492 end
493 
494 -- Maps headers to respective protocol value.
495 -- This list should be extended whenever a new protocol is added to 'IPv4 constants'.
496 local mapNameProto = {
497  icmp = ip.PROTO_ICMP,
498  udp = ip.PROTO_UDP,
499  tcp = ip.PROTO_TCP,
500  esp = ip.PROTO_ESP,
501  ah = ip.PROTO_AH,
502 }
503 
504 --- Resolve which header comes after this one (in a packet).
505 --- For instance: in tcp/udp based on the ports.
506 --- This function must exist and is only used when get/dump is executed on
507 --- an unknown (mbuf not yet casted to e.g. tcpv6 packet) packet (mbuf)
508 --- @return String next header (e.g. 'udp', 'icmp', nil)
509 function ip4Header:resolveNextHeader()
510  local proto = self:getProtocol()
511  for name, _proto in pairs(mapNameProto) do
512  if proto == _proto then
513  return name
514  end
515  end
516  return nil
517 end
518 
519 --- Change the default values for namedArguments (for fill/get).
520 --- This can be used to for instance calculate a length value based on the total packet length.
521 --- See proto/ip4.setDefaultNamedArgs as an example.
522 --- This function must exist and is only used by packet.fill.
523 --- @param pre The prefix used for the namedArgs, e.g. 'ip4'
524 --- @param namedArgs Table of named arguments (see See Also)
525 --- @param nextHeader The header following after this header in a packet
526 --- @param accumulatedLength The so far accumulated length for previous headers in a packet
527 --- @return Table of namedArgs
528 --- @see ip4Header:fill
529 function ip4Header:setDefaultNamedArgs(pre, namedArgs, nextHeader, accumulatedLength)
530  -- set length
531  if not namedArgs[pre .. "Length"] and namedArgs["pktLength"] then
532  namedArgs[pre .. "Length"] = namedArgs["pktLength"] - accumulatedLength
533  end
534 
535  -- set protocol
536  if not namedArgs[pre .. "Protocol"] then
537  for name, type in pairs(mapNameProto) do
538  if nextHeader == name then
539  namedArgs[pre .. "Protocol"] = type
540  break
541  end
542  end
543  end
544  return namedArgs
545 end
546 
547 
548 ----------------------------------------------------------------------------------
549 ---- Packets
550 ----------------------------------------------------------------------------------
551 
552 --- Cast the packet to an IP4 packet
553 pkt.getIP4Packet = packetCreate("eth", "ip4")
554 --- Cast the packet to either an IP4 (nil/true) or IP6 (false) packet, depending on the passed boolean.
555 pkt.getIPPacket = function(self, ip4)
556  ip4 = ip4 == nil or ip4
557  if ip4 then
558  return pkt.getIP4Packet(self)
559  else
560  return pkt.getIP6Packet(self)
561  end
562 end
563 
564 
565 ------------------------------------------------------------------------
566 ---- Metatypes
567 ------------------------------------------------------------------------
568 
569 ffi.metatype("union ip4_address", ip4Addr)
570 ffi.metatype("struct ip4_header", ip4Header)
571 
572 return ip
function ip4Header setProtocol(int)
Set the next layer protocol.
function ip4Header setFlags(int)
Set the flags.
pkt getIP6Packet
Cast the packet to an IP6 packet.
Definition: ip6.lua:260
function ip4Header getChecksum()
Retrieve the checksum.
local ffi
low-level dpdk wrapper
Definition: dpdkc.lua:6
function checksum(data, len)
Calculate a 16 bit checksum.
function ip4Header getFragment()
Retrieve the fragment.
function parseIPAddress(ip)
Parse a string to an IP address.
function ip4Header getProtocolString()
Retrieve the next layer protocol.
function pkt offloadUdpChecksum(ipv4, l2_len, l3_len)
Instruct the NIC to calculate the IP and UDP checksum for this packet.
function bswap16(n)
Byte swap for 16 bit integers.
function ip4Addr setString(ip)
Set the IPv4 address.
function ip4Header setSrc(int)
Set the source address.
function ip4Header getVersionString()
Retrieve the version.
function packetCreate(...)
Create struct and functions for a new packet.
function ip4Header getTTLString()
Retrieve the time-to-live.
function mod band(mask1, mask2, result)
Bitwise and.
function ip4Header setHeaderLength(int)
Set the header length.
function ip4Header getHeaderLength()
Retrieve the header length.
function ip4Header setSrcString(str)
Set the source address.
function pkt dump(bytes)
Dumps the packet data cast to the best fitting packet struct.
function ip4Header getFlags()
Retrieve the flags.
function ip4Header setDst(int)
Set the destination address.
function ip4Header getLengthString()
Retrieve the length.
function ip4Header getLength()
Retrieve the length.
function ip4Addr set(ip)
Set the IPv4 address.
function mod new(n)
function ip4Header fill(args, pre)
Set all members of the ip header.
function ip4Header setVersion(int)
Set the version.
function ip4Header getFragmentString()
Retrieve the fragemt.
local udp
Udp protocol constants.
Definition: udp.lua:23
function ip4Addr __eq(lhs, rhs)
Test equality of two IPv4 addresses.
ip PROTO_ICMP
Protocol field value for Icmp.
Definition: ip4.lua:28
function ip4Header setLength(int)
Set the total length.
function ip4Addr get()
Retrieve the IPv4 address.
ip PROTO_TCP
Protocol field value for Tcp.
Definition: ip4.lua:30
function mod bor(mask1, mask2, result)
Bitwise or.
function ip4Header setDefaultNamedArgs(pre, namedArgs, nextHeader, accumulatedLength)
Change the default values for namedArguments (for fill/get).
function ip4Header setChecksum(int)
Set the checksum.
function ip4Header setDstString(str)
Set the destination address.
function ip4Header getDst()
Retrieve the destination IP address.
function ip4Header getSrc()
Retrieve the source IP address.
function ip4Addr __sub(val)
Subtract a number from an IPv4 address.
function ip4Addr add(val)
Add a number to an IPv4 address in-place.
function ip4Header getTOS()
Retrieve the type of service.
function ip4Addr getString()
Retrieve the string representation of the IPv4 address.
function ip4Header setID(int)
Set the identification.
function ip4Header setTOS(int)
Set the type of service (TOS).
local ip4Addr
Module for ip4_address struct (see headers.lua).
Definition: ip4.lua:39
pkt getIP4Packet
Cast the packet to an IP4 packet.
Definition: ip4.lua:319
function ip4Header getIDString()
Retrieve the identification.
function ip4Header getHeaderLengthString()
Retrieve the header length.
function ip4Header getTOSString()
Retrieve the type of service.
local eth
Ethernet protocol constants.
Definition: ethernet.lua:24
function ip4Header getChecksumString()
Retrieve the checksum.
ip PROTO_UDP
Protocol field value for Udp.
Definition: ip4.lua:32
function ip4Header getProtocol()
Retrieve the next layer protocol.
local ip
IP4 protocol constants.
Definition: ip4.lua:25
function ip4Header setFragment(int)
Set the fragment.
function ip4Header getSrcString()
Retrieve the source IP address.
local pkt
Module for packets (rte_mbuf)
Definition: packet.lua:20
function mod bnot(mask, result)
Bitwise not.
function ip4Header getFlagsString()
Retrieve the flags.
n
Create a new array of memory buffers (initialized to nil).
Definition: memory.lua:76
local ip4Header
Module for ip4_header struct (see headers.lua).
Definition: ip4.lua:88
function ip4Header getTTL()
Retrieve the time-to-live.
function ip4Header getID()
Retrieve the identification.
function ip4Header calculateChecksum()
Calculate and set the checksum.
function ip4Header setTTL(int)
Set the time-to-live (TTL).
pkt getIPPacket
Cast the packet to either an IP4 (nil/true) or IP6 (false) packet, depending on the passed boolean...
Definition: ip4.lua:321
function ip4Header getVersion()
Retrieve the version.
local icmp
Icmp4 protocol constants.
Definition: icmp.lua:25
function ip4Addr __add(lhs, rhs)
Add a number to an IPv4 address.
function ip4Header getDstString()
Retrieve the destination IP address.
function ip4Header resolveNextHeader()
Resolve which header comes after this one (in a packet).