MoonGen
 All Files Functions Variables Pages
icmp.lua
Go to the documentation of this file.
1 ------------------------------------------------------------------------
2 --- @file icmp.lua
3 --- @brief Internet control message protocol utility.
4 --- Utility functions for the icmp_header struct
5 --- defined in \ref headers.lua . \n
6 --- Includes:
7 --- - Icmp4 constants
8 --- - Icmp6 constants
9 --- - Icmp header utility
10 --- - Definition of Icmp 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 bor, band, bnot, rshift, lshift= bit.bor, bit.band, bit.bnot, bit.rshift, bit.lshift
22 local istype = ffi.istype
23 local format = string.format
24 
25 -- FIXME
26 -- ICMPv6 and ICMPv4 use different values for the same types/codes which causes some complications when handling this with only one header:
27 -- - getString() does not work for ICMPv6 correctly without some ugly workarounds (basically adding 'ipv4' flags to getString()'s of type/code and header)
28 -- currently getString() simply does not recognise ICMPv6
29 -- - Furthermore, packetDump would need a change to pass this flag when calling getString()
30 -- TODO
31 -- remove messageBody, instead use new packetCreate with additional header { "ip4", "messageBody" } or similar
32 
33 
34 ---------------------------------------------------------------------------
35 ---- ICMPv4 constants
36 ---------------------------------------------------------------------------
37 
38 --- Icmp4 protocol constants
39 local icmp = {}
40 
41 --- Icmp4 type-code pair: echo reply
42 icmp.ECHO_REPLY = { type = 0, code = 0 }
43 --- Icmp4 type-code pair: echo request
44 icmp.ECHO_REQUEST = { type = 8, code = 0 }
45 
46 --- Icmp4 type-code pair: destination unreachable - port unreachable
47 icmp.DST_UNR_PORT_UNR = { type = 3, code = 3 }
48 
49 --- Icmp4 type-code pair: time exceeded - TTL exceeded
50 icmp.TIME_EXCEEDED_TTL_EXPIRED = { type = 11, code = 0 }
51 
52 
53 --------------------------------------------------------------------------
54 ---- ICMPv6 constants
55 ---------------------------------------------------------------------------
56 
57 --- Icmp6 protocol constants
58 local icmp6 = {}
59 
60 --- Icmp6 type-code pair: echo request
61 icmp6.ECHO_REQUEST = { type = 128, code = 0 }
62 --- Icmp6 type-code pair: echo reply
63 icmp6.ECHO_REPLY = { type = 129, code = 0 }
64 
65 
66 ---------------------------------------------------------------------------
67 ---- ICMP header
68 ---------------------------------------------------------------------------
69 
70 --- Module for icmp_header struct (see \ref headers.lua).
71 local icmpHeader = {}
72 icmpHeader.__index = icmpHeader
73 
74 --- Set the type.
75 --- @param int Type of the icmp header as 8 bit integer.
76 function icmpHeader:setType(int)
77  int = int or icmp.ECHO_REQUEST.type
78  self.type = int
79 end
80 
81 --- Retrieve the type.
82 --- @return Type as 8 bit integer.
83 function icmpHeader:getType()
84  return self.type
85 end
86 
87 --- Retrieve the type.
88 --- does not work for ICMPv6 (ICMPv6 uses different values)
89 --- @return Type as string.
90 function icmpHeader:getTypeString()
91  local type = self:getType()
92  local cleartext = "unknown"
93 
94  if type == icmp.ECHO_REPLY.type then
95  cleartext = "echo reply"
96  elseif type == icmp.ECHO_REQUEST.type then
97  cleartext = "echo request"
98  elseif type == icmp.DST_UNR_PORT_UNR.type then
99  cleartext = "dst. unr."
100  elseif type == icmp.TIME_EXCEEDED_TTL_EXPIRED.type then
101  cleartext = "time exceeded"
102  end
103 
104  return format("%s (%s)", type, cleartext)
105 end
106 
107 --- Set the code.
108 --- @param int Code of the icmp header as 8 bit integer.
109 function icmpHeader:setCode(int)
110  int = int or icmp.ECHO_REQUEST.code
111  self.code = int
112 end
113 
114 --- Retrieve the code.
115 --- @return Code as 8 bit integer.
116 function icmpHeader:getCode()
117  return self.code
118 end
119 
120 --- Retrieve the code.
121 --- does not work for ICMPv6
122 --- @return Code as string.
123 function icmpHeader:getCodeString()
124  local type = self:getType()
125  local code = self:getCode()
126  local cleartext = "unknown"
127 
128  if type == icmp.ECHO_REPLY.type then
129  cleartext = code == icmp.ECHO_REPLY.code and "correct" or "wrong"
130 
131  elseif type == icmp.ECHO_REQUEST.type then
132  cleartext = code == icmp.ECHO_REQUEST.code and "correct" or "wrong"
133 
134  elseif type == icmp.DST_UNR_PORT_UNR.type then
135  if code == icmp.DST_UNR_PORT_UNR.code then
136  cleartext = "port unr."
137  end
138 
139  elseif type == icmp.TIME_EXCEEDED_TTL_EXPIRED.type then
140  if code == icmp.TIME_EXCEEDED_TTL_EXPIRED.code then
141  cleartext = "ttl expired"
142  end
143  end
144 
145  return format("%s (%s)", code, cleartext)
146 end
147 
148 
149 --- Set the checksum.
150 --- @param int Checksum of the icmp header as 16 bit integer.
151 function icmpHeader:setChecksum(int)
152  int = int or 0
153  self.cs = hton16(int)
154 end
155 
156 --- Calculate the checksum
157 --- @param len Number of bytes that the checksum will be computed over
158 function icmpHeader:calculateChecksum(len)
159  len = len or sizeof(self)
160  self:setChecksum(0)
161  self:setChecksum(hton16(checksum(self, len)))
162 end
164 --- Retrieve the checksum.
165 --- @return Checksum as 16 bit integer.
166 function icmpHeader:getChecksum()
167  return hton16(self.cs)
168 end
169 
170 --- Retrieve the checksum.
171 --- @return Checksum as string.
172 function icmpHeader:getChecksumString()
173  return format("0x%04x", self:getChecksum())
174 end
175 
176 --- Set the message body.
177 --- @param int Message body of the icmp header as TODO.
178 function icmpHeader:setMessageBody(body)
179  body = body or 0
180  --self.body.uint8_t = body
181 end
182 
183 --- Retrieve the message body.
184 --- @return Message body as TODO.
185 function icmpHeader:getMessageBody()
186  return self.body
187 end
188 
189 --- Retrieve the message body.
190 --- @return Message body as string TODO.
192  return "<some data>"
193 end
194 
195 --- Set all members of the icmp header.
196 --- Per default, all members are set to default values specified in the respective set function.
197 --- Optional named arguments can be used to set a member to a user-provided value.
198 --- @param args Table of named arguments. Available arguments: Type, Code, Checksum, MessageBody
199 --- @param pre prefix for namedArgs. Default 'icmp'.
200 --- @code
201 --- fill() --- only default values
202 --- fill{ icmpCode=3 } --- all members are set to default values with the exception of icmpCode
203 --- @endcode
204 function icmpHeader:fill(args, pre)
205  args = args or {}
206  pre = pre or "icmp"
207 
208  self:setType(args[pre .. "Type"])
209  self:setCode(args[pre .. "Code"])
210  self:setChecksum(args[pre .. "Checksum"])
211  self:setMessageBody(args[pre .. "MessageBody"])
212 end
213 
214 --- Retrieve the values of all members.
215 --- @param pre prefix for namedArgs. Default 'icmp'.
216 --- @return Table of named arguments. For a list of arguments see "See also".
217 --- @see icmpHeader:fill
218 function icmpHeader:get(pre)
219  pre = pre or "icmp"
220 
221  local args = {}
222  args[pre .. "Type"] = self:getType()
223  args[pre .. "Code"] = self:getCode()
224  args[pre .. "Checksum"] = self:getChecksum()
225  args[pre .. "MessageBody"] = self:getMessageBody()
226 
227  return args
228 end
229 
230 --- Retrieve the values of all members.
231 --- Does not work correctly for ICMPv6 packets
232 --- @return Values in string format.
233 function icmpHeader:getString()
234  return "ICMP type " .. self:getTypeString()
235  .. " code " .. self:getCodeString()
236  .. " cksum " .. self:getChecksumString()
237  .. " body " .. self:getMessageBodyString() .. " "
238 end
239 
240 --- Resolve which header comes after this one (in a packet).
241 --- For instance: in tcp/udp based on the ports.
242 --- This function must exist and is only used when get/dump is executed on
243 --- an unknown (mbuf not yet casted to e.g. tcpv6 packet) packet (mbuf)
244 --- @return String next header (e.g. 'udp', 'icmp', nil)
245 function icmpHeader:resolveNextHeader()
246  return nil
247 end
248 
249 --- Change the default values for namedArguments (for fill/get).
250 --- This can be used to for instance calculate a length value based on the total packet length.
251 --- See proto/ip4.setDefaultNamedArgs as an example.
252 --- This function must exist and is only used by packet.fill.
253 --- @param pre The prefix used for the namedArgs, e.g. 'icmp'
254 --- @param namedArgs Table of named arguments (see See Also)
255 --- @param nextHeader The header following after this header in a packet
256 --- @param accumulatedLength The so far accumulated length for previous headers in a packet
257 --- @return Table of namedArgs
258 --- @see icmpHeader:fill
259 function icmpHeader:setDefaultNamedArgs(pre, namedArgs, nextHeader, accumulatedLength)
260  return namedArgs
261 end
262 
263 
264 ------------------------------------------------------------------------
265 ---- Packets
266 ------------------------------------------------------------------------
267 
268 --- Cast the packet to an Icmp4 packet
269 pkt.getIcmp4Packet = packetCreate("eth", "ip4", "icmp")
270 --- Cast the packet to an Icmp6 packet
271 pkt.getIcmp6Packet = packetCreate("eth", "ip6", "icmp")
272 --- Cast the packet to either an Icmp4 (nil/true) or Icmp6 (false) packet, depending on the passed boolean.
273 pkt.getIcmpPacket = function(self, ip4) ip4 = ip4 == nil or ip4 if ip4 then return pkt.getIcmp4Packet(self) else return pkt.getIcmp6Packet(self) end end
274 
275 
276 ------------------------------------------------------------------------
277 ---- Metatypes
278 ------------------------------------------------------------------------
279 
280 ffi.metatype("struct icmp_header", icmpHeader)
281 
282 return icmp, icmp6
icmp ECHO_REQUEST
Icmp4 type-code pair: echo request.
Definition: icmp.lua:30
local ffi
low-level dpdk wrapper
Definition: dpdkc.lua:6
function checksum(data, len)
Calculate a 16 bit checksum.
function icmpHeader resolveNextHeader()
Resolve which header comes after this one (in a packet).
function icmpHeader getTypeString()
Retrieve the type.
function packetCreate(...)
Create struct and functions for a new packet.
local icmpHeader
Module for icmp_header struct (see headers.lua).
Definition: icmp.lua:51
function mod band(mask1, mask2, result)
Bitwise and.
function icmpHeader getCodeString()
Retrieve the code.
function pkt dump(bytes)
Dumps the packet data cast to the best fitting packet struct.
function icmpHeader getMessageBody()
Retrieve the message body.
function icmpHeader setChecksum(int)
Set the checksum.
local icmp6
Icmp6 protocol constants.
Definition: icmp.lua:41
function ipsecICV set(icv)
Set the IPsec ICV.
function mod new(n)
local udp
Udp protocol constants.
Definition: udp.lua:23
function mod bor(mask1, mask2, result)
Bitwise or.
function icmpHeader setDefaultNamedArgs(pre, namedArgs, nextHeader, accumulatedLength)
Change the default values for namedArguments (for fill/get).
function icmpHeader setCode(int)
Set the code.
function icmpHeader getMessageBodyString()
Retrieve the message body.
function icmpHeader calculateChecksum(len)
Calculate the checksum.
icmp DST_UNR_PORT_UNR
Icmp4 type-code pair: destination unreachable - port unreachable.
Definition: icmp.lua:33
icmp TIME_EXCEEDED_TTL_EXPIRED
Icmp4 type-code pair: time exceeded - TTL exceeded.
Definition: icmp.lua:36
function icmpHeader getChecksum()
Retrieve the checksum.
function icmpHeader setMessageBody(body)
Set the message body.
function icmpHeader getCode()
Retrieve the code.
function icmpHeader setType(int)
Set the type.
function icmpHeader fill(args, pre)
Set all members of the icmp header.
function icmpHeader getChecksumString()
Retrieve the checksum.
function icmpHeader getString()
Retrieve the values of all members.
function icmpHeader get(pre)
Retrieve the values of all members.
function packetDump(self, bytes)
Print a hex dump of a packet.
local eth
Ethernet protocol constants.
Definition: ethernet.lua:24
local ip6
IP6 protocol constants.
Definition: ip6.lua:25
local pkt
Module for packets (rte_mbuf)
Definition: packet.lua:20
function mod bnot(mask, result)
Bitwise not.
n
Create a new array of memory buffers (initialized to nil).
Definition: memory.lua:76
pkt getIcmp4Packet
Cast the packet to an Icmp4 packet.
Definition: icmp.lua:163
local icmp
Icmp4 protocol constants.
Definition: icmp.lua:25
function icmpHeader getType()
Retrieve the type.
pkt getIcmp6Packet
Cast the packet to an Icmp6 packet.
Definition: icmp.lua:165
icmp ECHO_REPLY
Icmp4 type-code pair: echo reply.
Definition: icmp.lua:28