nopasaran 0.2.96__tar.gz → 0.2.97__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.
Files changed (89) hide show
  1. {nopasaran-0.2.96 → nopasaran-0.2.97}/PKG-INFO +1 -1
  2. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/tools/http_1_socket_server.py +2 -75
  3. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/tools/https_1_socket_server.py +41 -75
  4. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran.egg-info/PKG-INFO +1 -1
  5. {nopasaran-0.2.96 → nopasaran-0.2.97}/setup.py +1 -1
  6. {nopasaran-0.2.96 → nopasaran-0.2.97}/LICENSE +0 -0
  7. {nopasaran-0.2.96 → nopasaran-0.2.97}/README.md +0 -0
  8. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/__init__.py +0 -0
  9. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/__main__.py +0 -0
  10. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/controllers/__init__.py +0 -0
  11. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/controllers/controller.py +0 -0
  12. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/controllers/factory.py +0 -0
  13. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/controllers/protocol.py +0 -0
  14. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/decorators.py +0 -0
  15. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/definitions/__init__.py +0 -0
  16. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/definitions/commands.py +0 -0
  17. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/definitions/control_channel.py +0 -0
  18. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/definitions/events.py +0 -0
  19. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/definitions/transitions.py +0 -0
  20. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/errors/__init__.py +0 -0
  21. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/errors/parsing_error.py +0 -0
  22. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/http_2_utils.py +0 -0
  23. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/interpreters/__init__.py +0 -0
  24. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/interpreters/action_interpreter.py +0 -0
  25. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/interpreters/condition_interpreter.py +0 -0
  26. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/interpreters/interpreter.py +0 -0
  27. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/interpreters/transition_interpreter.py +0 -0
  28. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/machines/__init__.py +0 -0
  29. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/machines/action_queue.py +0 -0
  30. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/machines/state_machine.py +0 -0
  31. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/parsers/__init__.py +0 -0
  32. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/parsers/interpreter_parser.py +0 -0
  33. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/parsers/state_machine_parser.py +0 -0
  34. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/__init__.py +0 -0
  35. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/__init__.py +0 -0
  36. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/action_primitives.py +0 -0
  37. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/certificate_primitives.py +0 -0
  38. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/client_echo_primitives.py +0 -0
  39. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/control_channel_primitives.py +0 -0
  40. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/data_channel_primitives.py +0 -0
  41. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/data_manipulation.py +0 -0
  42. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/dns_primitives.py +0 -0
  43. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/event_primitives.py +0 -0
  44. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/http_1_request_primitives.py +0 -0
  45. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/http_1_response_primitives.py +0 -0
  46. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/http_2_client_primitives.py +0 -0
  47. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/http_2_server_primitives.py +0 -0
  48. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/http_simple_client_primitives.py +0 -0
  49. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/https_1_request_primitives.py +0 -0
  50. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/https_1_response_primitives.py +0 -0
  51. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/icmp_primitives.py +0 -0
  52. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/io_primitives.py +0 -0
  53. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/ip_primitives.py +0 -0
  54. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/nested_machine_utils.py +0 -0
  55. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/probing_primitives.py +0 -0
  56. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/replay_primitives.py +0 -0
  57. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/server_echo_primitives.py +0 -0
  58. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/signaling_primitive.py +0 -0
  59. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/tcp_dns_request_primitives.py +0 -0
  60. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/tcp_dns_response_primitives.py +0 -0
  61. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/tcp_primitives.py +0 -0
  62. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/timing_primitives.py +0 -0
  63. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/tls_primitives.py +0 -0
  64. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/action_primitives/udp_primitives.py +0 -0
  65. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/condition_primitives/__init__.py +0 -0
  66. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/condition_primitives/condition_primitives.py +0 -0
  67. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/condition_primitives/variable_comparisons.py +0 -0
  68. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/primitives.py +0 -0
  69. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/transition_primitives/__init__.py +0 -0
  70. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/transition_primitives/assignment_transitions.py +0 -0
  71. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/primitives/transition_primitives/transition_primitives.py +0 -0
  72. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/sniffers/__init__.py +0 -0
  73. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/sniffers/sniffer.py +0 -0
  74. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/tools/__init__.py +0 -0
  75. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/tools/checks.py +0 -0
  76. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/tools/echo_socket_server.py +0 -0
  77. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/tools/http_2_overwrite.py +0 -0
  78. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/tools/http_2_socket_base.py +0 -0
  79. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/tools/http_2_socket_client.py +0 -0
  80. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/tools/http_2_socket_server.py +0 -0
  81. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/tools/tcp_dns_socket_server.py +0 -0
  82. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran/utils.py +0 -0
  83. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran.egg-info/SOURCES.txt +0 -0
  84. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran.egg-info/dependency_links.txt +0 -0
  85. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran.egg-info/entry_points.txt +0 -0
  86. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran.egg-info/requires.txt +0 -0
  87. {nopasaran-0.2.96 → nopasaran-0.2.97}/nopasaran.egg-info/top_level.txt +0 -0
  88. {nopasaran-0.2.96 → nopasaran-0.2.97}/setup.cfg +0 -0
  89. {nopasaran-0.2.96 → nopasaran-0.2.97}/tests/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nopasaran
