gnu: services: Add iptables service.

* gnu/services/networking.scm (<iptables-configuration>): New record type.
(iptables-service-type): New variable.
* gnu/tests/networking.scm (run-iptables-test): New procedure.
(%test-iptables): New variable.
* doc/guix.texi (Networking Services): Document it.
This commit is contained in:
Arun Isaac 2018-08-17 16:39:07 +05:30
parent 3e63a83c0f
commit 9926b8f809
No known key found for this signature in database
GPG Key ID: 2E25EE8B61802BB3
3 changed files with 231 additions and 2 deletions

View File

@ -11612,6 +11612,54 @@ Thus, it can be instantiated like this:
@end lisp
@end defvr
@cindex iptables
@defvr {Scheme Variable} iptables-service-type
This is the service type to set up an iptables configuration. iptables is a
packet filtering framework supported by the Linux kernel. This service
supports configuring iptables for both IPv4 and IPv6. A simple example
configuration rejecting all incoming connections except those to the ssh port
22 is shown below.
@lisp
(service iptables-service-type
(iptables-configuration
(ipv4-rules (plain-file "iptables.rules" "*filter
:INPUT ACCEPT
:FORWARD ACCEPT
:OUTPUT ACCEPT
-A INPUT -p tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-port-unreachable
COMMIT
"))
(ipv6-rules (plain-file "ip6tables.rules" "*filter
:INPUT ACCEPT
:FORWARD ACCEPT
:OUTPUT ACCEPT
-A INPUT -p tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp6-port-unreachable
COMMIT
"))))
@end lisp
@end defvr
@deftp {Data Type} iptables-configuration
The data type representing the configuration of iptables.
@table @asis
@item @code{iptables} (default: @code{iptables})
The iptables package that provides @code{iptables-restore} and
@code{ip6tables-restore}.
@item @code{ipv4-rules} (default: @code{%iptables-accept-all-rules})
The iptables rules to use. It will be passed to @code{iptables-restore}.
This may be any ``file-like'' object (@pxref{G-Expressions, file-like
objects}).
@item @code{ipv6-rules} (default: @code{%iptables-accept-all-rules})
The ip6tables rules to use. It will be passed to @code{ip6tables-restore}.
This may be any ``file-like'' object (@pxref{G-Expressions, file-like
objects}).
@end table
@end deftp
@cindex NTP
@cindex real time clock
@deffn {Scheme Procedure} ntp-service [#:ntp @var{ntp}] @

View File

@ -8,6 +8,7 @@
;;; Copyright © 2017 Marius Bakke <mbakke@fastmail.com>
;;; Copyright © 2018 Tobias Geerinckx-Rice <me@tobias.gr>
;;; Copyright © 2018 Chris Marusich <cmmarusich@gmail.com>
;;; Copyright © 2018 Arun Isaac <arunisaac@systemreboot.net>
;;;
;;; This file is part of GNU Guix.
;;;
@ -103,7 +104,14 @@
wpa-supplicant-service-type
openvswitch-service-type
openvswitch-configuration))
openvswitch-configuration
iptables-configuration
iptables-configuration?
iptables-configuration-iptables
iptables-configuration-ipv4-rules
iptables-configuration-ipv6-rules
iptables-service-type))
;;; Commentary:
;;;
@ -1108,4 +1116,50 @@ networking."))))
switch designed to enable massive network automation through programmatic
extension.")))
;;;
;;; iptables
;;;
(define %iptables-accept-all-rules
(plain-file "iptables-accept-all.rules"
"*filter
:INPUT ACCEPT
:FORWARD ACCEPT
:OUTPUT ACCEPT
COMMIT
"))
(define-record-type* <iptables-configuration>
iptables-configuration make-iptables-configuration iptables-configuration?
(iptables iptables-configuration-iptables
(default iptables))
(ipv4-rules iptables-configuration-ipv4-rules
(default %iptables-accept-all-rules))
(ipv6-rules iptables-configuration-ipv6-rules
(default %iptables-accept-all-rules)))
(define iptables-shepherd-service
(match-lambda
(($ <iptables-configuration> iptables ipv4-rules ipv6-rules)
(let ((iptables-restore (file-append iptables "/sbin/iptables-restore"))
(ip6tables-restore (file-append iptables "/sbin/ip6tables-restore")))
(shepherd-service
(documentation "Packet filtering framework")
(provision '(iptables))
(start #~(lambda _
(invoke #$iptables-restore #$ipv4-rules)
(invoke #$ip6tables-restore #$ipv6-rules)))
(stop #~(lambda _
(invoke #$iptables-restore #$%iptables-accept-all-rules)
(invoke #$ip6tables-restore #$%iptables-accept-all-rules))))))))
(define iptables-service-type
(service-type
(name 'iptables)
(description
"Run @command{iptables-restore}, setting up the specified rules.")
(extensions
(list (service-extension shepherd-root-service-type
(compose list iptables-shepherd-service))))))
;;; networking.scm ends here

View File

@ -2,6 +2,7 @@
;;; Copyright © 2017 Thomas Danckaert <post@thomasdanckaert.be>
;;; Copyright © 2017 Marius Bakke <mbakke@fastmail.com>
;;; Copyright © 2018 Chris Marusich <cmmarusich@gmail.com>
;;; Copyright © 2018 Arun Isaac <arunisaac@systemreboot.net>
;;;
;;; This file is part of GNU Guix.
;;;
@ -29,9 +30,11 @@
#:use-module (guix store)
#:use-module (guix monads)
#:use-module (gnu packages bash)
#:use-module (gnu packages linux)
#:use-module (gnu packages networking)
#:use-module (gnu services shepherd)
#:export (%test-inetd %test-openvswitch %test-dhcpd %test-tor))
#:use-module (ice-9 match)
#:export (%test-inetd %test-openvswitch %test-dhcpd %test-tor %test-iptables))
(define %inetd-os
;; Operating system with 2 inetd services.
@ -434,3 +437,127 @@ subnet 192.168.1.0 netmask 255.255.255.0 {
(name "tor")
(description "Test a running Tor daemon configuration.")
(value (run-tor-test))))
(define* (run-iptables-test)
"Run tests of 'iptables-service-type'."
(define iptables-rules
"*filter
:INPUT ACCEPT
:FORWARD ACCEPT
:OUTPUT ACCEPT
-A INPUT -p tcp -m tcp --dport 7 -j REJECT --reject-with icmp-port-unreachable
COMMIT
")
(define ip6tables-rules
"*filter
:INPUT ACCEPT
:FORWARD ACCEPT
:OUTPUT ACCEPT
-A INPUT -p tcp -m tcp --dport 7 -j REJECT --reject-with icmp6-port-unreachable
COMMIT
")
(define inetd-echo-port 7)
(define os
(marionette-operating-system
(simple-operating-system
(dhcp-client-service)
(service inetd-service-type
(inetd-configuration
(entries (list
(inetd-entry
(name "echo")
(socket-type 'stream)
(protocol "tcp")
(wait? #f)
(user "root"))))))
(service iptables-service-type
(iptables-configuration
(ipv4-rules (plain-file "iptables.rules" iptables-rules))
(ipv6-rules (plain-file "ip6tables.rules" ip6tables-rules)))))
#:imported-modules '((gnu services herd))
#:requirements '(inetd iptables)))
(define test
(with-imported-modules '((gnu build marionette))
#~(begin
(use-modules (srfi srfi-64)
(gnu build marionette))
(define marionette
(make-marionette (list #$(virtual-machine os))))
(define (dump-iptables iptables-save marionette)
(marionette-eval
`(begin
(use-modules (ice-9 popen)
(ice-9 rdelim)
(ice-9 regex))
(call-with-output-string
(lambda (out)
(call-with-port
(open-pipe* OPEN_READ ,iptables-save)
(lambda (in)
(let loop ((line (read-line in)))
;; iptables-save does not output rules in the exact
;; same format we loaded using iptables-restore. It
;; adds comments, packet counters, etc. We remove
;; these additions.
(unless (eof-object? line)
(cond
;; Remove comments
((string-match "^#" line) #t)
;; Remove packet counters
((string-match "^:([A-Z]*) ([A-Z]*) .*" line)
=> (lambda (match-record)
(format out ":~a ~a~%"
(match:substring match-record 1)
(match:substring match-record 2))))
;; Pass other lines without modification
(else (display line out)
(newline out)))
(loop (read-line in)))))))))
marionette))
(mkdir #$output)
(chdir #$output)
(test-begin "iptables")
(test-equal "iptables-save dumps the same rules that were loaded"
(dump-iptables #$(file-append iptables "/sbin/iptables-save")
marionette)
#$iptables-rules)
(test-equal "ip6tables-save dumps the same rules that were loaded"
(dump-iptables #$(file-append iptables "/sbin/ip6tables-save")
marionette)
#$ip6tables-rules)
(test-error "iptables firewall blocks access to inetd echo service"
'misc-error
(wait-for-tcp-port inetd-echo-port marionette #:timeout 5))
;; TODO: This test freezes up at the login prompt without any
;; relevant messages on the console. Perhaps it is waiting for some
;; timeout. Find and fix this issue.
;; (test-assert "inetd echo service is accessible after iptables firewall is stopped"
;; (begin
;; (marionette-eval
;; '(begin
;; (use-modules (gnu services herd))
;; (stop-service 'iptables))
;; marionette)
;; (wait-for-tcp-port inetd-echo-port marionette #:timeout 5)))
(test-end)
(exit (= (test-runner-fail-count (test-runner-current)) 0)))))
(gexp->derivation "iptables" test))
(define %test-iptables
(system-test
(name "iptables")
(description "Test a running iptables daemon.")
(value (run-iptables-test))))