dpyproxy 2.2.0__py3-none-any.whl

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 (59) hide show
  1. dpyproxy/__init__.py +1 -0
  2. dpyproxy/__main__.py +4 -0
  3. dpyproxy-2.2.0.dist-info/METADATA +296 -0
  4. dpyproxy-2.2.0.dist-info/RECORD +59 -0
  5. dpyproxy-2.2.0.dist-info/WHEEL +4 -0
  6. dpyproxy-2.2.0.dist-info/entry_points.txt +2 -0
  7. dpyproxy-2.2.0.dist-info/licenses/LICENSE +201 -0
  8. enumerators/DnsProxyMode.py +39 -0
  9. enumerators/DnsResolvers.py +141 -0
  10. enumerators/HttpMethod.py +17 -0
  11. enumerators/Modules.py +38 -0
  12. enumerators/Port.py +11 -0
  13. enumerators/TcpProxyMode.py +17 -0
  14. enumerators/TlsVersion.py +21 -0
  15. enumerators/__init__.py +0 -0
  16. exception/DnsException.py +7 -0
  17. exception/ParserException.py +7 -0
  18. exception/__init__.py +0 -0
  19. main.py +94 -0
  20. modules/Module.py +45 -0
  21. modules/__init__.py +0 -0
  22. modules/dns/DnsModeDeterminator.py +358 -0
  23. modules/dns/DnsModule.py +113 -0
  24. modules/dns/DnsProxy.py +277 -0
  25. modules/dns/DnsResolver.py +18 -0
  26. modules/dns/__init__.py +0 -0
  27. modules/http/HttpModule.py +69 -0
  28. modules/http/HttpStrategies.py +849 -0
  29. modules/http/HttpUtils.py +94 -0
  30. modules/http/__init__.py +0 -0
  31. modules/tls/TcpProxy.py +106 -0
  32. modules/tls/TlsModule.py +173 -0
  33. modules/tls/__init__.py +0 -0
  34. network/DomainResolver.py +472 -0
  35. network/NetworkAddress.py +10 -0
  36. network/WrappedSocket.py +97 -0
  37. network/__init__.py +0 -0
  38. network/protocols/Dns.py +62 -0
  39. network/protocols/Http.py +109 -0
  40. network/protocols/Socksv4.py +70 -0
  41. network/protocols/Socksv5.py +106 -0
  42. network/protocols/Tls.py +113 -0
  43. network/protocols/__init__.py +0 -0
  44. network/tcp/Forwarder.py +203 -0
  45. network/tcp/TcpConnectionHandler.py +264 -0
  46. network/tcp/WrappedTcpSocket.py +30 -0
  47. network/tcp/__init__.py +0 -0
  48. network/udp/__init__.py +0 -0
  49. test/Sink.py +23 -0
  50. test/__init__.py +0 -0
  51. test/test_dns.py +98 -0
  52. test/test_http.py +57 -0
  53. test/test_tls.py +63 -0
  54. util/DnsAutoModeRuntimeMeasurement.py +62 -0
  55. util/DnsReachabilityCollector.py +160 -0
  56. util/DnsResolversDomainResolver.py +36 -0
  57. util/Util.py +62 -0
  58. util/__init__.py +0 -0
  59. util/constants.py +8 -0