3
- Version: 0.2.96
3
+ Version: 0.2.97
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
@@ -124,79 +124,6 @@ class HTTP1SocketServer:
124
124
 
125
125
  return EventNames.SERVER_STARTED.name, f"Server successfully started at {host}:{port}."
126
126
 
127
- def receive_test_frames(self):
128
- """
129
- Listen for HTTP/1.1 requests until a timeout occurs, then process all received requests.
130
-
131
- Returns:
132
- Tuple[str, str, str]: (event_name, message, received_data)
133
- - event_name: The type of event that occurred (from EventNames)
134
- - TIMEOUT: Timeout occurred before all requests were received
135
- - REJECTED: Received a 4xx or 5xx status code
136
- - RECEIVED_REQUESTS: All requests have been received
137
- - ERROR: Error occurred while receiving requests
138
- - message: A descriptive message about what happened
139
- - received_data: String representation of the received requests or None
140
- """
141
- if not self.sock:
142
- return EventNames.ERROR.name, "Server not started", None
143
-
144
- requests_received = []
145
- start_time = time.time()
146
-
147
- # Make the server socket non-blocking for accepting connections
148
- self.sock.setblocking(False)
149
-
150
- # Keep accepting connections until we hit a timeout
151
- while True:
152
- # Check for overall timeout
153
- elapsed_time = time.time() - start_time
154
- if elapsed_time > self.TIMEOUT:
155
- if len(requests_received) == 0:
156
- return EventNames.TIMEOUT.name, f"Timeout after {self.TIMEOUT}s and received no requests.", None
157
- else:
158
- break # We've received some requests, so consider it done
159
-
160
- try:
161
- # Try to accept a new connection
162
- ready_to_read, _, _ = select.select([self.sock], [], [], 0.5)
163
-
164
- if ready_to_read:
165
- client_socket, _ = self.sock.accept()
166
- client_socket.settimeout(0.5)
167
-
168
- try:
169
- data = client_socket.recv(4096)
170
-
171
- if data:
172
- # Parse the HTTP/1.1 request
173
- request_str = data.decode('utf-8', errors='ignore')
174
- requests_received.append(request_str)
175
-
176
- # Check for error status codes
177
- if "HTTP/1.1 5" in request_str or "HTTP/1.1 4" in request_str:
178
- try:
179
- status_line = request_str.split("\r\n")[0]
180
- status_code = status_line.split(" ")[1]
181
- client_socket.close()
182
- return EventNames.REJECTED.name, f"Received {status_code} status code.", request_str
183
- except (IndexError, ValueError):
184
- client_socket.close()
185
- return EventNames.REJECTED.name, "Received 4xx or 5xx status code.", request_str
186
- finally:
187
- client_socket.close()
188
- except socket.timeout:
189
- continue
190
- except Exception as e:
191
- return EventNames.ERROR.name, f"Error while receiving requests: {str(e)}", \
192
- str(requests_received) if requests_received else None
193
-
194
- # If we get here, we've either collected all requests or hit the timeout
195
- if len(requests_received) == 0:
196
- return EventNames.TIMEOUT.name, "No requests received before timeout.", None
197
-
198
- return EventNames.RECEIVED_REQUESTS.name, f"Received {len(requests_received)} HTTP/1.1 requests.", str(requests_received)
199
-
200
127
  def close(self):
