nopasaran 0.2.94__tar.gz → 0.2.96__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nopasaran-0.2.94 → nopasaran-0.2.96}/PKG-INFO +1 -1
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/action_primitives.py +6 -1
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/dns_primitives.py +1 -1
- nopasaran-0.2.96/nopasaran/primitives/action_primitives/tcp_dns_request_primitives.py +29 -0
- nopasaran-0.2.96/nopasaran/primitives/action_primitives/tcp_dns_response_primitives.py +40 -0
- nopasaran-0.2.96/nopasaran/tools/tcp_dns_socket_server.py +170 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/utils.py +76 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran.egg-info/PKG-INFO +1 -1
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran.egg-info/SOURCES.txt +3 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran.egg-info/requires.txt +1 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/setup.py +1 -1
- {nopasaran-0.2.94 → nopasaran-0.2.96}/LICENSE +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/README.md +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/__init__.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/__main__.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/controllers/__init__.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/controllers/controller.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/controllers/factory.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/controllers/protocol.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/decorators.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/definitions/__init__.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/definitions/commands.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/definitions/control_channel.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/definitions/events.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/definitions/transitions.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/errors/__init__.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/errors/parsing_error.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/http_2_utils.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/interpreters/__init__.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/interpreters/action_interpreter.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/interpreters/condition_interpreter.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/interpreters/interpreter.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/interpreters/transition_interpreter.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/machines/__init__.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/machines/action_queue.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/machines/state_machine.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/parsers/__init__.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/parsers/interpreter_parser.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/parsers/state_machine_parser.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/__init__.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/__init__.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/certificate_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/client_echo_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/control_channel_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/data_channel_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/data_manipulation.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/event_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/http_1_request_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/http_1_response_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/http_2_client_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/http_2_server_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/http_simple_client_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/https_1_request_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/https_1_response_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/icmp_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/io_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/ip_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/nested_machine_utils.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/probing_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/replay_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/server_echo_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/signaling_primitive.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/tcp_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/timing_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/tls_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/udp_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/condition_primitives/__init__.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/condition_primitives/condition_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/condition_primitives/variable_comparisons.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/transition_primitives/__init__.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/transition_primitives/assignment_transitions.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/transition_primitives/transition_primitives.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/sniffers/__init__.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/sniffers/sniffer.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/tools/__init__.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/tools/checks.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/tools/echo_socket_server.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/tools/http_1_socket_server.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/tools/http_2_overwrite.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/tools/http_2_socket_base.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/tools/http_2_socket_client.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/tools/http_2_socket_server.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/tools/https_1_socket_server.py +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran.egg-info/dependency_links.txt +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran.egg-info/entry_points.txt +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran.egg-info/top_level.txt +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/setup.cfg +0 -0
- {nopasaran-0.2.94 → nopasaran-0.2.96}/tests/__init__.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: nopasaran
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.96
|
4
4
|
Summary: NoPASARAN is an advanced network tool designed to detect, fingerprint, and locate network middleboxes in a unified framework.
|
5
5
|
Home-page: https://github.com/BenIlies/NoPASARAN
|
6
6
|
Author: Ilies Benhabbour
|
{nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/action_primitives.py
RENAMED
@@ -25,6 +25,9 @@ from nopasaran.primitives.action_primitives.client_echo_primitives import Client
|
|
25
25
|
from nopasaran.primitives.action_primitives.probing_primitives import PortProbingPrimitives
|
26
26
|
from nopasaran.primitives.action_primitives.replay_primitives import ReplayPrimitives
|
27
27
|
from nopasaran.primitives.action_primitives.http_simple_client_primitives import HTTPSimpleClientPrimitives
|
28
|
+
from nopasaran.primitives.action_primitives.tcp_dns_request_primitives import TCPDNSRequestPrimitives
|
29
|
+
from nopasaran.primitives.action_primitives.tcp_dns_response_primitives import TCPDNSResponsePrimitives
|
30
|
+
|
28
31
|
|
29
32
|
class ActionPrimitives(Primitives):
|
30
33
|
"""
|
@@ -56,5 +59,7 @@ class ActionPrimitives(Primitives):
|
|
56
59
|
ClientEchoPrimitives,
|
57
60
|
PortProbingPrimitives,
|
58
61
|
ReplayPrimitives,
|
59
|
-
HTTPSimpleClientPrimitives
|
62
|
+
HTTPSimpleClientPrimitives,
|
63
|
+
TCPDNSResponsePrimitives,
|
64
|
+
TCPDNSRequestPrimitives
|
60
65
|
]
|
{nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/dns_primitives.py
RENAMED
@@ -386,7 +386,7 @@ class DNSPrimitives:
|
|
386
386
|
"""
|
387
387
|
dns_query = state_machine.get_variable_value(inputs[0])
|
388
388
|
new_query_type = state_machine.get_variable_value(inputs[1])
|
389
|
-
dns_query.qtype = new_query_type
|
389
|
+
dns_query.qtype = int(new_query_type)
|
390
390
|
state_machine.set_variable_value(outputs[0], dns_query)
|
391
391
|
|
392
392
|
@staticmethod
|
@@ -0,0 +1,29 @@
|
|
1
|
+
from nopasaran.decorators import parsing_decorator
|
2
|
+
from nopasaran.definitions.events import EventNames
|
3
|
+
import nopasaran.utils as utils
|
4
|
+
|
5
|
+
class TCPDNSRequestPrimitives:
|
6
|
+
@staticmethod
|
7
|
+
@parsing_decorator(input_args=4, output_args=1)
|
8
|
+
def make_tcp_dns_query(inputs, outputs, state_machine):
|
9
|
+
"""
|
10
|
+
Make a DNS query over TCP with user-defined domain and query type.
|
11
|
+
inputs: [domain, query_type, server_ip, server_port]
|
12
|
+
outputs: [dns_response_dict]
|
13
|
+
"""
|
14
|
+
domain = state_machine.get_variable_value(inputs[0])
|
15
|
+
query_type = state_machine.get_variable_value(inputs[1])
|
16
|
+
server_ip = state_machine.get_variable_value(inputs[2])
|
17
|
+
server_port = int(state_machine.get_variable_value(inputs[3]))
|
18
|
+
|
19
|
+
# Call utility function with provided parameters
|
20
|
+
result = utils.send_tcp_dns_query(server_ip, server_port, domain, query_type)
|
21
|
+
|
22
|
+
# Store result and trigger events accordingly
|
23
|
+
if not result or result.get("response") is None:
|
24
|
+
state_machine.set_variable_value(outputs[0], {"received": None})
|
25
|
+
state_machine.trigger_event(EventNames.REQUEST_ERROR.name)
|
26
|
+
else:
|
27
|
+
state_machine.set_variable_value(outputs[0], {"received": result})
|
28
|
+
state_machine.trigger_event(EventNames.RESPONSE_RECEIVED.name)
|
29
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
from nopasaran.decorators import parsing_decorator
|
2
|
+
from nopasaran.tools.tcp_dns_socket_server import TCPDNSSocketServer
|
3
|
+
|
4
|
+
class TCPDNSResponsePrimitives:
|
5
|
+
|
6
|
+
@staticmethod
|
7
|
+
@parsing_decorator(input_args=0, output_args=1)
|
8
|
+
def create_tcp_dns_server(inputs, outputs, state_machine):
|
9
|
+
server = TCPDNSSocketServer()
|
10
|
+
state_machine.set_variable_value(outputs[0], server)
|
11
|
+
|
12
|
+
@staticmethod
|
13
|
+
@parsing_decorator(input_args=2, output_args=0)
|
14
|
+
def start_tcp_dns_server(inputs, outputs, state_machine):
|
15
|
+
server = state_machine.get_variable_value(inputs[0])
|
16
|
+
port = int(state_machine.get_variable_value(inputs[1]))
|
17
|
+
server.start(port)
|
18
|
+
|
19
|
+
@staticmethod
|
20
|
+
@parsing_decorator(input_args=4, output_args=1)
|
21
|
+
def wait_and_respond_tcp_dns_query(inputs, outputs, state_machine):
|
22
|
+
"""
|
23
|
+
Wait for a DNS query and respond based on provided spec.
|
24
|
+
Inputs: [server_instance, port, timeout, response_spec]
|
25
|
+
Outputs: [result_dict]
|
26
|
+
Example response_spec:
|
27
|
+
{"type": "CNAME", "value": "safe.com", "qname": "blocked.com."}
|
28
|
+
"""
|
29
|
+
server = state_machine.get_variable_value(inputs[0])
|
30
|
+
timeout = int(state_machine.get_variable_value(inputs[2]))
|
31
|
+
response_spec = state_machine.get_variable_value(inputs[3]) # can be None
|
32
|
+
|
33
|
+
result, _ = server.wait_for_query(timeout, response_spec)
|
34
|
+
state_machine.set_variable_value(outputs[0], result)
|
35
|
+
|
36
|
+
@staticmethod
|
37
|
+
@parsing_decorator(input_args=1, output_args=0)
|
38
|
+
def close_tcp_dns_server(inputs, outputs, state_machine):
|
39
|
+
server = state_machine.get_variable_value(inputs[0])
|
40
|
+
server.close()
|
@@ -0,0 +1,170 @@
|
|
1
|
+
import socket
|
2
|
+
import struct
|
3
|
+
import select
|
4
|
+
import time
|
5
|
+
from dnslib import DNSRecord, RR, QTYPE, A, CNAME, MX, TXT, NS, SOA, PTR, AAAA, SRV, DS, RRSIG, NSEC, DNSKEY
|
6
|
+
from nopasaran.definitions.events import EventNames
|
7
|
+
|
8
|
+
class TCPDNSSocketServer:
|
9
|
+
def __init__(self):
|
10
|
+
self.sock = None
|
11
|
+
|
12
|
+
def start(self, port):
|
13
|
+
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
14
|
+
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
15
|
+
self.sock.bind(('', port))
|
16
|
+
self.sock.listen(5)
|
17
|
+
return EventNames.SERVER_STARTED.name, f"TCP DNS server started on port {port}"
|
18
|
+
|
19
|
+
def wait_for_query(self, timeout, response_spec=None):
|
20
|
+
timeout = float(timeout)
|
21
|
+
start_time = time.time()
|
22
|
+
self.sock.setblocking(False)
|
23
|
+
|
24
|
+
print(f"[Server] Waiting for connections on port {self.sock.getsockname()[1]} with timeout {timeout} seconds")
|
25
|
+
|
26
|
+
while True:
|
27
|
+
remaining_time = timeout - (time.time() - start_time)
|
28
|
+
print(f"[Server] Remaining time: {remaining_time:.2f} seconds")
|
29
|
+
if remaining_time <= 0:
|
30
|
+
print("[Server] Timeout reached with no connection.")
|
31
|
+
return {"received": None}, EventNames.TIMEOUT.name
|
32
|
+
|
33
|
+
ready, _, _ = select.select([self.sock], [], [], remaining_time)
|
34
|
+
if ready:
|
35
|
+
print("[Server] Socket is ready, accepting...")
|
36
|
+
client_sock, client_addr = self.sock.accept()
|
37
|
+
print(f"[Server] Accepted connection from {client_addr}")
|
38
|
+
|
39
|
+
try:
|
40
|
+
# Set client socket read timeout
|
41
|
+
client_sock.settimeout(5)
|
42
|
+
length_data = client_sock.recv(2)
|
43
|
+
print(f"[Server] Received length_data: {length_data}")
|
44
|
+
|
45
|
+
if len(length_data) < 2:
|
46
|
+
print("[Server] Incomplete length_data")
|
47
|
+
return {"received": None}, EventNames.ERROR.name
|
48
|
+
|
49
|
+
expected_length = struct.unpack("!H", length_data)[0]
|
50
|
+
print(f"[Server] Expecting {expected_length} bytes of query data")
|
51
|
+
|
52
|
+
request_data = b""
|
53
|
+
receive_start_time = time.time()
|
54
|
+
receive_timeout = 5 # seconds
|
55
|
+
|
56
|
+
while len(request_data) < expected_length:
|
57
|
+
# Check elapsed time to prevent infinite waiting
|
58
|
+
if time.time() - receive_start_time > receive_timeout:
|
59
|
+
print("[Server] Timeout while receiving DNS query data")
|
60
|
+
return {"received": None}, EventNames.TIMEOUT.name
|
61
|
+
|
62
|
+
try:
|
63
|
+
chunk = client_sock.recv(expected_length - len(request_data))
|
64
|
+
if not chunk:
|
65
|
+
print("[Server] Connection closed before full query received")
|
66
|
+
return {"received": None}, EventNames.ERROR.name
|
67
|
+
request_data += chunk
|
68
|
+
print(f"[Server] Received {len(request_data)}/{expected_length} bytes")
|
69
|
+
except socket.timeout:
|
70
|
+
print("[Server] Socket recv() timed out")
|
71
|
+
return {"received": None}, EventNames.TIMEOUT.name
|
72
|
+
|
73
|
+
if not request_data:
|
74
|
+
print("[Server] No request data received")
|
75
|
+
return {"received": None}, EventNames.ERROR.name
|
76
|
+
|
77
|
+
print("[Server] Parsing DNS query...")
|
78
|
+
parsed_query = DNSRecord.parse(request_data)
|
79
|
+
print(f"[Server] Parsed query: {parsed_query.toZone()}")
|
80
|
+
|
81
|
+
print("[Server] Building DNS response...")
|
82
|
+
response = self.build_response(parsed_query, response_spec)
|
83
|
+
|
84
|
+
print("[Server] Sending DNS response...")
|
85
|
+
self.send_dns_response(client_sock, response)
|
86
|
+
print("[Server] DNS response sent successfully.")
|
87
|
+
|
88
|
+
return {
|
89
|
+
"received": parsed_query.toZone(),
|
90
|
+
"client_address": client_addr
|
91
|
+
}, EventNames.REQUEST_RECEIVED.name
|
92
|
+
|
93
|
+
finally:
|
94
|
+
print("[Server] Closing client socket")
|
95
|
+
client_sock.close()
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
def build_response(self, query_record, response_spec=None):
|
100
|
+
qname = str(query_record.q.qname)
|
101
|
+
qtype = query_record.q.qtype
|
102
|
+
response_qname = response_spec.get("qname") if response_spec and response_spec.get("qname") else qname
|
103
|
+
response_type = response_spec.get("type").upper() if response_spec and response_spec.get("type") else QTYPE[qtype].name
|
104
|
+
response_value = response_spec.get("value") if response_spec else None
|
105
|
+
|
106
|
+
response = query_record.reply()
|
107
|
+
|
108
|
+
handlers = {
|
109
|
+
"A": lambda: A(response_value or "127.0.0.1"),
|
110
|
+
"CNAME": lambda: CNAME(response_value or response_qname),
|
111
|
+
"MX": lambda: MX(response_value or f"mail.{response_qname}", preference=10),
|
112
|
+
"TXT": lambda: TXT(response_value or f"dummy record for {response_qname}"),
|
113
|
+
"NS": lambda: NS(response_value or f"ns1.{response_qname}"),
|
114
|
+
"SOA": lambda: SOA(response_value or f"ns1.{response_qname}", f"admin.{response_qname}", (2024051801, 3600, 3600, 3600, 3600)),
|
115
|
+
"PTR": lambda: PTR(response_value or f"ptr.{response_qname}"),
|
116
|
+
"AAAA": lambda: AAAA(response_value or "::1"),
|
117
|
+
"SRV": lambda: self._parse_srv(response_value or f"service.{response_qname},80,0,0"),
|
118
|
+
"DS": lambda: DS(12345, 1, 1, bytes(response_value or f"abcdef{response_qname}", 'utf-8')),
|
119
|
+
"RRSIG": lambda: RRSIG(1, 1, 0, 3600, 0, 0, 0, response_value or f"signer.{response_qname}", b"signature"),
|
120
|
+
"NSEC": lambda: NSEC(response_value or f"next.{response_qname}", []),
|
121
|
+
"DNSKEY": lambda: DNSKEY(256, 3, 8, bytes(response_value or f"publickey{response_qname}", 'utf-8')),
|
122
|
+
"ANY": lambda: A(response_value or "127.0.0.1")
|
123
|
+
}
|
124
|
+
|
125
|
+
handler = handlers.get(response_type)
|
126
|
+
if not handler:
|
127
|
+
print(f"[Server Error] No handler found for response_type: {response_type}")
|
128
|
+
return query_record.reply()
|
129
|
+
|
130
|
+
reverse_qtype = {QTYPE[k]: k for k in QTYPE if isinstance(k, int)}
|
131
|
+
rtype = reverse_qtype.get(response_type)
|
132
|
+
if rtype is None:
|
133
|
+
print(f"[Server Error] Unsupported response_type: {response_type}")
|
134
|
+
return query_record.reply()
|
135
|
+
|
136
|
+
try:
|
137
|
+
print(f"[Server] Calling handler for type {response_type}")
|
138
|
+
rdata = handler()
|
139
|
+
print(f"[Server] Handler produced rdata: {rdata}")
|
140
|
+
except Exception as e:
|
141
|
+
print(f"[Server Error] Handler for {response_type} failed: {e}")
|
142
|
+
return query_record.reply()
|
143
|
+
|
144
|
+
response.add_answer(RR(rname=response_qname, rtype=rtype, rclass=1, ttl=60, rdata=rdata))
|
145
|
+
return response
|
146
|
+
|
147
|
+
|
148
|
+
|
149
|
+
def _parse_srv(self, value):
|
150
|
+
try:
|
151
|
+
target, port, priority, weight = value.split(",")
|
152
|
+
return SRV(int(priority), int(weight), int(port), target)
|
153
|
+
except Exception:
|
154
|
+
return SRV(0, 0, 80, "service.example.com")
|
155
|
+
|
156
|
+
def send_dns_response(self, client_sock, dns_record):
|
157
|
+
response_bytes = dns_record.pack()
|
158
|
+
length_prefix = struct.pack("!H", len(response_bytes))
|
159
|
+
try:
|
160
|
+
client_sock.sendall(length_prefix + response_bytes)
|
161
|
+
return EventNames.RESPONSE_SENT.name
|
162
|
+
except Exception as e:
|
163
|
+
print(f"Failed to send DNS response: {e}")
|
164
|
+
return EventNames.ERROR.name
|
165
|
+
|
166
|
+
def close(self):
|
167
|
+
if self.sock:
|
168
|
+
self.sock.close()
|
169
|
+
self.sock = None
|
170
|
+
return EventNames.CONNECTION_CLOSED.name
|
@@ -4,6 +4,9 @@ import random
|
|
4
4
|
import socket
|
5
5
|
import select
|
6
6
|
import ssl
|
7
|
+
import struct
|
8
|
+
from dnslib import DNSRecord, QTYPE
|
9
|
+
|
7
10
|
|
8
11
|
|
9
12
|
from scapy.all import IP, TCP, UDP, ICMP, Raw
|
@@ -391,3 +394,76 @@ def group_ports(ports):
|
|
391
394
|
return result
|
392
395
|
|
393
396
|
|
397
|
+
|
398
|
+
|
399
|
+
def send_tcp_dns_query(server_ip, server_port, domain, query_type="A"):
|
400
|
+
dnsatypes = {
|
401
|
+
1: "A", 2: "NS", 5: "CNAME", 6: "SOA", 12: "PTR", 15: "MX",
|
402
|
+
16: "TXT", 28: "AAAA", 33: "SRV", 43: "DS",
|
403
|
+
46: "RRSIG", 47: "NSEC", 48: "DNSKEY", 255: "ANY"
|
404
|
+
}
|
405
|
+
|
406
|
+
result = {"query": None, "response": None, "error": None}
|
407
|
+
supported_types = ', '.join([f"{v}({k})" for k, v in dnsatypes.items()])
|
408
|
+
lookup_by_name = {v.upper(): k for k, v in dnsatypes.items()}
|
409
|
+
query_type_str = str(query_type).strip().upper()
|
410
|
+
|
411
|
+
print(f"[Debug] Received query_type: {query_type_str}")
|
412
|
+
|
413
|
+
# Validate query type
|
414
|
+
if query_type_str.isdigit():
|
415
|
+
qtype = int(query_type_str)
|
416
|
+
if qtype not in dnsatypes:
|
417
|
+
result["error"] = f"Unsupported numeric query type: {query_type}.\nSupported types are: {supported_types}"
|
418
|
+
print("[Error]", result["error"])
|
419
|
+
return result
|
420
|
+
else:
|
421
|
+
qtype = lookup_by_name.get(query_type_str)
|
422
|
+
if qtype is None:
|
423
|
+
result["error"] = f"Unsupported string query type: {query_type}.\nSupported types are: {supported_types}"
|
424
|
+
print("[Error]", result["error"])
|
425
|
+
return result
|
426
|
+
|
427
|
+
try:
|
428
|
+
print(f"[Debug] Building DNS query for domain {domain} with type {query_type_str} ({qtype})")
|
429
|
+
dns_query = DNSRecord.question(domain, qtype=query_type_str)
|
430
|
+
dns_query.header.id = random.randint(0, 65535)
|
431
|
+
query_packet = dns_query.pack()
|
432
|
+
result["query"] = dns_query.toZone()
|
433
|
+
|
434
|
+
print("[Debug] Opening socket")
|
435
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
436
|
+
sock.bind(('', 0))
|
437
|
+
sock.settimeout(2)
|
438
|
+
|
439
|
+
print(f"[Debug] Connecting to {server_ip}:{server_port}")
|
440
|
+
sock.connect((server_ip, server_port))
|
441
|
+
|
442
|
+
length_prefix = struct.pack("!H", len(query_packet))
|
443
|
+
print("[Debug] Sending DNS query")
|
444
|
+
sock.sendall(length_prefix + query_packet)
|
445
|
+
|
446
|
+
print("[Debug] Waiting for response")
|
447
|
+
length_data = sock.recv(2)
|
448
|
+
if len(length_data) < 2:
|
449
|
+
result["error"] = "Incomplete length prefix"
|
450
|
+
print("[Error]", result["error"])
|
451
|
+
return result
|
452
|
+
|
453
|
+
expected_length = struct.unpack("!H", length_data)[0]
|
454
|
+
response_data = b""
|
455
|
+
while len(response_data) < expected_length:
|
456
|
+
chunk = sock.recv(expected_length - len(response_data))
|
457
|
+
if not chunk:
|
458
|
+
break
|
459
|
+
response_data += chunk
|
460
|
+
|
461
|
+
print("[Debug] Received response data")
|
462
|
+
parsed_response = DNSRecord.parse(response_data)
|
463
|
+
result["response"] = parsed_response.to_dict()
|
464
|
+
return result
|
465
|
+
|
466
|
+
except Exception as e:
|
467
|
+
result["error"] = f"Exception occurred: {str(e)}"
|
468
|
+
print("[Error]", result["error"])
|
469
|
+
return result
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: nopasaran
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.96
|
4
4
|
Summary: NoPASARAN is an advanced network tool designed to detect, fingerprint, and locate network middleboxes in a unified framework.
|
5
5
|
Home-page: https://github.com/BenIlies/NoPASARAN
|
6
6
|
Author: Ilies Benhabbour
|
@@ -60,6 +60,8 @@ nopasaran/primitives/action_primitives/probing_primitives.py
|
|
60
60
|
nopasaran/primitives/action_primitives/replay_primitives.py
|
61
61
|
nopasaran/primitives/action_primitives/server_echo_primitives.py
|
62
62
|
nopasaran/primitives/action_primitives/signaling_primitive.py
|
63
|
+
nopasaran/primitives/action_primitives/tcp_dns_request_primitives.py
|
64
|
+
nopasaran/primitives/action_primitives/tcp_dns_response_primitives.py
|
63
65
|
nopasaran/primitives/action_primitives/tcp_primitives.py
|
64
66
|
nopasaran/primitives/action_primitives/timing_primitives.py
|
65
67
|
nopasaran/primitives/action_primitives/tls_primitives.py
|
@@ -81,4 +83,5 @@ nopasaran/tools/http_2_socket_base.py
|
|
81
83
|
nopasaran/tools/http_2_socket_client.py
|
82
84
|
nopasaran/tools/http_2_socket_server.py
|
83
85
|
nopasaran/tools/https_1_socket_server.py
|
86
|
+
nopasaran/tools/tcp_dns_socket_server.py
|
84
87
|
tests/__init__.py
|
@@ -13,7 +13,7 @@ with open(requirements_file, "r") as f:
|
|
13
13
|
# Version will automatically be updated when pushed on the main branch
|
14
14
|
setup(
|
15
15
|
name="nopasaran",
|
16
|
-
version='0.2.
|
16
|
+
version='0.2.96',
|
17
17
|
author="Ilies Benhabbour",
|
18
18
|
author_email="ilies.benhabbour@kaust.edu.sa",
|
19
19
|
description="NoPASARAN is an advanced network tool designed to detect, fingerprint, and locate network middleboxes in a unified framework.",
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/data_manipulation.py
RENAMED
File without changes
|
{nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/event_primitives.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/icmp_primitives.py
RENAMED
File without changes
|
{nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/io_primitives.py
RENAMED
File without changes
|
{nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/ip_primitives.py
RENAMED
File without changes
|
{nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/nested_machine_utils.py
RENAMED
File without changes
|
{nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/probing_primitives.py
RENAMED
File without changes
|
{nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/replay_primitives.py
RENAMED
File without changes
|
File without changes
|
{nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/signaling_primitive.py
RENAMED
File without changes
|
{nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/tcp_primitives.py
RENAMED
File without changes
|
{nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/timing_primitives.py
RENAMED
File without changes
|
{nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/tls_primitives.py
RENAMED
File without changes
|
{nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/action_primitives/udp_primitives.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{nopasaran-0.2.94 → nopasaran-0.2.96}/nopasaran/primitives/transition_primitives/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|