1#!/usr/local/bin/python3
2# send payload from client to relay before connecting to server
3
4import os
5import re
6import sys
7import threading
8from addr import *
9from scapy.all import *
10
11client=os.getpid() & 0xffff
12relay=int(sys.argv[2])
13server=int(sys.argv[1])
14
15class Sniff1(threading.Thread):
16	filter = None
17	captured = None
18	packet = None
19	def __init__(self):
20		# clear packets buffered by scapy bpf
21		sniff(iface=LOCAL_IF, timeout=1)
22		super(Sniff1, self).__init__()
23	def run(self):
24		self.captured = sniff(iface=LOCAL_IF, filter=self.filter,
25		    count=1, timeout=5)
26		if self.captured:
27			self.packet = self.captured[0]
28
29ip=IP(src=FAKE_NET_ADDR, dst=REMOTE_ADDR)
30
31print("Send SYN packet, receive SYN+ACK")
32syn=TCP(sport=client, dport=relay, seq=0, flags='S', window=(2**16)-1)
33synack=sr1(ip/syn, iface=LOCAL_IF, timeout=5)
34
35if synack is None:
36	print("ERROR: No matching SYN+ACK packet received")
37	exit(1)
38
39print("Send ACK packet to finish handshake")
40ack=TCP(sport=synack.dport, dport=synack.sport,
41    seq=1, ack=synack.seq+1,  flags='A')
42send(ip/ack, iface=LOCAL_IF)
43
44print("Expect spliced SYN")
45sniffer = Sniff1();
46sniffer.filter = "src %s and dst %s and tcp port %u " \
47    "and tcp[tcpflags] = tcp-syn" % (ip.dst, ip.src, server)
48sniffer.start()
49time.sleep(1)
50
51print("Send 10 bytes payload")
52data="0123456789"
53payload=TCP(sport=synack.dport, dport=synack.sport,
54    seq=1, ack=synack.seq+1,  flags='APU')/data
55payload_ack=sr1(ip/payload, iface=LOCAL_IF)
56
57if payload_ack is None:
58	print("ERROR: No payload ACK packet received")
59	exit(1)
60if payload_ack.ack != len(data)+1:
61	print("ERROR: Expected ack %d, got %d in payload ACK" %
62	    (len(data)+1, payload_ack.ack))
63	exit(1)
64
65sniffer.join(timeout=7)
66spliced_syn = sniffer.packet
67
68if spliced_syn is None:
69	print("ERROR: No spliced SYN packet received")
70	exit(1)
71
72print("Expect spliced payload")
73sniffer = Sniff1();
74sniffer.filter = "src %s and dst %s and tcp port %u " \
75    "and tcp[tcpflags] = tcp-ack|tcp-push" % (ip.dst, ip.src, server)
76sniffer.start()
77time.sleep(1)
78
79print("Wait for splicing syscall, grep it in relay log")
80def loggrep(file, regex, timeout):
81	for i in range(timeout):
82		for line in open(file, 'r'):
83			if re.search(regex, line):
84				return line
85		time.sleep(1)
86	return None
87if not loggrep("relay.log", "Spliced", 5):
88	print("ERROR: Relay did not splice")
89	exit(1)
90
91print("Send spliced SYN+ACK packet to finish handshake")
92spliced_synack=TCP(sport=spliced_syn.dport, dport=spliced_syn.sport,
93    seq=0, ack=spliced_syn.seq+1, flags='SA')
94spliced_ack=sr1(ip/spliced_synack, iface=LOCAL_IF)
95
96if spliced_ack is None:
97	print("ERROR: No spliced ACK packet received")
98	exit(1)
99
100sniffer.join(timeout=7)
101spliced_payload = sniffer.packet
102
103if spliced_payload is None:
104	print("ERROR: No spliced payload packet received")
105	exit(1)
106if spliced_payload.seq != spliced_ack.seq:
107	print("ERROR: Expected seq %d, got %d in spliced payload" %
108	    (spliced_ack.seq, spliced_payload.seq))
109	exit(1)
110if spliced_payload.len-20-20 != len(data):
111	print("ERROR: Expected len %d, got %d in spliced payload" %
112	    (len(data), spliced_payload.len-20-20))
113	exit(1)
114
115print("Kill connections with RST")
116spliced_rst=TCP(sport=spliced_ack.dport, dport=spliced_ack.sport,
117    seq=1, ack=spliced_ack.seq, flags='RA')
118send(ip/spliced_rst, iface=LOCAL_IF)
119rst=TCP(sport=synack.dport, dport=synack.sport,
120    seq=payload_ack.ack, ack=synack.seq+1, flags='RA')
121send(ip/rst, iface=LOCAL_IF)
122
123exit(0)
124