blob: d5b6571ce9fd0b4329bc3ea1b57ee911b116cee8 [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 Pesavento80baddf2019-02-23 15:51:59 -05003 * Copyright (c) 2011-2019, 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>
Davide Pesavento0ca7e692018-08-05 02:21:06 -040025#include <netinet/ip6.h>
Davide Pesavento051db002018-07-22 18:56:16 -040026#include <netinet/tcp.h>
27#include <netinet/udp.h>
Junxiao Shi2222a612015-06-06 08:01:38 -070028
Junxiao Shi022bddf2016-11-24 23:15:20 +000029#include <pcap/sll.h>
30
Junxiao Shi2222a612015-06-06 08:01:38 -070031#include <iomanip>
Davide Pesaventoc0702702017-08-24 22:04:00 -040032#include <sstream>
Junxiao Shi2222a612015-06-06 08:01:38 -070033
Vince Lehman277ecf02016-02-10 16:37:48 -060034#include <ndn-cxx/lp/nack.hpp>
35#include <ndn-cxx/lp/packet.hpp>
Davide Pesaventoecd44802018-07-23 23:48:10 -040036#include <ndn-cxx/net/ethernet.hpp>
Davide Pesaventob6b176c2018-07-28 22:05:16 -040037#include <ndn-cxx/util/string-helper.hpp>
38
39#include <boost/endian/conversion.hpp>
Junxiao Shi2222a612015-06-06 08:01:38 -070040
41namespace ndn {
Junxiao Shi3cd47df2015-06-07 20:58:14 -070042namespace dump {
Junxiao Shi2222a612015-06-06 08:01:38 -070043
Davide Pesaventob6b176c2018-07-28 22:05:16 -040044namespace endian = boost::endian;
45
46class OutputFormatter : noncopyable
47{
48public:
49 OutputFormatter(std::ostream& os, std::string d)
50 : m_os(os)
51 , m_delim(std::move(d))
52 {
53 }
54
55 OutputFormatter&
56 addDelimiter()
57 {
58 if (!m_isEmpty) {
59 m_wantDelim = true;
60 }
61 return *this;
62 }
63
64private:
65 std::ostream& m_os;
66 std::string m_delim;
67 bool m_isEmpty = true;
68 bool m_wantDelim = false;
69
70 template<typename T>
71 friend OutputFormatter& operator<<(OutputFormatter&, const T&);
72};
73
74template<typename T>
75OutputFormatter&
76operator<<(OutputFormatter& out, const T& val)
77{
78 if (out.m_wantDelim) {
79 out.m_os << out.m_delim;
80 out.m_wantDelim = false;
81 }
82 out.m_os << val;
83 out.m_isEmpty = false;
84 return out;
85}
86
Davide Pesaventoecd44802018-07-23 23:48:10 -040087NdnDump::~NdnDump()
Junxiao Shic1c2b832016-07-24 20:45:36 +000088{
Davide Pesaventoecd44802018-07-23 23:48:10 -040089 if (m_pcap)
90 pcap_close(m_pcap);
91}
92
Junxiao Shi2222a612015-06-06 08:01:38 -070093void
Davide Pesaventoecd44802018-07-23 23:48:10 -040094NdnDump::run()
Junxiao Shi2222a612015-06-06 08:01:38 -070095{
Davide Pesaventof9126532018-08-04 18:31:06 -040096 char errbuf[PCAP_ERRBUF_SIZE] = {};
Junxiao Shi2222a612015-06-06 08:01:38 -070097
Davide Pesaventoecd44802018-07-23 23:48:10 -040098 if (inputFile.empty() && interface.empty()) {
99 const char* defaultDevice = pcap_lookupdev(errbuf);
100
101 if (defaultDevice == nullptr) {
Davide Pesavento80baddf2019-02-23 15:51:59 -0500102 NDN_THROW(Error(errbuf));
Junxiao Shi2222a612015-06-06 08:01:38 -0700103 }
104
Davide Pesaventoecd44802018-07-23 23:48:10 -0400105 interface = defaultDevice;
Junxiao Shi2222a612015-06-06 08:01:38 -0700106 }
107
Davide Pesaventoecd44802018-07-23 23:48:10 -0400108 std::string action;
Junxiao Shi2222a612015-06-06 08:01:38 -0700109 if (!interface.empty()) {
Davide Pesavento24c08612018-07-26 13:33:24 -0400110 m_pcap = pcap_open_live(interface.data(), 65535, wantPromisc, 1000, errbuf);
Junxiao Shic1c2b832016-07-24 20:45:36 +0000111 if (m_pcap == nullptr) {
Davide Pesavento80baddf2019-02-23 15:51:59 -0500112 NDN_THROW(Error("Cannot open interface " + interface + ": " + errbuf));
Junxiao Shi2222a612015-06-06 08:01:38 -0700113 }
Davide Pesaventoecd44802018-07-23 23:48:10 -0400114 action = "listening on " + interface;
Junxiao Shi2222a612015-06-06 08:01:38 -0700115 }
116 else {
Davide Pesavento78de7352018-07-22 00:35:45 -0400117 m_pcap = pcap_open_offline(inputFile.data(), errbuf);
Junxiao Shic1c2b832016-07-24 20:45:36 +0000118 if (m_pcap == nullptr) {
Davide Pesavento80baddf2019-02-23 15:51:59 -0500119 NDN_THROW(Error("Cannot open file '" + inputFile + "' for reading: " + errbuf));
Junxiao Shi2222a612015-06-06 08:01:38 -0700120 }
Davide Pesaventoecd44802018-07-23 23:48:10 -0400121 action = "reading from file " + inputFile;
Junxiao Shi2222a612015-06-06 08:01:38 -0700122 }
123
Davide Pesaventoecd44802018-07-23 23:48:10 -0400124 m_dataLinkType = pcap_datalink(m_pcap);
125 const char* dltName = pcap_datalink_val_to_name(m_dataLinkType);
126 const char* dltDesc = pcap_datalink_val_to_description(m_dataLinkType);
127 std::string formattedDlt = dltName ? dltName : to_string(m_dataLinkType);
128 if (dltDesc) {
129 formattedDlt += " ("s + dltDesc + ")";
130 }
131
132 std::cerr << "ndndump: " << action << ", link-type " << formattedDlt << std::endl;
133
134 switch (m_dataLinkType) {
135 case DLT_EN10MB:
136 case DLT_LINUX_SLL:
137 case DLT_PPP:
138 // we know how to handle these
139 break;
140 default:
Davide Pesavento80baddf2019-02-23 15:51:59 -0500141 NDN_THROW(Error("Unsupported link-layer header type " + formattedDlt));
Davide Pesaventoecd44802018-07-23 23:48:10 -0400142 }
143
144 if (!pcapFilter.empty()) {
Davide Pesavento24c08612018-07-26 13:33:24 -0400145 if (wantVerbose) {
Davide Pesaventoecd44802018-07-23 23:48:10 -0400146 std::cerr << "ndndump: using pcap filter: " << pcapFilter << std::endl;
Junxiao Shi2222a612015-06-06 08:01:38 -0700147 }
148
149 bpf_program program;
Davide Pesaventofb42a3d2018-07-26 12:33:14 -0400150 int res = pcap_compile(m_pcap, &program, pcapFilter.data(), 1, PCAP_NETMASK_UNKNOWN);
Junxiao Shic1c2b832016-07-24 20:45:36 +0000151 if (res < 0) {
Davide Pesavento80baddf2019-02-23 15:51:59 -0500152 NDN_THROW(Error("Cannot compile pcap filter '" + pcapFilter + "': " + pcap_geterr(m_pcap)));
Junxiao Shi2222a612015-06-06 08:01:38 -0700153 }
154
Junxiao Shic1c2b832016-07-24 20:45:36 +0000155 res = pcap_setfilter(m_pcap, &program);
Junxiao Shi2222a612015-06-06 08:01:38 -0700156 pcap_freecode(&program);
Junxiao Shic1c2b832016-07-24 20:45:36 +0000157 if (res < 0) {
Davide Pesavento80baddf2019-02-23 15:51:59 -0500158 NDN_THROW(Error("Cannot set pcap filter: "s + pcap_geterr(m_pcap)));
Junxiao Shi2222a612015-06-06 08:01:38 -0700159 }
160 }
161
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400162 auto callback = [] (uint8_t* user, const pcap_pkthdr* pkthdr, const uint8_t* payload) {
163 reinterpret_cast<const NdnDump*>(user)->printPacket(pkthdr, payload);
164 };
165
166 if (pcap_loop(m_pcap, -1, callback, reinterpret_cast<uint8_t*>(this)) < 0) {
Davide Pesavento80baddf2019-02-23 15:51:59 -0500167 NDN_THROW(Error("pcap_loop: "s + pcap_geterr(m_pcap)));
Junxiao Shic1c2b832016-07-24 20:45:36 +0000168 }
Junxiao Shi2222a612015-06-06 08:01:38 -0700169}
170
Junxiao Shi2222a612015-06-06 08:01:38 -0700171void
Davide Pesaventoecd44802018-07-23 23:48:10 -0400172NdnDump::printPacket(const pcap_pkthdr* pkthdr, const uint8_t* payload) const
Junxiao Shi2222a612015-06-06 08:01:38 -0700173{
Davide Pesaventoecd44802018-07-23 23:48:10 -0400174 // sanity checks
175 if (pkthdr->caplen == 0) {
176 std::cout << "[Invalid header: caplen=0]" << std::endl;
177 return;
178 }
179 if (pkthdr->len == 0) {
180 std::cout << "[Invalid header: len=0]" << std::endl;
181 return;
182 }
183 else if (pkthdr->len < pkthdr->caplen) {
184 std::cout << "[Invalid header: len(" << pkthdr->len
185 << ") < caplen(" << pkthdr->caplen << ")]" << std::endl;
186 return;
187 }
Junxiao Shi2222a612015-06-06 08:01:38 -0700188
Davide Pesaventoecd44802018-07-23 23:48:10 -0400189 std::ostringstream os;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400190 OutputFormatter out(os, ", ");
Davide Pesaventoecd44802018-07-23 23:48:10 -0400191
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400192 bool shouldPrint = false;
193 switch (m_dataLinkType) {
194 case DLT_EN10MB:
195 shouldPrint = printEther(out, payload, pkthdr->len);
196 break;
197 case DLT_LINUX_SLL:
198 shouldPrint = printLinuxSll(out, payload, pkthdr->len);
199 break;
200 case DLT_PPP:
201 shouldPrint = printPpp(out, payload, pkthdr->len);
202 break;
203 default:
204 BOOST_ASSERT(false);
Junxiao Shi2222a612015-06-06 08:01:38 -0700205 return;
206 }
207
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400208 if (shouldPrint) {
209 if (wantTimestamp) {
210 printTimestamp(std::cout, pkthdr->ts);
Vince Lehman277ecf02016-02-10 16:37:48 -0600211 }
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400212 std::cout << os.str() << std::endl;
Junxiao Shi2222a612015-06-06 08:01:38 -0700213 }
214}
215
216void
Davide Pesaventoecd44802018-07-23 23:48:10 -0400217NdnDump::printTimestamp(std::ostream& os, const timeval& tv) const
Junxiao Shi2222a612015-06-06 08:01:38 -0700218{
Davide Pesaventoecd44802018-07-23 23:48:10 -0400219 /// \todo Add more timestamp formats (time since previous packet, time since first packet, ...)
220 os << tv.tv_sec
Junxiao Shi2222a612015-06-06 08:01:38 -0700221 << "."
Davide Pesaventoecd44802018-07-23 23:48:10 -0400222 << std::setfill('0') << std::setw(6) << tv.tv_usec
223 << " ";
Junxiao Shi2222a612015-06-06 08:01:38 -0700224}
225
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400226bool
227NdnDump::dispatchByEtherType(OutputFormatter& out, const uint8_t* pkt, size_t len, uint16_t etherType) const
Junxiao Shi2222a612015-06-06 08:01:38 -0700228{
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400229 out.addDelimiter();
Junxiao Shi2222a612015-06-06 08:01:38 -0700230
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400231 switch (etherType) {
232 case ETHERTYPE_IP:
233 return printIp4(out, pkt, len);
Davide Pesavento0ca7e692018-08-05 02:21:06 -0400234 case ETHERTYPE_IPV6:
235 return printIp6(out, pkt, len);
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400236 case ethernet::ETHERTYPE_NDN:
237 case 0x7777: // NDN ethertype used in ndnSIM
Davide Pesaventof9126532018-08-04 18:31:06 -0400238 out << "Ethernet";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400239 return printNdn(out, pkt, len);
240 default:
Davide Pesaventof9126532018-08-04 18:31:06 -0400241 out << "[Unsupported ethertype " << AsHex{etherType} << "]";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400242 return true;
Junxiao Shi2222a612015-06-06 08:01:38 -0700243 }
Junxiao Shi2222a612015-06-06 08:01:38 -0700244}
245
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400246bool
247NdnDump::dispatchByIpProto(OutputFormatter& out, const uint8_t* pkt, size_t len, uint8_t ipProto) const
Junxiao Shi2222a612015-06-06 08:01:38 -0700248{
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400249 out.addDelimiter();
Junxiao Shi2222a612015-06-06 08:01:38 -0700250
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400251 switch (ipProto) {
Davide Pesavento0ca7e692018-08-05 02:21:06 -0400252 case IPPROTO_NONE:
253 out << "[No next header]";
254 return true;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400255 case IPPROTO_TCP:
256 return printTcp(out, pkt, len);
257 case IPPROTO_UDP:
258 return printUdp(out, pkt, len);
259 default:
Davide Pesaventof9126532018-08-04 18:31:06 -0400260 out << "[Unsupported IP proto " << static_cast<int>(ipProto) << "]";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400261 return true;
262 }
263}
Junxiao Shi2222a612015-06-06 08:01:38 -0700264
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400265bool
266NdnDump::printEther(OutputFormatter& out, const uint8_t* pkt, size_t len) const
267{
268 // IEEE 802.3 Ethernet
Junxiao Shi2222a612015-06-06 08:01:38 -0700269
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400270 if (len < ethernet::HDR_LEN) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400271 out << "Truncated Ethernet frame, length " << len;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400272 return true;
Junxiao Shic1c2b832016-07-24 20:45:36 +0000273 }
Junxiao Shi2222a612015-06-06 08:01:38 -0700274
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400275 auto ether = reinterpret_cast<const ether_header*>(pkt);
276 pkt += ethernet::HDR_LEN;
277 len -= ethernet::HDR_LEN;
278
279 return dispatchByEtherType(out, pkt, len, endian::big_to_native(ether->ether_type));
280}
281
282bool
283NdnDump::printLinuxSll(OutputFormatter& out, const uint8_t* pkt, size_t len) const
284{
285 // Linux "cooked" capture encapsulation
286 // https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html
287
288 if (len < SLL_HDR_LEN) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400289 out << "Truncated LINUX_SLL frame, length " << len;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400290 return true;
291 }
292
293 auto sll = reinterpret_cast<const sll_header*>(pkt);
294 pkt += SLL_HDR_LEN;
295 len -= SLL_HDR_LEN;
296
297 return dispatchByEtherType(out, pkt, len, endian::big_to_native(sll->sll_protocol));
298}
299
300bool
301NdnDump::printPpp(OutputFormatter& out, const uint8_t* pkt, size_t len) const
302{
303 // PPP, as per RFC 1661 and RFC 1662; if the first 2 bytes are 0xff and 0x03,
304 // it's PPP in HDLC-like framing, with the PPP header following those two bytes,
305 // otherwise it's PPP without framing, and the packet begins with the PPP header.
306 // The data in the frame is not octet-stuffed or bit-stuffed.
307
308 if (len < 2) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400309 out << "Truncated PPP frame, length " << len;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400310 return true;
311 }
312
313 if (pkt[0] == 0xff && pkt[1] == 0x03) {
314 // PPP in HDLC-like framing, skip the Address and Control fields
315 if (len < 4) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400316 out << "Truncated PPP frame, length " << len;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400317 return true;
318 }
319 pkt += 2;
320 len -= 2;
321 }
322
323 unsigned int proto = pkt[0];
324 if (proto & 0x1) {
325 // Protocol field is compressed in 1 byte
326 pkt += 1;
327 len -= 1;
328 }
329 else {
330 // Protocol field is 2 bytes, in network byte order
331 proto = (proto << 8) | pkt[1];
332 pkt += 2;
333 len -= 2;
334 }
335
336 switch (proto) {
337 case 0x0077: // NDN in PPP frame, used by ndnSIM pcap traces
338 // For some reason, ndnSIM produces PPP frames with 2 extra bytes
339 // between the protocol field and the beginning of the NDN packet
340 if (len < 2) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400341 out << "Truncated NDN/PPP frame";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400342 return true;
343 }
344 pkt += 2;
345 len -= 2;
Davide Pesaventof9126532018-08-04 18:31:06 -0400346 out << "PPP";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400347 return printNdn(out, pkt, len);
348 default:
Davide Pesaventof9126532018-08-04 18:31:06 -0400349 out << "[Unsupported PPP proto " << AsHex{proto} << "]";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400350 return true;
351 }
352}
353
Davide Pesaventof9126532018-08-04 18:31:06 -0400354static void
355printIpAddress(OutputFormatter& out, int af, const void* addr)
356{
357 char addrStr[1 + std::max(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)] = {};
358 if (inet_ntop(af, addr, addrStr, sizeof(addrStr))) {
359 out << addrStr;
360 }
361 else {
362 out << "???";
363 }
364}
365
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400366bool
367NdnDump::printIp4(OutputFormatter& out, const uint8_t* pkt, size_t len) const
368{
Davide Pesaventof9126532018-08-04 18:31:06 -0400369 out.addDelimiter() << "IP ";
370
371 if (len < sizeof(ip)) {
372 out << "truncated header, length " << len;
373 return true;
374 }
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400375
376 auto ih = reinterpret_cast<const ip*>(pkt);
Davide Pesaventof9126532018-08-04 18:31:06 -0400377 if (ih->ip_v != 4) {
378 // huh? link layer said this was an IPv4 packet but IP header says otherwise
379 out << "bad version " << ih->ip_v;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400380 return true;
381 }
382
Davide Pesaventof9126532018-08-04 18:31:06 -0400383 size_t ipHdrLen = ih->ip_hl * 4;
384 if (ipHdrLen < sizeof(ip)) {
385 out << "bad header length " << ipHdrLen;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400386 return true;
387 }
388
Davide Pesaventof9126532018-08-04 18:31:06 -0400389 size_t ipLen = endian::big_to_native(ih->ip_len);
390 if (ipLen < ipHdrLen) {
391 out << "bad length " << ipLen;
392 return true;
393 }
394 if (ipLen > len) {
395 out << "truncated packet, " << ipLen - len << " bytes missing";
396 return true;
397 }
398 // if we reached this point, the following is true:
399 // sizeof(ip) <= ipHdrLen <= ipLen <= len
400
401 printIpAddress(out, AF_INET, &ih->ip_src);
402 out << " > ";
403 printIpAddress(out, AF_INET, &ih->ip_dst);
404
405 pkt += ipHdrLen;
406 len -= ipHdrLen;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400407
408 return dispatchByIpProto(out, pkt, len, ih->ip_p);
409}
410
411bool
Davide Pesavento0ca7e692018-08-05 02:21:06 -0400412NdnDump::printIp6(OutputFormatter& out, const uint8_t* pkt, size_t len) const
413{
414 out.addDelimiter() << "IP6 ";
415
416 if (len < sizeof(ip6_hdr)) {
417 out << "truncated header, length " << len;
418 return true;
419 }
420
421 auto ip6 = reinterpret_cast<const ip6_hdr*>(pkt);
422 unsigned int ipVer = (ip6->ip6_vfc & 0xf0) >> 4;
423 if (ipVer != 6) {
424 // huh? link layer said this was an IPv6 packet but IP header says otherwise
425 out << "bad version " << ipVer;
426 return true;
427 }
428
429 pkt += sizeof(ip6_hdr);
430 len -= sizeof(ip6_hdr);
431
432 size_t payloadLen = endian::big_to_native(ip6->ip6_plen);
433 if (len < payloadLen) {
434 out << "truncated payload, " << payloadLen - len << " bytes missing";
435 return true;
436 }
437
438 printIpAddress(out, AF_INET6, &ip6->ip6_src);
439 out << " > ";
440 printIpAddress(out, AF_INET6, &ip6->ip6_dst);
441
442 // we assume no extension headers are present
443 return dispatchByIpProto(out, pkt, len, ip6->ip6_nxt);
444}
445
446bool
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400447NdnDump::printTcp(OutputFormatter& out, const uint8_t* pkt, size_t len) const
448{
Davide Pesaventof9126532018-08-04 18:31:06 -0400449 out.addDelimiter() << "TCP";
450
451 if (len < sizeof(tcphdr)) {
452 out << " truncated header, length " << len;
453 return true;
454 }
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400455
456 auto th = reinterpret_cast<const tcphdr*>(pkt);
Davide Pesavento7b9837b2019-02-23 19:07:50 -0500457 size_t tcpHdrLen = th->TH_OFF * 4;
Davide Pesaventof9126532018-08-04 18:31:06 -0400458 if (tcpHdrLen < sizeof(tcphdr)) {
459 out << " bad header length " << tcpHdrLen;
460 return true;
461 }
462 if (tcpHdrLen > len) {
463 out << " truncated header, " << tcpHdrLen - len << " bytes missing";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400464 return true;
465 }
466
Davide Pesaventof9126532018-08-04 18:31:06 -0400467 pkt += tcpHdrLen;
468 len -= tcpHdrLen;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400469
Davide Pesaventof9126532018-08-04 18:31:06 -0400470 out.addDelimiter() << "length " << len;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400471
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400472 return printNdn(out, pkt, len);
473}
474
475bool
476NdnDump::printUdp(OutputFormatter& out, const uint8_t* pkt, size_t len) const
477{
Davide Pesaventof9126532018-08-04 18:31:06 -0400478 out.addDelimiter() << "UDP";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400479
480 if (len < sizeof(udphdr)) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400481 out << " truncated header, length " << len;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400482 return true;
483 }
484
Davide Pesaventof9126532018-08-04 18:31:06 -0400485 auto uh = reinterpret_cast<const udphdr*>(pkt);
Davide Pesavento7b9837b2019-02-23 19:07:50 -0500486 size_t udpLen = endian::big_to_native(uh->UH_LEN);
Davide Pesaventof9126532018-08-04 18:31:06 -0400487 if (udpLen < sizeof(udphdr)) {
488 out << " bad length " << udpLen;
489 return true;
490 }
491 if (udpLen > len) {
492 out << " truncated packet, " << udpLen - len << " bytes missing";
493 return true;
494 }
495 else {
496 len = udpLen;
497 }
498
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400499 pkt += sizeof(udphdr);
500 len -= sizeof(udphdr);
501
Davide Pesaventof9126532018-08-04 18:31:06 -0400502 out.addDelimiter() << "length " << len;
503
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400504 return printNdn(out, pkt, len);
505}
506
507bool
508NdnDump::printNdn(OutputFormatter& out, const uint8_t* pkt, size_t len) const
509{
510 if (len == 0) {
511 return false;
512 }
513 out.addDelimiter();
514
515 bool isOk = false;
516 Block block;
517 std::tie(isOk, block) = Block::fromBuffer(pkt, len);
518 if (!isOk) {
519 // if packet is incomplete, we will not be able to process it
Davide Pesaventof9126532018-08-04 18:31:06 -0400520 out << "NDN truncated packet, length " << len;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400521 return true;
522 }
523
524 lp::Packet lpPacket;
525 Block netPacket;
526
527 if (block.type() == lp::tlv::LpPacket) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400528 out << "NDNLPv2";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400529 try {
530 lpPacket.wireDecode(block);
531 }
532 catch (const tlv::Error& e) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400533 out << " invalid packet: " << e.what();
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400534 return true;
535 }
536
537 Buffer::const_iterator begin, end;
538 if (lpPacket.has<lp::FragmentField>()) {
539 std::tie(begin, end) = lpPacket.get<lp::FragmentField>();
540 }
541 else {
Davide Pesaventof9126532018-08-04 18:31:06 -0400542 out << " idle";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400543 return true;
544 }
545
546 bool isOk = false;
547 std::tie(isOk, netPacket) = Block::fromBuffer(&*begin, std::distance(begin, end));
548 if (!isOk) {
549 // if network packet is fragmented, we will not be able to process it
Davide Pesaventof9126532018-08-04 18:31:06 -0400550 out << " fragment";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400551 return true;
552 }
553 }
554 else {
555 netPacket = std::move(block);
556 }
Davide Pesaventof9126532018-08-04 18:31:06 -0400557 out.addDelimiter();
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400558
559 try {
560 switch (netPacket.type()) {
561 case tlv::Interest: {
562 Interest interest(netPacket);
563 if (!matchesFilter(interest.getName())) {
564 return false;
565 }
566
567 if (lpPacket.has<lp::NackField>()) {
568 lp::Nack nack(interest);
569 nack.setHeader(lpPacket.get<lp::NackField>());
Davide Pesaventof9126532018-08-04 18:31:06 -0400570 out << "NACK (" << nack.getReason() << "): " << interest;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400571 }
572 else {
573 out << "INTEREST: " << interest;
574 }
575 break;
576 }
577 case tlv::Data: {
578 Data data(netPacket);
579 if (!matchesFilter(data.getName())) {
580 return false;
581 }
582
583 out << "DATA: " << data.getName();
584 break;
585 }
586 default: {
Davide Pesaventof9126532018-08-04 18:31:06 -0400587 out << "[Unsupported NDN packet type " << netPacket.type() << "]";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400588 break;
589 }
590 }
591 }
592 catch (const tlv::Error& e) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400593 out << "invalid network packet: " << e.what();
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400594 }
595
596 return true;
Junxiao Shi2222a612015-06-06 08:01:38 -0700597}
598
Junxiao Shic1c2b832016-07-24 20:45:36 +0000599bool
Davide Pesaventoecd44802018-07-23 23:48:10 -0400600NdnDump::matchesFilter(const Name& name) const
Junxiao Shic1c2b832016-07-24 20:45:36 +0000601{
Davide Pesavento78de7352018-07-22 00:35:45 -0400602 if (!nameFilter)
Junxiao Shic1c2b832016-07-24 20:45:36 +0000603 return true;
604
605 /// \todo Switch to NDN regular expressions
Davide Pesavento78de7352018-07-22 00:35:45 -0400606 return std::regex_match(name.toUri(), *nameFilter);
Junxiao Shic1c2b832016-07-24 20:45:36 +0000607}
608
Junxiao Shi3cd47df2015-06-07 20:58:14 -0700609} // namespace dump
Junxiao Shi2222a612015-06-06 08:01:38 -0700610} // namespace ndn