-
Notifications
You must be signed in to change notification settings - Fork 190
Add environment variable to override daemon endpoint #1099
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
base: rolling
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,8 @@ | |
import argparse | ||
import os | ||
import time | ||
from urllib.parse import urlparse | ||
from urllib.parse import urlunparse | ||
import uuid | ||
|
||
import rclpy | ||
|
@@ -31,32 +33,66 @@ | |
from ros2cli.xmlrpc.local_server import SimpleXMLRPCRequestHandler | ||
|
||
|
||
SERVER_URL_VARIABLE_NAME = 'ROS2_DAEMON_SERVER_URL' | ||
|
||
|
||
def get_xmlrpc_server_url(address=None): | ||
url = urlparse( | ||
os.environ.get(SERVER_URL_VARIABLE_NAME) or '/ros2cli/', | ||
scheme='http') | ||
|
||
if address is None: | ||
address = ( | ||
url.hostname or '127.0.0.1', | ||
str( | ||
url.port | ||
if url.port not in (None, '') | ||
else (11511 + int(os.environ.get('ROS_DOMAIN_ID', 0))) | ||
), | ||
) | ||
|
||
return urlunparse(url._replace(netloc=':'.join(address))) | ||
|
||
|
||
def get_port(): | ||
base_port = 11511 | ||
base_port += int(os.environ.get('ROS_DOMAIN_ID', 0)) | ||
return base_port | ||
url = get_xmlrpc_server_url() | ||
return urlparse(url).port | ||
|
||
|
||
def get_address(): | ||
return '127.0.0.1', get_port() | ||
url = get_xmlrpc_server_url() | ||
parsed_url = urlparse(url) | ||
return parsed_url.hostname, parsed_url.port | ||
|
||
|
||
def get_path(): | ||
url = get_xmlrpc_server_url() | ||
return urlparse(url).path | ||
|
||
|
||
class RequestHandler(SimpleXMLRPCRequestHandler): | ||
rpc_paths = ('/ros2cli/',) | ||
|
||
class _GetRpcPaths(property): | ||
""" | ||
Getter for the RPC paths value to use on the request handler. | ||
|
||
def get_xmlrpc_server_url(address=None): | ||
if not address: | ||
address = get_address() | ||
host, port = address | ||
path = RequestHandler.rpc_paths[0] | ||
return f'http://{host}:{port}{path}' | ||
We need this property to work when accessed from the class reference, | ||
so we can't just use ``@property`` here. | ||
""" | ||
|
||
def __get__(self, instance, owner): | ||
return (get_path(),) | ||
|
||
rpc_paths = _GetRpcPaths() | ||
Comment on lines
+83
to
+86
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A little more explanation on this snippet: All of the other "getters" for endpoint-related information ( |
||
|
||
|
||
def make_xmlrpc_server() -> LocalXMLRPCServer: | ||
"""Make local XMLRPC server listening over ros2cli daemon's default port.""" | ||
address = get_address() | ||
|
||
assert urlparse(get_xmlrpc_server_url()).scheme == 'http', \ | ||
'Only http XMLRPC servers are supported at this time.' | ||
|
||
return LocalXMLRPCServer( | ||
address, logRequests=False, | ||
requestHandler=RequestHandler, | ||
|
@@ -143,7 +179,11 @@ def shutdown_handler(): | |
shutdown = True | ||
server.register_function(shutdown_handler, 'system.shutdown') | ||
|
||
print('Serving XML-RPC on ' + get_xmlrpc_server_url(server.server_address)) | ||
server_path = server.RequestHandlerClass.rpc_paths[0] | ||
server_hostname, server_port = server.server_address | ||
server_url = f'http://{server_hostname}:{server_port}{server_path}' | ||
|
||
print('Serving XML-RPC on ' + server_url) | ||
try: | ||
while rclpy.ok() and not shutdown: | ||
server.handle_request() | ||
|
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.
AFAIK, this is not officially documented anywhere, but currently we can only spawn the daemon process with
127.0.0.1
which is localhost loopback physical network IF (with only offset of port number that comes from ROS_DOMAIN_ID). and this fix can expose the daemon XMLRPC API to any IP address that is owned by this host.although I believe this is more flexible for user to manage the ros2 daemon process in the LAN (for example, we can set SERVER_URL_VARIABLE_NAME to all ROS 2 machines and use the single ros2 daemon server in the entire ROS 2 network. this is useful for resource constrained devices to avoid starting ros2 daemon process in local), this could generate the security concern when we use the security enclaves.
when this ros2 daemon is bound to IP address in the LAN with security enclaves, that exposes the ROS 2 connectivity information to anyone in the LAN via XLRPC. this did not happen before, and there is a possibility that 3rd party remote machine or application can collect this info that is NOT supposed to be seen if administrator is not careful enough. maybe this is just a corner case, but looks like a minor security concern.
after all i think this enhancement makes sense, but we probably do not advertise this environmental variable for end users? if we do that, i think there needs to be some explanation how this works.