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.
Revision 0:d494b853ce97, committed 2010-10-12
- Comitter:
- etherealflaim
- Date:
- Tue Oct 12 05:32:59 2010 +0000
- Child:
- 1:63d4ff534d65
- Commit message:
- Initial Publish - Slightly unfinished, but usable
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Tue Oct 12 05:32:59 2010 +0000 @@ -0,0 +1,232 @@ +#include "mbed.h" +#include "string.h" + +#include "util/types.h" +#include "util/log.h" +#include "util/util.h" +#include "sniffer.h" +#include "scanner.h" + +#include <string> +#include <queue> + +// The main logger (global scope) +Sniffer sniffer; +Log main_log; +bool main_running = true; + +Ethernet_MAC BROADCAST_MAC = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; +Ethernet_MAC your_mac; + +IP_Address my_ip = {0x00, 0x00, 0x00, 0x00}; +IP_Address your_ip; + +bool portscan_started = false; +bool ip_determined = false; + +LocalFileSystem local("local"); +queue<string> commands; + +inline void loadCommands() +{ + FILE *fp = fopen("/local/ntcmd.txt", "r"); + if (fp) + { + char buf[256]; + while (NULL != fgets(buf, 256, fp)) + { + if (buf[0] == '#') continue; + else if (strlen(buf) == 0) continue; + else if (!strncmp(buf, "ping", 4)) commands.push("ping"); + else if (!strncmp(buf, "portscan", 8)) commands.push("portscan"); + else if (!strncmp(buf, "identify", 8)) commands.push("identify"); + else main_log.printf("Unknown command: %s", buf); + } + } + else + { + // Write the ntcmd file with some help + main_log.printf("No net tool command file found!"); + fp = fopen("/local/ntcmd.txt", "w"); + fprintf(fp, "# Net Tool Command File Help:\n"); + fprintf(fp, "# 1. Comments start with the pound sign\n"); + fprintf(fp, "# 2. Commands are on a line by themselves\n"); + fprintf(fp, "# Known commands:\n"); + fprintf(fp, "# 1. ping - Send a ping to the host computer every 30 seconds and write results to PING.TXT\n"); + fprintf(fp, "# 2. portscan - Scan the host computer and write open TCP ports to PORTSCAN.TXT\n"); + fprintf(fp, "# 3. identify - Write host computer information to IDENTITY.TXT\n"); + } + fclose(fp); +} + +Ticker ping_timer; +void ping() +{ +#define PING_BUFEFERSIZE (sizeof(IP_PacketHeader) + sizeof(ICMP_Packet)) + 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, your_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); + + + FILE *fp = fopen("/local/ping.txt", "w"); + fprintf(fp, "PING sent...\n"); + fclose(fp); + + sniffer.inject(your_mac, ETHERTYPE_IPV4, buffer, PING_BUFEFERSIZE); +} + +void identify() +{ + FILE *fp = fopen("/local/identity.txt", "w"); + fprintf(fp, "Connected host identity:\n"); + + u8 *octets = your_mac.octet; + fprintf(fp, " MAC Address: %02X:%02X:%02X:%02X:%02X:%02X\n", octets[0],octets[1],octets[2],octets[3],octets[4],octets[5]); + + octets = your_ip.octet; + fprintf(fp, " IP Address: %d.%d.%d.%d\n", octets[0],octets[1],octets[2],octets[3]); + + fclose(fp); +} + +int main() { + // Enable logging via USB + main_log.enable(LOG_USB); + main_log.printf(""); + + // Startup sequence + main_log.printf("Booting..."); + Scanner scanner(&sniffer); // Hooks into TCP handler + + main_log.printf("Loading commands..."); + loadCommands(); + + main_log.printf("Starting..."); + while(main_running) { + // Get the next frame + sniffer.next(); + + // Handle ICMP packet + if (sniffer.icmp_packet) + { + // If the packet is an ICMP ECHO (Ping) request + if (sniffer.icmp_packet->type == ICMP_ECHO_REQUEST) + { + // Build the ICMP packet + sniffer.icmp_packet->type = ICMP_ECHO_REPLY; + + // Build the IP packet + sniffer.ip_packet->destination = sniffer.ip_packet->source; + sniffer.ip_packet->source = my_ip; + + // Inject the packet + fix_endian_icmp(sniffer.icmp_packet); + fix_endian_ip(sniffer.ip_packet); + sniffer.icmp_packet->checksum = checksum(sniffer.icmp_packet, sizeof(ICMP_Packet) + sniffer.data_bytes, &sniffer.icmp_packet->checksum, 2); + sniffer.ip_packet->header_checksum = checksum(sniffer.ip_packet, sizeof(IP_PacketHeader), &sniffer.ip_packet->header_checksum, 2); + sniffer.inject(sniffer.frame_header->source, ETHERTYPE_IPV4, sniffer.ip_packet, sizeof(IP_PacketHeader) + sizeof(ICMP_Packet) + sniffer.data_bytes); + } + else if (sniffer.icmp_packet->type == ICMP_ECHO_REPLY) + { + FILE *fp = fopen("/local/ping.txt", "a"); + fprintf(fp, "PING reply received\n"); + fclose(fp); + } + } + // Handle ARP packet + else if (sniffer.arp_packet) + { + // These conditions can be optimized a lot + // Check for an ARP request + if (is_nonzero_mem(sniffer.arp_packet->sender_hardware_address, 6) && + is_nonzero_mem(sniffer.arp_packet->sender_protocol_address, 4) && + is_nonzero_mem(my_ip.octet, 4) && + is_equal_mem(sniffer.arp_packet->target_protocol_address, my_ip.octet, 4) && + sniffer.arp_packet->operation == 1) + { + //main_log.printf("ARP Requested:"); + //main_log.printf(" Responding with IP - %03d.%03d.%03d.%03d", my_ip.octet[0],my_ip.octet[1],my_ip.octet[2],my_ip.octet[3]); + Ethernet_MAC *targmac = (Ethernet_MAC*)sniffer.arp_packet->target_hardware_address; + IP_Address *targip = (IP_Address*)sniffer.arp_packet->target_protocol_address; + Ethernet_MAC *srcmac = (Ethernet_MAC*)sniffer.arp_packet->sender_hardware_address; + IP_Address *srcip = (IP_Address*)sniffer.arp_packet->sender_protocol_address; + + // Set the ARP options + *targmac = *srcmac; + *srcmac = sniffer.mac; + *targip = *srcip; + *srcip = my_ip; + sniffer.arp_packet->operation = 2; + + fix_endian_arp(sniffer.arp_packet); + sniffer.inject(BROADCAST_MAC, ETHERTYPE_ARP, sniffer.arp_packet, sizeof(ARP_Packet)); + + if (!portscan_started) { + portscan_started = true; + } + } + // Check for an ARP announce + if (is_nonzero_mem(sniffer.arp_packet->sender_hardware_address, 6) && + is_zero_mem (sniffer.arp_packet->sender_protocol_address, 4) && + is_zero_mem (sniffer.arp_packet->target_hardware_address, 6) && + sniffer.arp_packet->operation == 1) + { + if (ip_determined) continue; + ip_determined = true; + + //main_log.printf("ARP Announce Received:"); + my_ip = your_ip = *(IP_Address*)sniffer.arp_packet->target_protocol_address; + main_log.printf("Host IP: %03d.%03d.%03d.%03d", my_ip.octet[0],my_ip.octet[1],my_ip.octet[2],my_ip.octet[3]); + do { my_ip.octet[3]++; } while (!my_ip.octet[3]); + main_log.printf("Tool IP: %03d.%03d.%03d.%03d", my_ip.octet[0],my_ip.octet[1],my_ip.octet[2],my_ip.octet[3]); + + Ethernet_MAC *targmac = (Ethernet_MAC*)sniffer.arp_packet->target_hardware_address; + IP_Address *targip = (IP_Address*)sniffer.arp_packet->target_protocol_address; + Ethernet_MAC *srcmac = (Ethernet_MAC*)sniffer.arp_packet->sender_hardware_address; + IP_Address *srcip = (IP_Address*)sniffer.arp_packet->sender_protocol_address; + + your_mac = *srcmac; + + // Set the ARP options + *targmac = sniffer.mac; + *srcmac = sniffer.mac; + *targip = my_ip; + *srcip = my_ip; + sniffer.arp_packet->operation = 2; + + fix_endian_arp(sniffer.arp_packet); + sniffer.inject(BROADCAST_MAC, ETHERTYPE_ARP, sniffer.arp_packet, sizeof(ARP_Packet)); + + while (!commands.empty()) + { + string command = commands.front(); + main_log.printf("NetTool> %s", command.c_str()); + if (command == "ping") + ping_timer.attach(&ping, 30); + else if (command == "portscan") + scanner.start(sniffer.mac, your_mac, my_ip, your_ip); + else if (command == "identify") + identify(); + commands.pop(); + } + } + } + else if (sniffer.tcp_packet) + { + } + } + + // This shouldn't really happen... + main_log.printf("Terminating..."); + return 0; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.h Tue Oct 12 05:32:59 2010 +0000 @@ -0,0 +1,9 @@ +#ifndef MAIN_H +#define MAIN_H + +#include "util/log.h" + +extern Log main_log; +extern bool main_running; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Tue Oct 12 05:32:59 2010 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/e2ac27c8e93e
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net/arp.h Tue Oct 12 05:32:59 2010 +0000 @@ -0,0 +1,46 @@ +#ifndef ARP_H +#define ARP_H + +#include "net.h" + +#define ETHERTYPE_ARP 0x0806 +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; + +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); +} + +inline void print_arp(ARP_Packet *packet) +{ + main_log.printf("ARP Packet:"); + main_log.printf(" Hardware: 0x%04X", packet->hardware_type); + main_log.printf(" Protocol: 0x%04X", packet->protocol_type); + main_log.printf(" Type: %d", packet->operation); + if (packet->hardware_type != 0x0001 || packet->protocol_type != 0x0800) return; + + u8 *bytes; + bytes = packet->sender_hardware_address; + main_log.printf(" Source: MAC - %02X:%02X:%02X:%02X:%02X:%02X", bytes[0],bytes[1],bytes[2],bytes[3],bytes[4],bytes[5]); + bytes = packet->target_hardware_address; + main_log.printf(" Target: MAC - %02X:%02X:%02X:%02X:%02X:%02X", bytes[0],bytes[1],bytes[2],bytes[3],bytes[4],bytes[5]); + bytes = packet->sender_protocol_address; + main_log.printf(" Source: IP - %03d.%03d.%03d.%03d", bytes[0], bytes[1], bytes[2], bytes[3]); + bytes = packet->target_protocol_address; + main_log.printf(" Target: IP - %03d.%03d.%03d.%03d", bytes[0], bytes[1], bytes[2], bytes[3]); +} + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net/ethernet.h Tue Oct 12 05:32:59 2010 +0000 @@ -0,0 +1,37 @@ +#ifndef ETHERNET_H +#define ETHERNET_H + +#include "net.h" + +typedef struct { + unsigned char octet[6]; +} Ethernet_MAC; + +typedef struct { + // In the Ethernet II Framing Standard: + // 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; + unsigned char payload[]; +} Ethernet_FrameHeader; + +inline void fix_endian_ethernet(Ethernet_FrameHeader *header) +{ + fix_endian_u16(&header->ethertype); +} + +inline void print_ethernet(Ethernet_FrameHeader *frame) +{ + main_log.printf("Ethernet frame:"); + u8 *src = frame->source.octet; + u8 *dst = frame->destination.octet; + main_log.printf(" Source: MAC - %02X:%02X:%02X:%02X:%02X:%02X", src[6], src[7], src[8], src[9], src[10], src[11]); + main_log.printf(" Dest: MAC - %02X:%02X:%02X:%02X:%02X:%02X", dst[0], dst[1], dst[2], dst[3], dst[4], dst[5]); + main_log.printf(" Ethertype: 0x%04X", frame->ethertype); +} + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net/icmp.h Tue Oct 12 05:32:59 2010 +0000 @@ -0,0 +1,35 @@ +#ifndef ICMP_H +#define ICMP_H + +#include "net.h" + +#define ICMP_ECHO_REPLY 0x00 +#define ICMP_ECHO_REQUEST 0x08 +#define IPPROTO_ICMP 0x01 +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[]; +} ICMP_Packet; + +inline void fix_endian_icmp(ICMP_Packet *segment) +{ + fix_endian_u16(&segment->checksum); + fix_endian_u16(&segment->id); + fix_endian_u16(&segment->sequence); +} + +inline void print_icmp(ICMP_Packet *segment) +{ + main_log.printf("ICMP Packet:"); + main_log.printf(" Type: 0x%02X", segment->type); + main_log.printf(" Code: 0x%02X", segment->code); + main_log.printf(" Checksum: 0x%04X", segment->checksum); + main_log.printf(" ID: 0x%04X", segment->id); + main_log.printf(" Sequence: 0x%04X", segment->sequence); +} + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net/ip.h Tue Oct 12 05:32:59 2010 +0000 @@ -0,0 +1,105 @@ +#ifndef IP_H +#define IP_H + +#include "net.h" + +#define ETHERTYPE_IPV4 0x0800 +#define ETHERTYPE_IPV6 0x86DD + +/************** IPv4 ***************/ + +typedef struct { + unsigned char octet[4]; +} IP_Address; + +// 0x0800 +typedef struct { + // IP packets are composed of a header and payload. The IPv4 packet header consists of: + // 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; + // Other flags are unsupported + unsigned char data[]; +} IP_PacketHeader; + +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 +} + +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>"; +} + +inline void print_ip(IP_PacketHeader *packet) +{ + main_log.printf("IPv%d Packet:", packet->version); + if (packet->version != 4) + { + main_log.printf("Not an IPv4 packet (skipping)"); + return; + } + + u8 *dst = packet->destination.octet; + u8 *src = packet->source.octet; + main_log.printf(" Source: IP - %03d.%03d.%03d.%03d", src[0], src[1], src[2], src[3]); + main_log.printf(" Dest: IP - %03d.%03d.%03d.%03d", dst[0], dst[1], dst[2], dst[3]); + main_log.printf(" TTL: %d", packet->ttl); + main_log.printf(" Protocol: 0x%02X (%s)", packet->protocol, ipproto2name(packet->protocol)); + main_log.printf(" ToS: 0x%02X", packet->tos); + main_log.printf(" Header: %d bytes", packet->header_bytes_div4*4); + main_log.printf(" Packet: %d bytes", packet->packet_bytes); + main_log.printf(" Fragment: 0x%04X DF=%d MF=%d OFFSET=0x04X", packet->fragment_id, packet->dont_fragment, packet->more_follow, packet->fragment_offset); + main_log.printf(" Checksum: 0x%04X", packet->header_checksum); +} + +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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net/net.h Tue Oct 12 05:32:59 2010 +0000 @@ -0,0 +1,93 @@ +#ifndef NETWORK_H +#define NETWORK_H + +#include "mbed.h" +#include "main.h" + +#include "ctype.h" + +// General networking 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 (may misbehave 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", 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])); + main_log.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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net/tcp.h Tue Oct 12 05:32:59 2010 +0000 @@ -0,0 +1,76 @@ +#ifndef TCP_H +#define TCP_H + +#include "net.h" + +#define IPPROTO_TCP 0x06 +typedef struct { + u16 source_port; + u16 destination_port; + u32 sequence_number; + u32 acknowledge_number; + + unsigned data_offset_bytes_div4:4; + unsigned unused_0:4; + + 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; + u16 checksum; + u16 urgent_pointer; + // Options (unsupported) + unsigned char data[]; +} TCP_SegmentHeader; + +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); +} + +inline void print_tcp(TCP_SegmentHeader *segment) +{ + main_log.printf("TCP Segment:"); + main_log.printf(" Source: PORT %d", segment->source_port); + main_log.printf(" Dest: PORT %d", segment->destination_port); + main_log.printf(" TCP Seqno: 0x%08X", segment->sequence_number); + main_log.printf(" TCP Ackno: 0x%08X", segment->acknowledge_number); + main_log.printf(" Header: %d bytes", segment->data_offset_bytes_div4*4); + if (segment->cwr) main_log.printf(" Flag: CWR"); + if (segment->ece) main_log.printf(" Flag: ECE"); + if (segment->urg) main_log.printf(" Flag: URG"); + if (segment->ack) main_log.printf(" Flag: ACK"); + if (segment->psh) main_log.printf(" Flag: PSH"); + if (segment->rst) main_log.printf(" Flag: RST"); + if (segment->syn) main_log.printf(" Flag: SYN"); + if (segment->fin) main_log.printf(" Flag: FIN"); +} + +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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/net/udp.h Tue Oct 12 05:32:59 2010 +0000 @@ -0,0 +1,30 @@ +#ifndef UDP_H +#define UDP_H + +#include "net.h" + +#define IPPROTO_UDP 0x11 +typedef struct { + u16 source_port; + u16 destination_port; + u16 length; // entire datagram in bytes + u16 checksum; + u8 data[]; +} UDP_Packet; + +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); +} + +inline void print_udp(UDP_Packet *segment) +{ + main_log.printf("UDP Packet:"); + main_log.printf(" Source: PORT %d", segment->source_port); + main_log.printf(" Dest: PORT %d", segment->destination_port); + main_log.printf(" Length: %d", segment->length); +} + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scanner.h Tue Oct 12 05:32:59 2010 +0000 @@ -0,0 +1,168 @@ +#ifndef SCANNER_H +#define SCANNER_H + +#include "main.h" +#include "net/net.h" +#include "util/log.h" +#include "sniffer.h" + +#include <cstring> +#include <set> + +#define SCANNER_PADSIZE 0 +#define SCANNER_FRAMESIZE (sizeof(Ethernet_FrameHeader) + sizeof(IP_PacketHeader) + sizeof(TCP_SegmentHeader) + SCANNER_PADSIZE) + +class Scanner +{ +private: + Sniffer *sniffer; + Ticker scan_timer; + Timeout scan_timeout; + + u8 raw_frame[SCANNER_FRAMESIZE]; + + IP_Address destip; + u16 port_idx; + u16 pseudo_checksum; + + set<u16> open_ports; + + LocalFileSystem local; + +public: + inline Scanner(Sniffer *_sniffer) + : sniffer(_sniffer), local("local") + { + sniffer->attach_tcp(this, &Scanner::handle_tcp); + } + + inline void handle_tcp(TCP_SegmentHeader *packet, u32 data_bytes) + { + if (packet->syn && packet->ack) + { + open_ports.insert(packet->source_port); + } + } + + inline void finish() + { + FILE *fp = fopen("/local/PortScan.txt", "w"); + fprintf(fp, "Open Ports on %d.%d.%d.%d:\n", destip.octet[0], destip.octet[1], destip.octet[2], destip.octet[3]); + for (set<u16>::iterator iter = open_ports.begin(); iter != open_ports.end(); ++iter) + { + fprintf(fp, " TCP:%-5d OPEN\n", *iter); + } + fclose(fp); + + main_log.printf("Open ports:"); + for (set<u16>::iterator iter = open_ports.begin(); iter != open_ports.end(); ++iter) + { + main_log.printf(" TCP:%-5d OPEN", *iter); + } + main_log.printf("Port scan complete."); + } + + inline void start(Ethernet_MAC src, Ethernet_MAC dst, IP_Address srcip, IP_Address dstip) + { + // Create the ethernet frame, IP packet, and TCP segment memory mapping + static Ethernet_FrameHeader *frame = (Ethernet_FrameHeader*)raw_frame; + static IP_PacketHeader *packet = (IP_PacketHeader*)frame->payload; + static TCP_SegmentHeader *segment = (TCP_SegmentHeader*)packet->data; + + destip = dstip; + main_log.printf("Starting TCP port scan of %d.%d.%d.%d...", dstip.octet[0], dstip.octet[1], dstip.octet[2], dstip.octet[3]); + + // Zero the frame + memset(raw_frame, '\0', SCANNER_FRAMESIZE); + + //sniffer->inject(dst, frame->ethertype, packet, 0); //sizeof(raw_frame)-sizeof(Ethernet_FrameHeader)); + + // Fill in the frame (constant for all TCP connections) + frame->destination = dst; + frame->source = src; + frame->ethertype = ETHERTYPE_IPV4; + + // Fill in the IP packet + packet->source = srcip; // Can't change with destination back-to-back? lol + packet->version = 0x04; + packet->header_bytes_div4 = 5; // *4 = 20 + packet->packet_bytes = SCANNER_FRAMESIZE-sizeof(Ethernet_FrameHeader); + packet->ttl = 64; + packet->protocol = IPPROTO_TCP; + packet->destination = dstip; + + // Fill in the TCP segment + segment->sequence_number = 0xBADBEEF0; + segment->data_offset_bytes_div4 = sizeof(TCP_SegmentHeader)/4; + segment->syn = 1; + segment->window_size = 8192; + pseudo_checksum = pseudo_header_checksum(srcip, dstip, sizeof(TCP_SegmentHeader)); + + // Initialize the scanning + port_idx = 0; + + open_ports.clear(); + scan_timer.attach_us(this, &Scanner::scan, 50); + //scan(); + } + + inline void scan() + { + static u16 ports[] = {1, 2, 3, 5, 7, 9, 11, 13, 17, 18, 19, 20, 21, 22, 23, 24, 25, 35, 37, 39, + 41, 42, 43, 47, 49, 50, 51, 52, 53, 54, 56, 58, 70, 79, 80, 83, 88, 90, 101, 102, + 104, 105, 107, 108, 109, 110, 111, 113, 113, 115, 117, 118, 119, 135, 137, 138, 139, 143, 152, 153, + 156, 162, 170, 177, 179, 194, 199, 201, 209, 210, 213, 218, 220, 259, 264, 308, 311, 318, 350, 351, + 366, 369, 371, 383, 384, 387, 389, 401, 427, 443, 444, 445, 464, 475, 497, 504, 512, 513, 514, 515, + 520, 524, 530, 532, 540, 542, 543, 544, 546, 547, 548, 554, 556, 563, 587, 591, 593, 604, 631, 635, + 636, 639, 641, 646, 647, 648, 653, 654, 657, 660, 674, 691, 692, 694, 695, 699, 700, 701, 702, 706, + 711, 712, 749, 750, 751, 752, 753, 754, 760, 860, 873, 902, 989, 990, 991, 992, 993, 995, 1058, + 1080, 1085, 1098, 1099, 1140, 1169, 1176, 1182, 1194, 1198, 1200, 1214, 1220, 1223, 1241, 1270, 1293, 1337, 1352, 1387, + 1414, 1417, 1418, 1419, 1420, 1431, 1433, 1470, 1494, 1512, 1513, 1521, 1524, 1533, 1547, 1677, 1720, 1723, 1755, 1761, + 1762, 1763, 1764, 1765, 1766, 1767, 1768, 1801, 1812, 1813, 1863, 1935, 1947, 1970, 1971, 1972, 1984, 1994, 1998, 2000, + 2031, 2053, 2073, 2074, 2082, 2083, 2086, 2102, 2103, 2104, 2105, 2144, 2145, 2161, 2181, 2210, 2211, 2212, 2219, 2220, + 2261, 2262, 2369, 2370, 2404, 2447, 2483, 2484, 2500, 2612, 2713, 2714, 2735, 2809, 2868, 2947, 2948, 2949, 3050, 3051, + 3074, 3225, 3233, 3235, 3260, 3268, 3269, 3283, 3305, 3306, 3386, 3389, 3396, 3412, 3455, 3423, 3424, 3478, 3483, 3516, + 3532, 3533, 3606, 3632, 3689, 3690, 3702, 3880, 3868, 3900, 3945, 3999, 4018, 4089, 4093, 4096, 4111, 4116, 4321, 4662, + 4728, 4840, 4843, 4847, 4993, 4894, 4899, 4950, 5000, 5001, 5003, 5004, 5005, 5051, 5060, 5061, 5070, 5084, 5085, 5099, + 5151, 5154, 5190, 5222, 5269, 5298, 5351, 5355, 5402, 5405, 5421, 5432, 5556, 5631, 5814, 5900, 5984, 5999, 6000, 6005, + 6086, 6110, 6111, 6112, 6129, 6346, 6347, 6350, 6432, 6444, 6445, 6619, 6665, 6666, 6667, 6668, 6669, 6888, 6969, 7005, + 7006, 7400, 7401, 7402, 7547, 7787, 7788, 8000, 8008, 8078, 8080, 8118, 8123, 8243, 8280, 8400, 8442, 8880, 8888, 9009, + 9080, 9100, 9105, 9119, 9306, 9312, 9418, 9535, 9536, 9800, 9898, 9996, 10008, 10010, 10050, 10051, 10113, 10114, 10115, + 10116, 13076, 13720, 13721, 13724, 13782, 13783, 13785, 13786, 15000, 15345, 17500, 18104, 19283, 19315, 22347, 22350, + 24465, 24554, 26000, 31457, 33434, 40000, 43047, 43048, 47808}; + + // Create the ethernet frame, IP packet, and TCP segment memory mapping + static Ethernet_FrameHeader *frame = (Ethernet_FrameHeader*)raw_frame; + static IP_PacketHeader *packet = (IP_PacketHeader*)frame->payload; + static TCP_SegmentHeader *segment = (TCP_SegmentHeader*)packet->data; + + segment->source_port = port_idx; //ports[port_idx]; + segment->destination_port = port_idx; //ports[port_idx]; + + fix_endian_tcp(segment); + segment->checksum = checksum(segment, sizeof(TCP_SegmentHeader), &segment->checksum, sizeof(segment->checksum), pseudo_checksum); + + fix_endian_ip(packet); + packet->header_checksum = checksum(packet, sizeof(IP_PacketHeader), &packet->header_checksum, sizeof(packet->header_checksum)); + + fix_endian_ethernet(frame); + sniffer->inject(frame, SCANNER_FRAMESIZE); + + fix_endian_ethernet(frame); + fix_endian_ip(packet); + fix_endian_tcp(segment); + + // Update sequence number + segment->sequence_number++; + + //if (port_idx >= sizeof(ports)/sizeof(u16)) scan_timer.detach(); + if (port_idx >= 65535) + { + scan_timer.detach(); + scan_timeout.attach(this, &Scanner::finish, 7); + } + port_idx++; + } +}; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sniffer.h Tue Oct 12 05:32:59 2010 +0000 @@ -0,0 +1,253 @@ +#ifndef SNIFFER_H +#define SNIFFER_H + +#include "mbed.h" + +#include "main.h" +#include "util/types.h" +#include "net/net.h" + +#include <cstdio> +#include <cstring> +#include <functional> + +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); } +}; + + +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 + Ethernet_FrameHeader *frame_header; + + // IP Packet Header + IP_PacketHeader *ip_packet; + + // ARP Packet + ARP_Packet *arp_packet; + + // TCP Packet + TCP_SegmentHeader *tcp_packet; + + // UDP Packet + UDP_Packet *udp_packet; + + // ICMP Packet + ICMP_Packet *icmp_packet; + + // Generic + unsigned int data_bytes; + +public: + // Constructor + inline Sniffer() + : linked(LED1), received(LED2) + { + eth.set_link(Ethernet::AutoNegotiate); + eth.address((char *)mac.octet); + } + + 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; + } + + 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)) + { + main_log.printf("ERROR: Attempt to inject packet failed; Payload size of %d is too large", 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; + } + + 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 + 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); + } + + 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 + } + } + + inline void decode_arp(ARP_Packet *packet) + { + fix_endian_arp(packet); + if (packet->hardware_type != 0x0001 || packet->protocol_type != 0x0800) return; + arp_packet = 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); + } + + 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); + } + + 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/util/log.h Tue Oct 12 05:32:59 2010 +0000 @@ -0,0 +1,114 @@ +#ifndef LOG_H +#define LOG_H + +#include "mbed.h" + +#include "stdarg.h" +#include "stdio.h" + +#define LOG_BUFSIZE 4096 + + + +typedef enum { + LOG_USB = 0, + LOG_SER_9_10, + LOG_SER_13_14, + LOG_SER_28_27, + LOG_MAX +} SerialLines; + +class Log { +private: + // Accomodate all 3 serial ports and USB + Serial *m_serial[4]; + bool m_enable[4]; + + // File log + LocalFileSystem local; + +public: + inline Log() : local("local") + { + // Write to file + FILE *logfile = fopen("/local/NetTool.log", "w"); + fputs("NetTool - Welcome!", logfile); + fclose(logfile); + + // Set up the serial classes + m_serial[LOG_USB] = new Serial(USBTX,USBRX); + m_serial[LOG_SER_9_10] = new Serial(p9,p10); + m_serial[LOG_SER_13_14] = new Serial(p13,p14); + m_serial[LOG_SER_28_27] = new Serial(p28,p27); + + // Disable logging to all of them by default + for (int idx = 0; idx < LOG_MAX; ++idx) + { + m_enable[idx] = false; + } + } + + // Enable logging to the given serial line + inline void enable(SerialLines idx) + { + m_enable[idx] = true; + } + + // Disable logging to the given serial line + inline void disable(SerialLines idx) + { + m_enable[idx] = false; + } + + // This can log messages up to 4095 characters and has printf semantics + // All log messages include an implicit \r\n at the end + inline bool printf(char *format, ...) + { + static char buffer[LOG_BUFSIZE]; + static int count; + static va_list va; + + va_start(va, format); + count = vsnprintf(buffer, LOG_BUFSIZE, format, va); + + // Ensure that the log message fit + if (count > LOG_BUFSIZE-1) + { + // Log an error message if it didn't + Log::printf("Log message too long: %4d", count); + } + else + { + // Write all characters from the message + puts(buffer); + // Send the EOM (\r\n) + puts("\r\n"); + } + va_end(va); + return true; + } // printf + + bool puts(const char *str) + { + // Write to file + FILE *logfile = fopen("/local/NetTool.log", "a"); + fputs(str, logfile); + fclose(logfile); + + // Write all characters from the message + while (*str) + { + // Write to all serial devices + for (int s = 0; s < LOG_MAX; ++s) + { + // Only write if enabled + if (m_enable[s]) + s[*m_serial].putc(*str++); + } + } + return true; + } + +}; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/util/types.h Tue Oct 12 05:32:59 2010 +0000 @@ -0,0 +1,8 @@ +#ifndef TYPES_H +#define TYPES_H + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/util/util.h Tue Oct 12 05:32:59 2010 +0000 @@ -0,0 +1,25 @@ +#ifndef UTIL_H +#define UTIL_H + +#include "types.h" +#include "log.h" + +inline bool is_nonzero_mem(u8 *start, unsigned int bytes) +{ + for (; bytes--; ++start) if (*start) return true; + return false; +} + +inline bool is_zero_mem(u8 *start, unsigned int bytes) +{ + for (; bytes--; ++start) if (*start) return false; + return true; +} + +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