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:21:05 2010 +0000
Revision:
4:88fc7fa58931
Parent:
0:d494b853ce97
Child:
5:c56386b9fc33
More documentation updates

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 0:d494b853ce97 67 // Ethernet Frame Header
etherealflaim 0:d494b853ce97 68 Ethernet_FrameHeader *frame_header;
etherealflaim 0:d494b853ce97 69
etherealflaim 0:d494b853ce97 70 // IP Packet Header
etherealflaim 0:d494b853ce97 71 IP_PacketHeader *ip_packet;
etherealflaim 0:d494b853ce97 72
etherealflaim 0:d494b853ce97 73 // ARP Packet
etherealflaim 0:d494b853ce97 74 ARP_Packet *arp_packet;
etherealflaim 0:d494b853ce97 75
etherealflaim 0:d494b853ce97 76 // TCP Packet
etherealflaim 0:d494b853ce97 77 TCP_SegmentHeader *tcp_packet;
etherealflaim 0:d494b853ce97 78
etherealflaim 0:d494b853ce97 79 // UDP Packet
etherealflaim 0:d494b853ce97 80 UDP_Packet *udp_packet;
etherealflaim 0:d494b853ce97 81
etherealflaim 0:d494b853ce97 82 // ICMP Packet
etherealflaim 0:d494b853ce97 83 ICMP_Packet *icmp_packet;
etherealflaim 0:d494b853ce97 84
etherealflaim 0:d494b853ce97 85 // Generic
etherealflaim 0:d494b853ce97 86 unsigned int data_bytes;
etherealflaim 0:d494b853ce97 87
etherealflaim 0:d494b853ce97 88 public:
etherealflaim 0:d494b853ce97 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 0:d494b853ce97 97 inline bool inject(void *data, unsigned int bytes)
etherealflaim 0:d494b853ce97 98 {
etherealflaim 0:d494b853ce97 99 // Send the packet
etherealflaim 0:d494b853ce97 100 eth.write((char*)data, bytes);
etherealflaim 0:d494b853ce97 101 int send_status = eth.send();
etherealflaim 0:d494b853ce97 102
etherealflaim 0:d494b853ce97 103 //decode_ethernet(data);
etherealflaim 0:d494b853ce97 104
etherealflaim 0:d494b853ce97 105 return send_status;
etherealflaim 0:d494b853ce97 106 }
etherealflaim 0:d494b853ce97 107
etherealflaim 0:d494b853ce97 108 inline bool inject(Ethernet_MAC dest, u16 ethertype, void *packet, unsigned int bytes)
etherealflaim 0:d494b853ce97 109 {
etherealflaim 0:d494b853ce97 110 memset(outframe, 0x00, bytes);
etherealflaim 0:d494b853ce97 111
etherealflaim 0:d494b853ce97 112 outframe_header = (Ethernet_FrameHeader*)outframe;
etherealflaim 0:d494b853ce97 113
etherealflaim 0:d494b853ce97 114 // Set the ethernet frame source
etherealflaim 0:d494b853ce97 115 memcpy(&outframe_header->source, mac.octet, 6);
etherealflaim 0:d494b853ce97 116
etherealflaim 0:d494b853ce97 117 // Set the ethernet frame destination
etherealflaim 0:d494b853ce97 118 outframe_header->destination = dest;
etherealflaim 0:d494b853ce97 119
etherealflaim 0:d494b853ce97 120 // Set the ethernet ethertype
etherealflaim 0:d494b853ce97 121 outframe_header->ethertype = ethertype;
etherealflaim 0:d494b853ce97 122
etherealflaim 0:d494b853ce97 123 // Make sure the payload won't be too large
etherealflaim 0:d494b853ce97 124 if (sizeof(Ethernet_FrameHeader) + bytes > sizeof(outframe))
etherealflaim 0:d494b853ce97 125 {
etherealflaim 0:d494b853ce97 126 main_log.printf("ERROR: Attempt to inject packet failed; Payload size of %d is too large", bytes);
etherealflaim 0:d494b853ce97 127 return false;
etherealflaim 0:d494b853ce97 128 }
etherealflaim 0:d494b853ce97 129
etherealflaim 0:d494b853ce97 130 // Set the payload
etherealflaim 0:d494b853ce97 131 memcpy(outframe_header->payload, packet, bytes);
etherealflaim 0:d494b853ce97 132 fix_endian_ethernet(outframe_header);
etherealflaim 0:d494b853ce97 133
etherealflaim 0:d494b853ce97 134 // Send the packet
etherealflaim 0:d494b853ce97 135 eth.write(outframe, sizeof(Ethernet_FrameHeader) + bytes);
etherealflaim 0:d494b853ce97 136 int send_status = eth.send();
etherealflaim 0:d494b853ce97 137
etherealflaim 0:d494b853ce97 138 //decode_ethernet(outframe);
etherealflaim 0:d494b853ce97 139
etherealflaim 0:d494b853ce97 140 return send_status;
etherealflaim 0:d494b853ce97 141 }
etherealflaim 0:d494b853ce97 142
etherealflaim 0:d494b853ce97 143 inline void wait_for_data()
etherealflaim 0:d494b853ce97 144 {
etherealflaim 0:d494b853ce97 145 while (true)
etherealflaim 0:d494b853ce97 146 {
etherealflaim 0:d494b853ce97 147 wait(0.0001);
etherealflaim 0:d494b853ce97 148
etherealflaim 0:d494b853ce97 149 if (!(linked = eth.link()))
etherealflaim 0:d494b853ce97 150 continue;
etherealflaim 0:d494b853ce97 151
etherealflaim 0:d494b853ce97 152 received = (frame_size = eth.receive());
etherealflaim 0:d494b853ce97 153 if (!frame_size)
etherealflaim 0:d494b853ce97 154 continue;
etherealflaim 0:d494b853ce97 155
etherealflaim 0:d494b853ce97 156 eth.read(frame, frame_size);
etherealflaim 0:d494b853ce97 157 break;
etherealflaim 0:d494b853ce97 158 }
etherealflaim 0:d494b853ce97 159 }
etherealflaim 0:d494b853ce97 160
etherealflaim 0:d494b853ce97 161 // Wait for an ethernet frame
etherealflaim 0:d494b853ce97 162 inline void next()
etherealflaim 0:d494b853ce97 163 {
etherealflaim 0:d494b853ce97 164 wait_for_data();
etherealflaim 0:d494b853ce97 165
etherealflaim 0:d494b853ce97 166 // Zero out all of the packet pointers
etherealflaim 0:d494b853ce97 167 frame_header = NULL;
etherealflaim 0:d494b853ce97 168 arp_packet = NULL;
etherealflaim 0:d494b853ce97 169 icmp_packet = NULL;
etherealflaim 0:d494b853ce97 170 tcp_packet = NULL;
etherealflaim 0:d494b853ce97 171 udp_packet = NULL;
etherealflaim 0:d494b853ce97 172 data_bytes = 0;
etherealflaim 0:d494b853ce97 173
etherealflaim 0:d494b853ce97 174 decode_ethernet(frame);
etherealflaim 0:d494b853ce97 175 }
etherealflaim 0:d494b853ce97 176
etherealflaim 0:d494b853ce97 177 inline void decode_ethernet(void *frame)
etherealflaim 0:d494b853ce97 178 {
etherealflaim 0:d494b853ce97 179 Ethernet_FrameHeader *header = frame_header = (Ethernet_FrameHeader*)frame;
etherealflaim 0:d494b853ce97 180 fix_endian_ethernet(header);
etherealflaim 0:d494b853ce97 181
etherealflaim 0:d494b853ce97 182 switch (header->ethertype)
etherealflaim 0:d494b853ce97 183 {
etherealflaim 0:d494b853ce97 184 case ETHERTYPE_IPV4:
etherealflaim 0:d494b853ce97 185 case ETHERTYPE_IPV6:
etherealflaim 0:d494b853ce97 186 decode_ip((IP_PacketHeader*)header->payload);
etherealflaim 0:d494b853ce97 187 break;
etherealflaim 0:d494b853ce97 188 case ETHERTYPE_ARP:
etherealflaim 0:d494b853ce97 189 decode_arp((ARP_Packet*)header->payload);
etherealflaim 0:d494b853ce97 190 break;
etherealflaim 0:d494b853ce97 191 default:
etherealflaim 0:d494b853ce97 192 break; // Unknown ethertype
etherealflaim 0:d494b853ce97 193 }
etherealflaim 0:d494b853ce97 194 }
etherealflaim 0:d494b853ce97 195
etherealflaim 0:d494b853ce97 196 inline void decode_arp(ARP_Packet *packet)
etherealflaim 0:d494b853ce97 197 {
etherealflaim 0:d494b853ce97 198 fix_endian_arp(packet);
etherealflaim 0:d494b853ce97 199 if (packet->hardware_type != 0x0001 || packet->protocol_type != 0x0800) return;
etherealflaim 0:d494b853ce97 200 arp_packet = packet;
etherealflaim 0:d494b853ce97 201 }
etherealflaim 0:d494b853ce97 202
etherealflaim 0:d494b853ce97 203 inline void decode_ip(IP_PacketHeader *packet)
etherealflaim 0:d494b853ce97 204 {
etherealflaim 0:d494b853ce97 205 u16 chk = checksum(packet, sizeof(IP_PacketHeader), &packet->header_checksum, 2);
etherealflaim 0:d494b853ce97 206 fix_endian_ip(packet);
etherealflaim 0:d494b853ce97 207 ip_packet = packet;
etherealflaim 0:d494b853ce97 208
etherealflaim 0:d494b853ce97 209 if (packet->version != 4) return;
etherealflaim 0:d494b853ce97 210
etherealflaim 0:d494b853ce97 211 data_bytes = packet->packet_bytes;
etherealflaim 0:d494b853ce97 212 data_bytes -= sizeof(IP_PacketHeader);
etherealflaim 0:d494b853ce97 213
etherealflaim 0:d494b853ce97 214 if (packet->protocol == IPPROTO_UDP)
etherealflaim 0:d494b853ce97 215 {
etherealflaim 0:d494b853ce97 216 UDP_Packet *segment = udp_packet = (UDP_Packet*)packet->data;
etherealflaim 0:d494b853ce97 217 fix_endian_udp(segment);
etherealflaim 0:d494b853ce97 218 data_bytes -= sizeof(UDP_Packet);
etherealflaim 0:d494b853ce97 219 }
etherealflaim 0:d494b853ce97 220 else if (packet->protocol == IPPROTO_ICMP)
etherealflaim 0:d494b853ce97 221 {
etherealflaim 0:d494b853ce97 222 ICMP_Packet *segment = icmp_packet = (ICMP_Packet *)packet->data;
etherealflaim 0:d494b853ce97 223 fix_endian_icmp(segment);
etherealflaim 0:d494b853ce97 224 data_bytes -= sizeof(ICMP_Packet);
etherealflaim 0:d494b853ce97 225 }
etherealflaim 0:d494b853ce97 226 else if (packet->protocol == IPPROTO_TCP)
etherealflaim 0:d494b853ce97 227 {
etherealflaim 0:d494b853ce97 228 TCP_SegmentHeader *segment = tcp_packet = (TCP_SegmentHeader*)packet->data;
etherealflaim 0:d494b853ce97 229 fix_endian_tcp(segment);
etherealflaim 0:d494b853ce97 230 data_bytes -= sizeof(TCP_SegmentHeader);
etherealflaim 0:d494b853ce97 231 dispatch_tcp(segment,data_bytes);
etherealflaim 0:d494b853ce97 232 }
etherealflaim 0:d494b853ce97 233 }
etherealflaim 0:d494b853ce97 234
etherealflaim 0:d494b853ce97 235 handler<TCP_SegmentHeader*,u32,void> *tcp_handler;
etherealflaim 0:d494b853ce97 236 inline void dispatch_tcp(TCP_SegmentHeader *tcp_packet, u32 data_bytes)
etherealflaim 0:d494b853ce97 237 {
etherealflaim 0:d494b853ce97 238 if (tcp_handler) (*tcp_handler)(tcp_packet,data_bytes);
etherealflaim 0:d494b853ce97 239 }
etherealflaim 0:d494b853ce97 240
etherealflaim 0:d494b853ce97 241 template <class T>
etherealflaim 0:d494b853ce97 242 inline void attach_tcp(T *inst, void (T::*func)(TCP_SegmentHeader *tcp_packet, u32 data_bytes))
etherealflaim 0:d494b853ce97 243 {
etherealflaim 0:d494b853ce97 244 tcp_handler = new member_handler<T,TCP_SegmentHeader*,u32,void>(inst, func);
etherealflaim 0:d494b853ce97 245 }
etherealflaim 0:d494b853ce97 246
etherealflaim 0:d494b853ce97 247 inline void attach_tcp(void (*func)(TCP_SegmentHeader *tcp_packet, u32 data_bytes))
etherealflaim 0:d494b853ce97 248 {
etherealflaim 0:d494b853ce97 249 tcp_handler = new function_handler<TCP_SegmentHeader*,u32,void>(func);
etherealflaim 0:d494b853ce97 250 }
etherealflaim 0:d494b853ce97 251 };
etherealflaim 0:d494b853ce97 252
etherealflaim 0:d494b853ce97 253 #endif // SNIFFER_H