This is a low-level network debugging utility that utilizes raw packet i/o to construct and deconstruct tcp, udp, ipv4, arp, and icmp packets over ethernet.

Dependencies:   mbed

main.cpp

Committer:
etherealflaim
Date:
2010-10-12
Revision:
8:1c1f6ce348c6
Parent:
7:e34ae4c7eb79

File content as of revision 8:1c1f6ce348c6:

#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>

/**
  \file main.cpp
  \brief This is the primary NetTool demo file.
  
  This file is the brains of the NetTool, utilizing the networking code
  found in other files to do some basic network diagnostic stuff.
  Note that for the nettool to connect to a computer, the computer has
  to already have an IP configured on the interface, which usually
  requires that the interface or connection be manually assigned an IP
  address.
*/

// 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;
}