James Sayer
/
smart2
test icmp
Fork of ethspam by
Revision 1:feaa107f56b3, committed 2015-04-24
- Comitter:
- jamessayer
- Date:
- Fri Apr 24 03:11:02 2015 +0000
- Parent:
- 0:852db76de235
- Commit message:
- first version;
Changed in this revision
diff -r 852db76de235 -r feaa107f56b3 main.cpp --- a/main.cpp Fri Sep 04 12:25:06 2009 +0000 +++ b/main.cpp Fri Apr 24 03:11:02 2015 +0000 @@ -1,5 +1,9 @@ #include "mbed.h" // Importing the mbed classes and tools. #include "Ethernet.h" +#include "util/types.h" +#include "net/net.h" +#include "sniffer.h" + using namespace mbed; @@ -20,54 +24,116 @@ unsigned char dhwaddr[6]; // Hardware address of the intended receiver. This field is ignored in requests. unsigned char dipaddr[4]; // Protocol address of the intended receiver. }; - -Ethernet eth; // The ethernet device +Sniffer sniffer; +Ethernet_MAC your_mac; +//Ethernet eth; // The ethernet device DigitalOut led4(LED4); // A LED for showing activity unsigned short htons(unsigned short n) { // Host short to network shor return ((n & 0xff) << 8) | ((n & 0xff00) >> 8); // Byte swapping } -void send(const char *ipaddr) { - static char data[0x600]; // Packet buffer - const unsigned char arplen = 6; // Hardware address length - const unsigned char ethlen = 4; // IP address length - char hwaddr[arplen]; // Hardware address buffer - struct ethpkt *pkg = (struct ethpkt *) &data[0]; // Force the buffer to an ethpkg - unsigned char pos = arplen; // Hardware/IP address position - - eth.address(hwaddr); // Get own hardware address +#define PING_BUFEFERSIZE (sizeof(IP_PacketHeader) + sizeof(ICMP_Packet)) - pkg->type = htons(0x0806); // Set type to ARP (0x0806) - pkg->hwtype = htons(0x0001); // Hardware type is Ethernet (0x0001) - pkg->proto = htons(0x0800); // Protocol is ARP Request (0x0800) - pkg->hwlen = arplen; // Hardware addresses are 6 Bytes long - pkg->protolen = ethlen; // And protocol addresses 4 Bytes - pkg->opcode = htons(0x0001); // Send: whois XX:XX:XX:XX:XX:XX? +void send(const char *ipaddr) { + IP_Address dest_ip; + IP_Address my_ip; + str2ipaddr(ipaddr,&dest_ip); + str2ipaddr("192.168.0.16",&my_ip); + + u8 buffer[PING_BUFEFERSIZE]; + IP_PacketHeader *ip_packet = (IP_PacketHeader*)buffer; + ICMP_Packet *ping_packet = (ICMP_Packet*)ip_packet->data; + + memset(buffer, '\0', PING_BUFEFERSIZE); + + *ip_packet = (IP_PacketHeader){0x04, 5, 0, sizeof(IP_PacketHeader)+sizeof(ICMP_Packet), 0, 0, 0, 0, 0, 32, IPPROTO_ICMP, 0x00, my_ip, dest_ip}; + *ping_packet = (ICMP_Packet){ICMP_ECHO_REQUEST, 0x00, 0x00, 0x00, 0x00}; + + fix_endian_icmp(ping_packet); + fix_endian_ip(ip_packet); + ip_packet->header_checksum = checksum(ip_packet, sizeof(IP_PacketHeader), &ip_packet->header_checksum, 2); + ping_packet->checksum = checksum(ping_packet, sizeof(ICMP_Packet), &ping_packet->checksum, 2); + + + printf("PING sent...\n"); + + sniffer.inject(your_mac, ETHERTYPE_IPV4, buffer, PING_BUFEFERSIZE); + + + +// printf("a\n"); +// IP_Address dest_ip; +// IP_Address my_ip; +// str2ipaddr(ipaddr,&dest_ip); +// str2ipaddr("192.168.0.5",&my_ip); +// printf("b\n"); +// u8 buffer[PING_BUFEFERSIZE]; +// IP_PacketHeader *ip_packet = (IP_PacketHeader*)buffer; +// ICMP_Packet *ping_packet = (ICMP_Packet*)ip_packet->data; +// printf("c\n"); +// memset(buffer, '\0', PING_BUFEFERSIZE); +// printf("d\n"); +// *ip_packet = (IP_PacketHeader){0x4, 5, 0, sizeof(IP_PacketHeader)+sizeof(ICMP_Packet), 0, 0, 0, 0, 0, 32, IPPROTO_ICMP, 0x00, my_ip, dest_ip}; +// *ping_packet = (ICMP_Packet){ICMP_ECHO_REQUEST, 0x00, 0x00, 0x00, 0x00}; +// printf("e\n"); + + +/// fix_endian_icmp(ping_packet); +// fix_endian_ip(ip_packet); +// printf("f\n"); +// ip_packet->header_checksum = checksum(ip_packet, sizeof(IP_PacketHeader), &ip_packet->header_checksum, 2); +// ping_packet->checksum = checksum(ping_packet, sizeof(ICMP_Packet), &ping_packet->checksum, 2); +// printf("h\n"); +// +// print_icmp(ping_packet); +// print_ip(ip_packet); +// +// printf("i\n"); +// eth.write((char*)buffer, PING_BUFEFERSIZE); // Write the package +// eth.send(); // Send the package +// printf("j\n"); - while(pos-- > 0) { // Write IP/MAC-Addresses (combined loop for all addresses) - pkg->src[pos] = hwaddr[pos]; // Set source MAC address to hwaddr on ethernet layer - pkg->dest[pos] = 0xFF; // Set destination MAC address to everybody (FF:FF:FF:FF:FF:FF) on ethernet layer - pkg->shwaddr[pos] = hwaddr[pos]; // Set source MAC address on ARP layer - pkg->dhwaddr[pos] = 0xFF; // Set destination MAC address on ARP layer - if(pos < ethlen) { // Check if we can copy IP addresses too. - pkg->sipaddr[pos] = 0xFF; // Set source ip address to 255.255.255.255 - pkg->dipaddr[pos] = ipaddr[pos]; // Set destination ip address to ipaddr - } - } - - eth.write(data, 60); // Write the package - eth.send(); // Send the package +// static char data[0x600]; // Packet buffer +// const unsigned char arplen = 6; // Hardware address length +// const unsigned char ethlen = 4; // IP address length +// char hwaddr[arplen]; // Hardware address buffer +// struct ethpkt *pkg = (struct ethpkt *) &data[0]; // Force the buffer to an ethpkg +// unsigned char pos = arplen; // Hardware/IP address position +// +// eth.address(hwaddr); // Get own hardware address +// +// pkg->type = htons(0x0806); // Set type to ARP (0x0806) +// pkg->hwtype = htons(0x0001); // Hardware type is Ethernet (0x0001) +// pkg->proto = htons(0x0800); // Protocol is ARP Request (0x0800) +// pkg->hwlen = arplen; // Hardware addresses are 6 Bytes long +// pkg->protolen = ethlen; // And protocol addresses 4 Bytes +// pkg->opcode = htons(0x0001); // Send: whois XX:XX:XX:XX:XX:XX? +// +// while(pos-- > 0) { // Write IP/MAC-Addresses (combined loop for all addresses) +// pkg->src[pos] = hwaddr[pos]; // Set source MAC address to hwaddr on ethernet layer +// pkg->dest[pos] = 0xFF; // Set destination MAC address to everybody (FF:FF:FF:FF:FF:FF) on ethernet layer +// pkg->shwaddr[pos] = hwaddr[pos]; // Set source MAC address on ARP layer +// pkg->dhwaddr[pos] = 0xFF; // Set destination MAC address on ARP layer +// if(pos < ethlen) { // Check if we can copy IP addresses too. +// pkg->sipaddr[pos] = 0xFF; // Set source ip address to 255.255.255.255 +// pkg->dipaddr[pos] = ipaddr[pos]; // Set destination ip address to ipaddr +// } +// } +// +// eth.write(data, 60); // Write the package +// eth.send(); // Send the package } // In this example we would like to make ARP requests to ask for every ip address. int main() { // The programm starts here! unsigned int i = 1; // The integer we use as counter and target IP address. - char *c = (char *)&i; // We cast the integer to an array of char c[4] to handle it as IP address. + //char *c = (char *)&i; // We cast the integer to an array of char c[4] to handle it as IP address. printf("Lowlevel Ethernet Spammer\n\n"); // Print out that the programm has been started. - while(1) { // Do forever: - send(c); // Assamble and send our request. See eth_send function! + while(1) { + char* ip = "192.168.10.10"; // Do forever: + send(ip); // Assamble and send our request. See eth_send function! i++; // Increment counter. What will increment the IP (c[4]) address as well. led4 = 1; // Show activity, by blinking with led 4:
diff -r 852db76de235 -r feaa107f56b3 mbed.bld --- a/mbed.bld Fri Sep 04 12:25:06 2009 +0000 +++ b/mbed.bld Fri Apr 24 03:11:02 2015 +0000 @@ -1,1 +1,1 @@ -http://mbed.org/users/mbed_official/code/mbed/builds/f63353af7be8 +http://mbed.org/users/mbed_official/code/mbed/builds/433970e64889 \ No newline at end of file
diff -r 852db76de235 -r feaa107f56b3 net/arp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net/arp.h Fri Apr 24 03:11:02 2015 +0000 @@ -0,0 +1,58 @@ +#ifndef ARP_H +#define ARP_H + +#include "net.h" + +/** + \file + \brief ARP packet + + This file contains the memory map and associated functions for ARP packet + creation and deconstruction. +*/ + +#define ETHERTYPE_ARP 0x0806 + +/// ARP Packet memory map +typedef struct { + u16 hardware_type; ///< 0x0001 for ethernet + u16 protocol_type; ///< 0x0800 for IPv4 + u8 hardware_length; ///< Bytes. Ethernet is 6 + u8 protocol_length; ///< Bytes. IPv4 is 4 + u16 operation; ///< Operation. 1 for request, 2 for reply or announce + // The following are only valid for IPv4 over Ethernet + u8 sender_hardware_address[6]; ///< Generator of the request or reply + u8 sender_protocol_address[4]; ///< All zeroes for an ARP probe + u8 target_hardware_address[6]; ///< Announce - same as SHA + u8 target_protocol_address[4]; ///< Announce - Same as TPA +} ARP_Packet; + +/// Convert from wire to host or host to wire endianness +inline void fix_endian_arp(ARP_Packet *packet) +{ + fix_endian_u16(&packet->hardware_type); + fix_endian_u16(&packet->protocol_type); + fix_endian_u16(&packet->operation); +} + +/// Print the ARP packet +inline void print_arp(ARP_Packet *packet) +{ + printf("ARP Packet: \n"); + printf(" Hardware: 0x%04X \n", packet->hardware_type); + printf(" Protocol: 0x%04X \n", packet->protocol_type); + printf(" Type: %d \n", packet->operation); + if (packet->hardware_type != 0x0001 || packet->protocol_type != 0x0800) return; + + u8 *bytes; + bytes = packet->sender_hardware_address; + printf(" Source: MAC - %02X:%02X:%02X:%02X:%02X:%02X \n", bytes[0],bytes[1],bytes[2],bytes[3],bytes[4],bytes[5]); + bytes = packet->target_hardware_address; + printf(" Target: MAC - %02X:%02X:%02X:%02X:%02X:%02X \n", bytes[0],bytes[1],bytes[2],bytes[3],bytes[4],bytes[5]); + bytes = packet->sender_protocol_address; + printf(" Source: IP - %03d.%03d.%03d.%03d \n", bytes[0], bytes[1], bytes[2], bytes[3]); + bytes = packet->target_protocol_address; + printf(" Target: IP - %03d.%03d.%03d.%03d \n", bytes[0], bytes[1], bytes[2], bytes[3]); +} + +#endif \ No newline at end of file
diff -r 852db76de235 -r feaa107f56b3 net/ethernet.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net/ethernet.h Fri Apr 24 03:11:02 2015 +0000 @@ -0,0 +1,49 @@ +#ifndef ETHERNET_H +#define ETHERNET_H + +#include "net.h" + +/** + \file ethernet.h + \brief Ethernet frame header + + This file contains the memory map and associated functions for Ethernet frame header + creation and deconstruction. +*/ + +/// Ethernet MAC address memory map +typedef struct { + unsigned char octet[6]; ///< Individual octsts of the MAC address +} Ethernet_MAC; + +/// Ethernet II Frame Header Memory map +typedef struct { + /// Destination MAC address (6 octets) + Ethernet_MAC destination; + /// Source MAC address (6 octets) + Ethernet_MAC source; + // (optional) VLAN Tag (unsupported) + /// Ethernet type or length (only <0x600 or 0x0800 IPv4 supported) + u16 ethertype; + /// Payload (used for memory mapping; has zero size) + unsigned char payload[]; +} Ethernet_FrameHeader; + +/// Convert from wire to host or host to wire endian-ness +inline void fix_endian_ethernet(Ethernet_FrameHeader *header) +{ + fix_endian_u16(&header->ethertype); +} + +/// Print out an ethernet packet +inline void print_ethernet(Ethernet_FrameHeader *frame) +{ + printf("Ethernet frame: \n"); + u8 *src = frame->source.octet; + u8 *dst = frame->destination.octet; + printf(" Source: MAC - %02X:%02X:%02X:%02X:%02X:%02X \n", src[6], src[7], src[8], src[9], src[10], src[11]); + printf(" Dest: MAC - %02X:%02X:%02X:%02X:%02X:%02X \n", dst[0], dst[1], dst[2], dst[3], dst[4], dst[5]); + printf(" Ethertype: 0x%04X \n", frame->ethertype); +} + +#endif \ No newline at end of file
diff -r 852db76de235 -r feaa107f56b3 net/icmp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net/icmp.h Fri Apr 24 03:11:02 2015 +0000 @@ -0,0 +1,47 @@ +#ifndef ICMP_H +#define ICMP_H + +#include "net.h" + +/** + \file icmp.h + \brief ICMP frame header + + This file contains the memory map and associated functions for ICMP packet + creation and deconstruction. +*/ + +#define ICMP_ECHO_REPLY 0x00 +#define ICMP_ECHO_REQUEST 0x08 +#define IPPROTO_ICMP 0x01 + +/// ICMP packet memory map +typedef struct { + u8 type; ///< type of ICMP message + u8 code; ///< code number associated with certain message types + u16 checksum; + u16 id; ///< ID value, returned in ECHO REPLY + u16 sequence; ///< Sequence value to be returned with ECHO REPLY + u8 data[]; ///< Data memory map +} ICMP_Packet; + +/// Convert from wire to host or host to wire endianness +inline void fix_endian_icmp(ICMP_Packet *segment) +{ + fix_endian_u16(&segment->checksum); + fix_endian_u16(&segment->id); + fix_endian_u16(&segment->sequence); +} + +/// Print the ICMP packet +inline void print_icmp(ICMP_Packet *segment) +{ + printf("ICMP Packet:"); + printf(" Type: 0x%02X \n", segment->type); + printf(" Code: 0x%02X \n", segment->code); + printf(" Checksum: 0x%04X \n", segment->checksum); + printf(" ID: 0x%04X \n", segment->id); + printf(" Sequence: 0x%04X \n", segment->sequence); +} + +#endif \ No newline at end of file
diff -r 852db76de235 -r feaa107f56b3 net/ip.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net/ip.h Fri Apr 24 03:11:02 2015 +0000 @@ -0,0 +1,115 @@ +#ifndef IP_H +#define IP_H + +#include "net.h" + +/** + \file ip.h + \brief IP Packet header + + This file contains the memory map and associated functions for IP packet header + creation and deconstruction. +*/ + +#define ETHERTYPE_IPV4 0x0800 +#define ETHERTYPE_IPV6 0x86DD + +/// IP Address memory map +typedef struct { + unsigned char octet[4]; ///< Individual address octets +} IP_Address; + +/// IP Packet memory map +typedef struct { + /// 4 bits that contain the version, that specifies if it's an IPv4 or IPv6 packet, + unsigned version:4; // Only 0x4 supported + /// 4 bits that contain the Internet Header Length which is the length of the header in multiples of 4 bytes (eg. 5 means 20 bytes). + unsigned header_bytes_div4:4; + /// 8 bits that contain the Type of Service, also referred to as Quality of Service (QoS), which describes what priority the packet should have, + unsigned tos:8; + /// 16 bits that contain the total length of the IP packet (datagram) in bytes, + u16 packet_bytes; + /// 16 bits that contain an identification tag to help reconstruct the packet from several fragments, + u16 fragment_id; + /// 3 bits that contain a zero, a flag that says whether the packet is allowed to be fragmented or not (DF: Don't fragment), and a flag to state whether more fragments of a packet follow (MF: More Fragments) + unsigned unused_0:1; + unsigned dont_fragment:1; + unsigned more_follow:1; + /// 13 bits that contain the fragment offset, a field to identify position of fragment within original packet + unsigned fragment_offset:13; ///< This and the ones above may not work properly due to endianness + /// 8 bits that contain the Time to live (TTL) which is the number of hops (router, computer or device along a network) the packet is allowed to pass before it dies (for example, a packet with a TTL of 16 will be allowed to go across 16 routers to get to its destination before it is discarded), + unsigned ttl:8; + /// 8 bits that contain the protocol (TCP, UDP, ICMP, etc...) + /// 0x01 ICMP + /// 0x06 TCP + /// 0x11 UDP + unsigned protocol:8; + /// 16 bits that contain the Header Checksum, a number used in error detection, + u16 header_checksum; + /// 32 bits that contain the source IP address, + IP_Address source; + /// 32 bits that contain the destination address. + IP_Address destination; + /// Zero-length field for memory mapping the packet data + unsigned char data[]; +} IP_PacketHeader; + +/// Convert from wire to host or host to wire endianness +inline void fix_endian_ip(IP_PacketHeader *packet) +{ + packet->version ^= packet->header_bytes_div4; + packet->header_bytes_div4 ^= packet->version; + packet->version ^= packet->header_bytes_div4; + fix_endian_u16(&packet->packet_bytes); + fix_endian_u16(&packet->fragment_id); + // Don't fix checksums; they are done bitwise +} + +/// Get a constant string of the given IP protocol (e.g. "ICMP", "TCP", "UDP") if known +inline const char *ipproto2name(u8 proto) +{ + switch (proto) + { + case 0x01: return "ICMP"; + case 0x02: return "IGMP"; + case 0x06: return "TCP"; + case 0x11: return "UDP"; + } + return "<UNKNOWN>"; +} + +/// Print the IP packet +inline void print_ip(IP_PacketHeader *packet) +{ + printf("IPv%d Packet: \n", packet->version); + if (packet->version != 4) + { + printf("Not an IPv4 packet (skipping)"); + return; + } + + u8 *dst = packet->destination.octet; + u8 *src = packet->source.octet; + printf(" Source: IP - %03d.%03d.%03d.%03d \n", src[0], src[1], src[2], src[3]); + printf(" Dest: IP - %03d.%03d.%03d.%03d \n", dst[0], dst[1], dst[2], dst[3]); + printf(" TTL: %d \n", packet->ttl); + printf(" Protocol: 0x%02X (%s) \n", packet->protocol, ipproto2name(packet->protocol)); + printf(" ToS: 0x%02X \n", packet->tos); + printf(" Header: %d bytes \n", packet->header_bytes_div4*4); + printf(" Packet: %d bytes \n", packet->packet_bytes); + printf(" Fragment: 0x%04X DF=%d MF=%d OFFSET=0x04X", packet->fragment_id, packet->dont_fragment, packet->more_follow, packet->fragment_offset); + printf(" Checksum: 0x%04X \n", packet->header_checksum); +} + +/// Parse the string (in decimal triple-dot notation) into the IP address structure +inline void str2ipaddr(const char *ip, IP_Address *addr) +{ + static short a,b,c,d; + sscanf(ip, "%3hd.%3hd.%3hd.%3hd", &a, &b, &c, &d); + addr->octet[0] = a; + addr->octet[1] = b; + addr->octet[2] = c; + addr->octet[3] = d; +} + +#endif \ No newline at end of file
diff -r 852db76de235 -r feaa107f56b3 net/net.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net/net.h Fri Apr 24 03:11:02 2015 +0000 @@ -0,0 +1,103 @@ +/** + @file net.h + @brief This file encompasses all of the networking headers and includes them automatically + + This file has some utility functions and definitions used by all of the networking headers, + and includes them all. This is the only file necessary to include to use all of the networking + facilities in nettool +*/ + +#ifndef NETWORK_H +#define NETWORK_H + +#include "mbed.h" + +#include "ctype.h" + +/// General networking checksum - Used for IP, TCP, UDP, ICMP, etc. +/// Computes the one's complement of the one's complement sum of all of the given bytes except for the memory +/// at skip_byte for skip_count bytes (e.g. the checksum). Optionally resumes computation from the (given) last checksum. +inline u16 checksum(void *_mem, unsigned int bytes, void *skip_byte = NULL, unsigned int skip_count = 0, u16 last = 0) +{ + u32 sum = 0; + u16 *mem = (u16*)_mem; + unsigned int skip_start = (u16*)skip_byte - mem; + + if (last) + sum = last ^ 0xFFFF; + + //main_log.printf("CK: 0x%8X", sum); + for (register unsigned int i = 0; i < bytes/sizeof(u16); ++i) + { + // Skip bytes we don't use (e.g. the checksum itself) + if (i == skip_start) + i += skip_count/sizeof(u16); + + // Sum them up + sum += mem[i]; + + //main_log.printf("CK: + 0x%04X = 0x%8X", mem[i], sum); + } + + // One's complement of the one's complement sum + sum += sum >> 16; + sum &= 0xFFFF; + sum ^= 0xFFFF; + + //main_log.printf("CK: ~ 0x%8X", sum); + + return (u16)(sum); +} + +/// Generic u16 endian swapping +inline void fix_endian_u16(u16 *p) +{ + char *bytes = (char*)p; + bytes[0] ^= bytes[1]; + bytes[1] ^= bytes[0]; + bytes[0] ^= bytes[1]; +} + +/// Generic u32 endian swapping +inline void fix_endian_u32(u32 *p) +{ + char *bytes = (char*)p; + // Swap outer bytes + bytes[0] ^= bytes[3]; + bytes[3] ^= bytes[0]; + bytes[0] ^= bytes[3]; + // Swap inner bytes + bytes[1] ^= bytes[2]; + bytes[2] ^= bytes[1]; + bytes[1] ^= bytes[2]; +} + +/* Printing character */ +#define PCHAR(x) (isprint(x)?(x):'.') + +/// Hex dump a word-aligned number of bytes (will print extra bytes if length is not a multiple of 32 bits) +inline void hex_dump(void *base, unsigned int length) +{ + char line[/*indent*/ 2 + /*0x*/ 2 + /*addr*/ 8 + /* : */ 3 + /*4xXXXX */ 4*5 + /*: */ 2 + /*8x.*/ 8 + /*\0*/ 1]; + for (char *p = (char*)base; p - (char*)base < length; p += 8) + { + sprintf(line, " 0x%08X : %02X%02X %02X%02X %02X%02X %02X%02X : %c%c%c%c%c%c%c%c \n", p, + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], + PCHAR(p[0]), PCHAR(p[1]), PCHAR(p[2]), PCHAR(p[3]), PCHAR(p[4]), PCHAR(p[5]), PCHAR(p[6]), PCHAR(p[7])); + printf(line); + } +} + +// Ethernet +#include "ethernet.h" + +// ARP and IP +#include "arp.h" +#include "ip.h" + +// TCP, UDP, and ICMP +#include "tcp.h" +#include "udp.h" +#include "icmp.h" + +#endif // NETWORK_H \ No newline at end of file
diff -r 852db76de235 -r feaa107f56b3 net/tcp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net/tcp.h Fri Apr 24 03:11:02 2015 +0000 @@ -0,0 +1,90 @@ +#ifndef TCP_H +#define TCP_H + +#include "net.h" + +/** + \file tcp.h + \brief TCP segment header + + This file contains the memory map and associated functions for TCP segment header + creation and deconstruction. +*/ + +#define IPPROTO_TCP 0x06 + +/// TCP Segment memory map +typedef struct { + u16 source_port; ///< Source port (1-65535) + u16 destination_port; ///< Destination port (1-65535) + u32 sequence_number; ///< TCP Sequence number (initial one if SYN set) + u32 acknowledge_number; ///< TCP Acknowledge number (valid if ACK set) + + unsigned data_offset_bytes_div4:4; ///< Length of this header (20) divided by 4 (should be 5) + unsigned unused_0:4; ///< Unused, should be zero + + unsigned fin:1; ///< connection FINished (no more data from sender) + unsigned syn:1; ///< SYNchronize sequence numbers + unsigned rst:1; ///< ReSeT the connection + unsigned psh:1; ///< PuSH to receiving application + unsigned ack:1; ///< ACKnowledge fiend is significant + unsigned urg:1; ///< URGent field is significant + unsigned ece:1; ///< ECn Echo + unsigned cwr:1; ///< Congestion Window Reduced + + u16 window_size; ///< TCP Maxumum window size (8192 is good) + u16 checksum; ///< TCP checksum (computed with pseudo header) + u16 urgent_pointer; ///< Urgent pointer (valid if URG set) + + /// Memory map for data if no options are set + unsigned char data[]; +} TCP_SegmentHeader; + +/// Convert from wire to host or host to wire endianness +inline void fix_endian_tcp(TCP_SegmentHeader *segment) +{ + segment->unused_0 ^= segment->data_offset_bytes_div4; + segment->data_offset_bytes_div4 ^= segment->unused_0; + segment->unused_0 ^= segment->data_offset_bytes_div4; + fix_endian_u16(&segment->source_port); + fix_endian_u16(&segment->destination_port); + fix_endian_u16(&segment->window_size); + // No fixing checksums + fix_endian_u16(&segment->urgent_pointer); + fix_endian_u32(&segment->sequence_number); + fix_endian_u32(&segment->acknowledge_number); +} + +/// Print the TCP segment header +inline void print_tcp(TCP_SegmentHeader *segment) +{ + printf("TCP Segment: \n"); + printf(" Source: PORT %d \n", segment->source_port); + printf(" Dest: PORT %d \n", segment->destination_port); + printf(" TCP Seqno: 0x%08X \n", segment->sequence_number); + printf(" TCP Ackno: 0x%08X \n", segment->acknowledge_number); + printf(" Header: %d bytes \n", segment->data_offset_bytes_div4*4); + if (segment->cwr) printf(" Flag: CWR \n"); + if (segment->ece) printf(" Flag: ECE \n"); + if (segment->urg) printf(" Flag: URG \n"); + if (segment->ack) printf(" Flag: ACK \n"); + if (segment->psh) printf(" Flag: PSH \n"); + if (segment->rst) printf(" Flag: RST \n"); + if (segment->syn) printf(" Flag: SYN \n"); + if (segment->fin) printf(" Flag: FIN \n"); +} + +/// Compute the pseudo header checksum with the given source, destination, and length +inline u16 pseudo_header_checksum(IP_Address source, IP_Address destination, u16 length) +{ + struct { + IP_Address src, dst; + u8 zeros; + u8 proto; + u16 length; + } pseudoheader = {source, destination, 0, IPPROTO_TCP, length}; + fix_endian_u16(&pseudoheader.length); + return checksum(&pseudoheader, sizeof(pseudoheader)); +} + +#endif \ No newline at end of file
diff -r 852db76de235 -r feaa107f56b3 net/udp.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net/udp.h Fri Apr 24 03:11:02 2015 +0000 @@ -0,0 +1,42 @@ +#ifndef UDP_H +#define UDP_H + +#include "net.h" + +/** + \file udp.h + \brief UDP packet + + This file contains the memory map and associated functions for UDP packet + creation and deconstruction. +*/ + +#define IPPROTO_UDP 0x11 + +/// UDP Packet memory map +typedef struct { + u16 source_port; ///< Source port (1-65535) + u16 destination_port; ///< Destination port (1-65535) + u16 length; ///< Entire datagram size in bytes + u16 checksum; ///< Checksum + u8 data[]; ///< Data memory map +} UDP_Packet; + +/// Convert from wire to host or host to wire endianness +inline void fix_endian_udp(UDP_Packet *segment) +{ + fix_endian_u16(&segment->source_port); + fix_endian_u16(&segment->destination_port); + fix_endian_u16(&segment->length); +} + +/// Print the UDP packet +inline void print_udp(UDP_Packet *segment) +{ + printf("UDP Packet: \n"); + printf(" Source: PORT %d \n", segment->source_port); + printf(" Dest: PORT %d \n", segment->destination_port); + printf(" Length: %d \n", segment->length); +} + +#endif \ No newline at end of file
diff -r 852db76de235 -r feaa107f56b3 sniffer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sniffer.h Fri Apr 24 03:11:02 2015 +0000 @@ -0,0 +1,268 @@ +#ifndef SNIFFER_H +#define SNIFFER_H + +#include "mbed.h" + +#include "util/types.h" +#include "net/net.h" + +#include <cstdio> +#include <cstring> +#include <functional> + +/** + \file sniffer.h + \brief Ethernet packet Sniffer + + This file is the bread and butter of the NetTool; it processes and constructs ethernet frames + on a bitwise level. +*/ + +template <class Arg1, class Arg2, class Result> +class handler +{ +public: + virtual inline Result operator() (Arg1 x, Arg2 y) const {}; +}; + +template <class Arg1, class Arg2, class Result> +class function_handler +: public handler <Arg1,Arg2,Result> +{ +protected: + Result (*pfunc)(Arg1,Arg2); +public: + explicit inline function_handler ( Result (*f)(Arg1,Arg2) ) : pfunc (f) {} + virtual inline Result operator() (Arg1 x, Arg2 y) const { return pfunc(x,y); } +}; + +template <class Type, class Arg1, class Arg2, class Result> +class member_handler +: public handler <Arg1,Arg2,Result> +{ +protected: + Type *inst; + Result (Type::*pfunc)(Arg1,Arg2); +public: + explicit inline member_handler ( Type *i, Result (Type::*f)(Arg1,Arg2) ) : inst(i), pfunc (f) {} + virtual inline Result operator() (Arg1 x, Arg2 y) const { return (inst->*pfunc)(x,y); } +}; + +/// Demo - Ethernet Packet Sniffer +class Sniffer { +public: + Ethernet_MAC mac; + +private: + // Ethernet interface + Ethernet eth; + IP_Address addr; + + // Status LEDs + DigitalOut linked; + DigitalOut received; + + // Frame data (big enough for largest ethernet frame) + int frame_size; + char frame[0x600]; + + // Outgoing frames + char outframe[0x600]; + Ethernet_FrameHeader *outframe_header; + +public: + /// Ethernet Frame Header (incoming) + Ethernet_FrameHeader *frame_header; + + /// IP Packet Header (incoming) + IP_PacketHeader *ip_packet; + + /// ARP Packet (incoming) + ARP_Packet *arp_packet; + + /// TCP Packet (incoming) + TCP_SegmentHeader *tcp_packet; + + /// UDP Packet (incoming) + UDP_Packet *udp_packet; + + /// ICMP Packet (incoming) + ICMP_Packet *icmp_packet; + + /// Generic - total data bytes + unsigned int data_bytes; + +public: + /// Constructor + inline Sniffer() + : linked(LED1), received(LED2) + { + eth.set_link(Ethernet::AutoNegotiate); + eth.address((char *)mac.octet); + } + + /// Inject the raw ethernet frame + inline bool inject(void *data, unsigned int bytes) + { + // Send the packet + eth.write((char*)data, bytes); + int send_status = eth.send(); + + //decode_ethernet(data); + + return send_status; + } + + /// Inject the raw payload into an ethernet frame with the given destination and ethertype + inline bool inject(Ethernet_MAC dest, u16 ethertype, void *packet, unsigned int bytes) + { + memset(outframe, 0x00, bytes); + + outframe_header = (Ethernet_FrameHeader*)outframe; + + // Set the ethernet frame source + memcpy(&outframe_header->source, mac.octet, 6); + + // Set the ethernet frame destination + outframe_header->destination = dest; + + // Set the ethernet ethertype + outframe_header->ethertype = ethertype; + + // Make sure the payload won't be too large + if (sizeof(Ethernet_FrameHeader) + bytes > sizeof(outframe)) + { + printf("ERROR: Attempt to inject packet failed; Payload size of %d is too large /n", bytes); + return false; + } + + // Set the payload + memcpy(outframe_header->payload, packet, bytes); + fix_endian_ethernet(outframe_header); + + // Send the packet + eth.write(outframe, sizeof(Ethernet_FrameHeader) + bytes); + int send_status = eth.send(); + + //decode_ethernet(outframe); + + return send_status; + } + + /// Wait until there is more data to receive + inline void wait_for_data() + { + while (true) + { + wait(0.0001); + + if (!(linked = eth.link())) + continue; + + received = (frame_size = eth.receive()); + if (!frame_size) + continue; + + eth.read(frame, frame_size); + break; + } + } + + /// Wait for an ethernet frame (will be stored in appropriate class member pointers) + inline void next() + { + wait_for_data(); + + // Zero out all of the packet pointers + frame_header = NULL; + arp_packet = NULL; + icmp_packet = NULL; + tcp_packet = NULL; + udp_packet = NULL; + data_bytes = 0; + + decode_ethernet(frame); + } + + /// Decode the given ethernet frame + inline void decode_ethernet(void *frame) + { + Ethernet_FrameHeader *header = frame_header = (Ethernet_FrameHeader*)frame; + fix_endian_ethernet(header); + + switch (header->ethertype) + { + case ETHERTYPE_IPV4: + case ETHERTYPE_IPV6: + decode_ip((IP_PacketHeader*)header->payload); + break; + case ETHERTYPE_ARP: + decode_arp((ARP_Packet*)header->payload); + break; + default: + break; // Unknown ethertype + } + } + + /// Decode the given ARP packet + inline void decode_arp(ARP_Packet *packet) + { + fix_endian_arp(packet); + if (packet->hardware_type != 0x0001 || packet->protocol_type != 0x0800) return; + arp_packet = packet; + } + + /// Decode the given IPv4 packet + inline void decode_ip(IP_PacketHeader *packet) + { + u16 chk = checksum(packet, sizeof(IP_PacketHeader), &packet->header_checksum, 2); + fix_endian_ip(packet); + ip_packet = packet; + + if (packet->version != 4) return; + + data_bytes = packet->packet_bytes; + data_bytes -= sizeof(IP_PacketHeader); + + if (packet->protocol == IPPROTO_UDP) + { + UDP_Packet *segment = udp_packet = (UDP_Packet*)packet->data; + fix_endian_udp(segment); + data_bytes -= sizeof(UDP_Packet); + } + else if (packet->protocol == IPPROTO_ICMP) + { + ICMP_Packet *segment = icmp_packet = (ICMP_Packet *)packet->data; + fix_endian_icmp(segment); + data_bytes -= sizeof(ICMP_Packet); + } + else if (packet->protocol == IPPROTO_TCP) + { + TCP_SegmentHeader *segment = tcp_packet = (TCP_SegmentHeader*)packet->data; + fix_endian_tcp(segment); + data_bytes -= sizeof(TCP_SegmentHeader); + dispatch_tcp(segment,data_bytes); + } + } + + handler<TCP_SegmentHeader*,u32,void> *tcp_handler; + inline void dispatch_tcp(TCP_SegmentHeader *tcp_packet, u32 data_bytes) + { + if (tcp_handler) (*tcp_handler)(tcp_packet,data_bytes); + } + + /// Attach a member function to be called on all TCP packets + template <class T> + inline void attach_tcp(T *inst, void (T::*func)(TCP_SegmentHeader *tcp_packet, u32 data_bytes)) + { + tcp_handler = new member_handler<T,TCP_SegmentHeader*,u32,void>(inst, func); + } + + /// Attach a non-member function to be called on all TCP packets + inline void attach_tcp(void (*func)(TCP_SegmentHeader *tcp_packet, u32 data_bytes)) + { + tcp_handler = new function_handler<TCP_SegmentHeader*,u32,void>(func); + } +}; + +#endif // SNIFFER_H \ No newline at end of file
diff -r 852db76de235 -r feaa107f56b3 util/types.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/util/types.h Fri Apr 24 03:11:02 2015 +0000 @@ -0,0 +1,20 @@ +#ifndef TYPES_H +#define TYPES_H + +/** + \file types.h + \brief Type definitions + + This file contains some utility type definitions +*/ + +/// Unsigned 8 bit value +typedef unsigned char u8; + +/// Unsigned 16 bit value +typedef unsigned short u16; + +/// Unsigned 32 bit value +typedef unsigned int u32; + +#endif \ No newline at end of file
diff -r 852db76de235 -r feaa107f56b3 util/util.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/util/util.h Fri Apr 24 03:11:02 2015 +0000 @@ -0,0 +1,35 @@ +#ifndef UTIL_H +#define UTIL_H + +#include "types.h" + +/** + \file util.h + \brief Primary utility header + + In addition to providing some utility functions, this file also includes + the other utility headers automatically. +*/ + +/// Is any byte memory at start for bytes nonzero? +inline bool is_nonzero_mem(u8 *start, unsigned int bytes) +{ + for (; bytes--; ++start) if (*start) return true; + return false; +} + +/// Are all bytes at start for bytes zero? +inline bool is_zero_mem(u8 *start, unsigned int bytes) +{ + for (; bytes--; ++start) if (*start) return false; + return true; +} + +/// Are the memory locations at and and b equal for bytes? +inline bool is_equal_mem(u8 *a, u8 *b, unsigned int bytes) +{ + for (; bytes--; ++a, ++b) if (*a != *b) return false; + return true; +} + +#endif \ No newline at end of file