blob: ed7fd935007c05a6c5c62b2eefbe51f86db65c3f [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/*
Junxiao Shied0017b2022-02-04 02:16:39 +00003 * Copyright (c) 2011-2022, 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>
Junxiao Shied0017b2022-02-04 02:16:39 +000037#include <ndn-cxx/util/scope.hpp>
Davide Pesaventob6b176c2018-07-28 22:05:16 -040038#include <ndn-cxx/util/string-helper.hpp>
39
40#include <boost/endian/conversion.hpp>
Junxiao Shi2222a612015-06-06 08:01:38 -070041
42namespace ndn {
Junxiao Shi3cd47df2015-06-07 20:58:14 -070043namespace dump {
Junxiao Shi2222a612015-06-06 08:01:38 -070044
Davide Pesaventob6b176c2018-07-28 22:05:16 -040045namespace endian = boost::endian;
46
47class OutputFormatter : noncopyable
48{
49public:
50 OutputFormatter(std::ostream& os, std::string d)
51 : m_os(os)
52 , m_delim(std::move(d))
53 {
54 }
55
56 OutputFormatter&
57 addDelimiter()
58 {
59 if (!m_isEmpty) {
60 m_wantDelim = true;
61 }
62 return *this;
63 }
64
65private:
66 std::ostream& m_os;
67 std::string m_delim;
68 bool m_isEmpty = true;
69 bool m_wantDelim = false;
70
71 template<typename T>
72 friend OutputFormatter& operator<<(OutputFormatter&, const T&);
73};
74
75template<typename T>
76OutputFormatter&
77operator<<(OutputFormatter& out, const T& val)
78{
79 if (out.m_wantDelim) {
80 out.m_os << out.m_delim;
81 out.m_wantDelim = false;
82 }
83 out.m_os << val;
84 out.m_isEmpty = false;
85 return out;
86}
87
Davide Pesaventoecd44802018-07-23 23:48:10 -040088NdnDump::~NdnDump()
Junxiao Shic1c2b832016-07-24 20:45:36 +000089{
Davide Pesaventoecd44802018-07-23 23:48:10 -040090 if (m_pcap)
91 pcap_close(m_pcap);
92}
93
Junxiao Shi2222a612015-06-06 08:01:38 -070094void
Davide Pesaventoecd44802018-07-23 23:48:10 -040095NdnDump::run()
Junxiao Shi2222a612015-06-06 08:01:38 -070096{
Davide Pesaventof9126532018-08-04 18:31:06 -040097 char errbuf[PCAP_ERRBUF_SIZE] = {};
Junxiao Shi2222a612015-06-06 08:01:38 -070098
Davide Pesaventoecd44802018-07-23 23:48:10 -040099 if (inputFile.empty() && interface.empty()) {
Junxiao Shied0017b2022-02-04 02:16:39 +0000100 pcap_if_t* allDevs = nullptr;
101 int res = pcap_findalldevs(&allDevs, errbuf);
102 auto freealldevs = ndn::make_scope_exit([=] { pcap_freealldevs(allDevs); });
Davide Pesaventoecd44802018-07-23 23:48:10 -0400103
Junxiao Shied0017b2022-02-04 02:16:39 +0000104 if (res != 0) {
Davide Pesavento80baddf2019-02-23 15:51:59 -0500105 NDN_THROW(Error(errbuf));
Junxiao Shi2222a612015-06-06 08:01:38 -0700106 }
Junxiao Shied0017b2022-02-04 02:16:39 +0000107 if (allDevs == nullptr) {
108 NDN_THROW(Error("No network interface found"));
109 }
Junxiao Shi2222a612015-06-06 08:01:38 -0700110
Junxiao Shied0017b2022-02-04 02:16:39 +0000111 interface = allDevs->name;
Junxiao Shi2222a612015-06-06 08:01:38 -0700112 }
113
Davide Pesaventoecd44802018-07-23 23:48:10 -0400114 std::string action;
Junxiao Shi2222a612015-06-06 08:01:38 -0700115 if (!interface.empty()) {
Davide Pesavento24c08612018-07-26 13:33:24 -0400116 m_pcap = pcap_open_live(interface.data(), 65535, wantPromisc, 1000, errbuf);
Junxiao Shic1c2b832016-07-24 20:45:36 +0000117 if (m_pcap == nullptr) {
Davide Pesavento80baddf2019-02-23 15:51:59 -0500118 NDN_THROW(Error("Cannot open interface " + interface + ": " + errbuf));
Junxiao Shi2222a612015-06-06 08:01:38 -0700119 }
Davide Pesaventoecd44802018-07-23 23:48:10 -0400120 action = "listening on " + interface;
Junxiao Shi2222a612015-06-06 08:01:38 -0700121 }
122 else {
Davide Pesavento78de7352018-07-22 00:35:45 -0400123 m_pcap = pcap_open_offline(inputFile.data(), errbuf);
Junxiao Shic1c2b832016-07-24 20:45:36 +0000124 if (m_pcap == nullptr) {
Davide Pesavento80baddf2019-02-23 15:51:59 -0500125 NDN_THROW(Error("Cannot open file '" + inputFile + "' for reading: " + errbuf));
Junxiao Shi2222a612015-06-06 08:01:38 -0700126 }
Davide Pesaventoecd44802018-07-23 23:48:10 -0400127 action = "reading from file " + inputFile;
Junxiao Shi2222a612015-06-06 08:01:38 -0700128 }
129
Davide Pesaventoecd44802018-07-23 23:48:10 -0400130 m_dataLinkType = pcap_datalink(m_pcap);
131 const char* dltName = pcap_datalink_val_to_name(m_dataLinkType);
132 const char* dltDesc = pcap_datalink_val_to_description(m_dataLinkType);
133 std::string formattedDlt = dltName ? dltName : to_string(m_dataLinkType);
134 if (dltDesc) {
135 formattedDlt += " ("s + dltDesc + ")";
136 }
137
138 std::cerr << "ndndump: " << action << ", link-type " << formattedDlt << std::endl;
139
140 switch (m_dataLinkType) {
141 case DLT_EN10MB:
142 case DLT_LINUX_SLL:
143 case DLT_PPP:
144 // we know how to handle these
145 break;
146 default:
Davide Pesavento80baddf2019-02-23 15:51:59 -0500147 NDN_THROW(Error("Unsupported link-layer header type " + formattedDlt));
Davide Pesaventoecd44802018-07-23 23:48:10 -0400148 }
149
150 if (!pcapFilter.empty()) {
Davide Pesavento24c08612018-07-26 13:33:24 -0400151 if (wantVerbose) {
Davide Pesaventoecd44802018-07-23 23:48:10 -0400152 std::cerr << "ndndump: using pcap filter: " << pcapFilter << std::endl;
Junxiao Shi2222a612015-06-06 08:01:38 -0700153 }
154
155 bpf_program program;
Davide Pesaventofb42a3d2018-07-26 12:33:14 -0400156 int res = pcap_compile(m_pcap, &program, pcapFilter.data(), 1, PCAP_NETMASK_UNKNOWN);
Junxiao Shic1c2b832016-07-24 20:45:36 +0000157 if (res < 0) {
Davide Pesavento80baddf2019-02-23 15:51:59 -0500158 NDN_THROW(Error("Cannot compile pcap filter '" + pcapFilter + "': " + pcap_geterr(m_pcap)));
Junxiao Shi2222a612015-06-06 08:01:38 -0700159 }
Junxiao Shied0017b2022-02-04 02:16:39 +0000160 auto freecode = ndn::make_scope_exit([&] { pcap_freecode(&program); });
Junxiao Shi2222a612015-06-06 08:01:38 -0700161
Junxiao Shic1c2b832016-07-24 20:45:36 +0000162 res = pcap_setfilter(m_pcap, &program);
Junxiao Shic1c2b832016-07-24 20:45:36 +0000163 if (res < 0) {
Davide Pesavento80baddf2019-02-23 15:51:59 -0500164 NDN_THROW(Error("Cannot set pcap filter: "s + pcap_geterr(m_pcap)));
Junxiao Shi2222a612015-06-06 08:01:38 -0700165 }
166 }
167
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400168 auto callback = [] (uint8_t* user, const pcap_pkthdr* pkthdr, const uint8_t* payload) {
169 reinterpret_cast<const NdnDump*>(user)->printPacket(pkthdr, payload);
170 };
171
172 if (pcap_loop(m_pcap, -1, callback, reinterpret_cast<uint8_t*>(this)) < 0) {
Davide Pesavento80baddf2019-02-23 15:51:59 -0500173 NDN_THROW(Error("pcap_loop: "s + pcap_geterr(m_pcap)));
Junxiao Shic1c2b832016-07-24 20:45:36 +0000174 }
Junxiao Shi2222a612015-06-06 08:01:38 -0700175}
176
Junxiao Shi2222a612015-06-06 08:01:38 -0700177void
Davide Pesaventoecd44802018-07-23 23:48:10 -0400178NdnDump::printPacket(const pcap_pkthdr* pkthdr, const uint8_t* payload) const
Junxiao Shi2222a612015-06-06 08:01:38 -0700179{
Davide Pesaventoecd44802018-07-23 23:48:10 -0400180 // sanity checks
181 if (pkthdr->caplen == 0) {
182 std::cout << "[Invalid header: caplen=0]" << std::endl;
183 return;
184 }
185 if (pkthdr->len == 0) {
186 std::cout << "[Invalid header: len=0]" << std::endl;
187 return;
188 }
189 else if (pkthdr->len < pkthdr->caplen) {
190 std::cout << "[Invalid header: len(" << pkthdr->len
191 << ") < caplen(" << pkthdr->caplen << ")]" << std::endl;
192 return;
193 }
Junxiao Shi2222a612015-06-06 08:01:38 -0700194
Davide Pesaventoecd44802018-07-23 23:48:10 -0400195 std::ostringstream os;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400196 OutputFormatter out(os, ", ");
Davide Pesaventoecd44802018-07-23 23:48:10 -0400197
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400198 bool shouldPrint = false;
199 switch (m_dataLinkType) {
200 case DLT_EN10MB:
201 shouldPrint = printEther(out, payload, pkthdr->len);
202 break;
203 case DLT_LINUX_SLL:
204 shouldPrint = printLinuxSll(out, payload, pkthdr->len);
205 break;
206 case DLT_PPP:
207 shouldPrint = printPpp(out, payload, pkthdr->len);
208 break;
209 default:
210 BOOST_ASSERT(false);
Junxiao Shi2222a612015-06-06 08:01:38 -0700211 return;
212 }
213
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400214 if (shouldPrint) {
215 if (wantTimestamp) {
216 printTimestamp(std::cout, pkthdr->ts);
Vince Lehman277ecf02016-02-10 16:37:48 -0600217 }
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400218 std::cout << os.str() << std::endl;
Junxiao Shi2222a612015-06-06 08:01:38 -0700219 }
220}
221
222void
Davide Pesaventoecd44802018-07-23 23:48:10 -0400223NdnDump::printTimestamp(std::ostream& os, const timeval& tv) const
Junxiao Shi2222a612015-06-06 08:01:38 -0700224{
Davide Pesaventoecd44802018-07-23 23:48:10 -0400225 /// \todo Add more timestamp formats (time since previous packet, time since first packet, ...)
226 os << tv.tv_sec
Junxiao Shi2222a612015-06-06 08:01:38 -0700227 << "."
Davide Pesaventoecd44802018-07-23 23:48:10 -0400228 << std::setfill('0') << std::setw(6) << tv.tv_usec
229 << " ";
Junxiao Shi2222a612015-06-06 08:01:38 -0700230}
231
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400232bool
233NdnDump::dispatchByEtherType(OutputFormatter& out, const uint8_t* pkt, size_t len, uint16_t etherType) const
Junxiao Shi2222a612015-06-06 08:01:38 -0700234{
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400235 out.addDelimiter();
Junxiao Shi2222a612015-06-06 08:01:38 -0700236
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400237 switch (etherType) {
238 case ETHERTYPE_IP:
239 return printIp4(out, pkt, len);
Davide Pesavento0ca7e692018-08-05 02:21:06 -0400240 case ETHERTYPE_IPV6:
241 return printIp6(out, pkt, len);
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400242 case ethernet::ETHERTYPE_NDN:
243 case 0x7777: // NDN ethertype used in ndnSIM
Davide Pesaventof9126532018-08-04 18:31:06 -0400244 out << "Ethernet";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400245 return printNdn(out, pkt, len);
246 default:
Davide Pesaventof9126532018-08-04 18:31:06 -0400247 out << "[Unsupported ethertype " << AsHex{etherType} << "]";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400248 return true;
Junxiao Shi2222a612015-06-06 08:01:38 -0700249 }
Junxiao Shi2222a612015-06-06 08:01:38 -0700250}
251
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400252bool
253NdnDump::dispatchByIpProto(OutputFormatter& out, const uint8_t* pkt, size_t len, uint8_t ipProto) const
Junxiao Shi2222a612015-06-06 08:01:38 -0700254{
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400255 out.addDelimiter();
Junxiao Shi2222a612015-06-06 08:01:38 -0700256
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400257 switch (ipProto) {
Davide Pesavento0ca7e692018-08-05 02:21:06 -0400258 case IPPROTO_NONE:
259 out << "[No next header]";
260 return true;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400261 case IPPROTO_TCP:
262 return printTcp(out, pkt, len);
263 case IPPROTO_UDP:
264 return printUdp(out, pkt, len);
265 default:
Davide Pesaventof9126532018-08-04 18:31:06 -0400266 out << "[Unsupported IP proto " << static_cast<int>(ipProto) << "]";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400267 return true;
268 }
269}
Junxiao Shi2222a612015-06-06 08:01:38 -0700270
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400271bool
272NdnDump::printEther(OutputFormatter& out, const uint8_t* pkt, size_t len) const
273{
274 // IEEE 802.3 Ethernet
Junxiao Shi2222a612015-06-06 08:01:38 -0700275
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400276 if (len < ethernet::HDR_LEN) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400277 out << "Truncated Ethernet frame, length " << len;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400278 return true;
Junxiao Shic1c2b832016-07-24 20:45:36 +0000279 }
Junxiao Shi2222a612015-06-06 08:01:38 -0700280
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400281 auto ether = reinterpret_cast<const ether_header*>(pkt);
282 pkt += ethernet::HDR_LEN;
283 len -= ethernet::HDR_LEN;
284
285 return dispatchByEtherType(out, pkt, len, endian::big_to_native(ether->ether_type));
286}
287
288bool
289NdnDump::printLinuxSll(OutputFormatter& out, const uint8_t* pkt, size_t len) const
290{
291 // Linux "cooked" capture encapsulation
292 // https://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html
293
294 if (len < SLL_HDR_LEN) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400295 out << "Truncated LINUX_SLL frame, length " << len;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400296 return true;
297 }
298
299 auto sll = reinterpret_cast<const sll_header*>(pkt);
300 pkt += SLL_HDR_LEN;
301 len -= SLL_HDR_LEN;
302
303 return dispatchByEtherType(out, pkt, len, endian::big_to_native(sll->sll_protocol));
304}
305
306bool
307NdnDump::printPpp(OutputFormatter& out, const uint8_t* pkt, size_t len) const
308{
309 // PPP, as per RFC 1661 and RFC 1662; if the first 2 bytes are 0xff and 0x03,
310 // it's PPP in HDLC-like framing, with the PPP header following those two bytes,
311 // otherwise it's PPP without framing, and the packet begins with the PPP header.
312 // The data in the frame is not octet-stuffed or bit-stuffed.
313
314 if (len < 2) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400315 out << "Truncated PPP frame, length " << len;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400316 return true;
317 }
318
319 if (pkt[0] == 0xff && pkt[1] == 0x03) {
320 // PPP in HDLC-like framing, skip the Address and Control fields
321 if (len < 4) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400322 out << "Truncated PPP frame, length " << len;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400323 return true;
324 }
325 pkt += 2;
326 len -= 2;
327 }
328
329 unsigned int proto = pkt[0];
330 if (proto & 0x1) {
331 // Protocol field is compressed in 1 byte
332 pkt += 1;
333 len -= 1;
334 }
335 else {
336 // Protocol field is 2 bytes, in network byte order
337 proto = (proto << 8) | pkt[1];
338 pkt += 2;
339 len -= 2;
340 }
341
342 switch (proto) {
343 case 0x0077: // NDN in PPP frame, used by ndnSIM pcap traces
344 // For some reason, ndnSIM produces PPP frames with 2 extra bytes
345 // between the protocol field and the beginning of the NDN packet
346 if (len < 2) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400347 out << "Truncated NDN/PPP frame";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400348 return true;
349 }
350 pkt += 2;
351 len -= 2;
Davide Pesaventof9126532018-08-04 18:31:06 -0400352 out << "PPP";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400353 return printNdn(out, pkt, len);
354 default:
Davide Pesaventof9126532018-08-04 18:31:06 -0400355 out << "[Unsupported PPP proto " << AsHex{proto} << "]";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400356 return true;
357 }
358}
359
Davide Pesaventof9126532018-08-04 18:31:06 -0400360static void
361printIpAddress(OutputFormatter& out, int af, const void* addr)
362{
363 char addrStr[1 + std::max(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)] = {};
364 if (inet_ntop(af, addr, addrStr, sizeof(addrStr))) {
365 out << addrStr;
366 }
367 else {
368 out << "???";
369 }
370}
371
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400372bool
373NdnDump::printIp4(OutputFormatter& out, const uint8_t* pkt, size_t len) const
374{
Davide Pesaventof9126532018-08-04 18:31:06 -0400375 out.addDelimiter() << "IP ";
376
377 if (len < sizeof(ip)) {
378 out << "truncated header, length " << len;
379 return true;
380 }
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400381
382 auto ih = reinterpret_cast<const ip*>(pkt);
Davide Pesaventof9126532018-08-04 18:31:06 -0400383 if (ih->ip_v != 4) {
384 // huh? link layer said this was an IPv4 packet but IP header says otherwise
385 out << "bad version " << ih->ip_v;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400386 return true;
387 }
388
Davide Pesaventof9126532018-08-04 18:31:06 -0400389 size_t ipHdrLen = ih->ip_hl * 4;
390 if (ipHdrLen < sizeof(ip)) {
391 out << "bad header length " << ipHdrLen;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400392 return true;
393 }
394
Davide Pesaventof9126532018-08-04 18:31:06 -0400395 size_t ipLen = endian::big_to_native(ih->ip_len);
396 if (ipLen < ipHdrLen) {
397 out << "bad length " << ipLen;
398 return true;
399 }
400 if (ipLen > len) {
401 out << "truncated packet, " << ipLen - len << " bytes missing";
402 return true;
403 }
404 // if we reached this point, the following is true:
405 // sizeof(ip) <= ipHdrLen <= ipLen <= len
406
407 printIpAddress(out, AF_INET, &ih->ip_src);
408 out << " > ";
409 printIpAddress(out, AF_INET, &ih->ip_dst);
410
411 pkt += ipHdrLen;
412 len -= ipHdrLen;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400413
414 return dispatchByIpProto(out, pkt, len, ih->ip_p);
415}
416
417bool
Davide Pesavento0ca7e692018-08-05 02:21:06 -0400418NdnDump::printIp6(OutputFormatter& out, const uint8_t* pkt, size_t len) const
419{
420 out.addDelimiter() << "IP6 ";
421
422 if (len < sizeof(ip6_hdr)) {
423 out << "truncated header, length " << len;
424 return true;
425 }
426
427 auto ip6 = reinterpret_cast<const ip6_hdr*>(pkt);
428 unsigned int ipVer = (ip6->ip6_vfc & 0xf0) >> 4;
429 if (ipVer != 6) {
430 // huh? link layer said this was an IPv6 packet but IP header says otherwise
431 out << "bad version " << ipVer;
432 return true;
433 }
434
435 pkt += sizeof(ip6_hdr);
436 len -= sizeof(ip6_hdr);
437
438 size_t payloadLen = endian::big_to_native(ip6->ip6_plen);
439 if (len < payloadLen) {
440 out << "truncated payload, " << payloadLen - len << " bytes missing";
441 return true;
442 }
443
444 printIpAddress(out, AF_INET6, &ip6->ip6_src);
445 out << " > ";
446 printIpAddress(out, AF_INET6, &ip6->ip6_dst);
447
448 // we assume no extension headers are present
449 return dispatchByIpProto(out, pkt, len, ip6->ip6_nxt);
450}
451
452bool
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400453NdnDump::printTcp(OutputFormatter& out, const uint8_t* pkt, size_t len) const
454{
Davide Pesaventof9126532018-08-04 18:31:06 -0400455 out.addDelimiter() << "TCP";
456
457 if (len < sizeof(tcphdr)) {
458 out << " truncated header, length " << len;
459 return true;
460 }
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400461
462 auto th = reinterpret_cast<const tcphdr*>(pkt);
Davide Pesavento7b9837b2019-02-23 19:07:50 -0500463 size_t tcpHdrLen = th->TH_OFF * 4;
Davide Pesaventof9126532018-08-04 18:31:06 -0400464 if (tcpHdrLen < sizeof(tcphdr)) {
465 out << " bad header length " << tcpHdrLen;
466 return true;
467 }
468 if (tcpHdrLen > len) {
469 out << " truncated header, " << tcpHdrLen - len << " bytes missing";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400470 return true;
471 }
472
Davide Pesaventof9126532018-08-04 18:31:06 -0400473 pkt += tcpHdrLen;
474 len -= tcpHdrLen;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400475
Davide Pesaventof9126532018-08-04 18:31:06 -0400476 out.addDelimiter() << "length " << len;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400477
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400478 return printNdn(out, pkt, len);
479}
480
481bool
482NdnDump::printUdp(OutputFormatter& out, const uint8_t* pkt, size_t len) const
483{
Davide Pesaventof9126532018-08-04 18:31:06 -0400484 out.addDelimiter() << "UDP";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400485
486 if (len < sizeof(udphdr)) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400487 out << " truncated header, length " << len;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400488 return true;
489 }
490
Davide Pesaventof9126532018-08-04 18:31:06 -0400491 auto uh = reinterpret_cast<const udphdr*>(pkt);
Davide Pesavento7b9837b2019-02-23 19:07:50 -0500492 size_t udpLen = endian::big_to_native(uh->UH_LEN);
Davide Pesaventof9126532018-08-04 18:31:06 -0400493 if (udpLen < sizeof(udphdr)) {
494 out << " bad length " << udpLen;
495 return true;
496 }
497 if (udpLen > len) {
498 out << " truncated packet, " << udpLen - len << " bytes missing";
499 return true;
500 }
501 else {
502 len = udpLen;
503 }
504
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400505 pkt += sizeof(udphdr);
506 len -= sizeof(udphdr);
507
Davide Pesaventof9126532018-08-04 18:31:06 -0400508 out.addDelimiter() << "length " << len;
509
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400510 return printNdn(out, pkt, len);
511}
512
513bool
514NdnDump::printNdn(OutputFormatter& out, const uint8_t* pkt, size_t len) const
515{
516 if (len == 0) {
517 return false;
518 }
519 out.addDelimiter();
520
521 bool isOk = false;
522 Block block;
523 std::tie(isOk, block) = Block::fromBuffer(pkt, len);
524 if (!isOk) {
525 // if packet is incomplete, we will not be able to process it
Davide Pesaventof9126532018-08-04 18:31:06 -0400526 out << "NDN truncated packet, length " << len;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400527 return true;
528 }
529
530 lp::Packet lpPacket;
531 Block netPacket;
532
533 if (block.type() == lp::tlv::LpPacket) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400534 out << "NDNLPv2";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400535 try {
536 lpPacket.wireDecode(block);
537 }
538 catch (const tlv::Error& e) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400539 out << " invalid packet: " << e.what();
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400540 return true;
541 }
542
543 Buffer::const_iterator begin, end;
544 if (lpPacket.has<lp::FragmentField>()) {
545 std::tie(begin, end) = lpPacket.get<lp::FragmentField>();
546 }
547 else {
Davide Pesaventof9126532018-08-04 18:31:06 -0400548 out << " idle";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400549 return true;
550 }
551
552 bool isOk = false;
553 std::tie(isOk, netPacket) = Block::fromBuffer(&*begin, std::distance(begin, end));
554 if (!isOk) {
555 // if network packet is fragmented, we will not be able to process it
Davide Pesaventof9126532018-08-04 18:31:06 -0400556 out << " fragment";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400557 return true;
558 }
559 }
560 else {
561 netPacket = std::move(block);
562 }
Davide Pesaventof9126532018-08-04 18:31:06 -0400563 out.addDelimiter();
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400564
565 try {
566 switch (netPacket.type()) {
567 case tlv::Interest: {
568 Interest interest(netPacket);
569 if (!matchesFilter(interest.getName())) {
570 return false;
571 }
572
573 if (lpPacket.has<lp::NackField>()) {
574 lp::Nack nack(interest);
575 nack.setHeader(lpPacket.get<lp::NackField>());
Davide Pesaventof9126532018-08-04 18:31:06 -0400576 out << "NACK (" << nack.getReason() << "): " << interest;
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400577 }
578 else {
579 out << "INTEREST: " << interest;
580 }
581 break;
582 }
583 case tlv::Data: {
584 Data data(netPacket);
585 if (!matchesFilter(data.getName())) {
586 return false;
587 }
588
589 out << "DATA: " << data.getName();
590 break;
591 }
592 default: {
Davide Pesaventof9126532018-08-04 18:31:06 -0400593 out << "[Unsupported NDN packet type " << netPacket.type() << "]";
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400594 break;
595 }
596 }
597 }
598 catch (const tlv::Error& e) {
Davide Pesaventof9126532018-08-04 18:31:06 -0400599 out << "invalid network packet: " << e.what();
Davide Pesaventob6b176c2018-07-28 22:05:16 -0400600 }
601
602 return true;
Junxiao Shi2222a612015-06-06 08:01:38 -0700603}
604
Junxiao Shic1c2b832016-07-24 20:45:36 +0000605bool
Davide Pesaventoecd44802018-07-23 23:48:10 -0400606NdnDump::matchesFilter(const Name& name) const
Junxiao Shic1c2b832016-07-24 20:45:36 +0000607{
Davide Pesavento78de7352018-07-22 00:35:45 -0400608 if (!nameFilter)
Junxiao Shic1c2b832016-07-24 20:45:36 +0000609 return true;
610
611 /// \todo Switch to NDN regular expressions
Davide Pesavento78de7352018-07-22 00:35:45 -0400612 return std::regex_match(name.toUri(), *nameFilter);
Junxiao Shic1c2b832016-07-24 20:45:36 +0000613}
614
Junxiao Shi3cd47df2015-06-07 20:58:14 -0700615} // namespace dump
Junxiao Shi2222a612015-06-06 08:01:38 -0700616} // namespace ndn