Skip to content

Netdump: tcpdump-like internal library #4678

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libraries/ESP8266WiFi/src/WiFiServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ void WiFiServer::begin() {

void WiFiServer::begin(uint16_t port) {
close();
_port = port;
_port = port;
err_t err;
tcp_pcb* pcb = tcp_new();
if (!pcb)
Expand Down
31 changes: 31 additions & 0 deletions libraries/NetDump/examples/netdump/netdump.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@

/*
dump network packets on serial console
released to the public domain
*/

#include <NetDump.h>
#include <lwipopts.h> // get global handler phy_capture

void dump (int netif_idx, const char* data, size_t len, int out, int success) {
(void)success;
Serial.print(out ? F("out ") : F(" in "));
Serial.printf("%d ", netif_idx);

// optional filter example: if (netDump_is_ARP(data))
{
netDump(Serial, data, len);
//netDumpHex(Serial, data, len);
}
}

void setup(void) {
Serial.begin(115200);
phy_capture = dump;

// put your setup code here, to run once:
}

void loop(void) {
// put your main code here, to run repeatedly:
}
22 changes: 22 additions & 0 deletions libraries/NetDump/examples/tcpdump/tcpdump.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

/*
provide a tcp-server for tcpdump of locally sent/received packets
under unix with NetCat, open a terminal, run:
nc esp-ip-address 2 | tcpdump -r - [<options>] [<pcap-filter>]

released to the public domain
*/

#include <NetDump.h>

void setup() {
// put your setup code here, to run once:
// setup WiFi
// now tcpdump server can be initialized
tcpdump_setup();
}

void loop() {
tcpdump_loop();
// put your main code here, to run repeatedly:
}
9 changes: 9 additions & 0 deletions libraries/NetDump/library.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name=NetDump
version=1
author=David Gauchard
maintainer=David Gauchard
sentence=tcpdump-like logger facility
paragraph=dump in/out packets on Printable, or provide a server for the real tcpdump
category=Uncategorized
url=https://
architectures=esp8266
194 changes: 194 additions & 0 deletions libraries/NetDump/src/NetDump.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
/*
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>

static void snap (Print& out)
{
out.println(F("(snap)"));
}

void netDumpMac (Print& out, const char* mac)
{
for (int i = 0; i < 6; i++)
{
out.printf("%02x", (unsigned char)mac[i]);
if (i < 5)
out.print(':');
}
}

void netDumpIPv4 (Print& out, const char* ethdata)
{
for (int i = 0; i < 4; i++)
{
out.printf("%u", (unsigned char)ethdata[i]);
if (i < 3)
out.print('.');
}
}

static void netDumpARP (Print& out, const char* ethdata, size_t size)
{
out.print(F(" ARP "));
if (size < ETH_HDR_LEN + 28)
return;
char type = netDump_getARPType(ethdata);
if (type == 1)
{
out.print(F("who has "));
netDumpIPv4(out, ethdata + ETH_HDR_LEN + 24);
out.print(F(" tell "));
netDumpIPv4(out, ethdata + ETH_HDR_LEN + 14);
}
else if (type == 2)
{
netDumpIPv4(out, ethdata + ETH_HDR_LEN + 14);
out.print(F(" is at "));
netDumpMac(out, ethdata + ETH_HDR_LEN + 8);
}
else
out.printf("(type=%d)", type);
out.println();
}

static void netDumpICMP (Print& out, const char* ethdata, size_t size)
{
out.print(F(" ICMP "));
if (size < 1)
return snap(out);

switch (ethdata[ETH_HDR_LEN + 20 + 0])
{
case 0: out.println(F("ping reply")); break;
case 8: out.println(F("ping request")); break;
default: out.printf("type(0x%02x)\r\n", ethdata[ETH_HDR_LEN + 20 + 0]);
}
}

static void netDumpIGMP (Print& out, const char* ethdata, size_t size)
{
out.println(F(" IGMP"));
if (size < 1)
return snap(out);
(void)ethdata;
}

static void netDumpPort (Print& out, const char* ethdata)
{
out.printf("%d>%d", netDump_getSrcPort(ethdata), netDump_getDstPort (ethdata));
}

void netDumpTCPFlags (Print& out, const char* ethdata)
{
uint16_t flags = netDump_getTcpFlags(ethdata);
out.print('[');
const char chars [] = "FSRP.UECN";
for (uint8_t i = 0; i < sizeof chars; i++)
if (flags & (1 << i))
out.print(chars[i]);
out.print(']');
}

static void netDumpTCP (Print& out, const char* ethdata, size_t size)
{
out.print(F(" TCP "));
if (size < ETH_HDR_LEN + 20 + 16)
return snap(out);
netDumpPort(out, ethdata);
netDumpTCPFlags(out, ethdata);

uint16_t tcplen = netDump_getIpUsrLen(ethdata) - netDump_getTcpHdrLen(ethdata);
uint32_t seq = netDump_getTcpSeq(ethdata);
out.printf(" seq:%u", seq);
if (tcplen)
out.printf("..%u", seq + tcplen);
out.printf(" ack:%u win:%d",
(unsigned)netDump_getTcpAck(ethdata),
netDump_getTcpWindow(ethdata));
if (tcplen)
out.printf(" len=%u", tcplen);

size_t options = ETH_HDR_LEN + netDump_getIpHdrLen(ethdata) + 20;
size_t options_len = netDump_getTcpHdrLen(ethdata) - 20;
for (size_t i = 0; i < options_len; )
{
uint8_t opt = ethdata[options + i];
uint8_t sz = opt >= 2? ethdata[options + i + 1]: 1;
switch (opt)
{
case 0:
case 1: break;
case 2: out.printf(" mss=%u", ntoh16(ethdata + options + i + 2)); break;
default: out.printf(" opt%u(%u)", opt, sz);
}
if (!opt)
// end of option
break;
i += sz;
}

out.println();
}

static void netDumpUDP (Print& out, const char* ethdata, size_t size)
{
out.print(F(" UDP "));
if (size < ETH_HDR_LEN + 20 + 8)
return snap(out);

netDumpPort(out, ethdata);
uint16_t udplen = netDump_getUdpUsrLen(ethdata);
uint16_t iplen = netDump_getIpUsrLen(ethdata) - 8/*udp hdr size*/;
if (udplen != iplen)
out.printf(" len=%d?", iplen);
out.printf(" len=%d\r\n", udplen);
}

static void netDumpIPv4 (Print& out, const char* ethdata, size_t size)
{
if (size < ETH_HDR_LEN + 20)
return snap(out);

out.print(F(" IPv4 "));

netDumpIPv4(out, ethdata + ETH_HDR_LEN + 12);
out.print('>');
netDumpIPv4(out, ethdata + ETH_HDR_LEN + 16);
//out.printf(" (iphdrlen=%d)", netDump_getIpHdrLen(ethdata));

if (netDump_is_ICMP(ethdata)) netDumpICMP(out, ethdata, size);
else if (netDump_is_IGMP(ethdata)) netDumpIGMP(out, ethdata, size);
else if (netDump_is_TCP(ethdata)) netDumpTCP (out, ethdata, size);
else if (netDump_is_UDP(ethdata)) netDumpUDP (out, ethdata, size);
else out.printf(" ip proto 0x%02x\r\n", netDump_getIpType(ethdata));
}

void netDump (Print& out, const char* ethdata, size_t size)
{
if (size < ETH_HDR_LEN)
return snap(out);

if (netDump_is_ARP(ethdata)) netDumpARP (out, ethdata, size);
else if (netDump_is_IPv4(ethdata)) netDumpIPv4(out, ethdata, size);
else if (netDump_is_IPv6(ethdata)) out.println(F(" IPV6"));
else out.printf(" eth proto 0x%04x\r\n", netDump_ethtype(ethdata));
}
84 changes: 84 additions & 0 deletions libraries/NetDump/src/NetDump.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
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
*/

#ifndef __NETDUMP_H
#define __NETDUMP_H

#include <Print.h>

#define ETH_HDR_LEN 14

// helpers that can be used for filtering

inline uint16_t ntoh16 (const char* data) { return data[1] | (((uint16_t)data[0]) << 8); }
inline uint32_t ntoh32 (const char* data) { return ntoh16(data + 2) | (((uint32_t)ntoh16(data)) << 16); }

inline uint16_t netDump_ethtype (const char* ethdata) { return ntoh16(ethdata + 12); }
inline bool netDump_is_ARP (const char* ethdata) { return netDump_ethtype(ethdata) == 0x0806; }
inline bool netDump_is_IPv4 (const char* ethdata) { return netDump_ethtype(ethdata) == 0x0800; }
inline bool netDump_is_IPv6 (const char* ethdata) { return netDump_ethtype(ethdata) == 0x86dd; }
inline uint8_t netDump_getIpType (const char* ethdata) { return ethdata[ETH_HDR_LEN + 9]; }
inline bool netDump_is_ICMP (const char* ethdata) { return netDump_getIpType(ethdata) == 1; }
inline bool netDump_is_IGMP (const char* ethdata) { return netDump_getIpType(ethdata) == 2; }
inline bool netDump_is_TCP (const char* ethdata) { return netDump_getIpType(ethdata) == 6; }
inline bool netDump_is_UDP (const char* ethdata) { return netDump_getIpType(ethdata) == 17; }

inline uint8_t netDump_getARPType (const char* ethdata) { return ethdata[ETH_HDR_LEN + 7]; }
inline bool netDump_is_ARP_who (const char* ethdata) { return netDump_getARPType(ethdata) == 1; }
inline bool netDump_is_ARP_is (const char* ethdata) { return netDump_getARPType(ethdata) == 2; }

inline uint16_t netDump_getIpHdrLen (const char* ethdata) { return (((unsigned char)ethdata[ETH_HDR_LEN]) & 0x0f) << 2; }
inline uint16_t netDump_getIpTotLen (const char* ethdata) { return ntoh16(ethdata + ETH_HDR_LEN + 2); }
inline uint16_t netDump_getIpOptLen (const char* ethdata) { return netDump_getIpHdrLen(ethdata) - 20; }
inline uint16_t netDump_getIpUsrLen (const char* ethdata) { return netDump_getIpTotLen(ethdata) - netDump_getIpHdrLen(ethdata); }

inline uint16_t netDump_getSrcPort (const char* ethdata) { return ntoh16(ethdata + ETH_HDR_LEN + netDump_getIpHdrLen(ethdata) + 0); }
inline uint16_t netDump_getDstPort (const char* ethdata) { return ntoh16(ethdata + ETH_HDR_LEN + netDump_getIpHdrLen(ethdata) + 2); }

inline uint16_t netDump_getUdpUsrLen (const char* ethdata) { return ntoh16(ethdata + ETH_HDR_LEN + netDump_getIpHdrLen(ethdata) + 4) - 8; }

inline uint32_t netDump_getTcpSeq (const char* ethdata) { return ntoh32(ethdata + ETH_HDR_LEN + netDump_getIpHdrLen(ethdata) + 4); }
inline uint32_t netDump_getTcpAck (const char* ethdata) { return ntoh32(ethdata + ETH_HDR_LEN + netDump_getIpHdrLen(ethdata) + 8); }
inline uint16_t netDump_getTcpFlags (const char* ethdata) { return ntoh16(ethdata + ETH_HDR_LEN + netDump_getIpHdrLen(ethdata) + 12); }
inline uint16_t netDump_getTcpHdrLen (const char* ethdata) { return (ntoh16(ethdata + ETH_HDR_LEN + netDump_getIpHdrLen(ethdata) + 12) >> 12) << 2; }
inline uint16_t netDump_getTcpWindow (const char* ethdata) { return ntoh16(ethdata + ETH_HDR_LEN + netDump_getIpHdrLen(ethdata) + 14); }
inline uint16_t netDump_getTcpUsrLen (const char* ethdata) { return netDump_getIpUsrLen(ethdata) - netDump_getTcpHdrLen(ethdata); }

void netDumpIPv4 (Print& out, const char* ethdata);
void netDumpMac (Print& out, const char* mac);
void netDumpMacs (Print& out, const char* mac);

// main dump functions

void netDump (Print& out, const char* ethdata, size_t size);
void netDumpHex (Print& out, const char* data, size_t size, bool show_hex = true, bool show_ascii = true, size_t per_line = 16);

// tcpdump server:
// call tcpdump_setup() in your setup()
// call tcpdump_loop() in your loop()
// open a terminal, run:
// nc esp-ip-address 2 | tcpdump -r - [<options>] [<pcap-filter>]

bool tcpdump_setup (uint16_t port = 2, size_t snap = 96, bool fast = true);
void tcpdump_loop ();
extern size_t tcpdump_err;

#endif // __NETDUMP_H
Loading