blob: 6872d4830d086d3ae438e045277e8772649ee1bd [file] [log] [blame]
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -07001-- Copyright (c) 2015, Regents of the University of California.
2--
3-- This file is part of ndn-tools (Named Data Networking Essential Tools).
4-- See AUTHORS.md for complete list of ndn-tools authors and contributors.
5--
6-- ndn-tools is free software: you can redistribute it and/or modify it under the terms
7-- of the GNU General Public License as published by the Free Software Foundation,
8-- either version 3 of the License, or (at your option) any later version.
9--
10-- ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
11-- without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12-- PURPOSE. See the GNU General Public License for more details.
13--
14-- You should have received a copy of the GNU General Public License along with
15-- ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
16--
17-- @author Qi Zhao <https://www.linkedin.com/pub/qi-zhao/73/835/9a3>
18-- @author Seunghyun Yoo <http://relue2718.com/>
19-- @author Seungbae Kim <https://sites.google.com/site/sbkimcv/>
Alexander Afanasyev357c2052015-08-10 21:26:52 -070020-- @author Alexander Afanasyev <http://lasr.cs.ucla.edu/afanasyev/index.html>
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -070021
22
23-- inspect.lua (https://github.com/kikito/inspect.lua) can be used for debugging.
24-- See more at http://stackoverflow.com/q/15175859/2150331
25-- local inspect = require('inspect')
26
27-- NDN protocol
Alexander Afanasyev357c2052015-08-10 21:26:52 -070028ndn = Proto("ndn", "Named Data Networking (NDN)")
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -070029
Alexander Afanasyev357c2052015-08-10 21:26:52 -070030-----------------------------------------------------
31-----------------------------------------------------
32-- Field formatting helpers
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -070033
Alexander Afanasyev357c2052015-08-10 21:26:52 -070034-- Borrowed from http://lua-users.org/wiki/StringRecipes
35function escapeString(str)
36 if (str) then
37 str = string.gsub(str, "\n", "\r\n")
38 str = string.gsub(str, "([^%w %-%_%.%~])",
39 function (c) return string.format ("%%%02X", string.byte(c)) end)
40 str = string.gsub(str, " ", "+")
41 end
42 return str
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -070043end
44
Alexander Afanasyev357c2052015-08-10 21:26:52 -070045function getUriFromNameComponent(block)
46 -- @todo Implement proper proper URL escaping
47 return block.tvb(block.offset + block.typeLen + block.lengthLen, block.length):string()
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -070048end
49
Alexander Afanasyev357c2052015-08-10 21:26:52 -070050function getUriFromName(nameBlock)
51 if (nameBlock.elements == nil) then
52 return ""
53 else
54 components = {}
55 for i, block in pairs(nameBlock.elements) do
56 table.insert(components, getUriFromNameComponent(block))
57 end
58
59 return "/" .. table.concat(components, "/")
60 end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -070061end
62
Alexander Afanasyev357c2052015-08-10 21:26:52 -070063function getNonNegativeInteger(b)
64 if (b.length == 1) then
65 return b.tvb(b.offset + b.typeLen + b.lengthLen, 1):uint()
66 elseif (b.length == 2) then
67 return b.tvb(b.offset + b.typeLen + b.lengthLen, 2):uint()
68 elseif (b.length == 4) then
69 return b.tvb(b.offset + b.typeLen + b.lengthLen, 4):uint()
70 -- Something strange with uint64, not supporting it for now
71 -- elseif (b.length == 8) then
72 -- return b.tvb(b.offset + b.typeLen + b.lengthLen, 8):uint64()
73 else
74 return 0xFFFFFFFF;
75 end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -070076end
77
Alexander Afanasyev357c2052015-08-10 21:26:52 -070078function getUriFromExclude(block)
79 -- @todo
80 return ""
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -070081end
82
Alexander Afanasyev357c2052015-08-10 21:26:52 -070083function getTrue(block)
84 return "Yes"
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -070085end
86
Alexander Afanasyev357c2052015-08-10 21:26:52 -070087local AppPrivateBlock1 = 128
88local AppPrivateBlock2 = 32767
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -070089
Alexander Afanasyev357c2052015-08-10 21:26:52 -070090function getGenericBlockInfo(block)
91 local name = ""
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -070092
Alexander Afanasyev357c2052015-08-10 21:26:52 -070093 if (block.type < AppPrivateBlock1) then
94 name = "RESERVED_1"
95 elseif (AppPrivateBlock1 <= block.type and block.type < 253) then
96 name = "APP_TAG_1"
97 elseif (253 <= block.type and block.type < AppPrivateBlock2) then
98 name = "RESERVED_3"
99 else
100 name = "APP_TAG_3"
101 end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700102
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700103 return name .. ", Type: " .. block.type .. ", Length: " .. block.length
104end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700105
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700106-----------------------------------------------------
107-----------------------------------------------------
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700108
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700109local NDN_DICT = {
110 -- Interest or Data packets
111 [5] = {name = "Interest" , summary = true},
112 [6] = {name = "Data" , summary = true},
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700113
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700114 -- Name field
115 [7] = {name = "Name" , field = ProtoField.string("ndn.name", "Name") , value = getUriFromName},
116 [1] = {name = "ImplicitSha256DigestComponent", field = ProtoField.string("ndn.implicitsha256", "ImplicitSha256DigestComponent"), value = getUriFromNameComponent},
117 [8] = {name = "NameComponent" , field = ProtoField.string("ndn.namecomponent", "NameComponent") , value = getUriFromNameComponent},
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700118
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700119 -- Sub-fields of Interest packet
120 [9] = {name = "Selectors" , summary = true},
121 [10] = {name = "Nonce" , field = ProtoField.bytes("ndn.nonce", "Nonce")},
122 [12] = {name = "InterestLifetime" , field = ProtoField.uint32("ndn.interestlifetime", "InterestLifetime", base.DEC) , value = getNonNegativeInteger},
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700123
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700124 -- Sub-fields of Interest/Selector field
125 [13] = {name = "MinSuffixComponents" , field = ProtoField.uint32("ndn.minsuffix", "MinSuffixComponents") , value = getNonNegativeInteger},
126 [14] = {name = "MaxSuffixComponents" , field = ProtoField.uint32("ndn.maxsuffix", "MaxSuffixComponents") , value = getNonNegativeInteger},
127 [15] = {name = "PublisherPublicKeyLocator" , summary = true},
128 [16] = {name = "Exclude" , field = ProtoField.string("ndn.exclude", "Exclude") , value = getUriFromExclude},
129 [17] = {name = "ChildSelector" , field = ProtoField.uint32("ndn.childselector", "ChildSelector", base.DEC) , value = getNonNegativeInteger},
130 [18] = {name = "MustBeFresh" , field = ProtoField.string("ndn.mustbefresh", "MustBeFresh") , value = getTrue},
131 [19] = {name = "Any" , field = ProtoField.string("ndn.any", "Any") , value = getTrue},
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700132
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700133 -- Sub-fields of Data packet
134 [20] = {name = "MetaInfo" , summary = true},
135 [21] = {name = "Content" , field = ProtoField.string("ndn.content", "Content")},
136 [22] = {name = "SignatureInfo" , summary = true},
137 [23] = {name = "SignatureValue" , field = ProtoField.bytes("ndn.signaturevalue", "SignatureValue")},
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700138
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700139 -- Sub-fields of Data/MetaInfo field
140 [24] = {name = "ContentType" , field = ProtoField.uint32("ndn.contenttype", "Content Type", base.DEC) , value = getNonNegativeInteger},
141 [25] = {name = "FreshnessPeriod" , field = ProtoField.uint32("ndn.freshnessperiod", "FreshnessPeriod", base.DEC) , value = getNonNegativeInteger},
142 [26] = {name = "FinalBlockId" , field = ProtoField.string("ndn.finalblockid", "FinalBlockId") , value = getUriFromNameComponent},
143
144 -- Sub-fields of Data/Signature field
145 [27] = {name = "SignatureType" , field = ProtoField.uint32("ndn.signaturetype", "SignatureType", base.DEC) , value = getNonNegativeInteger},
146 [28] = {name = "KeyLocator" , summary = true},
147 [29] = {name = "KeyDigest" , field = ProtoField.bytes("ndn.keydigest", "KeyDigest")},
148
149 -- Other fields
150 [30] = {name = "LinkPreference" , field = ProtoField.uint32("ndn.link_preference", "LinkPreference", base.DEC) , value = getNonNegativeInteger},
151 [31] = {name = "LinkDelegation" , summary = true},
152 [32] = {name = "SelectedDelegation" , field = ProtoField.uint32("ndn.selected_delegation", "SelectedDelegation", base.DEC), value = getNonNegativeInteger},
153}
154
155
156-- -- Add protofields in NDN protocol
157ndn.fields = {
158}
159for key, value in pairs(NDN_DICT) do
160 table.insert(ndn.fields, value.field)
161end
162
163
164-----------------------------------------------------
165-----------------------------------------------------
166
167-- block
168-- .tvb
169-- .offset
170-- .type
171-- .typeLen
172-- .length
173-- .lengthLen
174-- .size = .typeLen + .lengthLen + .length
175
176function addInfo(block, root) -- may be add additional context later
177 local info = NDN_DICT[block.type]
178
179 if (info == nil) then
180 info = {}
181 info.value = getGenericBlockInfo
182 end
183
184 local treeInfo
185 if (info.value == nil) then
186
187 if (info.field ~= nil) then
188 treeInfo = root:add(info.field, block.tvb(block.offset, block.size))
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700189 else
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700190 treeInfo = root:add(block.tvb(block.offset, block.size), info.name)
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700191 end
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700192
193 treeInfo:append_text(", Type: " .. block.type .. ", Length: " .. block.length)
194 else
195 block.value = info.value(block)
196
197 if (info.field ~= nil) then
198 treeInfo = root:add(info.field, block.tvb(block.offset, block.size), block.value)
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700199 else
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700200 treeInfo = root:add(block.tvb(block.offset, block.size), info.name)
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700201 end
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700202 end
203 block.root = treeInfo
204 return block.root
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700205end
206
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700207function addSummary(block)
208 if (block.elements == nil) then
209 return
210 end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700211
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700212 local info = NDN_DICT[block.type]
213 if (info == nil or info.summary == nil) then
214 return
215 end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700216
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700217 local summary = {}
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700218
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700219 for k, subblock in pairs(block.elements) do
220 if (subblock.value ~= nil) then
221 local info = NDN_DICT[subblock.type]
222 if (info ~= nil) then
223 table.insert(summary, info.name .. ": " .. subblock.value)
224 end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700225 end
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700226 end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700227
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700228 if (#summary > 0) then
229 block.summary = table.concat(summary, ", ")
230 if (block.value == nil) then
231 block.value = block.summary
232 end
233 block.root:append_text(", " .. block.summary)
234 end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700235end
236
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700237-----------------------------------------------------
238-----------------------------------------------------
239
240function readVarNumber(tvb, offset)
241 local firstOctet = tvb(offset, 1):uint()
242 if (firstOctet < 253) then
243 return firstOctet, 1
244 elseif (firstOctet == 253) then
245 return tvb(offset + 1, 2):uint(), 3
246 elseif (firstOctet == 254) then
247 return tvb(offset + 1, 4):uint(), 5
248 elseif (firstOctet == 255) then
249 return tvb(offset + 1, 8):uint64(), 6
250 end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700251end
252
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700253function getBlock(tvb, offset)
254 local block = {}
255 block.tvb = tvb
256 block.offset = offset
257
258 block.type, block.typeLen = readVarNumber(block.tvb, block.offset)
259 block.length, block.lengthLen = readVarNumber(block.tvb, block.offset + block.typeLen)
260
261 block.size = block.typeLen + block.lengthLen + block.length
262
263 return block
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700264end
265
Alexander Afanasyev7f43c532015-08-12 15:28:51 -0700266function canBeValidNdnPacket(block)
267 if ((block.type == 5 or block.type == 6) and block.length <= 8800) then
268 return true
269 else
270 return false
271 end
272end
273
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700274function findNdnPacket(tvb)
275 offset = 0
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700276
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700277 while offset + 2 < tvb:len() do
278 local block = getBlock(tvb, offset)
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700279
Alexander Afanasyev7f43c532015-08-12 15:28:51 -0700280 if canBeValidNdnPacket(block) then
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700281 return block
282 end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700283
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700284 offset = offset + 1
285 end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700286
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700287 return nil
288end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700289
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700290function getSubBlocks(block)
291 local valueLeft = block.length
292 local subBlocks = {}
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700293
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700294 while valueLeft > 0 do
295 local child = getBlock(block.tvb,
296 block.offset + block.typeLen + block.lengthLen + (block.length - valueLeft))
297
298 valueLeft = valueLeft - child.size
299 table.insert(subBlocks, child)
300 end
301
302 if (valueLeft == 0) then
303 return subBlocks
304 else
305 return nil
306 end
307end
308
309-----------------------------------------------------
310-----------------------------------------------------
311
312-- NDN protocol dissector function
313function ndn.dissector(tvb, pInfo, root) -- Tvb, Pinfo, TreeItem
314
315 if (tvb:len() ~= tvb:reported_len()) then
316 return 0 -- ignore partially captured packets
317 -- this can/may be re-enabled only for unfragmented UDP packets
318 end
319
320 local ok, block = pcall(findNdnPacket, tvb)
321 if (not ok) then
322 return 0
323 end
324
325 if (block == nil or block.offset == nil) then
326 -- no valid NDN packets found
327 return 0
328 end
329
330 local nBytesLeft = tvb:len() - block.offset
331 -- print (pInfo.number .. ":: Found block: " .. block.type .. " of length " .. block.size .. " bytesLeft: " .. nBytesLeft)
332
333 while (block.size <= nBytesLeft) do
334 -- Create TreeItems
335 block.tree = root:add(ndn, tvb(block.offset, block.size))
336
337 local queue = {block}
338 while (#queue > 0) do
339 local block = queue[1]
340 table.remove(queue, 1)
341
342 block.elements = getSubBlocks(block)
343 local subtree = addInfo(block, block.tree)
344
345 if (block.elements ~= nil) then
346 for i, subBlock in pairs(block.elements) do
347 subBlock.tree = subtree
348 table.insert(queue, subBlock)
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700349 end
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700350 end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700351 end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700352
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700353 -- Make summaries
354 local queue = {block}
355 while (#queue > 0) do
356 local block = queue[1]
357 if (block.visited ~= nil or block.elements == nil) then
358 -- try to make summary
359 table.remove(queue, 1)
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700360
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700361 addSummary(block)
362 else
363 for i, subBlock in pairs(block.elements) do
364 table.insert(queue, 1, subBlock)
365 end
366 block.visited = true
367 end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700368 end
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700369
370 local info = NDN_DICT[block.type]
371 if (info ~= nil) then
372 block.tree:append_text(", " .. NDN_DICT[block.type].name .. ", " .. block.summary)
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700373 end
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700374
375 nBytesLeft = nBytesLeft - block.size
376
377 if (nBytesLeft > 0) then
378 ok, block = pcall(getBlock, tvb, tvb:len() - nBytesLeft)
Alexander Afanasyev7f43c532015-08-12 15:28:51 -0700379 if (not ok or not canBeValidNdnPacket(block)) then
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700380 break
381 end
382 end
383 end
384
385 pInfo.cols.protocol = tostring(pInfo.cols.protocol) .. " (" .. ndn.name .. ")"
386
Alexander Afanasyev7f43c532015-08-12 15:28:51 -0700387 if (nBytesLeft > 0 and block ~= nil and block.size ~= nil and block.size > nBytesLeft) then
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700388 pInfo.desegment_offset = tvb:len() - nBytesLeft
389
390 -- Originally, I set desegment_len to the exact lenght, but it mysteriously didn't work for TCP
391 -- pInfo.desegment_len = block.size -- this will not work to desegment TCP streams
392 pInfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT
393 end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700394end
395
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700396local udpDissectorTable = DissectorTable.get("udp.port")
397udpDissectorTable:add("6363", ndn)
398udpDissectorTable:add("56363", ndn)
399
400local tcpDissectorTable = DissectorTable.get("tcp.port")
401tcpDissectorTable:add("6363", ndn)
402
403local websocketDissectorTable = DissectorTable.get("ws.port")
404-- websocketDissectorTable:add("9696", ndn)
405websocketDissectorTable:add("1-65535", ndn)
406
Alexander Afanasyev7f43c532015-08-12 15:28:51 -0700407local ethernetDissectorTable = DissectorTable.get("ethertype")
408ethernetDissectorTable:add(0x8624, ndn)
409
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700410io.stderr:write("ndn.lua is successfully loaded\n")