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.
sniffer.h@6:66c4cd9073aa, 2010-10-12 (annotated)
- Committer:
- etherealflaim
- Date:
- Tue Oct 12 06:46:22 2010 +0000
- Revision:
- 6:66c4cd9073aa
- Parent:
- 5:c56386b9fc33
- Child:
- 8:1c1f6ce348c6
File documentation updates
Who changed what in which revision?
User | Revision | Line number | New 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 | 6:66c4cd9073aa | 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 |