blob: 6722a78981e779e513c128b9b2da50301fe6d305 [file] [log] [blame]
Junxiao Shi2222a612015-06-06 08:01:38 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento60f8cc12018-05-10 22:05:21 -04002/*
Davide Pesaventob6b176c2018-07-28 22:05:16 -04003 * Copyright (c) 2011-2018, Regents of the University of California.
Junxiao Shi3cd47df2015-06-07 20:58:14 -07004 *
5 * This file is part of ndn-tools (Named Data Networking Essential Tools).
6 * See AUTHORS.md for complete list of ndn-tools authors and contributors.
7 *
8 * ndn-tools is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
18 */
Junxiao Shi2222a612015-06-06 08:01:38 -070019
20#include "ndndump.hpp"
21
Davide Pesaventof9126532018-08-04 18:31:06 -040022#include <arpa/inet.h>
Davide Pesavento051db002018-07-22 18:56:16 -040023#include <net/ethernet.h>
24#include <netinet/ip.h>
25#include <netinet/tcp.h>
26#include <netinet/udp.h>
Junxiao Shi2222a612015-06-06 08:01:38 -070027
Junxiao Shi022bddf2016-11-24 23:15:20 +000028#include <pcap/sll.h>
29
Junxiao Shi2222a612015-06-06 08:01:38 -070030#include <iomanip>
Davide Pesaventoc0702702017-08-24 22:04:00 -040031#include <sstream>
Junxiao Shi2222a612015-06-06 08:01:38 -070032
Vince Lehman277ecf02016-02-10 16:37:48 -060033#include <ndn-cxx/lp/nack.hpp>
34#include <ndn-cxx/lp/packet.hpp>
Davide Pesaventoecd44802018-07-23 23:48:10 -040035#include <ndn-cxx/net/ethernet.hpp>
Davide Pesaventob6b176c2018-07-28 22:05:16 -040036#include <ndn-cxx/util/string-helper.hpp>
37
38#include <boost/endian/conversion.hpp>
Junxiao Shi2222a612015-06-06 08:01:38 -070039
40namespace ndn {
Junxiao Shi3cd47df2015-06-07 20:58:14 -070041namespace dump {
Junxiao Shi2222a612015-06-06 08:01:38 -070042
Davide Pesaventob6b176c2018-07-28 22:05:16 -040043namespace endian = boost::endian;
44
45class OutputFormatter : noncopyable
46{
47public:
48 OutputFormatter(std::ostream& os, std::string d)
49 : m_os(os)
50 , m_delim(std::move(d))
51 {
52 }
53
54 OutputFormatter&
55 addDelimiter()
56 {
57 if (!m_isEmpty) {
58 m_wantDelim = true;
59 }
60 return *this;
61 }
62
63private:
64 std::ostream& m_os;
65 std::string m_delim;
66 bool m_isEmpty = true;
67 bool m_wantDelim = false;
68
69 template<typename T>
70 friend OutputFormatter& operator<<(OutputFormatter&, const T&);
71};
72
73template<typename T>
74OutputFormatter&
75operator<<(OutputFormatter& out, const T& val)
76{
77 if (out.m_wantDelim) {
78 out.m_os << out.m_delim;
79 out.m_wantDelim = false;
80 }
81 out.m_os << val;
82 out.m_isEmpty = false;
83 return out;
84}
85
Davide Pesaventoecd44802018-07-23 23:48:10 -040086NdnDump::~NdnDump()
Junxiao Shic1c2b832016-07-24 20:45:36 +000087{
Davide Pesaventoecd44802018-07-23 23:48:10 -040088 if (m_pcap)
89 pcap_close(m_pcap);
90}
91
Junxiao Shi2222a612015-06-06 08:01:38 -070092void
Davide Pesaventoecd44802018-07-23 23:48:10 -040093NdnDump::run()
Junxiao Shi2222a612015-06-06 08:01:38 -070094{
Davide Pesaventof9126532018-08-04 18:31:06 -040095 char errbuf[PCAP_ERRBUF_SIZE] = {};
Junxiao Shi2222a612015-06-06 08:01:38 -070096
Davide Pesaventoecd44802018-07-23 23:48:10 -040097 if (inputFile.empty() && interface.empty()) {
98 const char* defaultDevice = pcap_lookupdev(errbuf);
99
100 if (defaultDevice == nullptr) {
Junxiao Shic7599632016-07-24 20:46:24 +0000101 BOOST_THROW_EXCEPTION(Error(errbuf));
Junxiao Shi2222a612015-06-06 08:01:38 -0700102 }
103
Davide Pesaventoecd44802018-07-23 23:48:10 -0400104 interface = defaultDevice;
Junxiao Shi2222a612015-06-06 08:01:38 -0700105 }
106
Davide Pesaventoecd44802018-07-23 23:48:10 -0400107 std::string action;
Junxiao Shi2222a612015-06-06 08:01:38 -0700108 if (!interface.empty()) {
Davide Pesavento24c08612018-07-26 13:33:24 -0400109 m_pcap = pcap_open_live(interface.data(), 65535, wantPromisc, 1000, errbuf);
Junxiao Shic1c2b832016-07-24 20:45:36 +0000110 if (m_pcap == nullptr) {
Davide Pesaventoecd44802018-07-23 23:48:10 -0400111 BOOST_THROW_EXCEPTION(Error("Cannot open interface " + interface + ": " + errbuf));
Junxiao Shi2222a612015-06-06 08:01:38 -0700112 }
Davide Pesaventoecd44802018-07-23 23:48:10 -0400113 action = "listening on " + interface;
Junxiao Shi2222a612015-06-06 08:01:38 -0700114 }
115 else {
Davide Pesavento78de7352018-07-22 00:35:45 -0400116 m_pcap = pcap_open_offline(inputFile.data(), errbuf);
Junxiao Shic1c2b832016-07-24 20:45:36 +0000117 if (m_pcap == nullptr) {
Davide Pesaventoecd44802018-07-23 23:48:10 -0400118 BOOST_THROW_EXCEPTION(Error("Cannot open file '" + inputFile + "' for reading: " + errbuf));
Junxiao Shi2222a612015-06-06 08:01:38 -0700119 }
Davide Pesaventoecd44802018-07-23 23:48:10 -0400120 action = "reading from file " + inputFile;
Junxiao Shi2222a612015-06-06 08:01:38 -0700121 }
122
Davide Pesaventoecd44802018-07-23 23:48:10 -0400123 m_dataLinkType = pcap_datalink(m_pcap);
124 const char* dltName = pcap_datalink_val_to_name(m_dataLinkType);
125 const char* dltDesc = pcap_datalink_val_to_description(m_dataLinkType);
126 std::string formattedDlt = dltName ? dltName : to_string(m_dataLinkType);
127 if (dltDesc) {
128 formattedDlt += " ("s + dltDesc + ")";
129 }
130
131 std::cerr << "ndndump: " << action << ", link-type " << formattedDlt << std::endl;
132
133 switch (m_dataLinkType) {
134 case DLT_EN10MB:
135 case DLT_LINUX_SLL:
136 case DLT_PPP:
137 // we know how to handle these
138 break;
139 default:
140 BOOST_THROW_EXCEPTION(Error("Unsupported link-layer header type " + formattedDlt));
141 }
142
143 if (!pcapFilter.empty()) {
Davide Pesavento24c08612018-07-26 13:33:24 -0400144 if (wantVerbose) {
Davide Pesaventoecd44802018-07-23 23:48:10 -0400145 std::cerr << "ndndump: using pcap filter: " << pcapFilter << std::endl;
Junxiao Shi2222a612015-06-06 08:01:38 -0700146 }
147
148 bpf_program program;
Davide Pesaventofb42a3d2018-07-26 12:33:14 -0400149 int res = pcap_compile(m_pcap, &program, pcapFilter.data(), 1, PCAP_NETMASK_UNKNOWN);
Junxiao Shic1c2b832016-07-24 20:45:36 +0000150 if (res < 0) {
Davide Pesaventofb42a3d2018-07-26 12:33:14 -0400151 BOOST_THROW_EXCEPTION(Error("Cannot compile pcap filter '" + pcapFilter + "': " + pcap_geterr(m_pcap)));
Junxiao Shi2222a612015-06-06 08:01:38 -0700152 }
153
Junxiao Shic1c2b832016-07-24 20:45:36 +0000154 res = pcap_setfilter(m_pcap, &program);
Junxiao Shi2222a612015-06-06 08:01:38 -0700155 pcap_freecode(&program);
Junxiao Shic1c2b832016-07-24 20:45:36 +0000156 if (res < 0) {
Davide Pesaventoecd44802018-07-23 23:48:10 -0400157 BOOST_THROW_EXCEPTION(Error("Cannot set pcap filter: "s + pcap_geterr(m_pcap)));
Junxiao Shi2222a612015-06-06 08:01:38 -0700158 }
159 }
160
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400161 auto callback = [] (uint8_t* user, const pcap_pkthdr* pkthdr, const uint8_t* payload) {
162 reinterpret_cast<const NdnDump*>(user)->printPacket(pkthdr, payload);
163 };
164
165 if (pcap_loop(m_pcap, -1, callback, reinterpret_cast<uint8_t*>(this)) < 0) {
Davide Pesaventoecd44802018-07-23 23:48:10 -0400166 BOOST_THROW_EXCEPTION(Error("pcap_loop: "s + pcap_geterr(m_pcap)));
Junxiao Shic1c2b832016-07-24 20:45:36 +0000167 }
Junxiao Shi2222a612015-06-06 08:01:38 -0700168}
169
Junxiao Shi2222a612015-06-06 08:01:38 -0700170void
Davide Pesaventoecd44802018-07-23 23:48:10 -0400171NdnDump::printPacket(const pcap_pkthdr* pkthdr, const uint8_t* payload) const
Junxiao Shi2222a612015-06-06 08:01:38 -0700172{
Davide Pesaventoecd44802018-07-23 23:48:10 -0400173 // sanity checks
174 if (pkthdr->caplen == 0) {
175 std::cout << "[Invalid header: caplen=0]" << std::endl;
176 return;
177 }
178 if (pkthdr->len == 0) {
179 std::cout << "[Invalid header: len=0]" << std::endl;
180 return;
181 }
182 else if (pkthdr->len < pkthdr->caplen) {
183 std::cout << "[Invalid header: len(" << pkthdr->len
184 << ") < caplen(" << pkthdr->caplen << ")]" << std::endl;
185 return;
186 }
Junxiao Shi2222a612015-06-06 08:01:38 -0700187
Davide Pesaventoecd44802018-07-23 23:48:10 -0400188 std::ostringstream os;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400189 OutputFormatter out(os, ", ");
Davide Pesaventoecd44802018-07-23 23:48:10 -0400190
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400191 bool shouldPrint = false;
192 switch (m_dataLinkType) {
193 case DLT_EN10MB:
194 shouldPrint = printEther(out, payload, pkthdr->len);
195 break;
196 case DLT_LINUX_SLL:
197 shouldPrint = printLinuxSll(out, payload, pkthdr->len);
198 break;
199 case DLT_PPP:
200 shouldPrint = printPpp(out, payload, pkthdr->len);
201 break;
202 default:
203 BOOST_ASSERT(false);
Junxiao Shi2222a612015-06-06 08:01:38 -0700204 return;
205 }
206
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400207 if (shouldPrint) {
208 if (wantTimestamp) {
209 printTimestamp(std::cout, pkthdr->ts);
Vince Lehman277ecf02016-02-10 16:37:48 -0600210 }
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400211 std::cout << os.str() << std::endl;
Junxiao Shi2222a612015-06-06 08:01:38 -0700212 }
213}
214
215void
Davide Pesaventoecd44802018-07-23 23:48:10 -0400216NdnDump::printTimestamp(std::ostream& os, const timeval& tv) const
Junxiao Shi2222a612015-06-06 08:01:38 -0700217{
Davide Pesaventoecd44802018-07-23 23:48:10 -0400218 /// \todo Add more timestamp formats (time since previous packet, time since first packet, ...)
219 os << tv.tv_sec
Junxiao Shi2222a612015-06-06 08:01:38 -0700220 << "."
Davide Pesaventoecd44802018-07-23 23:48:10 -0400221 << std::setfill('0') << std::setw(6) << tv.tv_usec
222 << " ";
Junxiao Shi2222a612015-06-06 08:01:38 -0700223}
224
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400225bool
226NdnDump::dispatchByEtherType(OutputFormatter& out, const uint8_t* pkt, size_t len, uint16_t etherType) const
Junxiao Shi2222a612015-06-06 08:01:38 -0700227{
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400228 out.addDelimiter();
Junxiao Shi2222a612015-06-06 08:01:38 -0700229
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400230 switch (etherType) {
231 case ETHERTYPE_IP:
232 return printIp4(out, pkt, len);
233 case ethernet::ETHERTYPE_NDN:
234 case 0x7777: // NDN ethertype used in ndnSIM
Davide Pesaventof9126532018-08-04 18:31:06 -0400235 out << "Ethernet";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400236 return printNdn(out, pkt, len);
237 default:
Davide Pesaventof9126532018-08-04 18:31:06 -0400238 out << "[Unsupported ethertype " << AsHex{etherType} << "]";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400239 return true;
Junxiao Shi2222a612015-06-06 08:01:38 -0700240 }
Junxiao Shi2222a612015-06-06 08:01:38 -0700241}
242
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400243bool
244NdnDump::dispatchByIpProto(OutputFormatter& out, const uint8_t* pkt, size_t len, uint8_t ipProto) const
Junxiao Shi2222a612015-06-06 08:01:38 -0700245{
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400246 out.addDelimiter();
Junxiao Shi2222a612015-06-06 08:01:38 -0700247
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400248 switch (ipProto) {
249 case IPPROTO_TCP:
250 return printTcp(out, pkt, len);
251 case IPPROTO_UDP:
252 return printUdp(out, pkt, len);
253 default:
Davide Pesaventof9126532018-08-04 18:31:06 -0400254 out << "[Unsupported IP proto " << static_cast<int>(ipProto) << "]";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400255 return true;
256 }
257}
Junxiao Shi2222a612015-06-06 08:01:38 -0700258
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400259bool
260NdnDump::printEther(OutputFormatter& out, const uint8_t* pkt, size_t len) const
261{
262 // IEEE 802.3 Ethernet
Junxiao Shi2222a612015-06-06 08:01:38 -0700263
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400264 if (len < ethernet::HDR_LEN) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400265 out << "Truncated Ethernet frame, length " << len;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400266 return true;
Junxiao Shic1c2b832016-07-24 20:45:36 +0000267 }
Junxiao Shi2222a612015-06-06 08:01:38 -0700268
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400269 auto ether = reinterpret_cast<const ether_header*>(pkt);
270 pkt += ethernet::HDR_LEN;
271 len -= ethernet::HDR_LEN;
272
273 return dispatchByEtherType(out, pkt, len, endian::big_to_native(ether->ether_type));
274}
275
276bool
277NdnDump::printLinuxSll(OutputFormatter& out, const uint8_t* pkt, size_t len) const
278{
279 // Linux "cooked" capture encapsulation
280 // https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html
281
282 if (len < SLL_HDR_LEN) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400283 out << "Truncated LINUX_SLL frame, length " << len;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400284 return true;
285 }
286
287 auto sll = reinterpret_cast<const sll_header*>(pkt);
288 pkt += SLL_HDR_LEN;
289 len -= SLL_HDR_LEN;
290
291 return dispatchByEtherType(out, pkt, len, endian::big_to_native(sll->sll_protocol));
292}
293
294bool
295NdnDump::printPpp(OutputFormatter& out, const uint8_t* pkt, size_t len) const
296{
297 // PPP, as per RFC 1661 and RFC 1662; if the first 2 bytes are 0xff and 0x03,
298 // it's PPP in HDLC-like framing, with the PPP header following those two bytes,
299 // otherwise it's PPP without framing, and the packet begins with the PPP header.
300 // The data in the frame is not octet-stuffed or bit-stuffed.
301
302 if (len < 2) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400303 out << "Truncated PPP frame, length " << len;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400304 return true;
305 }
306
307 if (pkt[0] == 0xff && pkt[1] == 0x03) {
308 // PPP in HDLC-like framing, skip the Address and Control fields
309 if (len < 4) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400310 out << "Truncated PPP frame, length " << len;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400311 return true;
312 }
313 pkt += 2;
314 len -= 2;
315 }
316
317 unsigned int proto = pkt[0];
318 if (proto & 0x1) {
319 // Protocol field is compressed in 1 byte
320 pkt += 1;
321 len -= 1;
322 }
323 else {
324 // Protocol field is 2 bytes, in network byte order
325 proto = (proto << 8) | pkt[1];
326 pkt += 2;
327 len -= 2;
328 }
329
330 switch (proto) {
331 case 0x0077: // NDN in PPP frame, used by ndnSIM pcap traces
332 // For some reason, ndnSIM produces PPP frames with 2 extra bytes
333 // between the protocol field and the beginning of the NDN packet
334 if (len < 2) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400335 out << "Truncated NDN/PPP frame";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400336 return true;
337 }
338 pkt += 2;
339 len -= 2;
Davide Pesaventof9126532018-08-04 18:31:06 -0400340 out << "PPP";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400341 return printNdn(out, pkt, len);
342 default:
Davide Pesaventof9126532018-08-04 18:31:06 -0400343 out << "[Unsupported PPP proto " << AsHex{proto} << "]";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400344 return true;
345 }
346}
347
Davide Pesaventof9126532018-08-04 18:31:06 -0400348static void
349printIpAddress(OutputFormatter& out, int af, const void* addr)
350{
351 char addrStr[1 + std::max(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)] = {};
352 if (inet_ntop(af, addr, addrStr, sizeof(addrStr))) {
353 out << addrStr;
354 }
355 else {
356 out << "???";
357 }
358}
359
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400360bool
361NdnDump::printIp4(OutputFormatter& out, const uint8_t* pkt, size_t len) const
362{
Davide Pesaventof9126532018-08-04 18:31:06 -0400363 out.addDelimiter() << "IP ";
364
365 if (len < sizeof(ip)) {
366 out << "truncated header, length " << len;
367 return true;
368 }
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400369
370 auto ih = reinterpret_cast<const ip*>(pkt);
Davide Pesaventof9126532018-08-04 18:31:06 -0400371 if (ih->ip_v != 4) {
372 // huh? link layer said this was an IPv4 packet but IP header says otherwise
373 out << "bad version " << ih->ip_v;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400374 return true;
375 }
376
Davide Pesaventof9126532018-08-04 18:31:06 -0400377 size_t ipHdrLen = ih->ip_hl * 4;
378 if (ipHdrLen < sizeof(ip)) {
379 out << "bad header length " << ipHdrLen;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400380 return true;
381 }
382
Davide Pesaventof9126532018-08-04 18:31:06 -0400383 size_t ipLen = endian::big_to_native(ih->ip_len);
384 if (ipLen < ipHdrLen) {
385 out << "bad length " << ipLen;
386 return true;
387 }
388 if (ipLen > len) {
389 out << "truncated packet, " << ipLen - len << " bytes missing";
390 return true;
391 }
392 // if we reached this point, the following is true:
393 // sizeof(ip) <= ipHdrLen <= ipLen <= len
394
395 printIpAddress(out, AF_INET, &ih->ip_src);
396 out << " > ";
397 printIpAddress(out, AF_INET, &ih->ip_dst);
398
399 pkt += ipHdrLen;
400 len -= ipHdrLen;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400401
402 return dispatchByIpProto(out, pkt, len, ih->ip_p);
403}
404
405bool
406NdnDump::printTcp(OutputFormatter& out, const uint8_t* pkt, size_t len) const
407{
Davide Pesaventof9126532018-08-04 18:31:06 -0400408 out.addDelimiter() << "TCP";
409
410 if (len < sizeof(tcphdr)) {
411 out << " truncated header, length " << len;
412 return true;
413 }
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400414
415 auto th = reinterpret_cast<const tcphdr*>(pkt);
Davide Pesaventof9126532018-08-04 18:31:06 -0400416 size_t tcpHdrLen = th->th_off * 4;
417 if (tcpHdrLen < sizeof(tcphdr)) {
418 out << " bad header length " << tcpHdrLen;
419 return true;
420 }
421 if (tcpHdrLen > len) {
422 out << " truncated header, " << tcpHdrLen - len << " bytes missing";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400423 return true;
424 }
425
Davide Pesaventof9126532018-08-04 18:31:06 -0400426 pkt += tcpHdrLen;
427 len -= tcpHdrLen;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400428
Davide Pesaventof9126532018-08-04 18:31:06 -0400429 out.addDelimiter() << "length " << len;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400430
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400431 return printNdn(out, pkt, len);
432}
433
434bool
435NdnDump::printUdp(OutputFormatter& out, const uint8_t* pkt, size_t len) const
436{
Davide Pesaventof9126532018-08-04 18:31:06 -0400437 out.addDelimiter() << "UDP";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400438
439 if (len < sizeof(udphdr)) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400440 out << " truncated header, length " << len;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400441 return true;
442 }
443
Davide Pesaventof9126532018-08-04 18:31:06 -0400444 auto uh = reinterpret_cast<const udphdr*>(pkt);
445 size_t udpLen = endian::big_to_native(uh->uh_ulen);
446 if (udpLen < sizeof(udphdr)) {
447 out << " bad length " << udpLen;
448 return true;
449 }
450 if (udpLen > len) {
451 out << " truncated packet, " << udpLen - len << " bytes missing";
452 return true;
453 }
454 else {
455 len = udpLen;
456 }
457
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400458 pkt += sizeof(udphdr);
459 len -= sizeof(udphdr);
460
Davide Pesaventof9126532018-08-04 18:31:06 -0400461 out.addDelimiter() << "length " << len;
462
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400463 return printNdn(out, pkt, len);
464}
465
466bool
467NdnDump::printNdn(OutputFormatter& out, const uint8_t* pkt, size_t len) const
468{
469 if (len == 0) {
470 return false;
471 }
472 out.addDelimiter();
473
474 bool isOk = false;
475 Block block;
476 std::tie(isOk, block) = Block::fromBuffer(pkt, len);
477 if (!isOk) {
478 // if packet is incomplete, we will not be able to process it
Davide Pesaventof9126532018-08-04 18:31:06 -0400479 out << "NDN truncated packet, length " << len;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400480 return true;
481 }
482
483 lp::Packet lpPacket;
484 Block netPacket;
485
486 if (block.type() == lp::tlv::LpPacket) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400487 out << "NDNLPv2";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400488 try {
489 lpPacket.wireDecode(block);
490 }
491 catch (const tlv::Error& e) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400492 out << " invalid packet: " << e.what();
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400493 return true;
494 }
495
496 Buffer::const_iterator begin, end;
497 if (lpPacket.has<lp::FragmentField>()) {
498 std::tie(begin, end) = lpPacket.get<lp::FragmentField>();
499 }
500 else {
Davide Pesaventof9126532018-08-04 18:31:06 -0400501 out << " idle";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400502 return true;
503 }
504
505 bool isOk = false;
506 std::tie(isOk, netPacket) = Block::fromBuffer(&*begin, std::distance(begin, end));
507 if (!isOk) {
508 // if network packet is fragmented, we will not be able to process it
Davide Pesaventof9126532018-08-04 18:31:06 -0400509 out << " fragment";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400510 return true;
511 }
512 }
513 else {
514 netPacket = std::move(block);
515 }
Davide Pesaventof9126532018-08-04 18:31:06 -0400516 out.addDelimiter();
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400517
518 try {
519 switch (netPacket.type()) {
520 case tlv::Interest: {
521 Interest interest(netPacket);
522 if (!matchesFilter(interest.getName())) {
523 return false;
524 }
525
526 if (lpPacket.has<lp::NackField>()) {
527 lp::Nack nack(interest);
528 nack.setHeader(lpPacket.get<lp::NackField>());
Davide Pesaventof9126532018-08-04 18:31:06 -0400529 out << "NACK (" << nack.getReason() << "): " << interest;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400530 }
531 else {
532 out << "INTEREST: " << interest;
533 }
534 break;
535 }
536 case tlv::Data: {
537 Data data(netPacket);
538 if (!matchesFilter(data.getName())) {
539 return false;
540 }
541
542 out << "DATA: " << data.getName();
543 break;
544 }
545 default: {
Davide Pesaventof9126532018-08-04 18:31:06 -0400546 out << "[Unsupported NDN packet type " << netPacket.type() << "]";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400547 break;
548 }
549 }
550 }
551 catch (const tlv::Error& e) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400552 out << "invalid network packet: " << e.what();
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400553 }
554
555 return true;
Junxiao Shi2222a612015-06-06 08:01:38 -0700556}
557
Junxiao Shic1c2b832016-07-24 20:45:36 +0000558bool
Davide Pesaventoecd44802018-07-23 23:48:10 -0400559NdnDump::matchesFilter(const Name& name) const
Junxiao Shic1c2b832016-07-24 20:45:36 +0000560{
Davide Pesavento78de7352018-07-22 00:35:45 -0400561 if (!nameFilter)
Junxiao Shic1c2b832016-07-24 20:45:36 +0000562 return true;
563
564 /// \todo Switch to NDN regular expressions
Davide Pesavento78de7352018-07-22 00:35:45 -0400565 return std::regex_match(name.toUri(), *nameFilter);
Junxiao Shic1c2b832016-07-24 20:45:36 +0000566}
567
Junxiao Shi3cd47df2015-06-07 20:58:14 -0700568} // namespace dump
Junxiao Shi2222a612015-06-06 08:01:38 -0700569} // namespace ndn