#!/usr/bin/env python
#
# original fun from http://lcamtuf.coredump.cx/soft/0trace.tgz
# bolchoe spacibo http://secdev.org/projects/scapy/ potomy chto razrabotka stala bistroi
# udp was already proved with DNS http://sid.rstack.org/articles/0309_MISC_Traceroute_en.pdf
#
# J. for TGW
#

import logging
logging.getLogger("scapy").setLevel(0)
from scapy import IP, TCP, UDP, DNS, DNSQR, ICMP, IPerror, sr1, sr, random, conf
conf.checkIPsrc = 1
conf.verb = 0

import getopt,sys,os

Gip = ""
Gport = ""
Gverb = 0
Gretry = 3
Gwait = 1
Gprot = 0
Gfw = 1

def usage(version):
  print "trt-scapy.py - v0.0"
  if version == 1: sys.exit(0)
  if version == 2: return()
  print '''---------------

Usage:
  ./trt-scapy.py [-h|-V]
  ./trt-scapy.py -i ip -p port [-v] [-r retry] [-w wait] [-F] [-U]

Arguments:
  -h\thelp
  -V\tversion\n
  -i\tip dest
  -p\tport dest
  -r\tretry x time (default %d)
  -w\twait x secs (default %d)
  -F\tDisable iptables RST behaviour
  -U\tudp protocol (DNS query to ebay)
  -v\tverbose''' % (Gretry,Gwait)
  sys.exit(0)

def params():
  global Gverb,Gip,Gport,Gwait,Gretry,Gprot
  if (len(sys.argv) == 1) : usage(0)
  try:
    opts = getopt.getopt(sys.argv[1:],"hVvi:p:r:w:FU")
  except:
    usage(0)
  for opt,optarg in opts[0]:
    if (opt == "-h"): usage(0)
    elif (opt == "-V"): usage(1)
    elif (opt == "-v"): Gverb=1
    elif (opt == "-i"): Gip=optarg
    elif (opt == "-p"): Gport=int(optarg)
    elif (opt == "-r"): Gretry=int(optarg)
    elif (opt == "-w"): Gwait=float(optarg)
    elif (opt == "-F"): Gfw = 0
    elif (opt == "-U"): Gprot = 1
  if not Gip or not Gport: usage(0)

def msg(m,quit):
  print m
  if not quit == 0: sys.exit(quit)

def trt_tcp():
  usage(2)
  print "TCP - Connecting to %s:%d" % (Gip,Gport)
  sport = random.randint(1025,65355)
  sa_p = IP(dst=Gip) / TCP(sport=sport, dport=Gport, flags='S')
  if Gverb == 1: print sa_p.summary()

  sa = sr1(sa_p, retry=Gretry, verbose=0, timeout=Gwait)
  if not sa: msg("Cannot connect to %s:%d.\n" % (Gip,Gport),-1)
  if not sa[TCP].flags == 18: msg("Not a SynAck reply.\n",-1)
  if Gverb == 1: print sa.summary()

  a_p = IP(dst=Gip) / TCP(sport=sport, dport=Gport, flags='A', seq=sa[TCP].ack, ack=sa[TCP].seq+1)
  if Gverb == 1: print a_p.summary()
  a = sr1(a_p, retry=Gretry, verbose=0, timeout=Gwait)
  if a: msg("debug: %s\n" % a.summary(),-1)

  seq = sa[TCP].ack
  ack = sa[TCP].seq+1
  ttl = sa[IP].ttl

  i = 1
  while 1:
    sys.stdout.write("%2d - " % i)
    t_p = IP(dst=Gip, ttl=i) / TCP(sport=sport, dport=Gport, seq=seq+1, ack=ack, flags="PA") / "Privet"
    t = sr1(t_p, retry=Gretry, verbose=0, timeout=Gwait)
    if t:
      if t[TCP] and t[TCP].dport == sport:
        sys.stdout.write(t.sprintf("%IP.src%\nDone...\n"))
	return()
      elif t[ICMP]: 
        sys.stdout.write("%s\n" % t.sprintf("%IP.src% - %ICMP.code% / %ICMP.type%"))
	if t[IPerror]: sys.stdout.write(t.sprintf("     IPerror payload : %IPerror.src% -> %IPerror.dst%\n"))
      else: msg("debug: %s\n", t.summary(),-1)
    else:
      sys.stdout.write("?\n")
    i = i + 1
    if i >= 32: msg("debug ttl i\n",-1)

def trt_udp():
  usage(2)

  print "UDP - Connecting to %s:%d" % (Gip,Gport)
  sport = random.randint(1025,65355)
  p = IP(dst=Gip) / UDP(sport=sport, dport=Gport) / DNS(rd=1,qd=DNSQR(qname="www.ebay.com")) 
  if Gverb == 1: print p.summary()

  r = sr1(p, retry=Gretry, verbose=0, timeout=Gwait) 
  if not r: msg("No reply from %s:%d.\n" % (Gip,Gport),-1)
  if Gverb == 1: r.summary()

  i = 12
  while 1:
    sys.stdout.write("%2d - " % i)
    t_p = IP(dst=Gip, ttl=i) / UDP(sport=sport, dport=Gport) / DNS(rd=1,qd=DNSQR(qname="www.ebay.com")) 
    t = sr1(t_p, retry=Gretry, verbose=0, timeout=Gwait)
    if t:
      if t[UDP]: 
        sys.stdout.write(t.sprintf("%IP.src%\nDone...\n"))
	return()
      elif t[ICMP]: 
        sys.stdout.write("%s\n" % t.sprintf("%IP.src% - %ICMP.code% / %ICMP.type%"))
	if t[IPerror]: sys.stdout.write(t.sprintf("     IPerror payload : %IPerror.src% -> %IPerror.dst%\n"))
      else: msg("debug: %s\n", t.summary(),-1)
    else:
      sys.stdout.write("?\n")
    i = i + 1
    if i >= 32: msg("debug ttl i\n",-1)

### nachalo

params()
if Gfw == 1:
  os.system("/sbin/iptables -A OUTPUT -p tcp -d "+Gip+" --dport "+str(Gport)+" --tcp-flags RST RST -j DROP") 
try:
  if Gprot == 0: trt_tcp()
  if Gprot == 1: trt_udp()
except KeyboardInterrupt:
  print "Aborted by user..."
  if Gfw == 1:
    os.system("/sbin/iptables -D OUTPUT -p tcp -d "+Gip+" --dport "+str(Gport)+" --tcp-flags RST RST -j DROP")
except:
  if Gfw == 1:
    os.system("/sbin/iptables -D OUTPUT -p tcp -d "+Gip+" --dport "+str(Gport)+" --tcp-flags RST RST -j DROP")

