diff mbox series

[bug#70341,v3] services: tor: Add support for pluggable transports.

Message ID 3af678c4310a58373fe1e86b84f75a1d37e02295.1713758319.git.nigko.yerden@gmail.com
State New
Headers show
Series [bug#70341,v3] services: tor: Add support for pluggable transports. | expand

Commit Message

Nigko Yerden April 22, 2024, 3:58 a.m. UTC
Pluggable transports are programs that disguise Tor traffic, which
can be useful in case Tor is censored.  Pluggable transports
cannot be configured by #:config-file file exclusively because Tor
process is run via 'least-authority-wrapper' and cannot have access
to transport plugin, which is a separate executable (Bug#70302,
Bug#70332).

* doc/guix.texi (Networking Services): Document 'transport-plugin' and
'pluggable-transport' options for 'tor-configuration'.
* gnu/services/networking.scm: Export 'tor-configuration-transport-plugin-path',
'tor-configuration-pluggable-transport'.
(<tor-configuration>): Add 'transport-plugin' and 'pluggable-transport'
fields.
(tor-configuration->torrc)[transport-plugin]: Add content to 'torrc'
computed-file.
(tor-shepherd-service)[transport-plugin]: Add file-system-mapping.

Change-Id: I64e7632729287ea0ab27818bb7322fddae43de48
---
 doc/guix.texi               | 11 ++++++++
 gnu/services/networking.scm | 54 ++++++++++++++++++++++++++-----------
 2 files changed, 49 insertions(+), 16 deletions(-)


base-commit: 9fa34ad616b94ad881b5ca48ef88bd84f877a0e9

Comments

André Batista April 24, 2024, 9:11 p.m. UTC | #1
Hi Nigko,

seg 22 abr 2024 às 08:58:39 (1713787119), nigko.yerden@gmail.com enviou:
> Pluggable transports are programs that disguise Tor traffic, which
> can be useful in case Tor is censored.  Pluggable transports
> cannot be configured by #:config-file file exclusively because Tor
> process is run via 'least-authority-wrapper' and cannot have access
> to transport plugin, which is a separate executable (Bug#70302,
> Bug#70332).

I can confirm that the tor service is unable to fork-exec a
pluggable-transport and the bootstrap process is halted at its start
when trying to use a system wide bridge + PT. However, this patch
does not seem to address the issue at hand, since it just creates
new tor-service-type configuration options that accomplish the
same as configuring on config-file directly. Have you had success
with this? I had no luck.

More comments bellow.

> * doc/guix.texi (Networking Services): Document 'transport-plugin' and
> 'pluggable-transport' options for 'tor-configuration'.
> * gnu/services/networking.scm: Export 'tor-configuration-transport-plugin-path',
> 'tor-configuration-pluggable-transport'.
> (<tor-configuration>): Add 'transport-plugin' and 'pluggable-transport'
> fields.
> (tor-configuration->torrc)[transport-plugin]: Add content to 'torrc'
> computed-file.
> (tor-shepherd-service)[transport-plugin]: Add file-system-mapping.
> 
> Change-Id: I64e7632729287ea0ab27818bb7322fddae43de48
> ---
>  doc/guix.texi               | 11 ++++++++
>  gnu/services/networking.scm | 54 ++++++++++++++++++++++++++-----------
>  2 files changed, 49 insertions(+), 16 deletions(-)
> 
> diff --git a/doc/guix.texi b/doc/guix.texi
> index 65af136e61..eb0837860e 100644
> --- a/doc/guix.texi
> +++ b/doc/guix.texi
> @@ -127,6 +127,7 @@
>  Copyright @copyright{} 2024 Herman Rimm@*
>  Copyright @copyright{} 2024 Matthew Trzcinski@*
>  Copyright @copyright{} 2024 Richard Sent@*
> +Copyright @copyright{} 2024 Nigko Yerden@*
>  
>  Permission is granted to copy, distribute and/or modify this document
>  under the terms of the GNU Free Documentation License, Version 1.3 or
> @@ -21849,6 +21850,16 @@ Networking Services
>  @file{/var/run/tor/control-sock}, which will be made writable by members of the
>  @code{tor} group.
>  
> +@item @code{transport-plugin} (default: @code{#f})
> +This must be either @code{#f} or a ``file-like'' object pointing to the
> +pluggable transport plugin executable.  In the latter case the
> +@code{#:config-file} file should contain line(s) configuring
> +one or more bridges.
> +
> +@item @code{pluggable-transport} (default: @code{"obfs4"})
> +A string that specifies the type of the pluggable transport in
> +case @code{#:transport-plugin} is not @code{#f}.
> +
>  @end table
>  @end deftp
>  
> diff --git a/gnu/services/networking.scm b/gnu/services/networking.scm
> index 8e64e529ab..6e535ea8ef 100644
> --- a/gnu/services/networking.scm
> +++ b/gnu/services/networking.scm
> @@ -22,6 +22,7 @@
>  ;;; Copyright © 2023 Declan Tsien <declantsien@riseup.net>
>  ;;; Copyright © 2023 Bruno Victal <mirai@makinata.eu>
>  ;;; Copyright © 2023 muradm <mail@muradm.net>
> +;;; Copyright © 2024 Nigko Yerden <nigko.yerden@gmail.com>
>  ;;;
>  ;;; This file is part of GNU Guix.
>  ;;;
> @@ -159,6 +160,8 @@ (define-module (gnu services networking)
>              tor-configuration-hidden-services
>              tor-configuration-socks-socket-type
>              tor-configuration-control-socket-path
> +            tor-configuration-transport-plugin-path
> +            tor-configuration-pluggable-transport
>              tor-onion-service-configuration
>              tor-onion-service-configuration?
>              tor-onion-service-configuration-name
> @@ -955,7 +958,11 @@ (define-record-type* <tor-configuration>
>    (socks-socket-type tor-configuration-socks-socket-type ; 'tcp or 'unix
>                       (default 'tcp))
>    (control-socket?  tor-configuration-control-socket-path
> -                    (default #f)))
> +                    (default #f))
> +  (transport-plugin tor-configuration-transport-plugin-path
> +                    (default #f))
> +  (pluggable-transport tor-configuration-pluggable-transport
> +                    (default "obfs4")))
>  
>  (define %tor-accounts
>    ;; User account and groups for Tor.
> @@ -988,7 +995,8 @@ (define-configuration/no-serialization tor-onion-service-configuration
>  (define (tor-configuration->torrc config)
>    "Return a 'torrc' file for CONFIG."
>    (match-record config <tor-configuration>
> -    (tor config-file hidden-services socks-socket-type control-socket?)
> +    (tor config-file hidden-services socks-socket-type control-socket?
> +         transport-plugin pluggable-transport)
>      (computed-file
>       "torrc"
>       (with-imported-modules '((guix build utils))
> @@ -1027,6 +1035,13 @@ (define (tor-configuration->torrc config)
>                                      (cons name mapping)))
>                                   hidden-services))
>  
> +               (when #$transport-plugin
> +                 (format port "\
> +UseBridges 1
> +ClientTransportPlugin ~a exec ~a~%"
> +                         #$pluggable-transport
> +                         #$transport-plugin))
> +
>                 (display "\
>  ### End of automatically generated lines.\n\n" port)

Even if it had succeded though, I'm not sure if this is the best
approach to it, since it would break guix system configuration, right?
How would one know beforehand which binary to point to? One would first
need to install the PT and look to its path on store and then link to
it in a new configuration. And then this link would have to be manualy
updated. Am I missing something here?

Finally, next time, try to keep the issue to a single thread. I'm
replying to #70332 and #70302 just for reference, but let's keep to
#70341 going forward.

Cheers!
Nigko Yerden April 25, 2024, 6:08 a.m. UTC | #2
Hi André,

Thank you for the feedback!

> I can confirm that the tor service is unable to fork-exec a 
> pluggable-transport and the bootstrap process is halted at its start 
> when trying to use a system wide bridge + PT. However, this patch 
> does not seem to address the issue at hand, since it just creates new
> tor-service-type configuration options that accomplish the same as
> configuring on config-file directly. Have you had success with this?
> I had no luck.
Yes, I have! This patch not only creates new tor-service-type
configuration options but, which is crucial, adds pluggable transport
(PT) executable, if provided, to #:mappings argument of the
least-authority-wrapper, see 'tor-shepherd-service' chunk. With this
patch Tor process gets access to PT plugin and, if bridges are
configured via config-file field, Tor starts using obfuscated traffic.

> Even if it had succeeded though, I'm not sure if this is the best 
> approach to it, since it would break guix system configuration,
> right?
No, the patch does not break any existing tor-service-type
configuration. If PT is not used, 'transport-plugin' defaults to '#f',
and the Tor works exactly as if there wasn't any patch at all.

> How would one know beforehand which binary to point to? One would
> first need to install the PT and look to its path on store and then
> link to it in a new configuration. And then this link would have to
> be manualy updated. Am I missing something here?
There is much simpler and convenient way of doing this. If users want to 
bring PT into action, they may simply write

(service tor-service-type
	(config-file ".... Bridge obfs4 ...")
	(transport-plugin (file-append PT-PACKAGE "/bin/name-of-executable"))

The PT-PACKAGE does not even have to be present in the list of
'operating-system 'packages field, since Guix will find the reference to
PT-package and install it automatically. The only thing which should be
known beforehand is the "name-of-executable".
For
'go-gitlab-torproject-org-tpo-anti-censorship-pluggable-transports-lyrebird 
package it is "lyrebird", while for 
'go-github-com-operatorfoundation-obfs4 it is "obfs4proxy". It is
unlikely that these names will change with upgrades.

> Finally, next time, try to keep the issue to a single thread. I'm 
> replying to #70332 and #70302 just for reference, but let's keep to 
> #70341 going forward.
Sorry about that! I have tried not to create new bug issue but was
unsuccessful. Perhaps I shouldn't have touched the email heading.

Regards,
Nigko



André Batista wrote:
> Hi Nigko,
> 
> seg 22 abr 2024 às 08:58:39 (1713787119), nigko.yerden@gmail.com
> enviou:
>> Pluggable transports are programs that disguise Tor traffic, which 
>> can be useful in case Tor is censored.  Pluggable transports cannot
>> be configured by #:config-file file exclusively because Tor process
>> is run via 'least-authority-wrapper' and cannot have access to
>> transport plugin, which is a separate executable (Bug#70302, 
>> Bug#70332).
> 
> I can confirm that the tor service is unable to fork-exec a 
> pluggable-transport and the bootstrap process is halted at its start 
> when trying to use a system wide bridge + PT. However, this patch 
> does not seem to address the issue at hand, since it just creates new
> tor-service-type configuration options that accomplish the same as
> configuring on config-file directly. Have you had success with this?
> I had no luck.
> 
> More comments bellow.
> 
>> * doc/guix.texi (Networking Services): Document 'transport-plugin'
>> and 'pluggable-transport' options for 'tor-configuration'. *
>> gnu/services/networking.scm: Export
>> 'tor-configuration-transport-plugin-path', 
>> 'tor-configuration-pluggable-transport'. (<tor-configuration>): Add
>> 'transport-plugin' and 'pluggable-transport' fields. 
>> (tor-configuration->torrc)[transport-plugin]: Add content to
>> 'torrc' computed-file. (tor-shepherd-service)[transport-plugin]:
>> Add file-system-mapping.
>> 
>> Change-Id: I64e7632729287ea0ab27818bb7322fddae43de48 --- 
>> doc/guix.texi               | 11 ++++++++ 
>> gnu/services/networking.scm | 54
>> ++++++++++++++++++++++++++----------- 2 files changed, 49
>> insertions(+), 16 deletions(-)
>> 
>> diff --git a/doc/guix.texi b/doc/guix.texi index
>> 65af136e61..eb0837860e 100644 --- a/doc/guix.texi +++
>> b/doc/guix.texi @@ -127,6 +127,7 @@ Copyright @copyright{} 2024
>> Herman Rimm@* Copyright @copyright{} 2024 Matthew Trzcinski@* 
>> Copyright @copyright{} 2024 Richard Sent@* +Copyright @copyright{}
>> 2024 Nigko Yerden@*
>> 
>> Permission is granted to copy, distribute and/or modify this
>> document under the terms of the GNU Free Documentation License,
>> Version 1.3 or @@ -21849,6 +21850,16 @@ Networking Services 
>> @file{/var/run/tor/control-sock}, which will be made writable by
>> members of the @code{tor} group.
>> 
>> +@item @code{transport-plugin} (default: @code{#f}) +This must be
>> either @code{#f} or a ``file-like'' object pointing to the 
>> +pluggable transport plugin executable.  In the latter case the 
>> +@code{#:config-file} file should contain line(s) configuring +one
>> or more bridges. + +@item @code{pluggable-transport} (default:
>> @code{"obfs4"}) +A string that specifies the type of the pluggable
>> transport in +case @code{#:transport-plugin} is not @code{#f}. + 
>> @end table @end deftp
>> 
>> diff --git a/gnu/services/networking.scm
>> b/gnu/services/networking.scm index 8e64e529ab..6e535ea8ef 100644 
>> --- a/gnu/services/networking.scm +++
>> b/gnu/services/networking.scm @@ -22,6 +22,7 @@ ;;; Copyright ©
>> 2023 Declan Tsien <declantsien@riseup.net> ;;; Copyright © 2023
>> Bruno Victal <mirai@makinata.eu> ;;; Copyright © 2023 muradm
>> <mail@muradm.net> +;;; Copyright © 2024 Nigko Yerden
>> <nigko.yerden@gmail.com> ;;; ;;; This file is part of GNU Guix. 
>> ;;; @@ -159,6 +160,8 @@ (define-module (gnu services networking) 
>> tor-configuration-hidden-services 
>> tor-configuration-socks-socket-type 
>> tor-configuration-control-socket-path +
>> tor-configuration-transport-plugin-path +
>> tor-configuration-pluggable-transport 
>> tor-onion-service-configuration tor-onion-service-configuration? 
>> tor-onion-service-configuration-name @@ -955,7 +958,11 @@
>> (define-record-type* <tor-configuration> (socks-socket-type
>> tor-configuration-socks-socket-type ; 'tcp or 'unix (default
>> 'tcp)) (control-socket?  tor-configuration-control-socket-path -
>> (default #f))) +                    (default #f)) +
>> (transport-plugin tor-configuration-transport-plugin-path +
>> (default #f)) +  (pluggable-transport
>> tor-configuration-pluggable-transport +                    (default
>> "obfs4")))
>> 
>> (define %tor-accounts ;; User account and groups for Tor. @@ -988,7
>> +995,8 @@ (define-configuration/no-serialization
>> tor-onion-service-configuration (define (tor-configuration->torrc
>> config) "Return a 'torrc' file for CONFIG." (match-record config
>> <tor-configuration> -    (tor config-file hidden-services
>> socks-socket-type control-socket?) +    (tor config-file
>> hidden-services socks-socket-type control-socket? +
>> transport-plugin pluggable-transport) (computed-file "torrc" 
>> (with-imported-modules '((guix build utils)) @@ -1027,6 +1035,13 @@
>> (define (tor-configuration->torrc config) (cons name mapping))) 
>> hidden-services))
>> 
>> +               (when #$transport-plugin +                 (format
>> port "\ +UseBridges 1 +ClientTransportPlugin ~a exec ~a~%" +
>> #$pluggable-transport +
>> #$transport-plugin)) + (display "\ ### End of automatically
>> generated lines.\n\n" port)
> 
> Even if it had succeded though, I'm not sure if this is the best 
> approach to it, since it would break guix system configuration,
> right? How would one know beforehand which binary to point to? One
> would first need to install the PT and look to its path on store and
> then link to it in a new configuration. And then this link would have
> to be manualy updated. Am I missing something here?
> 
> Finally, next time, try to keep the issue to a single thread. I'm 
> replying to #70332 and #70302 just for reference, but let's keep to 
> #70341 going forward.
> 
> Cheers!
Nigko Yerden April 30, 2024, 9:13 a.m. UTC | #3
Hi André,

Here is some additional information about the patched tor-service-type 
which reveals:
1) Why it can fail if not properly configured.
2) Its internal workings which I find kind of cool.

First, it is not necessary to use PT-plugin from ready-to-go Guix 
package. It is possible to download PT-plugin source code and compile it 
directly, say, somewhere in $HOME folder. The corresponding 
configuration may look like this

(service tor-service-type
     (config-file (plain-file "torrc" ".... Bridge obfs4 ..."))
     (transport-plugin
        (local-file "/home/..../lyrebird"
                    #:recursive? #t)))

But this will not necessary work. The reason why it can fail is somewhat 
interesting. As we know, the tor process, thanks to the 
'least-authority-wrapper', is run inside a container, which, in 
particular, means it has very limited view of the file system. But 
PT-plugin executable is linked dynamically by default and has its 
dependency libraries inaccessible from within the container. However, if 
PT-plugin is linked statically, the configuration above will work.

Similarly, if PT-plugin is specified as a direct string path to the 
store item like this

(transport-plugin "/gnu/store/..../bin/lyrebird")

it may not work for the same reason.


However, if a file-like object is used instead like this

(transport-plugin (file-append PT-PACKAGE "/bin/lyrebird"))

all the dependencies of PT-PACKAGE are added automatically to the list 
of allowed paths inside the container (this is provided by the call to
'references-file' from inside 'least-authority-wrapper' procedure). As 
for me this means that the suggested patch fits very well to the guix'y 
way of doing things.


Regards,
Nigko
diff mbox series

Patch

diff --git a/doc/guix.texi b/doc/guix.texi
index 65af136e61..eb0837860e 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -127,6 +127,7 @@ 
 Copyright @copyright{} 2024 Herman Rimm@*
 Copyright @copyright{} 2024 Matthew Trzcinski@*
 Copyright @copyright{} 2024 Richard Sent@*
+Copyright @copyright{} 2024 Nigko Yerden@*
 
 Permission is granted to copy, distribute and/or modify this document
 under the terms of the GNU Free Documentation License, Version 1.3 or
@@ -21849,6 +21850,16 @@  Networking Services
 @file{/var/run/tor/control-sock}, which will be made writable by members of the
 @code{tor} group.
 
+@item @code{transport-plugin} (default: @code{#f})
+This must be either @code{#f} or a ``file-like'' object pointing to the
+pluggable transport plugin executable.  In the latter case the
+@code{#:config-file} file should contain line(s) configuring
+one or more bridges.
+
+@item @code{pluggable-transport} (default: @code{"obfs4"})
+A string that specifies the type of the pluggable transport in
+case @code{#:transport-plugin} is not @code{#f}.
+
 @end table
 @end deftp
 
diff --git a/gnu/services/networking.scm b/gnu/services/networking.scm
index 8e64e529ab..6e535ea8ef 100644
--- a/gnu/services/networking.scm
+++ b/gnu/services/networking.scm
@@ -22,6 +22,7 @@ 
 ;;; Copyright © 2023 Declan Tsien <declantsien@riseup.net>
 ;;; Copyright © 2023 Bruno Victal <mirai@makinata.eu>
 ;;; Copyright © 2023 muradm <mail@muradm.net>
+;;; Copyright © 2024 Nigko Yerden <nigko.yerden@gmail.com>
 ;;;
 ;;; This file is part of GNU Guix.
 ;;;
@@ -159,6 +160,8 @@  (define-module (gnu services networking)
             tor-configuration-hidden-services
             tor-configuration-socks-socket-type
             tor-configuration-control-socket-path
+            tor-configuration-transport-plugin-path
+            tor-configuration-pluggable-transport
             tor-onion-service-configuration
             tor-onion-service-configuration?
             tor-onion-service-configuration-name
@@ -955,7 +958,11 @@  (define-record-type* <tor-configuration>
   (socks-socket-type tor-configuration-socks-socket-type ; 'tcp or 'unix
                      (default 'tcp))
   (control-socket?  tor-configuration-control-socket-path
-                    (default #f)))
+                    (default #f))
+  (transport-plugin tor-configuration-transport-plugin-path
+                    (default #f))
+  (pluggable-transport tor-configuration-pluggable-transport
+                    (default "obfs4")))
 
 (define %tor-accounts
   ;; User account and groups for Tor.
@@ -988,7 +995,8 @@  (define-configuration/no-serialization tor-onion-service-configuration
 (define (tor-configuration->torrc config)
   "Return a 'torrc' file for CONFIG."
   (match-record config <tor-configuration>
-    (tor config-file hidden-services socks-socket-type control-socket?)
+    (tor config-file hidden-services socks-socket-type control-socket?
+         transport-plugin pluggable-transport)
     (computed-file
      "torrc"
      (with-imported-modules '((guix build utils))
@@ -1027,6 +1035,13 @@  (define (tor-configuration->torrc config)
                                     (cons name mapping)))
                                  hidden-services))
 
+               (when #$transport-plugin
+                 (format port "\
+UseBridges 1
+ClientTransportPlugin ~a exec ~a~%"
+                         #$pluggable-transport
+                         #$transport-plugin))
+
                (display "\
 ### End of automatically generated lines.\n\n" port)
 
@@ -1039,23 +1054,30 @@  (define (tor-configuration->torrc config)
 (define (tor-shepherd-service config)
   "Return a <shepherd-service> running Tor."
   (let* ((torrc (tor-configuration->torrc config))
+         (transport-plugin-path (tor-configuration-transport-plugin-path config))
          (tor   (least-authority-wrapper
                  (file-append (tor-configuration-tor config) "/bin/tor")
                  #:name "tor"
-                 #:mappings (list (file-system-mapping
-                                   (source "/var/lib/tor")
-                                   (target source)
-                                   (writable? #t))
-                                  (file-system-mapping
-                                   (source "/dev/log") ;for syslog
-                                   (target source))
-                                  (file-system-mapping
-                                   (source "/var/run/tor")
-                                   (target source)
-                                   (writable? #t))
-                                  (file-system-mapping
-                                   (source torrc)
-                                   (target source)))
+                 #:mappings (append
+                             (list (file-system-mapping
+                                    (source "/var/lib/tor")
+                                    (target source)
+                                    (writable? #t))
+                                   (file-system-mapping
+                                    (source "/dev/log") ;for syslog
+                                    (target source))
+                                   (file-system-mapping
+                                    (source "/var/run/tor")
+                                    (target source)
+                                    (writable? #t))
+                                   (file-system-mapping
+                                    (source torrc)
+                                    (target source)))
+                             (if transport-plugin-path
+                                 (list (file-system-mapping
+                                        (source transport-plugin-path)
+                                        (target source)))
+                                 '()))
                  #:namespaces (delq 'net %namespaces))))
     (list (shepherd-service
            (provision '(tor))