201
128
  """Close the HTTP/1.1 connection and clean up resources"""
202
129
  try:
@@ -209,6 +136,6 @@ class HTTP1SocketServer:
209
136
  self.client_socket = None
210
137
  self.sock = None
211
138
 
212
- return EventNames.CONNECTION_CLOSED.name
139
+ return EventNames.CONNECTION_ENDING.name
213
140
  except Exception as e:
214
- return EventNames.CONNECTION_CLOSED.name
141
+ return EventNames.CONNECTION_ENDING.name
@@ -30,13 +30,10 @@ class HTTPS1SocketServer:
30
30
  def generate_and_load_cert(self, identifier):
31
31
  cert_path, key_path = self.generate_self_signed_cert(identifier)
32
32
 
33
- # Check if paths are valid
34
33
  if not cert_path or not os.path.exists(cert_path):
35
34
  raise FileNotFoundError(f"[HTTPS1SocketServer] Certificate file not found at {cert_path}")
36
35
  if not key_path or not os.path.exists(key_path):
37
36
  raise FileNotFoundError(f"[HTTPS1SocketServer] Key file not found at {key_path}")
38
-
39
- # Optional: Ensure they're not empty (some systems fail silently on write)
40
37
  if os.path.getsize(cert_path) == 0:
41
38
  raise ValueError(f"[HTTPS1SocketServer] Certificate file is empty at {cert_path}")
42
39
  if os.path.getsize(key_path) == 0:
@@ -50,7 +47,6 @@ class HTTPS1SocketServer:
50
47
  self._cert_path = cert_path
51
48
  self._key_path = key_path
52
49
 
53
-
54
50
  def generate_self_signed_cert(self, identifier):
55
51
  key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
56
52
 
@@ -60,11 +56,10 @@ class HTTPS1SocketServer:
60
56
 
61
57
  alt_names = [x509.DNSName(identifier)]
62
58
  try:
63
- # Try to interpret as IP address
64
59
  import ipaddress
65
60
  alt_names.append(x509.IPAddress(ipaddress.ip_address(identifier)))
66
61
  except ValueError:
67
- pass # it's not an IP, skip adding IPAddress
62
+ pass
68
63
 
