From 5b839f7d22ab104d3266c35d0cf805bdebd46567 Mon Sep 17 00:00:00 2001 From: kannibalox Date: Tue, 4 Jul 2023 01:17:45 -0400 Subject: [PATCH] Updated RPC Setup XMLRPC (markdown) --- RPC-Setup-XMLRPC.md | 65 ++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/RPC-Setup-XMLRPC.md b/RPC-Setup-XMLRPC.md index 2b054b6..c908cea 100644 --- a/RPC-Setup-XMLRPC.md +++ b/RPC-Setup-XMLRPC.md @@ -1,40 +1,39 @@ # Using XMLRPC with rTorrent +## Security concerns regarding exposing the `XMLRPC` API -## Security concerns regarding exposing the `xmlrpc` API +Before continuing, it's worth mentioning that rTorrent methods are very flexible, and powerful, and can be used to execute arbitrary commands on your system. Think of exposing access to your rTorrent API as equivalent to exposing access to your system's shell. -Before continuing, it's worth mentioning that `rtorrent` methods are very flexible, and powerful, and can be used to execute arbitrary commands on your system. Think of exposing access to your `rtorrent` API as equivalent to exposing access to your system's shell. +You **do not** want your rTorrent XMLRPC API to fall into the wrong hands. -You **do not** want your rtorrent XMLRPC api to fall into the wrong hands. - -There are two ways to expose the xmlrpc endpoint for `rtorrent`: +There are two ways to expose the XMLRPC endpoint for rTorrent: You can: -✔️ Configure rtorrent to expose the endpoint to a local unix domain socket, for example `~/.local/rtorrent.sock`. +✔️ Configure rTorrent to expose the endpoint to a local unix domain socket, for example `~/.local/rtorrent.sock`. * You will then use a reverse proxy to publish this socket under some host, __with some authentication mechanism set up__. * ✔️ This is considered **more secure** as local unix domain sockets can be assigned unix file read/write modes that can control which users on the system can & cannot access the API. -❌ Configure rtorrent to expose this socket on some address + port, eg `localhost:5000`/`127.0.0.1:5000` - * :bangbang: **Never** bind the SCGI port to anything *but* 127.0.0.1. Anyone who can send rtorrent xmlrpc commands does have the ability to execute code with the privileges of the user running rtorrent. +❌ Configure rTorrent to expose this socket on some address + port, eg `localhost:5000`/`127.0.0.1:5000` + * :bangbang: **Never** bind the SCGI port to anything *but* 127.0.0.1. Anyone who can send rTorrent XMLRPC commands does have the ability to execute code with the privileges of the user running rTorrent. * ⚠️ Even if you do bind this to localhost, publishing directly to a port is still **less secure** than publishing to a unix domain socket & proxying that - * Directly publishing to localhost is less secure because *any user* on the localhost can access `localhost:5000` and use the API, thereby getting access to everything that the user that runs `rtorrent` has access to. + * Directly publishing to localhost is less secure because *any user* on the localhost can access `localhost:5000` and use the API, thereby getting access to everything that the user that runs rTorrent has access to. * ❌ In addition, you will most likely need to configure a reverse proxy to help publish your endpoint, so the convenience is not great. -This warning being said- Any time in this guide that you see `rtorrent` configured to publish to a local unix socket, and a reverse proxy configured to forward that, a similar effect could be achieved by directly publishing to a port, and the reverse proxy exposing that endpoint. -In `rtorrent.rc`, the **deprecated** method `network.scgi.open_port = 127.0.0.1:5000` may be used to publish directly to a port. +This warning being said- Any time in this guide that you see rTorrent configured to publish to a local unix socket, and a reverse proxy configured to forward that, a similar effect could be achieved by directly publishing to a port, and the reverse proxy exposing that endpoint. +In `rtorrent.rc`, the method `network.scgi.open_port = 127.0.0.1:5000` may be used to publish directly to a port. Without much further ado -## Configuring rtorrent and your webserver +## Configuring rTorrent and your webserver What you need: -* rtorrent compiled / configured with the `--with-xmlrpc-c` flag +* rTorrent compiled / configured with the `--with-xmlrpc-c` flag * `scgi` for your reverse proxy: * http://python.ca/scgi/ for Apache 2.2, * mod_proxy_scgi enabled for Apache 2.4, @@ -44,16 +43,16 @@ What you need: You will be: -* Publishing the `xmlrpc` endpoint to a socker on the local filesytem, & setting user permissions on this socket to to restrict unauthorized user accounts on your computer from accessing it. +* Publishing the `xmlrpc` endpoint to a socket on the local filesystem, & setting user permissions on this socket to to restrict unauthorized user accounts on your computer from accessing it. * Proxying this socket to a network address + port, **with some kind of authentication set up on your reverse proxy** -### rtorrent configuration (rtorrent.rc) +### rTorrent configuration (rtorrent.rc) ```ini network.scgi.open_local = /home/user/rtorrent/rpc.socket # Set correct access rights to the socket file ----------+ -# so both rtorrent & your reverse proxy can performed | +# so both rTorrent & your reverse proxy can performed | # read-write operations | # but most users on the system can not v schedule2 = scgi_permission,0,0,"execute.nothrow=chmod,\"g+w,o=\",/home/user/rtorrent/rpc.socket" @@ -63,12 +62,12 @@ schedule2 = scgi_permission,0,0,"execute.nothrow=chmod,\"g+w,o=\",/home/user/rto **httpd.conf (2.2)**: ```ini -SCGIMount /RPC2 socket_path +SCGIMount /RPC2 socket_path ``` **httpd.conf (2.4)**: ```ini ProxyPass /RPC2 scgi://localhost:9999 # SCGI network port -ProxyPass /RPC2 unix:///home/user/rtorrent/rpc.socket|scgi://localhost/ # SCGI unix socket (2.4.7+) +ProxyPass /RPC2 unix:///home/user/rtorrent/rpc.socket|scgi://localhost/ # SCGI Unix socket (2.4.7+) ``` ### Lighttpd: @@ -82,7 +81,7 @@ scgi.server = ( ( "socket" => "/home/user/rtorrent/rpc.socket", "check-local" => "disable", - "disable-time" => 0, # don't disable scgi if connection fails + "disable-time" => 0, # don't disable SCGI if connection fails ) # YOU MUST ADD SOME KIND OF AUTH ) @@ -91,7 +90,7 @@ scgi.server = ( ### Nginx: -*Recent version of nginx support scgi by default* +*Recent versions of nginx support SCGI by default* **nginx.conf**: @@ -116,7 +115,7 @@ server { } ``` -Do not forget, that on http://localhost:8008/RPC2 you will not see anything (through in rtorrent.error_log you will see something as `upstream prematurely closed connection while reading response header from upstream, client: 192.168.93.104, server: ngnix-rtorrent, request: "GET /RPC2 HTTP/1.1", upstream: "scgi://127.0.0.1:5000", host: "192.168.93.242:8008"`. It is xmlrpc, not web service. You can test it by xmlrpc (see later)) +Do not forget, that on http://localhost:8008/RPC2 you will not see anything (through in rtorrent.error_log you will see something as `upstream prematurely closed connection while reading response header from upstream, client: 192.168.93.104, server: nginx-rtorrent, request: "GET /RPC2 HTTP/1.1", upstream: "scgi://127.0.0.1:5000", host: "192.168.93.242:8008"`. It is XMLRPC, not a web service. You can test it with the `xmlrpc` CLI tool (see later)). **SECURITY NOTE**: @@ -128,33 +127,33 @@ It's worth mentioning that most clients do not provide support for authenticatio ## Other notes -If any of your downloads have non-ascii characters in the filenames, you must also set the following in rtorrent.rc to force rtorrent to use the UTF-8 encoding. The XMLRPC standard requires UTF-8 replies, and rtorrent presently has no facilities to convert between encodings so it might generate invalid replies otherwise. +If any of your downloads have non-ASCII characters in the filenames, you must also set the following in `rtorrent.rc` to force rTorrent to use the UTF-8 encoding. The XMLRPC standard requires UTF-8 replies, and rTorrent presently has no facilities to convert between encodings so it might generate invalid replies otherwise. ``` encoding.add = UTF-8 ``` -The web server will now route xmlrpc requests to rtorrent, which is listening only on connections from the local machine or on the local socket file. Also make sure the /RPC2 location is properly protected, (as in, has *at least* basic auth enabled, and is secured by SSL) and ~also name it differently to evade attackers probing for vulnerabilities~ (security through obscurity is not security, though this may reduce frequency of attempted exploits) +The web server will now route XMLRPC requests to rTorrent, which is listening only on connections from the local machine or on the local socket file. Also make sure the /RPC2 location is properly protected, (as in, has *at least* basic auth enabled, and is secured by SSL) and ~also name it differently to evade attackers probing for vulnerabilities~ (security through obscurity is not security, though this may reduce frequency of attempted exploits) -You may also use `network.scgi.open_local = /foo/bar` to create a local domain socket, which supports file permissions. Set the rw permissions of the directory the socket will reside in to only allow the necessary processes. This is the recommended way of using XMLRPC with rtorrent, though not all http servers support local domain sockets for scgi. +You may also use `network.scgi.open_local = /foo/bar` to create a local domain socket, which supports file permissions. Set the read/write permissions of the directory the socket will reside in to only allow the necessary processes. This is the recommended way of using XMLRPC with rTorrent, though not all HTTP servers support local domain sockets for SCGI. ## Test and usage -Access the XMLRPC interface using any XMLRPC-capable client. For example, using the xmlrpc utility that comes with xmlrpc-c: +Access the XMLRPC interface using any XMLRPC-capable client. For example, using the `xmlrpc` utility that comes with xmlrpc-c: ``` - > # To list all the xmlrpc methods rtorrent supports. + > # To list all the XMLRPC methods rTorrent supports. > xmlrpc localhost:8008 system.listMethods > # Get max upload rate. - > xmlrpc localhost:8008 get_upload_rate "" + > xmlrpc localhost:8008 throttle.global_up.max_rate "" > # Set upload rate, exact 100000 bytes. - > xmlrpc localhost:8008 set_upload_rate "" i/100000 + > xmlrpc localhost:8008 throttle.global_up.max_rate.set "" i/100000 > # Set upload rate, 100kb. - > xmlrpc localhost:8008 set_upload_rate "" 100k + > xmlrpc localhost:8008 throttle.global_up.max_rate.set "" 100k > # See list of downloads in "main" view > xmlrpc localhost:8008 download_list "" @@ -163,16 +162,16 @@ Access the XMLRPC interface using any XMLRPC-capable client. For example, using > xmlrpc localhost:8008 download_list "" started > # Get uploaded bytes for specific download by info-hash - > xmlrpc localhost:8008 d.get_up_total e66e7012b8346271009110ac38f91bc0ad8ce281 + > xmlrpc localhost:8008 d.up.total e66e7012b8346271009110ac38f91bc0ad8ce281 > # Change the directory for a specific download. - > xmlrpc localhost:8008 d.set_directory 91A2DF0C9288BC4C5D03EC8D8C26B4CF95A4DBEF foo/bar/ + > xmlrpc localhost:8008 d.directory.set 91A2DF0C9288BC4C5D03EC8D8C26B4CF95A4DBEF foo/bar/ > # Size of the first file in a specific download. - > xmlrpc localhost:8008 f.get_size_bytes 91A2DF0C9288BC4C5D03EC8D8C26B4CF95A4DBEF:f0 + > xmlrpc localhost:8008 f.size_bytes 91A2DF0C9288BC4C5D03EC8D8C26B4CF95A4DBEF:f0 ``` -It supports both single strings akin to what the option file accepts, and proper xmlrpc integer, string and lists. +It supports both single strings akin to what the option file accepts, and proper XMLRPC integer, string and lists. See the man page and the rtorrent/src/command_* source files for more details on what parameters some of the commands take.