-
Notifications
You must be signed in to change notification settings - Fork 0
FEAT: DISPATCHER: embed tunnel server #85
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
lukasz-glen
wants to merge
8
commits into
main
Choose a base branch
from
feat/tunnel-endpoint
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
4af688f
feat: dispatcher, embed tunnel server
c6e669c
fix: view
32536b6
separate tunnel service code
a3487a6
tunnel service configuration
16165f7
fix: tunnel service - circular deps
12ac0df
fix: declarative connection type: direct or tunnel
521eb87
fix: connection factories for all
35cc5d1
Merge branch 'main' into feat/tunnel-endpoint
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
60 changes: 60 additions & 0 deletions
60
web3pi_proxy/core/rpc/node/endpoint_pool/tunnel_connection_pool.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| import socket | ||
|
|
||
| from web3pi_proxy.config import Config | ||
| from web3pi_proxy.core.rpc.node.endpoint_pool.endpoint_connection_pool import EndpointConnectionPool | ||
| from web3pi_proxy.core.rpc.node.endpoint_pool.tunnel_connection_pool_intf import TunnelConnectionPoolIntf | ||
| from web3pi_proxy.core.rpc.node.endpoint_pool.tunnel_service import TunnelService | ||
| from web3pi_proxy.core.rpc.node.rpcendpoint.connection.endpointconnection import EndpointConnection | ||
| from web3pi_proxy.core.rpc.node.rpcendpoint.endpointimpl import RPCEndpoint | ||
|
|
||
| from web3pi_proxy.utils.logger import get_logger | ||
|
|
||
|
|
||
| class TunnelConnectionPool(EndpointConnectionPool, TunnelConnectionPoolIntf): | ||
|
|
||
| def __init__( | ||
| self, | ||
| endpoint: RPCEndpoint, | ||
| ): | ||
| super().__init__(endpoint) | ||
| self.__logger = get_logger(f"TunnelConnectionPool.{id(self)}") | ||
|
|
||
| self.tunnel_api_key = endpoint.conn_descr.extras["tunnel_service_auth_key"] | ||
| self.tunnel_proxy_establish_port: int = endpoint.conn_descr.extras["tunnel_proxy_establish_port"] | ||
|
|
||
| tunnel_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
| tunnel_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | ||
| tunnel_socket.bind((Config.PROXY_LISTEN_ADDRESS, self.tunnel_proxy_establish_port)) | ||
| tunnel_socket.listen(Config.LISTEN_BACKLOG_PARAM) | ||
| self.tunnel_socket = tunnel_socket | ||
|
|
||
| self.tunnel_service_socket = None | ||
|
|
||
| self.status = self.PoolStatus.DISABLED.value | ||
|
|
||
| TunnelService.register(self.tunnel_api_key, self) | ||
|
|
||
| def new_connection(self) -> EndpointConnection: | ||
|
|
||
| def connection_factory() -> socket: # TODO is it worth to move it to object level and reuse? | ||
| self.__logger.debug("Creating socket") | ||
| self.tunnel_service_socket.sendall(b"NEWCONN") | ||
| new_conn_sock, new_conn_addr = self.tunnel_socket.accept() | ||
| self.__logger.debug("Finished connecting socket") | ||
| return new_conn_sock | ||
|
|
||
| return EndpointConnection(self.endpoint, connection_factory) | ||
|
|
||
| def new_tunnel_service_socket(self, tunnel_service_socket: socket): | ||
| with self._EndpointConnectionPool__lock: | ||
| self.tunnel_service_socket = tunnel_service_socket | ||
| self.status = self.PoolStatus.ACTIVE.value | ||
|
|
||
| def close(self) -> None: | ||
| super().close() | ||
| self.tunnel_socket.close() | ||
| self.tunnel_socket = None | ||
| if self.tunnel_service_socket: | ||
| self.tunnel_service_socket.close() | ||
| self.tunnel_service_socket = None | ||
| TunnelService.unregister(self.tunnel_api_key, self) |
9 changes: 9 additions & 0 deletions
9
web3pi_proxy/core/rpc/node/endpoint_pool/tunnel_connection_pool_intf.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import socket | ||
|
|
||
|
|
||
| class TunnelConnectionPoolIntf: | ||
| """Added to resolve the circular dependencies""" | ||
| tunnel_proxy_establish_port: int | ||
|
|
||
| def new_tunnel_service_socket(self, tunnel_service_socket: socket): | ||
| pass |
69 changes: 69 additions & 0 deletions
69
web3pi_proxy/core/rpc/node/endpoint_pool/tunnel_service.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| import socket | ||
| import select | ||
| from threading import Lock, Thread | ||
|
|
||
| from web3pi_proxy.config import Config | ||
| from web3pi_proxy.core.rpc.node.endpoint_pool.tunnel_connection_pool_intf import TunnelConnectionPoolIntf | ||
| from web3pi_proxy.utils.logger import get_logger | ||
|
|
||
|
|
||
| class TunnelServiceImpl: | ||
| """The service is lazy initialized at the first pool registration | ||
| to avoid resource allocation when there is not pool with a tunnel""" | ||
| def __init__(self): | ||
| self.__registry = dict() | ||
| self.__lock = Lock() | ||
| self.__initialized = False | ||
| self.__logger = get_logger(f"TunnelServiceImpl") | ||
|
|
||
| def register(self, api_key: str, tunnel_connection_pool: TunnelConnectionPoolIntf): | ||
| with self.__lock: | ||
| if not self.__initialized: | ||
| self.__initialize__() | ||
| self.__initialized = True | ||
| self.__registry[api_key] = tunnel_connection_pool | ||
|
|
||
| def unregister(self, api_key: str, tunnel_connection_pool: TunnelConnectionPoolIntf): | ||
| with self.__lock: | ||
| if self.__registry.get(api_key) == tunnel_connection_pool: | ||
| del self.__registry[api_key] | ||
|
|
||
| def __initialize__(self): | ||
| tunnel_srv_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
| tunnel_srv_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) | ||
| tunnel_srv_socket.bind((Config.PROXY_LISTEN_ADDRESS, Config.TUNNEL_ESTABLISH_PORT)) | ||
| tunnel_srv_socket.listen(Config.LISTEN_BACKLOG_PARAM) | ||
| self.tunnel_srv_socket = tunnel_srv_socket | ||
| self.tunnel_thread = Thread( | ||
| target=self.__tunnel_service_run, | ||
| daemon=True, | ||
| ) | ||
| self.tunnel_thread.start() | ||
|
|
||
| def __tunnel_service_run(self): | ||
| while True: | ||
| ready_read, _, _ = select.select([self.tunnel_srv_socket], [], [], Config.BLOCKING_ACCEPT_TIMEOUT) | ||
|
|
||
| if len(ready_read) == 0: | ||
| continue | ||
| tunnel_sock, cli_addr = self.tunnel_srv_socket.accept() | ||
| self.__logger.debug( | ||
| f"New tunnel request from {cli_addr}" | ||
| ) | ||
|
|
||
| cli_api_key = tunnel_sock.recv(2048).decode("utf-8") # TODO the attack: a tunnel client does not send api key | ||
| if not cli_api_key: | ||
| tunnel_sock.close() | ||
| continue | ||
|
|
||
| with self.__lock: | ||
| pool: TunnelConnectionPoolIntf = self.__registry.get(cli_api_key) | ||
| if not pool: | ||
| tunnel_sock.close() | ||
| tunnel_sock.sendall(f'RJCT|invalid_auth_key'.encode("utf-8")) | ||
| continue | ||
| tunnel_sock.sendall(f'ACPT|{Config.PROXY_LISTEN_ADDRESS}:{pool.tunnel_proxy_establish_port}'.encode("utf-8")) | ||
| pool.new_tunnel_service_socket(tunnel_sock) | ||
|
|
||
|
|
||
| TunnelService = TunnelServiceImpl() |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of naming it like that, please change the name to
__new_connectionor_new_connectionto make it obvious that it's an internal function...