This is a low-level network debugging utility that utilizes raw packet i/o to construct and deconstruct tcp, udp, ipv4, arp, and icmp packets over ethernet.

Dependencies:   mbed

Committer:
etherealflaim
Date:
Tue Oct 12 06:48:59 2010 +0000
Revision:
8:1c1f6ce348c6
Parent:
6:66c4cd9073aa
Documentation

Who changed what in which revision?

UserRevisionLine numberNew contents of line
etherealflaim 0:d494b853ce97 1 #ifndef SNIFFER_H
etherealflaim 0:d494b853ce97 2 #define SNIFFER_H
etherealflaim 0:d494b853ce97 3
etherealflaim 0:d494b853ce97 4 #include "mbed.h"
etherealflaim 0:d494b853ce97 5
etherealflaim 0:d494b853ce97 6 #include "main.h"
etherealflaim 0:d494b853ce97 7 #include "util/types.h"
etherealflaim 0:d494b853ce97 8 #include "net/net.h"
etherealflaim 0:d494b853ce97 9
etherealflaim 0:d494b853ce97 10 #include <cstdio>
etherealflaim 0:d494b853ce97 11 #include <cstring>
etherealflaim 0:d494b853ce97 12 #include <functional>
etherealflaim 0:d494b853ce97 13
etherealflaim 6:66c4cd9073aa 14 /**
etherealflaim 6:66c4cd9073aa 15 \file sniffer.h
etherealflaim 8:1c1f6ce348c6 16 \brief Ethernet packet Sniffer
etherealflaim 6:66c4cd9073aa 17
etherealflaim 6:66c4cd9073aa 18 This file is the bread and butter of the NetTool; it processes and constructs ethernet frames
etherealflaim 6:66c4cd9073aa 19 on a bitwise level.
etherealflaim 6:66c4cd9073aa 20 */
etherealflaim 6:66c4cd9073aa 21
etherealflaim 0:d494b853ce97 22 template <class Arg1, class Arg2, class Result>
etherealflaim 0:d494b853ce97 23 class handler
etherealflaim 0:d494b853ce97 24 {
etherealflaim 0:d494b853ce97 25 public:
etherealflaim 0:d494b853ce97 26 virtual inline Result operator() (Arg1 x, Arg2 y) const {};
etherealflaim 0:d494b853ce97 27 };
etherealflaim 0:d494b853ce97 28
etherealflaim 0:d494b853ce97 29 template <class Arg1, class Arg2, class Result>
etherealflaim 0:d494b853ce97 30 class function_handler
etherealflaim 0:d494b853ce97 31 : public handler <Arg1,Arg2,Result>
etherealflaim 0:d494b853ce97 32 {
etherealflaim 0:d494b853ce97 33 protected:
etherealflaim 0:d494b853ce97 34 Result (*pfunc)(Arg1,Arg2);
etherealflaim 0:d494b853ce97 35 public:
etherealflaim 0:d494b853ce97 36 explicit inline function_handler ( Result (*f)(Arg1,Arg2) ) : pfunc (f) {}
etherealflaim 0:d494b853ce97 37 virtual inline Result operator() (Arg1 x, Arg2 y) const { return pfunc(x,y); }
etherealflaim 0:d494b853ce97 38 };
etherealflaim 0:d494b853ce97 39
etherealflaim 0:d494b853ce97 40 template <class Type, class Arg1, class Arg2, class Result>
etherealflaim 0:d494b853ce97 41 class member_handler
etherealflaim 0:d494b853ce97 42 : public handler <Arg1,Arg2,Result>
etherealflaim 0:d494b853ce97 43 {
etherealflaim 0:d494b853ce97 44 protected:
etherealflaim 0:d494b853ce97 45 Type *inst;
etherealflaim 0:d494b853ce97 46 Result (Type::*pfunc)(Arg1,Arg2);
etherealflaim 0:d494b853ce97 47 public:
etherealflaim 0:d494b853ce97 48 explicit inline member_handler ( Type *i, Result (Type::*f)(Arg1,Arg2) ) : inst(i), pfunc (f) {}
etherealflaim 0:d494b853ce97 49 virtual inline Result operator() (Arg1 x, Arg2 y) const { return (inst->*pfunc)(x,y); }
etherealflaim 0:d494b853ce97 50 };
etherealflaim 0:d494b853ce97 51
etherealflaim 4:88fc7fa58931 52 /// Demo - Ethernet Packet Sniffer
etherealflaim 0:d494b853ce97 53 class Sniffer {
etherealflaim 0:d494b853ce97 54 public:
etherealflaim 0:d494b853ce97 55 Ethernet_MAC mac;
etherealflaim 0:d494b853ce97 56
etherealflaim 0:d494b853ce97 57 private:
etherealflaim 0:d494b853ce97 58 // Ethernet interface
etherealflaim 0:d494b853ce97 59 Ethernet eth;
etherealflaim 0:d494b853ce97 60 IP_Address addr;
etherealflaim 0:d494b853ce97 61
etherealflaim 0:d494b853ce97 62 // Status LEDs
etherealflaim 0:d494b853ce97 63 DigitalOut linked;
etherealflaim 0:d494b853ce97 64 DigitalOut received;
etherealflaim 0:d494b853ce97 65
etherealflaim 0:d494b853ce97 66 // Frame data (big enough for largest ethernet frame)
etherealflaim 0:d494b853ce97 67 int frame_size;
etherealflaim 0:d494b853ce97 68 char frame[0x600];
etherealflaim 0:d494b853ce97 69
etherealflaim 0:d494b853ce97 70 // Outgoing frames
etherealflaim 0:d494b853ce97 71 char outframe[0x600];
etherealflaim 0:d494b853ce97 72 Ethernet_FrameHeader *outframe_header;
etherealflaim 0:d494b853ce97 73
etherealflaim 0:d494b853ce97 74 public:
etherealflaim 5:c56386b9fc33 75 /// Ethernet Frame Header (incoming)
etherealflaim 0:d494b853ce97 76 Ethernet_FrameHeader *frame_header;
etherealflaim 0:d494b853ce97 77
etherealflaim 5:c56386b9fc33 78 /// IP Packet Header (incoming)
etherealflaim 0:d494b853ce97 79 IP_PacketHeader *ip_packet;
etherealflaim 0:d494b853ce97 80
etherealflaim 5:c56386b9fc33 81 /// ARP Packet (incoming)
etherealflaim 0:d494b853ce97 82 ARP_Packet *arp_packet;
etherealflaim 0:d494b853ce97 83
etherealflaim 5:c56386b9fc33 84 /// TCP Packet (incoming)
etherealflaim 0:d494b853ce97 85 TCP_SegmentHeader *tcp_packet;
etherealflaim 0:d494b853ce97 86
etherealflaim 5:c56386b9fc33 87 /// UDP Packet (incoming)
etherealflaim 0:d494b853ce97 88 UDP_Packet *udp_packet;
etherealflaim 0:d494b853ce97 89
etherealflaim 5:c56386b9fc33 90 /// ICMP Packet (incoming)
etherealflaim 0:d494b853ce97 91 ICMP_Packet *icmp_packet;
etherealflaim 0:d494b853ce97 92
etherealflaim 5:c56386b9fc33 93 /// Generic - total data bytes
etherealflaim 0:d494b853ce97 94 unsigned int data_bytes;
etherealflaim 0:d494b853ce97 95
etherealflaim 0:d494b853ce97 96 public:
etherealflaim 5:c56386b9fc33 97 /// Constructor
etherealflaim 0:d494b853ce97 98 inline Sniffer()
etherealflaim 0:d494b853ce97 99 : linked(LED1), received(LED2)
etherealflaim 0:d494b853ce97 100 {
etherealflaim 0:d494b853ce97 101 eth.set_link(Ethernet::AutoNegotiate);
etherealflaim 0:d494b853ce97 102 eth.address((char *)mac.octet);
etherealflaim 0:d494b853ce97 103 }
etherealflaim 0:d494b853ce97 104
etherealflaim 5:c56386b9fc33 105 /// Inject the raw ethernet frame
etherealflaim 0:d494b853ce97 106 inline bool inject(void *data, unsigned int bytes)
etherealflaim 0:d494b853ce97 107 {
etherealflaim 0:d494b853ce97 108 // Send the packet
etherealflaim 0:d494b853ce97 109 eth.write((char*)data, bytes);
etherealflaim 0:d494b853ce97 110 int send_status = eth.send();
etherealflaim 0:d494b853ce97 111
etherealflaim 0:d494b853ce97 112 //decode_ethernet(data);
etherealflaim 0:d494b853ce97 113
etherealflaim 0:d494b853ce97 114 return send_status;
etherealflaim 0:d494b853ce97 115 }
etherealflaim 0:d494b853ce97 116
etherealflaim 5:c56386b9fc33 117 /// Inject the raw payload into an ethernet frame with the given destination and ethertype
etherealflaim 0:d494b853ce97 118 inline bool inject(Ethernet_MAC dest, u16 ethertype, void *packet, unsigned int bytes)
etherealflaim 0:d494b853ce97 119 {
etherealflaim 0:d494b853ce97 120 memset(outframe, 0x00, bytes);
etherealflaim 0:d494b853ce97 121
etherealflaim 0:d494b853ce97 122 outframe_header = (Ethernet_FrameHeader*)outframe;
etherealflaim 0:d494b853ce97 123
etherealflaim 0:d494b853ce97 124 // Set the ethernet frame source
etherealflaim 0:d494b853ce97 125 memcpy(&outframe_header->source, mac.octet, 6);
etherealflaim 0:d494b853ce97 126
etherealflaim 0:d494b853ce97 127 // Set the ethernet frame destination
etherealflaim 0:d494b853ce97 128 outframe_header->destination = dest;
etherealflaim 0:d494b853ce97 129
etherealflaim 0:d494b853ce97 130 // Set the ethernet ethertype
etherealflaim 0:d494b853ce97 131 outframe_header->ethertype = ethertype;
etherealflaim 0:d494b853ce97 132
etherealflaim 0:d494b853ce97 133 // Make sure the payload won't be too large
etherealflaim 0:d494b853ce97 134 if (sizeof(Ethernet_FrameHeader) + bytes > sizeof(outframe))
etherealflaim 0:d494b853ce97 135 {
etherealflaim 0:d494b853ce97 136 main_log.printf("ERROR: Attempt to inject packet failed; Payload size of %d is too large", bytes);
etherealflaim 0:d494b853ce97 137 return false;
etherealflaim 0:d494b853ce97 138 }
etherealflaim 0:d494b853ce97 139
etherealflaim 0:d494b853ce97 140 // Set the payload
etherealflaim 0:d494b853ce97 141 memcpy(outframe_header->payload, packet, bytes);
etherealflaim 0:d494b853ce97 142 fix_endian_ethernet(outframe_header);
etherealflaim 0:d494b853ce97 143
etherealflaim 0:d494b853ce97 144 // Send the packet
etherealflaim 0:d494b853ce97 145 eth.write(outframe, sizeof(Ethernet_FrameHeader) + bytes);
etherealflaim 0:d494b853ce97 146 int send_status = eth.send();
etherealflaim 0:d494b853ce97 147
etherealflaim 0:d494b853ce97 148 //decode_ethernet(outframe);
etherealflaim 0:d494b853ce97 149
etherealflaim 0:d494b853ce97 150 return send_status;
etherealflaim 0:d494b853ce97 151 }
etherealflaim 0:d494b853ce97 152
etherealflaim 5:c56386b9fc33 153 /// Wait until there is more data to receive
etherealflaim 0:d494b853ce97 154 inline void wait_for_data()
etherealflaim 0:d494b853ce97 155 {
etherealflaim 0:d494b853ce97 156 while (true)
etherealflaim 0:d494b853ce97 157 {
etherealflaim 0:d494b853ce97 158 wait(0.0001);
etherealflaim 0:d494b853ce97 159
etherealflaim 0:d494b853ce97 160 if (!(linked = eth.link()))
etherealflaim 0:d494b853ce97 161 continue;
etherealflaim 0:d494b853ce97 162
etherealflaim 0:d494b853ce97 163 received = (frame_size = eth.receive());
etherealflaim 0:d494b853ce97 164 if (!frame_size)
etherealflaim 0:d494b853ce97 165 continue;
etherealflaim 0:d494b853ce97 166
etherealflaim 0:d494b853ce97 167 eth.read(frame, frame_size);
etherealflaim 0:d494b853ce97 168 break;
etherealflaim 0:d494b853ce97 169 }
etherealflaim 0:d494b853ce97 170 }
etherealflaim 0:d494b853ce97 171
etherealflaim 5:c56386b9fc33 172 /// Wait for an ethernet frame (will be stored in appropriate class member pointers)
etherealflaim 0:d494b853ce97 173 inline void next()
etherealflaim 0:d494b853ce97 174 {
etherealflaim 0:d494b853ce97 175 wait_for_data();
etherealflaim 0:d494b853ce97 176
etherealflaim 0:d494b853ce97 177 // Zero out all of the packet pointers
etherealflaim 0:d494b853ce97 178 frame_header = NULL;
etherealflaim 0:d494b853ce97 179 arp_packet = NULL;
etherealflaim 0:d494b853ce97 180 icmp_packet = NULL;
etherealflaim 0:d494b853ce97 181 tcp_packet = NULL;
etherealflaim 0:d494b853ce97 182 udp_packet = NULL;
etherealflaim 0:d494b853ce97 183 data_bytes = 0;
etherealflaim 0:d494b853ce97 184
etherealflaim 0:d494b853ce97 185 decode_ethernet(frame);
etherealflaim 0:d494b853ce97 186 }
etherealflaim 0:d494b853ce97 187
etherealflaim 5:c56386b9fc33 188 /// Decode the given ethernet frame
etherealflaim 0:d494b853ce97 189 inline void decode_ethernet(void *frame)
etherealflaim 0:d494b853ce97 190 {
etherealflaim 0:d494b853ce97 191 Ethernet_FrameHeader *header = frame_header = (Ethernet_FrameHeader*)frame;
etherealflaim 0:d494b853ce97 192 fix_endian_ethernet(header);
etherealflaim 0:d494b853ce97 193
etherealflaim 0:d494b853ce97 194 switch (header->ethertype)
etherealflaim 0:d494b853ce97 195 {
etherealflaim 0:d494b853ce97 196 case ETHERTYPE_IPV4:
etherealflaim 0:d494b853ce97 197 case ETHERTYPE_IPV6:
etherealflaim 0:d494b853ce97 198 decode_ip((IP_PacketHeader*)header->payload);
etherealflaim 0:d494b853ce97 199 break;
etherealflaim 0:d494b853ce97 200 case ETHERTYPE_ARP:
etherealflaim 0:d494b853ce97 201 decode_arp((ARP_Packet*)header->payload);
etherealflaim 0:d494b853ce97 202 break;
etherealflaim 0:d494b853ce97 203 default:
etherealflaim 0:d494b853ce97 204 break; // Unknown ethertype
etherealflaim 0:d494b853ce97 205 }
etherealflaim 0:d494b853ce97 206 }
etherealflaim 0:d494b853ce97 207
etherealflaim 5:c56386b9fc33 208 /// Decode the given ARP packet
etherealflaim 0:d494b853ce97 209 inline void decode_arp(ARP_Packet *packet)
etherealflaim 0:d494b853ce97 210 {
etherealflaim 0:d494b853ce97 211 fix_endian_arp(packet);
etherealflaim 0:d494b853ce97 212 if (packet->hardware_type != 0x0001 || packet->protocol_type != 0x0800) return;
etherealflaim 0:d494b853ce97 213 arp_packet = packet;
etherealflaim 0:d494b853ce97 214 }
etherealflaim 0:d494b853ce97 215
etherealflaim 5:c56386b9fc33 216 /// Decode the given IPv4 packet
etherealflaim 0:d494b853ce97 217 inline void decode_ip(IP_PacketHeader *packet)
etherealflaim 0:d494b853ce97 218 {
etherealflaim 0:d494b853ce97 219 u16 chk = checksum(packet, sizeof(IP_PacketHeader), &packet->header_checksum, 2);
etherealflaim 0:d494b853ce97 220 fix_endian_ip(packet);
etherealflaim 0:d494b853ce97 221 ip_packet = packet;
etherealflaim 0:d494b853ce97 222
etherealflaim 0:d494b853ce97 223 if (packet->version != 4) return;
etherealflaim 0:d494b853ce97 224
etherealflaim 0:d494b853ce97 225 data_bytes = packet->packet_bytes;
etherealflaim 0:d494b853ce97 226 data_bytes -= sizeof(IP_PacketHeader);
etherealflaim 0:d494b853ce97 227
etherealflaim 0:d494b853ce97 228 if (packet->protocol == IPPROTO_UDP)
etherealflaim 0:d494b853ce97 229 {
etherealflaim 0:d494b853ce97 230 UDP_Packet *segment = udp_packet = (UDP_Packet*)packet->data;
etherealflaim 0:d494b853ce97 231 fix_endian_udp(segment);
etherealflaim 0:d494b853ce97 232 data_bytes -= sizeof(UDP_Packet);
etherealflaim 0:d494b853ce97 233 }
etherealflaim 0:d494b853ce97 234 else if (packet->protocol == IPPROTO_ICMP)
etherealflaim 0:d494b853ce97 235 {
etherealflaim 0:d494b853ce97 236 ICMP_Packet *segment = icmp_packet = (ICMP_Packet *)packet->data;
etherealflaim 0:d494b853ce97 237 fix_endian_icmp(segment);
etherealflaim 0:d494b853ce97 238 data_bytes -= sizeof(ICMP_Packet);
etherealflaim 0:d494b853ce97 239 }
etherealflaim 0:d494b853ce97 240 else if (packet->protocol == IPPROTO_TCP)
etherealflaim 0:d494b853ce97 241 {
etherealflaim 0:d494b853ce97 242 TCP_SegmentHeader *segment = tcp_packet = (TCP_SegmentHeader*)packet->data;
etherealflaim 0:d494b853ce97 243 fix_endian_tcp(segment);
etherealflaim 0:d494b853ce97 244 data_bytes -= sizeof(TCP_SegmentHeader);
etherealflaim 0:d494b853ce97 245 dispatch_tcp(segment,data_bytes);
etherealflaim 0:d494b853ce97 246 }
etherealflaim 0:d494b853ce97 247 }
etherealflaim 0:d494b853ce97 248
etherealflaim 0:d494b853ce97 249 handler<TCP_SegmentHeader*,u32,void> *tcp_handler;
etherealflaim 0:d494b853ce97 250 inline void dispatch_tcp(TCP_SegmentHeader *tcp_packet, u32 data_bytes)
etherealflaim 0:d494b853ce97 251 {
etherealflaim 0:d494b853ce97 252 if (tcp_handler) (*tcp_handler)(tcp_packet,data_bytes);
etherealflaim 0:d494b853ce97 253 }
etherealflaim 0:d494b853ce97 254
etherealflaim 5:c56386b9fc33 255 /// Attach a member function to be called on all TCP packets
etherealflaim 0:d494b853ce97 256 template <class T>
etherealflaim 0:d494b853ce97 257 inline void attach_tcp(T *inst, void (T::*func)(TCP_SegmentHeader *tcp_packet, u32 data_bytes))
etherealflaim 0:d494b853ce97 258 {
etherealflaim 0:d494b853ce97 259 tcp_handler = new member_handler<T,TCP_SegmentHeader*,u32,void>(inst, func);
etherealflaim 0:d494b853ce97 260 }
etherealflaim 0:d494b853ce97 261
etherealflaim 5:c56386b9fc33 262 /// Attach a non-member function to be called on all TCP packets
etherealflaim 0:d494b853ce97 263 inline void attach_tcp(void (*func)(TCP_SegmentHeader *tcp_packet, u32 data_bytes))
etherealflaim 0:d494b853ce97 264 {
etherealflaim 0:d494b853ce97 265 tcp_handler = new function_handler<TCP_SegmentHeader*,u32,void>(func);
etherealflaim 0:d494b853ce97 266 }
etherealflaim 0:d494b853ce97 267 };
etherealflaim 0:d494b853ce97 268
etherealflaim 0:d494b853ce97 269 #endif // SNIFFER_H