Skip to content

Commit

Permalink
Fix and improve 1 (#23)
Browse files Browse the repository at this point in the history
* source IP correction

* set correct ephemeral port for UDP and add firewall comment

* fix and improve tcphandshake

* add tcp handshae to annotations and improve naming
  • Loading branch information
xhdix authored Jan 3, 2022
1 parent bad17f8 commit 8def65b
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 26 deletions.
7 changes: 6 additions & 1 deletion tracevis.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import argparse
import os
import platform

import utils.csv
import utils.dns
Expand All @@ -15,6 +16,7 @@
MAX_TTL = 50
DEFAULT_OUTPUT_DIR = "./tracevis_data/"
DEFAULT_REQUEST_IPS = ["1.1.1.1", "8.8.8.8", "9.9.9.9"]
OS_NAME = platform.system()


def get_args():
Expand Down Expand Up @@ -121,7 +123,10 @@ def main(args):
if request_ips == "":
print("You must set at least one IP. (--ips || -i)")
exit()
packet_1, packet_2, do_tcph1, do_tcph2 = utils.packet_input.copy_input_packets()
packet_1, packet_2, do_tcph1, do_tcph2 = utils.packet_input.copy_input_packets(
OS_NAME)
if do_tcph1 or do_tcph2:
name_prefix = name_prefix + "-tcph"
if do_traceroute:
was_successful, measurement_path = utils.trace.trace_route(
ip_list=request_ips, request_packet_1=packet_1, output_dir=output_dir,
Expand Down
21 changes: 17 additions & 4 deletions utils/packet_input.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,17 @@
from scapy.layers.inet import IP
from scapy.utils import import_hexcap

firewall_commands_help = "\r\n( · - · · · \r\n\
You may need to temporarily block RST output packets in your firewall.\r\n\
For example:\r\n\
iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP\r\n\
After the test, you can delete it:\r\n\
iptables -D OUTPUT -p tcp --tcp-flags RST RST -j DROP\r\n · - · - · )\r\n\
"


def yesno_second_packet(question):
prompt = f'{question} ? (y/n): '
prompt = f'{question} (y/n): '
answer = input(prompt).strip().lower()
if answer not in ['y', 'n']:
print(f'{answer} is invalid, please try again...')
Expand All @@ -14,7 +22,7 @@ def yesno_second_packet(question):
return False


def copy_input_packets():
def copy_input_packets(os_name):
copy_packet_1 = ""
copy_packet_2 = ""
do_tcph1 = False
Expand All @@ -25,8 +33,13 @@ def copy_input_packets():
" paste here the first packet hex dump start with the IP layer and then enter :")
copy_packet_1 = IP(import_hexcap())
print(" . . . - . . . . - . . . . - . . . . - . ")
do_tcph1 = yesno_second_packet(
"Would you like to do a TCP Handshake before sending this packet?")
if os_name == "Linux":
do_tcph1 = yesno_second_packet(
"Would you like to do a TCP Handshake before sending this packet?"
+ firewall_commands_help)
else:
do_tcph1 = yesno_second_packet(
"Would you like to do a TCP Handshake before sending this packet?")
print(" · - · - · · - · - · · - · - · · - · - · ")
if yesno_second_packet("Would you like to add a second packet"):
print(
Expand Down
54 changes: 34 additions & 20 deletions utils/trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,21 @@

import contextlib
import json
import socket
import sys
import time
from datetime import datetime
from socket import socket
from time import sleep

from scapy.all import conf, get_if_addr
from scapy.layers.dns import DNS
from scapy.layers.inet import ICMP, IP, TCP, UDP
from scapy.sendrecv import send, sr, sr1
from scapy.volatile import RandInt, RandShort

from utils.traceroute_struct import Traceroute

#from scapy.arch import get_if_addr
#from scapy.interfaces import conf
from utils.traceroute_struct import traceroute_data

SOURCE_IP_ADDRESS = get_if_addr(conf.iface)
LOCALHOST = '127.0.0.1'
SLEEP_TIME = 1
have_2_packet = False
Expand Down Expand Up @@ -61,31 +60,41 @@ def parse_packet(request_and_answer, current_ttl, elapsed_ms):
# ephemeral_port_reserve() function is based on https://github.com/Yelp/ephemeral-port-reserve


def ephemeral_port_reserve():
with contextlib.closing(socket()) as s:
s.bind((LOCALHOST, 0))
def ephemeral_port_reserve(proto: str = "tcp"):
socketkind = socket.SOCK_STREAM
ipproto = socket.IPPROTO_TCP
if proto == "udp":
socketkind = socket.SOCK_DGRAM
ipproto = socket.IPPROTO_UDP
with contextlib.closing(socket.socket(socket.AF_INET, socketkind, ipproto)) as s:
s.bind((SOURCE_IP_ADDRESS, 0))
# the connect below deadlocks on kernel >= 4.4.0 unless this arg is greater than zero
s.listen(1)
if proto == "tcp":
s.listen(1)
sockname = s.getsockname()
# these three are necessary just to get the port into a TIME_WAIT state
with contextlib.closing(socket()) as s2:
with contextlib.closing(socket.socket(socket.AF_INET, socketkind, ipproto)) as s2:
s2.connect(sockname)
sock, _ = s.accept()
with contextlib.closing(sock):
if proto == "tcp":
sock, _ = s.accept()
with contextlib.closing(sock):
return sockname[1]
with contextlib.closing(s2):
return sockname[1]


def send_packet_with_tcphandshake(this_request, timeout):
timeout += 2
ip_address = this_request[IP].dst
source_port = ephemeral_port_reserve()
source_port = ephemeral_port_reserve("tcp")
destination_port = this_request[TCP].dport
send_syn = IP(
dst=ip_address, id=RandShort())/TCP(
sport=source_port, dport=destination_port, seq=RandInt(), flags="S")
ans, unans = sr(send_syn, verbose=0, timeout=timeout)
if len(ans) == 0:
print("Error: No response to SYN packet") # todo: xhdix
return ans, unans
else:
send_ack = IP(
dst=ip_address, id=(ans[0][0][IP].id + 1))/TCP(
Expand Down Expand Up @@ -117,10 +126,10 @@ def send_packet_with_tcphandshake(this_request, timeout):
def send_single_packet(this_request, timeout):
this_request[IP].id = RandShort()
if this_request.haslayer(TCP):
this_request[TCP].sport = ephemeral_port_reserve()
this_request[TCP].sport = ephemeral_port_reserve("tcp")
del(this_request[TCP].chksum)
elif this_request.haslayer(UDP):
this_request[UDP].sport = RandShort()
this_request[UDP].sport = ephemeral_port_reserve("udp")
del(this_request[UDP].chksum)
if this_request.haslayer(DNS):
this_request.id = RandShort()
Expand All @@ -145,12 +154,13 @@ def send_packet(request_packet, request_ip, current_ttl, timeout, do_tcphandshak
if do_tcphandshake:
request_and_answers, unanswered = send_packet_with_tcphandshake(
this_request, timeout)
sleep(timeout) # maybe we should wait more
else:
request_and_answers, unanswered = send_single_packet(
this_request, timeout)
end_time = time.perf_counter()
elapsed_ms = float(format(abs((end_time - start_time) * 1000), '.3f'))
if do_tcphandshake:
sleep(timeout) # double sleep ( ̄o ̄) . z Z. maybe we should wait more
if len(request_and_answers) == 0:
return parse_packet(None, current_ttl, elapsed_ms)
else:
Expand Down Expand Up @@ -182,7 +192,7 @@ def are_equal(original_list, result_list):
def initialize_first_nodes(request_ips):
nodes = []
for _ in request_ips:
nodes.append(LOCALHOST)
nodes.append(SOURCE_IP_ADDRESS)
if have_2_packet:
return [nodes, nodes.copy()]
else:
Expand All @@ -192,18 +202,18 @@ def initialize_first_nodes(request_ips):
def initialize_json_first_nodes(
request_ips, annotation_1, annotation_2, packet_1_proto, packet_2_proto):
# source_address = get_if_addr(conf.iface) #todo: xhdix
source_address = LOCALHOST
source_address = SOURCE_IP_ADDRESS
start_time = int(datetime.utcnow().timestamp())
for request_ip in request_ips:
measurement_data[0].append(
Traceroute(
traceroute_data(
dst_addr=request_ip, annotation=annotation_1,
src_addr=source_address, proto=packet_1_proto, timestamp=start_time
)
)
if have_2_packet:
measurement_data[1].append(
Traceroute(
traceroute_data(
dst_addr=request_ip, annotation=annotation_2,
src_addr=source_address, proto=packet_2_proto, timestamp=start_time
)
Expand Down Expand Up @@ -278,6 +288,10 @@ def trace_route(
do_tcphandshake = []
was_successful = False
global have_2_packet
if do_tcph1:
annotation_1 += " (+tcph)"
if do_tcph2:
annotation_2 += " (+tcph)"
if request_packet_1 is None:
print("packet is invalid!")
exit()
Expand Down
2 changes: 1 addition & 1 deletion utils/traceroute_struct.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import json


class Traceroute:
class traceroute_data:
def __init__(
self, dst_addr: str, annotation: str, proto: str, timestamp: int,
src_addr: str = "127.0.0.2", from_ip: str = "127.0.0.1",
Expand Down

0 comments on commit 8def65b

Please sign in to comment.