mirror of
https://github.com/esp8266/Arduino.git
synced 2025-06-06 05:21:22 +03:00
382 lines
11 KiB
C++
382 lines
11 KiB
C++
/*
|
|
NetDump library - tcpdump-like packet logger facility
|
|
|
|
Copyright (c) 2018 David Gauchard. All rights reserved.
|
|
This file is part of the esp8266 core for Arduino environment.
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "Netdump.h"
|
|
#include <lwip/init.h>
|
|
|
|
namespace NetCapture
|
|
{
|
|
|
|
void Packet::printDetail(Print& out, const String& indent, const char* data, size_t size, PacketDetail pd) const
|
|
{
|
|
if (pd == PacketDetail::NONE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
uint16_t charCount = (pd == PacketDetail::CHAR) ? 80 : 24;
|
|
|
|
size_t start = 0;
|
|
while (start < size)
|
|
{
|
|
size_t end = start + charCount;
|
|
if (end > size)
|
|
{
|
|
end = size;
|
|
}
|
|
out.printf("%s", indent.c_str());
|
|
if (pd != PacketDetail::CHAR)
|
|
{
|
|
for (size_t i = start; i < end; i++)
|
|
{
|
|
out.printf("%02x ", (unsigned char)data[i]);
|
|
}
|
|
for (size_t i = end; i < start + charCount; i++)
|
|
{
|
|
out.print(" ");
|
|
}
|
|
}
|
|
for (size_t i = start; i < end; i++)
|
|
{
|
|
out.printf("%c", data[i] >= 32 && data[i] < 128 ? data[i] : '.');
|
|
}
|
|
out.println();
|
|
|
|
start += charCount;
|
|
}
|
|
}
|
|
|
|
void Packet::setPacketType(PacketType pt)
|
|
{
|
|
thisPacketType = pt;
|
|
thisAllPacketTypes.emplace_back(pt);
|
|
}
|
|
|
|
void Packet::setPacketTypes()
|
|
{
|
|
if (isARP())
|
|
{
|
|
setPacketType(PacketType::ARP);
|
|
}
|
|
else if (isIP())
|
|
{
|
|
setPacketType(PacketType::IP);
|
|
setPacketType(isIPv4() ? PacketType::IPv4 : PacketType::IPv6);
|
|
if (isUDP())
|
|
{
|
|
setPacketType(PacketType::UDP);
|
|
if (isMDNS())
|
|
{
|
|
setPacketType(PacketType::MDNS);
|
|
}
|
|
if (isDNS())
|
|
{
|
|
setPacketType(PacketType::DNS);
|
|
}
|
|
if (isSSDP())
|
|
{
|
|
setPacketType(PacketType::SSDP);
|
|
}
|
|
if (isDHCP())
|
|
{
|
|
setPacketType(PacketType::DHCP);
|
|
}
|
|
if (isWSDD())
|
|
{
|
|
setPacketType(PacketType::WSDD);
|
|
}
|
|
if (isNETBIOS())
|
|
{
|
|
setPacketType(PacketType::NETBIOS);
|
|
}
|
|
if (isSMB())
|
|
{
|
|
setPacketType(PacketType::SMB);
|
|
}
|
|
if (isOTA())
|
|
{
|
|
setPacketType(PacketType::OTA);
|
|
}
|
|
}
|
|
if (isTCP())
|
|
{
|
|
setPacketType(PacketType::TCP);
|
|
if (isHTTP())
|
|
{
|
|
setPacketType(PacketType::HTTP);
|
|
}
|
|
}
|
|
if (isICMP())
|
|
{
|
|
setPacketType(PacketType::ICMP);
|
|
}
|
|
if (isIGMP())
|
|
{
|
|
setPacketType(PacketType::IGMP);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
setPacketType(PacketType::UKNW);
|
|
}
|
|
}
|
|
|
|
const PacketType Packet::packetType() const
|
|
{
|
|
return thisPacketType;
|
|
}
|
|
|
|
const std::vector<PacketType>& Packet::allPacketTypes() const
|
|
{
|
|
return thisAllPacketTypes;
|
|
}
|
|
|
|
void Packet::MACtoString(int dataIdx, StreamString& sstr) const
|
|
{
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
sstr.printf_P(PSTR("%02x"), (unsigned char)data[dataIdx + i]);
|
|
if (i < 5)
|
|
{
|
|
sstr.print(':');
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void Packet::ARPtoString(PacketDetail netdumpDetail, StreamString& sstr) const
|
|
{
|
|
switch (getARPType())
|
|
{
|
|
case 1 : sstr.printf_P(PSTR("who has %s tell %s"), getIP(ETH_HDR_LEN + 24).toString().c_str(), getIP(ETH_HDR_LEN + 14).toString().c_str());
|
|
break;
|
|
case 2 : sstr.printf_P(PSTR("%s is at "), getIP(ETH_HDR_LEN + 14).toString().c_str());
|
|
MACtoString(ETH_HDR_LEN + 8, sstr);
|
|
break;
|
|
}
|
|
sstr.printf("\r\n");
|
|
printDetail(sstr, PSTR(" D "), &data[ETH_HDR_LEN], packetLength - ETH_HDR_LEN, netdumpDetail);
|
|
}
|
|
|
|
void Packet::DNStoString(PacketDetail netdumpDetail, StreamString& sstr) const
|
|
{
|
|
sstr.printf_P(PSTR("%s>%s "), sourceIP().toString().c_str(), destIP().toString().c_str());
|
|
sstr.printf_P(PSTR("ID=0x%04x "), ntoh16(ETH_HDR_LEN + getIpHdrLen() + 8));
|
|
sstr.printf_P(PSTR("F=0x%04x "), ntoh16(ETH_HDR_LEN + getIpHdrLen() + 8 + 2));
|
|
if (uint16_t t = ntoh16(ETH_HDR_LEN + getIpHdrLen() + 8 + 4))
|
|
{
|
|
sstr.printf_P(PSTR("Q=%d "), t);
|
|
}
|
|
if (uint16_t t = ntoh16(ETH_HDR_LEN + getIpHdrLen() + 8 + 6))
|
|
{
|
|
sstr.printf_P(PSTR("R=%d "), t);
|
|
}
|
|
if (uint16_t t = ntoh16(ETH_HDR_LEN + getIpHdrLen() + 8 + 8))
|
|
{
|
|
sstr.printf_P(PSTR("TR=%d "), t);
|
|
}
|
|
if (uint16_t t = ntoh16(ETH_HDR_LEN + getIpHdrLen() + 8 + 10))
|
|
{
|
|
sstr.printf_P(PSTR("DR=%d "), t);
|
|
}
|
|
sstr.printf_P(PSTR("\r\n"));
|
|
printDetail(sstr, PSTR(" H "), &data[ETH_HDR_LEN + getIpHdrLen()], getUdpHdrLen(), netdumpDetail);
|
|
printDetail(sstr, PSTR(" D "), &data[ETH_HDR_LEN + getIpHdrLen() + getUdpHdrLen()], getUdpLen(), netdumpDetail);
|
|
}
|
|
|
|
void Packet::UDPtoString(PacketDetail netdumpDetail, StreamString& sstr) const
|
|
{
|
|
sstr.printf_P(PSTR("%s>%s "), sourceIP().toString().c_str(), destIP().toString().c_str());
|
|
sstr.printf_P(PSTR("%d:%d"), getSrcPort(), getDstPort());
|
|
sstr.printf_P(PSTR("\r\n"));
|
|
printDetail(sstr, PSTR(" H "), &data[ETH_HDR_LEN + getIpHdrLen()], getUdpHdrLen(), netdumpDetail);
|
|
printDetail(sstr, PSTR(" D "), &data[ETH_HDR_LEN + getIpHdrLen() + getUdpHdrLen()], getUdpLen(), netdumpDetail);
|
|
}
|
|
|
|
void Packet::TCPtoString(PacketDetail netdumpDetail, StreamString& sstr) const
|
|
{
|
|
sstr.printf_P(PSTR("%s>%s "), sourceIP().toString().c_str(), destIP().toString().c_str());
|
|
sstr.printf_P(PSTR("%d:%d "), getSrcPort(), getDstPort());
|
|
uint16_t flags = getTcpFlags();
|
|
sstr.print('[');
|
|
const char chars [] = "FSRPAUECN";
|
|
for (uint8_t i = 0; i < sizeof chars; i++)
|
|
if (flags & (1 << i))
|
|
{
|
|
sstr.print(chars[i]);
|
|
}
|
|
sstr.print(']');
|
|
sstr.printf_P(PSTR(" len: %u seq: %u, ack: %u, wnd: %u "), getTcpLen(), getTcpSeq(), getTcpAck(), getTcpWindow());
|
|
sstr.printf_P(PSTR("\r\n"));
|
|
printDetail(sstr, PSTR(" H "), &data[ETH_HDR_LEN + getIpHdrLen()], getTcpHdrLen(), netdumpDetail);
|
|
printDetail(sstr, PSTR(" D "), &data[ETH_HDR_LEN + getIpHdrLen() + getTcpHdrLen()], getTcpLen(), netdumpDetail);
|
|
}
|
|
|
|
void Packet::ICMPtoString(PacketDetail, StreamString& sstr) const
|
|
{
|
|
sstr.printf_P(PSTR("%s>%s "), sourceIP().toString().c_str(), destIP().toString().c_str());
|
|
if (isIPv4())
|
|
{
|
|
switch (getIcmpType())
|
|
{
|
|
case 0 : sstr.printf_P(PSTR("ping reply")); break;
|
|
case 8 : sstr.printf_P(PSTR("ping request")); break;
|
|
default: sstr.printf_P(PSTR("type(0x%02x)"), getIcmpType()); break;
|
|
}
|
|
}
|
|
if (isIPv6())
|
|
{
|
|
switch (getIcmpType())
|
|
{
|
|
case 129 : sstr.printf_P(PSTR("ping reply")); break;
|
|
case 128 : sstr.printf_P(PSTR("ping request")); break;
|
|
case 135 : sstr.printf_P(PSTR("Neighbour solicitation")); break;
|
|
case 136 : sstr.printf_P(PSTR("Neighbour advertisement")); break;
|
|
default: sstr.printf_P(PSTR("type(0x%02x)"), getIcmpType()); break;
|
|
}
|
|
}
|
|
sstr.printf("\r\n");
|
|
}
|
|
|
|
void Packet::IGMPtoString(PacketDetail, StreamString& sstr) const
|
|
{
|
|
switch (getIgmpType())
|
|
{
|
|
case 1 : sstr.printf_P(PSTR("Create Group Request")); break;
|
|
case 2 : sstr.printf_P(PSTR("Create Group Reply")); break;
|
|
case 3 : sstr.printf_P(PSTR("Join Group Request")); break;
|
|
case 4 : sstr.printf_P(PSTR("Join Group Reply")); break;
|
|
case 5 : sstr.printf_P(PSTR("Leave Group Request")); break;
|
|
case 6 : sstr.printf_P(PSTR("Leave Group Reply")); break;
|
|
case 7 : sstr.printf_P(PSTR("Confirm Group Request")); break;
|
|
case 8 : sstr.printf_P(PSTR("Confirm Group Reply")); break;
|
|
case 0x11 : sstr.printf_P(PSTR("Group Membership Query")); break;
|
|
case 0x12 : sstr.printf_P(PSTR("IGMPv1 Membership Report")); break;
|
|
case 0x22 : sstr.printf_P(PSTR("IGMPv3 Membership Report")); break;
|
|
default: sstr.printf_P(PSTR("type(0x%02x)"), getIgmpType()); break;
|
|
}
|
|
sstr.printf_P(PSTR("\r\n"));
|
|
}
|
|
|
|
void Packet::IPtoString(PacketDetail netdumpDetail, StreamString& sstr) const
|
|
{
|
|
sstr.printf_P(PSTR("%s>%s "), sourceIP().toString().c_str(), destIP().toString().c_str());
|
|
sstr.printf_P(PSTR("Unknown IP type : %d\r\n"), ipType());
|
|
printDetail(sstr, PSTR(" H "), &data[ETH_HDR_LEN], getIpHdrLen(), netdumpDetail);
|
|
printDetail(sstr, PSTR(" D "), &data[ETH_HDR_LEN + getIpHdrLen()], getIpTotalLen() - getIpHdrLen(), netdumpDetail);
|
|
}
|
|
|
|
void Packet::UKNWtoString(PacketDetail, StreamString& sstr) const
|
|
{
|
|
sstr.printf_P(PSTR("Unknown EtherType 0x%04x Src : "), ethType());
|
|
MACtoString(0, sstr);
|
|
sstr.printf_P(PSTR(" Dst : "));
|
|
MACtoString(6, sstr);
|
|
sstr.printf_P(PSTR("\r\n"));
|
|
}
|
|
|
|
const String Packet::toString() const
|
|
{
|
|
return toString(PacketDetail::NONE);
|
|
}
|
|
|
|
|
|
const String Packet::toString(PacketDetail netdumpDetail) const
|
|
{
|
|
StreamString sstr;
|
|
sstr.reserve(128);
|
|
|
|
sstr.printf_P(PSTR("%d %3s %-4s "), netif_idx, out ? "out" : "in ", packetType().toString().c_str());
|
|
|
|
if (netdumpDetail == PacketDetail::RAW)
|
|
{
|
|
sstr.printf_P(PSTR(" : "));
|
|
for (auto at : thisAllPacketTypes)
|
|
{
|
|
sstr.printf_P(PSTR("%s "), at.toString().c_str());
|
|
}
|
|
sstr.printf_P(PSTR("\r\n"));
|
|
printDetail(sstr, PSTR(" D "), data, packetLength, netdumpDetail);
|
|
return sstr;
|
|
}
|
|
|
|
switch (thisPacketType)
|
|
{
|
|
case PacketType::ARP :
|
|
{
|
|
ARPtoString(netdumpDetail, sstr);
|
|
break;
|
|
}
|
|
case PacketType::MDNS :
|
|
case PacketType::DNS :
|
|
{
|
|
DNStoString(netdumpDetail, sstr);
|
|
break;
|
|
}
|
|
case PacketType::SSDP :
|
|
case PacketType::DHCP :
|
|
case PacketType::WSDD :
|
|
case PacketType::NETBIOS :
|
|
case PacketType::SMB :
|
|
case PacketType::OTA :
|
|
case PacketType::UDP :
|
|
{
|
|
UDPtoString(netdumpDetail, sstr);
|
|
break;
|
|
}
|
|
case PacketType::TCP :
|
|
case PacketType::HTTP :
|
|
{
|
|
TCPtoString(netdumpDetail, sstr);
|
|
break;
|
|
}
|
|
case PacketType::ICMP :
|
|
{
|
|
ICMPtoString(netdumpDetail, sstr);
|
|
break;
|
|
}
|
|
case PacketType::IGMP :
|
|
{
|
|
IGMPtoString(netdumpDetail, sstr);
|
|
break;
|
|
}
|
|
case PacketType::IPv4 :
|
|
case PacketType::IPv6 :
|
|
{
|
|
IPtoString(netdumpDetail, sstr);
|
|
break;
|
|
}
|
|
case PacketType::UKNW :
|
|
{
|
|
UKNWtoString(netdumpDetail, sstr);
|
|
break;
|
|
}
|
|
default :
|
|
{
|
|
sstr.printf_P(PSTR("Non identified packet\r\n"));
|
|
break;
|
|
}
|
|
}
|
|
return sstr;
|
|
}
|
|
|
|
} // namespace NetCapture
|