@@ -0,0 +1,94 @@
1
+ class HttpUtils:
2
+ @staticmethod
3
+ def insert(s: str, insertion: str, num: int, position: str, index: int = None) -> str:
4
+ """
5
+ Inserts a string into another string a specified number of times at a specified position.
6
+ :param s: string to insert into
7
+ :param insertion: string to insert
8
+ :param num: number of times to insert
9
+ :param position: position to insert at, either "start", "end", "middle", "random", or "index"
10
+ :param index: index to insert at if position is
11
+ :return: modified string
12
+ """
13
+ if position == "start":
14
+ result = num * insertion + s
15
+ if position == "end":
16
+ result = s + num * insertion
17
+ if position == "middle" or position == "random":
18
+ index = len(s) // 2
19
+ result = s[:index] + num * insertion + s[index:]
20
+ if position == "index" and index is not None:
21
+ result = s[:index] + num * insertion + s[index:]
22
+ return result
23
+
24
+ @staticmethod
25
+ def replace(s: str, replacement: str, num: int, start_index: int, end_index: int) -> str:
26
+ """
27
+ Replaces a part of a string with another string a specified number of times.
28
+ :param s: string to replace in
29
+ :param replacement: string to replace with
30
+ :param num: number of times to replace
31
+ :param start_index: start index of part to replace
32
+ :param end_index: end index of part to replace
33
+ :return: modified string
34
+ """
35
+ return s[:start_index] + num * replacement + s[end_index:]
36
+
37
+ @staticmethod
38
+ def duplicate(s: str, start_index: int, end_index: int) -> str:
39
+ """
40
+ Duplicates a part of a string with another string a specified number of times.
41
+ :param s: string to duplicate in
42
+ :param start_index: start index of part to duplicate in
43
+ :param end_index: end index of part to duplicate in
44
+ :return: modified string
45
+ """
46
+ return 2 * s[start_index:end_index]
47
+
48
+ @staticmethod
49
+ def index_host_header(data_list: list[list[str]], number: int = 1) -> int:
50
+ """
51
+ Indexes all host headers.
52
+ :param data_list: list of host headers
53
+ :param number: number of host headers
54
+ :return: indexed host headers
55
+ """
56
+ count = 0
57
+ for i, line in enumerate(data_list):
58
+ if "HOST" in line[0].upper():
59
+ count += 1
60
+ if count == number:
61
+ return i
62
+ return -1
63
+
64
+ @staticmethod
65
+ def index_content_length_header(data_list: list[list[str]], number: int = 1) -> int:
66
+ """
67
+ Indexes all content length headers.
68
+ :param data_list: list of content length headers
69
+ :param number: number of content length headers
70
+ :return: indexed content length headers
71
+ """
72
+ count = 0
73
+ for i, line in enumerate(data_list):
74
+ if "CONTENT-LENGTH" in line[0].upper():
75
+ count += 1
76
+ if count == number:
77
+ return i
78
+ return -1
79
+
80
+ @staticmethod
81
+ def index_transfer_encoding_header(data_list: list[list[str]], number: int = 1) -> int:
82
+ """
83
+ Indexes all transfer encoding headers.
84
+ :param data_list: list of transfer encoding headers
85
+ :param number: number of transfer encoding headers
86
+ :return: indexed transfer encoding headers
87
+ """
88
+ count = 0
89
+ for i, line in enumerate(data_list):
90
+ if "TRANSFER-ENCODING" in line[0].upper():
91
+ count += 1
92
+ if count == number:
93
+ return i
94
+ return -1
File without changes
@@ -0,0 +1,106 @@
1
+ import logging
2
+ import select
3
+ import socket
4
+ import threading
5
+
6
+ from enumerators.TcpProxyMode import TcpProxyMode
7
+ from enumerators.TlsVersion import TlsVersion
8
+ from network.NetworkAddress import NetworkAddress
9
+ from network.tcp.TcpConnectionHandler import TcpConnectionHandler
10
+ from network.tcp.WrappedTcpSocket import WrappedTcpSocket
11
+
12
+
13
+ class TcpProxy:
14
+ """
15
+ Proxy server
16
+ """
17
+
18
+ def __init__(
19
+ self,
20
+ address: NetworkAddress,
21
+ timeout: int = 120,
22
+ record_version: str = TlsVersion.DEFAULT.value,
23
+ record_frag: bool = False,
24
+ tcp_frag: bool = False,
25
+ frag_size: int = 20,
26
+ http_strategy: int = None,
27
+ http_smuggling_uncensored_url: str = "",
28
+ dns_server: NetworkAddress = None,
29
+ disabled_modes: list[TcpProxyMode] = None,
30
+ forward_proxy: NetworkAddress = None,
31
+ forward_proxy_mode: TcpProxyMode = TcpProxyMode.HTTPS,
32
+ forward_proxy_resolve_address: bool = False,
33
+ ):
34
+ # timeout for socket reads and message reception
35
+ self.timeout = timeout
36
+ # own port
37
+ self.address = address
38
+ # record header version settings
39
+ self.record_version = record_version
40
+ # record fragmentation settings
41
+ self.record_frag = record_frag
42
+ self.tcp_frag = tcp_frag
43
+ self.frag_size = frag_size
44
+ # http manipulation strategy
45
+ self.http_strategy = http_strategy
46
+ self.http_smuggling_uncensored_url = http_smuggling_uncensored_url
47
+ # whether to use dot for domain resolution
48
+ self.dns_server = dns_server
49
+ self.disabled_modes = disabled_modes
50
+ if self.disabled_modes is None:
51
+ self.disabled_modes = []
52
+ # settings for another proxy to contact further down the line
53
+ self.forward_proxy = forward_proxy
54
+ self.forward_proxy_mode = forward_proxy_mode
55
+ self.forward_proxy_resolve_address = forward_proxy_resolve_address
56
+ self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
57
+ self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
58
+ self.continue_processing = True
59
+
60
+ def handle(self, client_socket: WrappedTcpSocket, address: NetworkAddress):
61
+ return TcpConnectionHandler(
62
+ client_socket,
63
+ address,
64
+ self.timeout,
65
+ self.record_version,
66
+ self.record_frag,
67
+ self.tcp_frag,
68
+ self.frag_size,
69
+ self.http_strategy,
70
+ self.http_smuggling_uncensored_url,
71
+ self.dns_server,
72
+ self.disabled_modes,
73
+ self.forward_proxy,
74
+ self.forward_proxy_mode,
75
+ self.forward_proxy_resolve_address,
76
+ ).handle()
77
+
78
+ def start(self):
79
+ """
80
+ Starts the proxy. After calling the proxy is listening for connections.
81
+ :return:
82
+ """
83
+ # opening server socket
84
+ self.server.bind((self.address.host, self.address.port))
85
+ self.server.listen()
86
+ print(f"### Started TCP proxy on {self.address.host}:{self.address.port} ###")
87
+ if self.dns_server:
88
+ logging.debug(f"Using DNS server {self.dns_server}")
89
+ if self.forward_proxy:
90
+ logging.debug(f"Using forward proxy {self.forward_proxy}")
91
+ while self.continue_processing:
92
+ readable, _, _ = select.select([self.server], [], [], 1)
93
+ if not readable:
94
+ continue
95
+ # listen for incoming connections
96
+ try:
97
+ client_socket, address = self.server.accept()
98
+ except OSError:
99
+ logging.error("### Socket closed by OS. Stopping TCP Proxy ###")
100
+ return
101
+ address = NetworkAddress(address[0], address[1])
102
+ client_socket = WrappedTcpSocket(self.timeout, client_socket)
103
+ logging.info(f"request from {address.host}:{address.port}")
104
+ # spawn a new thread that runs the function handle()
105
+ threading.Thread(target=self.handle, args=(client_socket, address)).start()
106
+ logging.info("### Stopped proxy ###")
@@ -0,0 +1,173 @@
1
+ import logging
2
+ import string
3
+ from argparse import ArgumentParser, BooleanOptionalAction, Namespace
4
+
5
+ from enumerators.TcpProxyMode import TcpProxyMode
6
+ from enumerators.TlsVersion import TlsVersion
7
+ from modules.Module import Module
8
+ from modules.tls.TcpProxy import TcpProxy
9
+ from network.NetworkAddress import NetworkAddress
10
+
11
+
12
+ class TlsModule(Module):
13
+ """
14
+ Implements circumvention methods for the TLS SNI censorship. Currently, implements options for a general TCP socket
15
+ as TLS is the only TCP-based protocol we support. In future version, those should be abstracted into their own
16
+ module.
17
+ """
18
+
19
+ def __init__(self, parser: ArgumentParser):
20
+ super().__init__(parser)
21
+ self.proxy: TcpProxy | None = None
22
+ self.dns_server = None
23
+
24
+ @staticmethod
25
+ def register_parameters(parser: ArgumentParser):
26
+
27
+ def list_of_modes(arg):
28
+ return list(map(lambda x: TcpProxyMode(x), arg.split(",")))
29
+
30
+ def record_header_version(arg):
31
+ try:
32
+ return TlsVersion.__getitem__(arg).value
33
+ except KeyError:
34
+ if len(arg) == 4 and all(c in string.hexdigits for c in arg):
35
+ return arg
36
+ else:
37
+ logging.error(
38
+ f"{arg} not a predefined TLS version, not 2 bytes long or contains non-hex characters."
39
+ )
40
+ exit()
41
+
42
+ tls_module = parser.add_argument_group("TLS Module")
43
+
44
+ tls_module.add_argument(
45
+ "--tls_disabled_modes",
46
+ type=list_of_modes,
47
+ choices=TcpProxyMode,
48
+ default=[],
49
+ help="List of proxy modes to ignore. By default, all none are disabled. Hence, all are enabled",
50
+ )
51
+
52
+ tls_module.add_argument("--tls_timeout", type=int, default=10, help="Connection timeout in seconds")
53
+
54
+ tls_module.add_argument("--tls_host", type=str, default="localhost", help="Address the proxy server runs on")
55
+
56
+ tls_module.add_argument("--tls_port", type=int, default=4433, help="Port the proxy server runs on")
57
+
58
+ tls_module.add_argument(
59
+ "--tls_record_version",
60
+ type=record_header_version,
61
+ default=TlsVersion.DEFAULT.name,
62
+ help=f"Overwrites the TLS version in the TLS record with the given bytes. Pre-defined "
63
+ f"values {[x.name for x in TlsVersion]} or 2 byte long values such as 0303 or "
64
+ f"FFFF can be provided.",
65
+ )
66
+
67
+ tls_module.add_argument(
68
+ "--tls_record_frag",
69
+ default=True,
70
+ action=BooleanOptionalAction,
71
+ help="Whether to use record fragmentation to forwarded TLS handshake messages",
72
+ )
73
+
74
+ tls_module.add_argument(
75
+ "--tls_tcp_frag",
76
+ default=True,
77
+ action=BooleanOptionalAction,
78
+ help="Whether to use TCP fragmentation to forwarded messages.",
79
+ )
80
+
81
+ tls_module.add_argument("--tls_frag_size", type=int, default=20, help="Bytes in each TCP/TLS record fragment")
82
+
83
+ tls_module.add_argument(
84
+ "--tls_dns_server_ip",
85
+ type=str,
86
+ default=None,
87
+ help="DNS server IP for all DNS queries of the TLS module. If not given, the DNS server started by the "
88
+ "DNS module us used. If DNS module is not used, the OS default DNS server is used.",
89
+ )
90
+
91
+ tls_module.add_argument(
92
+ "--tls_dns_server_port",
93
+ type=int,
94
+ default=53,
95
+ help="DNS server port for all DNS queries. Only set if a DNS server IP is given. If not given, the "
96
+ "default port 53 is used.",
97
+ )
98
+
99
+ tls_module.add_argument(
100
+ "--tls_forward_proxy_host",
101
+ type=str,
102
+ default="localhost",
103
+ help="Host of the forward proxy if any is present",
104
+ )
105
+
106
+ tls_module.add_argument(
107
+ "--tls_forward_proxy_port", type=int, default=None, help="Port the forward proxy server runs on"
108
+ )
109
+
110
+ tls_module.add_argument(
111
+ "--tls_forward_proxy_mode",
112
+ type=TcpProxyMode.__getitem__,
113
+ choices=TcpProxyMode,
114
+ default=TcpProxyMode.HTTPS,
115
+ help="The proxy type of the forward proxy",
116
+ )
117
+
118
+ tls_module.add_argument(
119
+ "--tls_forward_proxy_resolve_address",
120
+ default=False,
121
+ action=BooleanOptionalAction,
122
+ help="""Whether to resolve domains before including them in the HTTP CONNECT request to the
123
+ second proxy""",
124
+ )
125
+
126
+ def extract_parameters(self, args: Namespace):
127
+ server_address = NetworkAddress(args.tls_host, args.tls_port)
128
+ forward_proxy = None
129
+ if args.tls_forward_proxy_port is not None:
130
+ forward_proxy = NetworkAddress(args.tls_forward_proxy_host, args.tls_forward_proxy_port)
131
+
132
+ if args.tls_dns_server_ip is not None and self.dns_server is None:
133
+ self.dns_server = NetworkAddress(args.tls_dns_server_ip, args.tls_dns_server_port)
134
+
135
+ if (
136
+ args.tls_forward_proxy_mode in [TcpProxyMode.HTTP, TcpProxyMode.SNI]
137
+ and args.tls_forward_proxy_mode != args.proxy_mode
138
+ ):
139
+ logging.debug("Forward proxy modes HTTP and SNI only usable if proxy mode is HTTP or SNI respectively.")
140
+ exit()
141
+
142
+ self.proxy = TcpProxy(
143
+ address=server_address,
144
+ timeout=args.tls_timeout,
145
+ record_version=args.tls_record_version,
146
+ record_frag=args.tls_record_frag,
147
+ tcp_frag=args.tls_tcp_frag,
148
+ frag_size=args.tls_frag_size,
149
+ dns_server=self.dns_server,
150
+ disabled_modes=args.tls_disabled_modes,
151
+ forward_proxy=forward_proxy,
152
+ forward_proxy_mode=args.tls_forward_proxy_mode,
153
+ forward_proxy_resolve_address=args.tls_forward_proxy_resolve_address,
154
+ )
155
+
156
+ def start(self):
157
+ self.proxy.start()
158
+
159
+ def stop(self):
160
+ self.proxy.continue_processing = False
161
+ logging.info("Waiting for proxy to stop")
162
+
163
+ def set_dns_server(self, dns_server: NetworkAddress):
164
+ """
165
+ Sets the DNS server for the TLS module.
166
+ :param dns_server: NetworkAddress of the DNS server to use.
167
+ """
168
+ if not self.dns_server:
169
+ self.dns_server = NetworkAddress(
170
+ "127.0.0.1" if dns_server.host == "0.0.0.0" else dns_server.host, dns_server.port
171
+ )
172
+ else:
173
+ logging.warning("DNS server manually overwritten in TLS module. Not setting address of DNS module server.")
File without changes