69
64
  cert = (
70
65
  x509.CertificateBuilder()
@@ -102,16 +97,18 @@ class HTTPS1SocketServer:
102
97
  self.sock.bind((host, port))
103
98
  self.sock.listen(5)
104
99
  return EventNames.SERVER_STARTED.name, f"HTTPS server started at {host}:{port}"
105
-
106
-
107
-
108
100
 
109
101
  def handle_client_connection(self, tls_socket):
110
- request = tls_socket.recv(4096)
102
+ try:
103
+ request = tls_socket.recv(4096)
104
+ if not request:
105
+ return # Client closed connection or sent nothing
106
+ except socket.timeout:
107
+ return # Timed out waiting for client data
108
+
111
109
  request_str = request.decode("utf-8", errors="ignore")
112
110
  self.received_request_data = request
113
111
 
114
- # Parse request line
115
112
  headers_end_index = request_str.find("\r\n\r\n")
116
113
  headers_part = request_str[:headers_end_index] if headers_end_index != -1 else request_str
117
114
  request_line = headers_part.split("\r\n")[0]
@@ -147,51 +144,12 @@ class HTTPS1SocketServer:
147
144
  with self.request_received:
148
145
  self.request_received.notify_all()
149
146
 
150
- def receive_test_frames(self):
151
- if not self.sock:
152
- return EventNames.ERROR.name, "Server not started", None
153
-
154
- requests_received = []
155
- start_time = time.time()
156
- self.sock.setblocking(False)
157
-
158
- while True:
159
- if time.time() - start_time > self.TIMEOUT:
160
- if not requests_received:
161
- return EventNames.TIMEOUT.name, "Timeout with no request", None
162
- break
163
-
164
- try:
165
- ready_to_read, _, _ = select.select([self.sock], [], [], 0.5)
166
- if ready_to_read:
167
- client_sock, _ = self.sock.accept()
168
- tls_sock = self.context.wrap_socket(client_sock, server_side=True)
169
- tls_sock.settimeout(1.0)
170
- try:
171
- self.handle_client_connection(tls_sock)
172
- req_str = self.received_request_data.decode("utf-8", errors="ignore")
173
- requests_received.append(req_str)
174
- except Exception as e:
175
- return EventNames.ERROR.name, f"TLS error: {e}", None
176
- except Exception as e:
177
- return EventNames.ERROR.name, str(e), None
178
-
179
- return EventNames.RECEIVED_REQUESTS.name, f"Received {len(requests_received)} HTTPS requests.", str(requests_received)
180
-
181
147
  def wait_for_request(self, port, timeout):
182
148
  """
183
149
  Wait for a single HTTPS request with TLS handshake and user-defined timeout.
184
-
185
- Args:
186
- port (int): The port to bind and listen on.
187
- timeout (int): Timeout duration in seconds.
188
-
189
- Returns:
190
- Tuple[bytes or None, str]: The raw request data (or None if timed out) and an event name.
191
150
  """
192
151
  self.received_request_data = None
193
- self.request_received = None
194
-
152
+ self.request_received = None
195
153
  context = self.context
196
154
  start_time = time.time()
197
155
 
@@ -207,36 +165,44 @@ class HTTPS1SocketServer:
207
165
  return None, EventNames.TIMEOUT.name
208
166
 
209
167
  try:
210
- ready, _, _ = select.select([server_socket], [], [], timeout - elapsed)
168
+ remaining = timeout - elapsed
169
+ ready, _, _ = select.select([server_socket], [], [], remaining)
211
170
  if ready:
212
171
  client_sock, _ = server_socket.accept()
213
- with context.wrap_socket(client_sock, server_side=True) as tls_sock:
214
- tls_sock.settimeout(1.0)
215
- try:
172
+ client_sock.settimeout(2.0) # Important: Timeout for TLS handshake and recv
173
+ try:
174
+ with context.wrap_socket(client_sock, server_side=True) as tls_sock:
175
+ tls_sock.settimeout(2.0) # Also set after TLS handshake
216
176
  self.handle_client_connection(tls_sock)
217
- return self.received_request_data, EventNames.REQUEST_RECEIVED.name
218
- except Exception as e:
219
- return None, EventNames.ERROR.name
220
- except Exception as e:
221
- return None, EventNames.ERROR.name
177
+ if self.received_request_data:
178
+ return self.received_request_data, EventNames.REQUEST_RECEIVED.name
179
+ else:
180
+ return None, EventNames.TIMEOUT.name
181
+ except (ssl.SSLError, socket.timeout):
182
+ return None, EventNames.TIMEOUT.name
183
+ except Exception:
184
+ return None, EventNames.ERROR.name
185
+ except Exception:
186
+ return None, EventNames.ERROR.name
222
187
 
223
188
  def close(self):
224
- if self.client_socket:
225
- self.client_socket.close()
226
- if self.sock:
227
- self.sock.close()
228
- self.client_socket = None
229
- self.sock = None
230
-
231
189
  try:
232
- if self._cert_path and os.path.exists(self._cert_path):
233
- os.remove(self._cert_path)
234
- if self._key_path and os.path.exists(self._key_path):
235
- os.remove(self._key_path)
236
- except Exception as e:
237
- return EventNames.ERROR.name, f"Certificate cleanup error: {str(e)}"
190
+ if self.client_socket:
191
+ self.client_socket.close()
192
+ if self.sock:
193
+ self.sock.close()
238
194
 
239
- return EventNames.CONNECTION_CLOSED.name
195
+ self.client_socket = None
196
+ self.sock = None
240
197
 
241
-
198
+ try:
199
+ if self._cert_path and os.path.exists(self._cert_path):
200
+ os.remove(self._cert_path)
201
+ if self._key_path and os.path.exists(self._key_path):
202
+ os.remove(self._key_path)
203
+ except Exception as e:
204
+ return EventNames.ERROR.name, f"Certificate cleanup error: {str(e)}"
242
205
 
206
+ return EventNames.CONNECTION_ENDING.name
207
+ except Exception:
208
+ return EventNames.CONNECTION_ENDING.name
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: nopasaran
3
- Version: 0.2.96
3
+ Version: 0.2.97
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
@@ -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.96',
16
+ version='0.2.97',
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