Package: guix-patches;
Reported by: Thomas Danckaert <post <at> thomasdanckaert.be>
Date: Tue, 14 Mar 2017 19:54:02 UTC
Severity: normal
Tags: patch
Done: Thomas Danckaert <post <at> thomasdanckaert.be>
Bug is archived. No further changes may be made.
View this message in rfc822 format
From: Thomas Danckaert <post <at> thomasdanckaert.be> To: 26099 <at> debbugs.gnu.org Subject: bug#26099: [PATCH] services: Add inetd-service-type. Date: Mon, 20 Mar 2017 22:11:55 +0100 (CET)
[Message part 1 (text/plain, inline)]
Hi! Thanks for the review. I've attached an improved version of the patch. Overview of what was changed: - some coding style changes as requested. - added an <inetd-configuration> type, which consists of a list and an optional "program" field, a file-like expression, default to (file-append inetutils "libexec/inetd"). I did it like this instead of adding a package field, because some packages put the inetd executable in a ".../bin" directory, others use ”.../sbin", en inetutils uses ".../libexec". - <inetd-entry> arguments field is now a list of strings/file-like objects. It's much more useful like this! - added a test (new file tests/networking.scm, I stole a lot from the nginx-test code, without fully understanding the details, but it works!). The test uses the built-in echo, and a fantasy version of a dict service, implemented as a bash script :-) - added documentation. Some questions: - AFAIU, there is currently no easy way to extend /etc/services with custom services in the os configuration? Should we provide something like "sudoers-file" for services? - Does it make sense to provide more defaults in the inetd-entry? e.g. make user default to "root", make "nowait" the default, set a default socket type and protocol? I've always used inetd for a very specific purpose, and have no idea what is the typical way people use it. - Should we provide configuration settings for all inetd command line arguments? inetutils' inetd provides --environment, --pidfile, --resolve and --rate options. I think other inetd's have still other arguments, so if we want the service to work with many different inetd implementations, providing the option to specifiy an arbitrary command line in the forkexec-constructor might be good? - Other inetd packages might (optionally) have slightly different configuration syntax. e.g. openbsd-inetd (not packaged for Guix atm) provides some extra configuration options in the "wait" field. Perhaps add an “escape hatch” after all? cheers! Thomas
[0001-services-Add-inetd-service-type.patch (text/x-patch, inline)]
From 7df61f7d442cb5f97d84ece5cc427a13c678a3c3 Mon Sep 17 00:00:00 2001 From: Thomas Danckaert <post <at> thomasdanckaert.be> Date: Tue, 14 Mar 2017 18:12:34 +0100 Subject: [PATCH] services: Add inetd-service-type. * gnu/services/networking.scm (<inetd-configuration>, <inetd-entry>): New record types. (inetd-config-file, inetd-shepherd-service): New procedures. (inetd-service-type): New variable. * doc/guix.texi (Networking Services): Document it. * gnu/tests/networking.scm: New file. * gnu/local.mk: Add it. --- doc/guix.texi | 93 +++++++++++++++++++++++++++- gnu/local.mk | 1 + gnu/services/networking.scm | 89 +++++++++++++++++++++++++++ gnu/tests/networking.scm | 147 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 329 insertions(+), 1 deletion(-) create mode 100644 gnu/tests/networking.scm diff --git a/doc/guix.texi b/doc/guix.texi index f4cc207e7..40eb30748 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -33,7 +33,8 @@ Copyright @copyright{} 2016 Alex ter Weele@* Copyright @copyright{} 2017 Clément Lassieur@* Copyright @copyright{} 2017 Mathieu Othacehe@* Copyright @copyright{} 2017 Federico Beffa@* -Copyright @copyright{} 2017 Carlo Zancanaro +Copyright @copyright{} 2017 Carlo Zancanaro@* +Copyright @copyright{} 2017 Thomas Danckaert Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or @@ -9255,6 +9256,96 @@ make an initial adjustment of more than 1,000 seconds. List of host names used as the default NTP servers. @end defvr +@cindex inetd +@deffn {Scheme variable} inetd-service-type +This service runs the inetd daemon. inetd listens for connections on +internet sockets, and can run various server programs to service +requests on those sockets. + +The value of this service is an @code{inetd-configuration} object. The +following example configures the inetd daemon to provide the built-in +@code{echo} service, as well as an smtp service forwards smtp traffic +over ssh to a server @code{smtp-server} behind a gateway +@code{hostname}: + +@example +(service + inetd-service-type + (inetd-configuration + (entries (list + (inetd-entry + (name "echo") + (socket-type 'stream) + (protocol "tcp") + (wait? #f) + (user "root")) + (inetd-entry + (node "127.0.0.1") + (name "smtp") + (socket-type 'stream) + (protocol "tcp") + (wait? #f) + (user "root") + (program (file-append openssh "/bin/ssh")) + (arguments + '("ssh" "-qT" "-i" "/path/to/ssh_key" + "-W" "smtp-server:25" "user@@hostname"))))) +@end example + +See below for more details about @code{inetd-configuration}. +@end deffn + +@deftp {Data Type} inetd-configuration +Data type representing the configuration of inetd. + +@table @asis +@item @code{program} (default: @code{(file-append inetutils "/libexec/inetd")}) +The inetd executable to use. + +@item @code{entries} (default: @code{'()}) +A list of inetd service entries. Each entry should be created by the +@code{inetd-entry} constructor. +@end table +@end deftp + +@deftp {Data Type} inetd-entry +Data type representing an entry in the inetd configuration. Each entry +corresponds to a socket where inetd will listen for requests. + +@table @asis +@item @code{node} (default: @code{#f}) +Optional string, a comma-separated list of local addresses inetd should +use when listening for this service. @xref{Configuration file,,, +inetutils, GNU Inetutils} for a complete description of all options. +@item @code{name} +A string, the name must correspond to an entry in @code{/etc/services}. +@item @code{socket-type} +One of @code{'stream}, @code{'dgram}, @code{'raw}, @code{'rdm} or +@code{'seqpacket}. +@item @code{protocol} +A string, must correspond to an entry in @code{/etc/protocols}. +@item @code{wait?} (default: @code{#t}) +Whether inetd should wait for the server to exit before listening to new +service requests. +@item @code{user} +A string containing the user (and, optionally, group) name of the user +as whom the server should run. The group name can be specified in a +suffix, separated by a colon or period, i.e. @code{"user"}, +@code{"user:group"} or @code{"user.group"}. +@item @code{program} (default: @code{"internal"}) +The server program which will serve the requests, or @code{"internal"} +if inetd should use a built-in service. +@item @code{arguments} (default: @code{'()}) +A list strings or file-like objects, which are the server program's +arguments, starting with the zeroth argument, i.e. the name of the +program itself. For inetd's internal services, this entry must be +@code{'()} or @code{'("internal")}. +@end table + +@xref{Configuration file,,, inetutils, GNU Inetutils} for a more +detailed discussion of each configuration field. +@end deftp + @cindex Tor @deffn {Scheme Procedure} tor-service [@var{config-file}] [#:tor @var{tor}] Return a service to run the @uref{https://torproject.org, Tor} anonymous diff --git a/gnu/local.mk b/gnu/local.mk index c1b076a5f..1fb1cb9d9 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -461,6 +461,7 @@ GNU_SYSTEM_MODULES = \ %D%/tests/install.scm \ %D%/tests/mail.scm \ %D%/tests/messaging.scm \ + %D%/tests/networking.scm \ %D%/tests/ssh.scm \ %D%/tests/web.scm diff --git a/gnu/services/networking.scm b/gnu/services/networking.scm index 18bce2a2b..553269359 100644 --- a/gnu/services/networking.scm +++ b/gnu/services/networking.scm @@ -4,6 +4,7 @@ ;;; Copyright © 2016 Efraim Flashner <efraim <at> flashner.co.il> ;;; Copyright © 2016 John Darrington <jmd <at> gnu.org> ;;; Copyright © 2017 Clément Lassieur <clement <at> lassieur.org> +;;; Copyright © 2017 Thomas Danckaert <post <at> thomasdanckaert.be> ;;; ;;; This file is part of GNU Guix. ;;; @@ -61,6 +62,10 @@ ntp-service ntp-service-type + inetd-configuration + inetd-entry + inetd-service-type + tor-configuration tor-configuration? tor-hidden-service @@ -429,6 +434,90 @@ make an initial adjustment of more than 1,000 seconds." ;;; +;;; Inetd. +;;; + +(define-record-type* <inetd-configuration> inetd-configuration + make-inetd-configuration + inetd-configuration? + (program inetd-configuration-program ;file-like + (default (file-append inetutils "/libexec/inetd"))) + (entries inetd-configuration-entries ;list of <inetd-entry> + (default '()))) + +(define-record-type* <inetd-entry> inetd-entry make-inetd-entry + inetd-entry? + (node inetd-entry-node ;string or #f + (default #f)) + (name inetd-entry-name) ;string, from /etc/services + + (socket-type inetd-entry-socket-type) ;stream | dgram | raw | + ;rdm | seqpacket + (protocol inetd-entry-protocol) ;string, from /etc/protocols + + (wait? inetd-entry-wait? ;Boolean + (default #t)) + (user inetd-entry-user) ;string + + (program inetd-entry-program ;string or file-like object + (default "internal")) + (arguments inetd-entry-arguments ;list of strings or file-like objects + (default '()))) + +(define (inetd-config-file entries) + (apply mixed-text-file "inetd.conf" + (map + (lambda (entry) + (let* ((node (inetd-entry-node entry)) + (name (inetd-entry-name entry)) + (socket + (if node (string-append node ":" name) name)) + (type + (match (inetd-entry-socket-type entry) + ((or 'stream 'dgram 'raw 'rdm 'seqpacket) + (symbol->string (inetd-entry-socket-type entry))))) + (protocol (inetd-entry-protocol entry)) + (wait (if (inetd-entry-wait? entry) "wait" "nowait")) + (user (inetd-entry-user entry)) + (program (inetd-entry-program entry)) + (args (inetd-entry-arguments entry))) + #~(string-append + (string-join + (list #$@(list socket type protocol wait user program) #$@args) + " ") "\n"))) + entries))) + +(define inetd-shepherd-service + (match-lambda + (($ <inetd-configuration> program ()) '()) ; empty list of entries -> do nothing + (($ <inetd-configuration> program entries) + (list + (shepherd-service + (documentation "Run inetd.") + (provision '(inetd)) + (requirement '(user-processes networking syslogd)) + (start #~(make-forkexec-constructor + (list #$program #$(inetd-config-file entries)) + #:pid-file "/var/run/inetd.pid")) + (stop #~(make-kill-destructor))))))) + +(define-public inetd-service-type + (service-type + (name 'inetd) + (extensions + (list (service-extension shepherd-root-service-type + inetd-shepherd-service))) + + ;; The service can be extended with additional lists of entries. + (compose concatenate) + (extend (lambda (config entries) + (inetd-configuration + (inherit config) + (entries (append (inetd-configuration-entries config) + entries))))))) + + +;;; ;;; Tor. ;;; diff --git a/gnu/tests/networking.scm b/gnu/tests/networking.scm new file mode 100644 index 000000000..531231409 --- /dev/null +++ b/gnu/tests/networking.scm @@ -0,0 +1,147 @@ +;;; GNU Guix --- Functional package management for GNU +;;; Copyright © 2017 Thomas Danckaert <post <at> thomasdanckaert.be> +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. + +(define-module (gnu tests networking) + #:use-module (gnu tests) + #:use-module (gnu system) + #:use-module (gnu system grub) + #:use-module (gnu system file-systems) + #:use-module (gnu system shadow) + #:use-module (gnu system vm) + #:use-module (gnu services) + #:use-module (gnu services base) + #:use-module (gnu services networking) + #:use-module (guix gexp) + #:use-module (guix store) + #:use-module (guix monads) + #:use-module (gnu packages bash) + #:export (%test-inetd)) + +(define %inetd-os + ;; Operating system with 2 inetd services. + (operating-system + (host-name "komputilo") + (timezone "Europe/Brussels") + (locale "en_US.utf8") + + (bootloader (grub-configuration (device "/dev/sdX"))) + (file-systems %base-file-systems) + (firmware '()) + (users %base-user-accounts) + (services (cons* (dhcp-client-service) + (service inetd-service-type + (inetd-configuration + (entries (list + (inetd-entry + (name "echo") + (socket-type 'stream) + (protocol "tcp") + (wait? #f) + (user "root")) + (inetd-entry + (name "dict") + (socket-type 'stream) + (protocol "tcp") + (wait? #f) + (user "root") + (program (file-append bash + "/bin/bash")) + (arguments + (list "bash" (plain-file "my-dict.sh" "\ +while read line +do + if [[ $line =~ ^DEFINE\\ (.*)$ ]] + then + case ${BASH_REMATCH[1]} in + Guix) + echo GNU Guix is a package management tool for the GNU system. + ;; + G-expression) + echo Like an S-expression but with a G. + ;; + *) + echo NO DEFINITION FOUND + ;; + esac + else + echo ERROR + fi +done" )))))))) + %base-services)))) + +(define* (run-inetd-test) + "Run tests in %INETD-OS, where the inetd service provides an echo service on +port 7, and a dict service on port 2628." + (mlet* %store-monad ((os -> (marionette-operating-system %inetd-os)) + (command (system-qemu-image/shared-store-script + os #:graphic? #f))) + (define test + (with-imported-modules '((gnu build marionette)) + #~(begin + (use-modules (ice-9 rdelim) + (srfi srfi-64) + (gnu build marionette)) + (define marionette + ;; Forward guest ports 7 and 2628 to host ports 8007 and 8628. + (make-marionette (list #$command "-net" + (string-append + "user" + ",hostfwd=tcp::8007-:7" + ",hostfwd=tcp::8628-:2628")))) + + (mkdir #$output) + (chdir #$output) + + (test-begin "inetd") + + ;; Make sure the PID file is created. + (test-assert "PID file" + (marionette-eval + '(file-exists? "/var/run/inetd.pid") + marionette)) + + ;; Test the echo service. + (test-equal "echo response" + "Hello, Guix!" + (let ((echo (socket PF_INET SOCK_STREAM 0)) + (addr (make-socket-address AF_INET INADDR_LOOPBACK 8007))) + (begin + (connect echo addr) + (display "Hello, Guix!\n" echo) + (read-line echo)))) ; TODO ensure socket is closed? + + ;; Test the dict service + (test-equal "dict response" + "GNU Guix is a package management tool for the GNU system." + (let ((dict (socket PF_INET SOCK_STREAM 0)) + (addr (make-socket-address AF_INET INADDR_LOOPBACK 8628))) + (begin + (connect dict addr) + (display "DEFINE Guix\n" dict) + (read-line dict)))) + + (test-end) + (exit (= (test-runner-fail-count (test-runner-current)) 0))))) + + (gexp->derivation "inetd-test" test))) + +(define %test-inetd + (system-test + (name "inetd") + (description "Connect to a host with an INETD server.") + (value (run-inetd-test)))) -- 2.11.1
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.