-
Notifications
You must be signed in to change notification settings - Fork 576
Expand file tree
/
Copy pathproxy.py
More file actions
148 lines (128 loc) · 4.3 KB
/
proxy.py
File metadata and controls
148 lines (128 loc) · 4.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
"""
Set proxy if avaiable otherwise exception
"""
# pylint: disable=protected-access
import logging
import socket
import time
import asyncore_pollchoose as asyncore
from advanceddispatcher import AdvancedDispatcher
from network import config
from node import Peer
logger = logging.getLogger('default')
class ProxyError(Exception):
"""Base proxy exception class"""
errorCodes = ("Unknown error",)
def __init__(self, code=-1):
self.code = code
try:
self.message = self.errorCodes[code]
except IndexError:
self.message = self.errorCodes[-1]
super(ProxyError, self).__init__(self.message)
class GeneralProxyError(ProxyError):
"""General proxy error class (not specfic to an implementation)"""
errorCodes = (
"Success",
"Invalid data",
"Not connected",
"Not available",
"Bad proxy type",
"Bad input",
"Timed out",
"Network unreachable",
"Connection refused",
"Host unreachable"
)
class Proxy(AdvancedDispatcher):
"""Base proxy class"""
# these are global, and if you change config during runtime,
# all active/new instances should change too
_proxy = ("127.0.0.1", 9050)
_auth = None
_onion_proxy = None
_onion_auth = None
_remote_dns = True
@property
def proxy(self):
"""Return proxy IP and port"""
return self.__class__._proxy
@proxy.setter
def proxy(self, address):
"""Set proxy IP and port"""
if (not isinstance(address, tuple) or len(address) < 2
or not isinstance(address[0], str)
or not isinstance(address[1], int)):
raise ValueError
self.__class__._proxy = address
@property
def auth(self):
"""Return proxy authentication settings"""
return self.__class__._auth
@auth.setter
def auth(self, authTuple):
"""Set proxy authentication (username and password)"""
self.__class__._auth = authTuple
@property
def onion_proxy(self):
"""
Return separate proxy IP and port for use only with onion
addresses. Untested.
"""
return self.__class__._onion_proxy
@onion_proxy.setter
def onion_proxy(self, address):
"""Set onion proxy address"""
if address is not None and (
not isinstance(address, tuple) or len(address) < 2
or not isinstance(address[0], str)
or not isinstance(address[1], int)
):
raise ValueError
self.__class__._onion_proxy = address
@property
def onion_auth(self):
"""Return proxy authentication settings for onion hosts only"""
return self.__class__._onion_auth
@onion_auth.setter
def onion_auth(self, authTuple):
"""Set proxy authentication for onion hosts only. Untested."""
self.__class__._onion_auth = authTuple
def __init__(self, address):
if not isinstance(address, Peer):
raise ValueError
AdvancedDispatcher.__init__(self)
self.destination = address
self.isOutbound = True
self.fullyEstablished = False
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
if config.safeGetBoolean(
"bitmessagesettings", "socksauthentication"):
self.auth = (
config.safeGet(
"bitmessagesettings", "socksusername"),
config.safeGet(
"bitmessagesettings", "sockspassword"))
else:
self.auth = None
self.connect(
self.onion_proxy
if address.host.endswith(".onion") and self.onion_proxy else
self.proxy
)
def handle_connect(self):
"""Handle connection event (to the proxy)"""
self.set_state("init")
try:
AdvancedDispatcher.handle_connect(self)
except socket.error as e:
if e.errno in asyncore._DISCONNECTED:
logger.debug(
"%s:%i: Connection failed: %s",
self.destination.host, self.destination.port, e)
return
self.state_init()
def state_proxy_handshake_done(self):
"""Handshake is complete at this point"""
self.connectedAt = time.time()
return False