blob: b6f31c7add1315a511f9f3a22e337c3ea35e70ca [file] [log] [blame]
Junxiao Shie65c6d72016-07-24 21:53:19 +00001-- Copyright (c) 2015-2016, Regents of the University of California.
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -07002--
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)
Junxiao Shie65c6d72016-07-24 21:53:19 +0000241 if offset >= tvb:len() then
242 return 0, 0
243 end
244
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700245 local firstOctet = tvb(offset, 1):uint()
246 if (firstOctet < 253) then
247 return firstOctet, 1
Junxiao Shie65c6d72016-07-24 21:53:19 +0000248 elseif (firstOctet == 253) and (offset + 3 < tvb:len()) then
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700249 return tvb(offset + 1, 2):uint(), 3
Junxiao Shie65c6d72016-07-24 21:53:19 +0000250 elseif (firstOctet == 254) and (offset + 5 < tvb:len()) then
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700251 return tvb(offset + 1, 4):uint(), 5
Junxiao Shie65c6d72016-07-24 21:53:19 +0000252 elseif (firstOctet == 255) and (offset + 9 < tvb:len()) then
253 return tvb(offset + 1, 8):uint64(), 9
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700254 end
Junxiao Shie65c6d72016-07-24 21:53:19 +0000255
256 return 0, 0
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700257end
258
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700259function getBlock(tvb, offset)
260 local block = {}
261 block.tvb = tvb
262 block.offset = offset
263
264 block.type, block.typeLen = readVarNumber(block.tvb, block.offset)
Junxiao Shie65c6d72016-07-24 21:53:19 +0000265 if block.typeLen == 0 then
266 return nil
267 end
268
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700269 block.length, block.lengthLen = readVarNumber(block.tvb, block.offset + block.typeLen)
Junxiao Shie65c6d72016-07-24 21:53:19 +0000270 if block.lengthLen == 0 then
271 return nil
272 end
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700273
274 block.size = block.typeLen + block.lengthLen + block.length
275
276 return block
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700277end
278
Alexander Afanasyev7f43c532015-08-12 15:28:51 -0700279function canBeValidNdnPacket(block)
280 if ((block.type == 5 or block.type == 6) and block.length <= 8800) then
281 return true
282 else
283 return false
284 end
285end
286
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700287function findNdnPacket(tvb)
288 offset = 0
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700289
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700290 while offset + 2 < tvb:len() do
291 local block = getBlock(tvb, offset)
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700292
Junxiao Shie65c6d72016-07-24 21:53:19 +0000293 if (block ~= nil) and canBeValidNdnPacket(block) then
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700294 return block
295 end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700296
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700297 offset = offset + 1
298 end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700299
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700300 return nil
301end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700302
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700303function getSubBlocks(block)
304 local valueLeft = block.length
305 local subBlocks = {}
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700306
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700307 while valueLeft > 0 do
Junxiao Shie65c6d72016-07-24 21:53:19 +0000308 local offset = block.offset + block.typeLen + block.lengthLen + (block.length - valueLeft)
309 local child = getBlock(block.tvb, offset)
310 if child == nil then
311 return nil
312 end
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700313
314 valueLeft = valueLeft - child.size
315 table.insert(subBlocks, child)
316 end
317
318 if (valueLeft == 0) then
319 return subBlocks
320 else
321 return nil
322 end
323end
324
325-----------------------------------------------------
326-----------------------------------------------------
327
328-- NDN protocol dissector function
329function ndn.dissector(tvb, pInfo, root) -- Tvb, Pinfo, TreeItem
330
331 if (tvb:len() ~= tvb:reported_len()) then
332 return 0 -- ignore partially captured packets
333 -- this can/may be re-enabled only for unfragmented UDP packets
334 end
335
336 local ok, block = pcall(findNdnPacket, tvb)
337 if (not ok) then
338 return 0
339 end
340
341 if (block == nil or block.offset == nil) then
342 -- no valid NDN packets found
343 return 0
344 end
345
346 local nBytesLeft = tvb:len() - block.offset
347 -- print (pInfo.number .. ":: Found block: " .. block.type .. " of length " .. block.size .. " bytesLeft: " .. nBytesLeft)
348
349 while (block.size <= nBytesLeft) do
350 -- Create TreeItems
351 block.tree = root:add(ndn, tvb(block.offset, block.size))
352
353 local queue = {block}
354 while (#queue > 0) do
355 local block = queue[1]
356 table.remove(queue, 1)
357
358 block.elements = getSubBlocks(block)
359 local subtree = addInfo(block, block.tree)
360
361 if (block.elements ~= nil) then
362 for i, subBlock in pairs(block.elements) do
363 subBlock.tree = subtree
364 table.insert(queue, subBlock)
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700365 end
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700366 end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700367 end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700368
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700369 -- Make summaries
370 local queue = {block}
371 while (#queue > 0) do
372 local block = queue[1]
373 if (block.visited ~= nil or block.elements == nil) then
374 -- try to make summary
375 table.remove(queue, 1)
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700376
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700377 addSummary(block)
378 else
379 for i, subBlock in pairs(block.elements) do
380 table.insert(queue, 1, subBlock)
381 end
382 block.visited = true
383 end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700384 end
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700385
386 local info = NDN_DICT[block.type]
387 if (info ~= nil) then
388 block.tree:append_text(", " .. NDN_DICT[block.type].name .. ", " .. block.summary)
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700389 end
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700390
391 nBytesLeft = nBytesLeft - block.size
392
393 if (nBytesLeft > 0) then
394 ok, block = pcall(getBlock, tvb, tvb:len() - nBytesLeft)
Alexander Afanasyev7f43c532015-08-12 15:28:51 -0700395 if (not ok or not canBeValidNdnPacket(block)) then
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700396 break
397 end
398 end
399 end
400
401 pInfo.cols.protocol = tostring(pInfo.cols.protocol) .. " (" .. ndn.name .. ")"
402
Alexander Afanasyev7f43c532015-08-12 15:28:51 -0700403 if (nBytesLeft > 0 and block ~= nil and block.size ~= nil and block.size > nBytesLeft) then
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700404 pInfo.desegment_offset = tvb:len() - nBytesLeft
405
406 -- Originally, I set desegment_len to the exact lenght, but it mysteriously didn't work for TCP
407 -- pInfo.desegment_len = block.size -- this will not work to desegment TCP streams
408 pInfo.desegment_len = DESEGMENT_ONE_MORE_SEGMENT
409 end
Alexander Afanasyev6fbb7b42015-08-10 11:53:49 -0700410end
411
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700412local udpDissectorTable = DissectorTable.get("udp.port")
413udpDissectorTable:add("6363", ndn)
414udpDissectorTable:add("56363", ndn)
415
416local tcpDissectorTable = DissectorTable.get("tcp.port")
417tcpDissectorTable:add("6363", ndn)
418
419local websocketDissectorTable = DissectorTable.get("ws.port")
420-- websocketDissectorTable:add("9696", ndn)
421websocketDissectorTable:add("1-65535", ndn)
422
Alexander Afanasyev7f43c532015-08-12 15:28:51 -0700423local ethernetDissectorTable = DissectorTable.get("ethertype")
424ethernetDissectorTable:add(0x8624, ndn)
425
Alexander Afanasyev357c2052015-08-10 21:26:52 -0700426io.stderr:write("ndn.lua is successfully loaded\n")