![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
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@5:c56386b9fc33, 2010-10-12 (annotated)
- 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?
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 | 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 |