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:37:21 2010 +0000
Revision:
5:c56386b9fc33
Parent:
4:88fc7fa58931
Child:
6:66c4cd9073aa
Documentation enhancements

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