diff options
Diffstat (limited to 'nixos/modules/services/networking')
52 files changed, 6797 insertions, 0 deletions
diff --git a/nixos/modules/services/networking/amuled.nix b/nixos/modules/services/networking/amuled.nix new file mode 100644 index 00000000000..8652d0daf4c --- /dev/null +++ b/nixos/modules/services/networking/amuled.nix @@ -0,0 +1,78 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + cfg = config.services.amule; + user = if cfg.user != null then cfg.user else "amule"; +in + +{ + + ###### interface + + options = { + + services.amule = { + + enable = mkOption { + default = false; + description = '' + Whether to run the AMule daemon. You need to manually run "amuled --ec-config" to configure the service for the first time. + ''; + }; + + dataDir = mkOption { + default = ''/home/${user}/''; + description = '' + The directory holding configuration, incoming and temporary files. + ''; + }; + + user = mkOption { + default = null; + description = '' + The user the AMule daemon should run as. + ''; + }; + + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + users.extraUsers = mkIf (cfg.user == null) [ + { name = "amule"; + description = "AMule daemon"; + group = "amule"; + uid = config.ids.uids.amule; + } ]; + + users.extraGroups = mkIf (cfg.user == null) [ + { name = "amule"; + gid = config.ids.gids.amule; + } ]; + + jobs.amuled = + { description = "AMule daemon"; + + startOn = "ip-up"; + + preStart = '' + mkdir -p ${cfg.dataDir} + chown ${user} ${cfg.dataDir} + ''; + + exec = '' + ${pkgs.su}/bin/su -s ${pkgs.stdenv.shell} ${user} \ + -c 'HOME="${cfg.dataDir}" ${pkgs.amuleDaemon}/bin/amuled' + ''; + }; + + }; + +} diff --git a/nixos/modules/services/networking/avahi-daemon.nix b/nixos/modules/services/networking/avahi-daemon.nix new file mode 100644 index 00000000000..3603d677837 --- /dev/null +++ b/nixos/modules/services/networking/avahi-daemon.nix @@ -0,0 +1,144 @@ +# Avahi daemon. +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.avahi; + + inherit (pkgs) avahi; + + avahiDaemonConf = with cfg; pkgs.writeText "avahi-daemon.conf" '' + [server] + ${# Users can set `networking.hostName' to the empty string, when getting + # a host name from DHCP. In that case, let Avahi take whatever the + # current host name is; setting `host-name' to the empty string in + # `avahi-daemon.conf' would be invalid. + if hostName != "" + then "host-name=${hostName}" + else ""} + browse-domains=${concatStringsSep ", " browseDomains} + use-ipv4=${if ipv4 then "yes" else "no"} + use-ipv6=${if ipv6 then "yes" else "no"} + + [wide-area] + enable-wide-area=${if wideArea then "yes" else "no"} + + [publish] + disable-publishing=${if publishing then "no" else "yes"} + ''; + +in + +{ + + ###### interface + + options = { + + services.avahi = { + + enable = mkOption { + default = false; + description = '' + Whether to run the Avahi daemon, which allows Avahi clients + to use Avahi's service discovery facilities and also allows + the local machine to advertise its presence and services + (through the mDNS responder implemented by `avahi-daemon'). + ''; + }; + + hostName = mkOption { + type = types.uniq types.string; + description = ''Host name advertised on the LAN.''; + }; + + browseDomains = mkOption { + default = [ "0pointer.de" "zeroconf.org" ]; + description = '' + List of non-local DNS domains to be browsed. + ''; + }; + + ipv4 = mkOption { + default = true; + description = ''Whether to use IPv4''; + }; + + ipv6 = mkOption { + default = false; + description = ''Whether to use IPv6''; + }; + + wideArea = mkOption { + default = true; + description = ''Whether to enable wide-area service discovery.''; + }; + + publishing = mkOption { + default = true; + description = ''Whether to allow publishing.''; + }; + + nssmdns = mkOption { + default = false; + description = '' + Whether to enable the mDNS NSS (Name Service Switch) plug-in. + Enabling it allows applications to resolve names in the `.local' + domain by transparently querying the Avahi daemon. + ''; + }; + + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + services.avahi.hostName = mkDefault config.networking.hostName; + + users.extraUsers = singleton + { name = "avahi"; + uid = config.ids.uids.avahi; + description = "`avahi-daemon' privilege separation user"; + home = "/var/empty"; + }; + + users.extraGroups = singleton + { name = "avahi"; + gid = config.ids.gids.avahi; + }; + + system.nssModules = optional cfg.nssmdns pkgs.nssmdns; + + environment.systemPackages = [ avahi ]; + + jobs.avahi_daemon = + { name = "avahi-daemon"; + + startOn = "ip-up"; + + script = + '' + export PATH="${avahi}/bin:${avahi}/sbin:$PATH" + + # Make NSS modules visible so that `avahi_nss_support ()' can + # return a sensible value. + export LD_LIBRARY_PATH="${config.system.nssModules.path}" + + mkdir -p /var/run/avahi-daemon + + exec ${avahi}/sbin/avahi-daemon --syslog -f "${avahiDaemonConf}" + ''; + }; + + services.dbus.enable = true; + services.dbus.packages = [avahi]; + + }; + +} diff --git a/nixos/modules/services/networking/bind.nix b/nixos/modules/services/networking/bind.nix new file mode 100644 index 00000000000..765dc014dcb --- /dev/null +++ b/nixos/modules/services/networking/bind.nix @@ -0,0 +1,152 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.bind; + + bindUser = "named"; + + confFile = pkgs.writeText "named.conf" + '' + acl cachenetworks { ${concatMapStrings (entry: " ${entry}; ") cfg.cacheNetworks} }; + acl badnetworks { ${concatMapStrings (entry: " ${entry}; ") cfg.blockedNetworks} }; + + options { + listen-on {any;}; + listen-on-v6 {any;}; + allow-query { cachenetworks; }; + blackhole { badnetworks; }; + forward first; + forwarders { ${concatMapStrings (entry: " ${entry}; ") cfg.forwarders} }; + directory "/var/run/named"; + pid-file "/var/run/named/named.pid"; + }; + + ${ concatMapStrings + ({ name, file, master ? true, slaves ? [], masters ? [] }: + '' + zone "${name}" { + type ${if master then "master" else "slave"}; + file "${file}"; + ${ if master then + '' + allow-transfer { + ${concatMapStrings (ip: "${ip};\n") slaves} + }; + '' + else + '' + masters { + ${concatMapStrings (ip: "${ip};\n") masters} + }; + '' + } + allow-query { any; }; + }; + '') + cfg.zones } + ''; + +in + +{ + + ###### interface + + options = { + + services.bind = { + + enable = mkOption { + default = false; + description = " + Whether to enable BIND domain name server. + "; + }; + + cacheNetworks = mkOption { + default = ["127.0.0.0/24"]; + description = " + What networks are allowed to use us as a resolver. + "; + }; + + blockedNetworks = mkOption { + default = []; + description = " + What networks are just blocked. + "; + }; + + ipv4Only = mkOption { + default = false; + description = " + Only use ipv4, even if the host supports ipv6. + "; + }; + + forwarders = mkOption { + default = config.networking.nameservers; + description = " + List of servers we should forward requests to. + "; + }; + + zones = mkOption { + default = []; + description = " + List of zones we claim authority over. + master=false means slave server; slaves means addresses + who may request zone transfer. + "; + example = [{ + name = "example.com"; + master = false; + file = "/var/dns/example.com"; + masters = ["192.168.0.1"]; + slaves = []; + }]; + }; + + configFile = mkOption { + default = confFile; + description = " + Overridable config file to use for named. By default, that + generated by nixos. + "; + }; + + }; + + }; + + + ###### implementation + + config = mkIf config.services.bind.enable { + + users.extraUsers = singleton + { name = bindUser; + uid = config.ids.uids.bind; + description = "BIND daemon user"; + }; + + jobs.bind = + { description = "BIND name server job"; + + startOn = "started network-interfaces"; + + preStart = + '' + ${pkgs.coreutils}/bin/mkdir -p /var/run/named + chown ${bindUser} /var/run/named + ''; + + exec = "${pkgs.bind}/sbin/named -u ${bindUser} ${optionalString cfg.ipv4Only "-4"} -c ${cfg.configFile} -f"; + }; + + }; + +} diff --git a/nixos/modules/services/networking/bitlbee.nix b/nixos/modules/services/networking/bitlbee.nix new file mode 100644 index 00000000000..82e875f5aae --- /dev/null +++ b/nixos/modules/services/networking/bitlbee.nix @@ -0,0 +1,123 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.bitlbee; + bitlbeeUid = config.ids.uids.bitlbee; + + authModeCheck = v: + v == "Open" || + v == "Closed" || + v == "Registered"; + + bitlbeeConfig = pkgs.writeText "bitlbee.conf" + '' + [settings] + RunMode = Daemon + User = bitlbee + ConfigDir = /var/lib/bitlbee + DaemonInterface = ${cfg.interface} + DaemonPort = ${toString cfg.portNumber} + AuthMode = ${cfg.authMode} + ${cfg.extraSettings} + + [defaults] + ${cfg.extraDefaults} + ''; + +in + +{ + + ###### interface + + options = { + + services.bitlbee = { + + enable = mkOption { + default = false; + description = '' + Whether to run the BitlBee IRC to other chat network gateway. + Running it allows you to access the MSN, Jabber, Yahoo! and ICQ chat + networks via an IRC client. + ''; + }; + + interface = mkOption { + default = "127.0.0.1"; + description = '' + The interface the BitlBee deamon will be listening to. If `127.0.0.1', + only clients on the local host can connect to it; if `0.0.0.0', clients + can access it from any network interface. + ''; + }; + + portNumber = mkOption { + default = 6667; + description = '' + Number of the port BitlBee will be listening to. + ''; + }; + + authMode = mkOption { + default = "Open"; + check = authModeCheck; + description = '' + The following authentication modes are available: + Open -- Accept connections from anyone, use NickServ for user authentication. + Closed -- Require authorization (using the PASS command during login) before allowing the user to connect at all. + Registered -- Only allow registered users to use this server; this disables the register- and the account command until the user identifies himself. + ''; + }; + + extraSettings = mkOption { + default = ""; + description = '' + Will be inserted in the Settings section of the config file. + ''; + }; + + extraDefaults = mkOption { + default = ""; + description = '' + Will be inserted in the Default section of the config file. + ''; + }; + + }; + + }; + + ###### implementation + + config = mkIf config.services.bitlbee.enable { + + users.extraUsers = singleton + { name = "bitlbee"; + uid = bitlbeeUid; + description = "BitlBee user"; + home = "/var/lib/bitlbee"; + createHome = true; + }; + + users.extraGroups = singleton + { name = "bitlbee"; + gid = config.ids.gids.bitlbee; + }; + + systemd.services.bitlbee = + { description = "BitlBee IRC to other chat networks gateway"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig.User = "bitlbee"; + serviceConfig.ExecStart = "${pkgs.bitlbee}/sbin/bitlbee -F -n -c ${bitlbeeConfig}"; + }; + + environment.systemPackages = [ pkgs.bitlbee ]; + + }; + +} diff --git a/nixos/modules/services/networking/chrony.nix b/nixos/modules/services/networking/chrony.nix new file mode 100644 index 00000000000..5e9818858e0 --- /dev/null +++ b/nixos/modules/services/networking/chrony.nix @@ -0,0 +1,118 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + inherit (pkgs) chrony; + + stateDir = "/var/lib/chrony"; + + chronyUser = "chrony"; + + cfg = config.services.chrony; + + configFile = pkgs.writeText "chrony.conf" '' + ${toString (map (server: "server " + server + "\n") cfg.servers)} + + ${optionalString cfg.initstepslew.enabled '' + initstepslew ${toString cfg.initstepslew.threshold} ${toString (map (server: server + " ") cfg.initstepslew.servers)} + ''} + + driftfile ${stateDir}/chrony.drift + + ${optionalString (!config.time.hardwareClockInLocalTime) "rtconutc"} + + ${cfg.extraConfig} + ''; + + chronyFlags = "-m -f ${configFile} -u ${chronyUser}"; + +in + +{ + + ###### interface + + options = { + + services.chrony = { + + enable = mkOption { + default = false; + description = '' + Whether to synchronise your machine's time using chrony. + Make sure you disable NTP if you enable this service. + ''; + }; + + servers = mkOption { + default = [ + "0.pool.ntp.org" + "1.pool.ntp.org" + "2.pool.ntp.org" + ]; + description = '' + The set of NTP servers from which to synchronise. + ''; + }; + + initstepslew = mkOption { + default = { + enabled = true; + threshold = 1000; # by default, same threshold as 'ntpd -g' (1000s) + servers = cfg.servers; + }; + description = '' + Allow chronyd to make a rapid measurement of the system clock error at + boot time, and to correct the system clock by stepping before normal + operation begins. + ''; + }; + + extraConfig = mkOption { + default = ""; + description = '' + Extra configuration directives that should be added to + <literal>chrony.conf</literal> + ''; + }; + }; + + }; + + + ###### implementation + + config = mkIf config.services.chrony.enable { + + # Make chronyc available in the system path + environment.systemPackages = [ pkgs.chrony ]; + + users.extraUsers = singleton + { name = chronyUser; + uid = config.ids.uids.chrony; + description = "chrony daemon user"; + home = stateDir; + }; + + jobs.chronyd = + { description = "chrony daemon"; + + wantedBy = [ "ip-up.target" ]; + partOf = [ "ip-up.target" ]; + + path = [ chrony ]; + + preStart = + '' + mkdir -m 0755 -p ${stateDir} + chown ${chronyUser} ${stateDir} + ''; + + exec = "chronyd -n ${chronyFlags}"; + }; + + }; + +} diff --git a/nixos/modules/services/networking/cntlm.nix b/nixos/modules/services/networking/cntlm.nix new file mode 100644 index 00000000000..bfe7209b991 --- /dev/null +++ b/nixos/modules/services/networking/cntlm.nix @@ -0,0 +1,115 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.cntlm; + uid = config.ids.uids.cntlm; + +in + +{ + + options = { + + services.cntlm = { + + enable = mkOption { + default = false; + description = '' + Whether to enable the cntlm, which start a local proxy. + ''; + }; + + username = mkOption { + description = '' + Proxy account name, without the possibility to include domain name ('at' sign is interpreted literally). + ''; + }; + + domain = mkOption { + description = ''Proxy account domain/workgroup name.''; + }; + + password = mkOption { + default = "/etc/cntlm.password"; + type = with pkgs.lib.types; string; + description = ''Proxy account password. Note: use chmod 0600 on /etc/cntlm.password for security.''; + }; + + netbios_hostname = mkOption { + type = types.uniq types.string; + description = '' + The hostname of your machine. + ''; + }; + + proxy = mkOption { + description = '' + A list of NTLM/NTLMv2 authenticating HTTP proxies. + + Parent proxy, which requires authentication. The same as proxy on the command-line, can be used more than once to specify unlimited + number of proxies. Should one proxy fail, cntlm automatically moves on to the next one. The connect request fails only if the whole + list of proxies is scanned and (for each request) and found to be invalid. Command-line takes precedence over the configuration file. + ''; + }; + + port = mkOption { + default = [3128]; + description = "Specifies on which ports the cntlm daemon listens."; + }; + + extraConfig = mkOption { + default = ""; + description = "Verbatim contents of <filename>cntlm.conf</filename>."; + }; + + }; + + }; + + + ###### implementation + + config = mkIf config.services.cntlm.enable { + + services.cntlm.netbios_hostname = mkDefault config.networking.hostName; + + users.extraUsers = singleton { + name = "cntlm"; + description = "cntlm system-wide daemon"; + home = "/var/empty"; + }; + + jobs.cntlm = + { description = "CNTLM is an NTLM / NTLM Session Response / NTLMv2 authenticating HTTP proxy"; + + startOn = "started network-interfaces"; + + daemonType = "fork"; + + exec = + '' + ${pkgs.cntlm}/bin/cntlm -U cntlm \ + -c ${pkgs.writeText "cntlm_config" cfg.extraConfig} + ''; + }; + + services.cntlm.extraConfig = + '' + # Cntlm Authentication Proxy Configuration + Username ${cfg.username} + Domain ${cfg.domain} + Password ${cfg.password} + Workstation ${cfg.netbios_hostname} + ${concatMapStrings (entry: "Proxy ${entry}\n") cfg.proxy} + + ${concatMapStrings (port: '' + Listen ${toString port} + '') cfg.port} + ''; + + }; + +} diff --git a/nixos/modules/services/networking/ddclient.nix b/nixos/modules/services/networking/ddclient.nix new file mode 100644 index 00000000000..62709a040a1 --- /dev/null +++ b/nixos/modules/services/networking/ddclient.nix @@ -0,0 +1,127 @@ +{ config, pkgs, ... }: + +let + + inherit (pkgs.lib) mkOption mkIf singleton; + + inherit (pkgs) ddclient; + + stateDir = "/var/spool/ddclient"; + + ddclientUser = "ddclient"; + + ddclientFlags = "-foreground -file ${ddclientCfg}"; + + ddclientCfg = pkgs.writeText "ddclient.conf" '' + daemon=600 + cache=${stateDir}/ddclient.cache + pid=${stateDir}/ddclient.pid + use=${config.services.ddclient.web} + login=${config.services.ddclient.username} + password=${config.services.ddclient.password} + protocol=${config.services.ddclient.protocol} + server=${config.services.ddclient.server} + wildcard=YES + ${config.services.ddclient.domain} + ${config.services.ddclient.extraConfig} + ''; + +in + +{ + + ###### interface + + options = { + + services.ddclient = { + + enable = mkOption { + default = false; + description = '' + Whether to synchronise your machine's IP address with a dynamic DNS provider (e.g. dyndns.org). + ''; + }; + + domain = mkOption { + default = ""; + description = '' + Domain name to synchronize. + ''; + }; + + username = mkOption { + default = ""; + description = '' + Username. + ''; + }; + + password = mkOption { + default = "" ; + description = '' + Password. + ''; + }; + + protocol = mkOption { + default = "dyndns2" ; + description = '' + Protocol to use with dynamic DNS provider. (see also, http://sourceforge.net/apps/trac/ddclient/wiki/Protocols) + ''; + }; + + server = mkOption { + default = "members.dyndns.org" ; + description = '' + Server + ''; + }; + + extraConfig = mkOption { + default = "" ; + description = '' + Extra configuration. Contents will be added verbatim to the configuration file. + ''; + }; + + web = mkOption { + default = "web, web=checkip.dyndns.com/, web-skip='IP Address'" ; + description = ""; + }; + + }; + + }; + + + ###### implementation + + config = mkIf config.services.ddclient.enable { + + environment.systemPackages = [ ddclient ]; + + users.extraUsers = singleton + { name = ddclientUser; + uid = config.ids.uids.ddclient; + description = "ddclient daemon user"; + home = stateDir; + }; + + jobs.ddclient = + { name = "ddclient"; + + startOn = "startup"; + + preStart = + '' + mkdir -m 0755 -p ${stateDir} + chown ${ddclientUser} ${stateDir} + ''; + + exec = "${ddclient}/bin/ddclient ${ddclientFlags}"; + }; + + }; + +} diff --git a/nixos/modules/services/networking/dhclient.nix b/nixos/modules/services/networking/dhclient.nix new file mode 100644 index 00000000000..1e343443899 --- /dev/null +++ b/nixos/modules/services/networking/dhclient.nix @@ -0,0 +1,111 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + inherit (pkgs) nettools dhcp lib; + + # Don't start dhclient on explicitly configured interfaces or on + # interfaces that are part of a bridge. + ignoredInterfaces = + map (i: i.name) (lib.filter (i: i ? ipAddress && i.ipAddress != "" ) config.networking.interfaces) + ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bridges)); + + stateDir = "/var/lib/dhcp"; # Don't use /var/state/dhcp; not FHS-compliant. + + dhclientExitHooks = pkgs.writeText "dhclient-exit-hooks" + '' + #echo "$reason" >> /tmp/dhcp-exit + #echo "$exit_status" >> /tmp/dhcp-exit + + if test "$reason" = BOUND -o "$reason" = REBOOT; then + # Restart ntpd. (The "ip-up" event below will trigger the + # restart.) We need to restart it to make sure that it will + # actually do something: if ntpd cannot resolve the server + # hostnames in its config file, then it will never do + # anything ever again ("couldn't resolve ..., giving up on + # it"), so we silently lose time synchronisation. + ${config.system.build.upstart}/sbin/initctl stop ntpd + + ${config.system.build.upstart}/sbin/initctl emit -n ip-up + fi + + if test "$reason" = EXPIRE -o "$reason" = RELEASE; then + ${config.system.build.upstart}/sbin/initctl emit -n ip-down + fi + ''; + +in + +{ + + ###### implementation + + config = mkIf config.networking.useDHCP { + + # dhclient barfs if /proc/net/if_inet6 doesn't exist. + boot.kernelModules = [ "ipv6" ]; + + jobs.dhclient = + { startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; + + path = [ dhcp ]; + + script = + '' + # Determine the interface on which to start dhclient. + interfaces= + + for i in $(cd /sys/class/net && ls -d *); do + # Only run dhclient on interfaces of type ARPHRD_ETHER + # (1), i.e. Ethernet. Ignore peth* devices; on Xen, + # they're renamed physical Ethernet cards used for + # bridging. Likewise for vif* and tap* (Xen) and + # virbr* and vnet* (libvirt). + if [ "$(cat /sys/class/net/$i/type)" = 1 ]; then + if ! for j in ${toString ignoredInterfaces}; do echo $j; done | grep -F -x -q "$i" && + ! echo "$i" | grep -x -q "peth.*\|vif.*\|tap.*\|virbr.*\|vnet.*"; + then + echo "Running dhclient on $i" + interfaces="$interfaces $i" + fi + fi + done + + if test -z "$interfaces"; then + echo 'No interfaces on which to start dhclient!' + exit 1 + fi + + mkdir -m 755 -p ${stateDir} + + exec dhclient -d $interfaces -e "PATH=$PATH" -lf ${stateDir}/dhclient.leases -sf ${dhcp}/sbin/dhclient-script + ''; + }; + + environment.systemPackages = [dhcp]; + + environment.etc = + [ # Dhclient hooks for emitting ip-up/ip-down events. + { source = dhclientExitHooks; + target = "dhclient-exit-hooks"; + } + ]; + + powerManagement.resumeCommands = + '' + ${config.system.build.upstart}/sbin/restart dhclient + ''; + + networking.interfaceMonitor.commands = + '' + if [ "$status" = up ]; then + ${config.system.build.upstart}/sbin/restart dhclient + fi + ''; + + }; + +} diff --git a/nixos/modules/services/networking/dhcpcd.nix b/nixos/modules/services/networking/dhcpcd.nix new file mode 100644 index 00000000000..48803511a5e --- /dev/null +++ b/nixos/modules/services/networking/dhcpcd.nix @@ -0,0 +1,143 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + inherit (pkgs) dhcpcd; + + # Don't start dhclient on explicitly configured interfaces or on + # interfaces that are part of a bridge. + ignoredInterfaces = + map (i: i.name) (filter (i: i.ipAddress != null) (attrValues config.networking.interfaces)) + ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bridges)) + ++ config.networking.dhcpcd.denyInterfaces; + + # Config file adapted from the one that ships with dhcpcd. + dhcpcdConf = pkgs.writeText "dhcpcd.conf" + '' + # Inform the DHCP server of our hostname for DDNS. + hostname + + # A list of options to request from the DHCP server. + option domain_name_servers, domain_name, domain_search, host_name + option classless_static_routes, ntp_servers, interface_mtu + + # A ServerID is required by RFC2131. + # Commented out because of many non-compliant DHCP servers in the wild :( + #require dhcp_server_identifier + + # A hook script is provided to lookup the hostname if not set by + # the DHCP server, but it should not be run by default. + nohook lookup-hostname + + # Ignore peth* devices; on Xen, they're renamed physical + # Ethernet cards used for bridging. Likewise for vif* and tap* + # (Xen) and virbr* and vnet* (libvirt). + denyinterfaces ${toString ignoredInterfaces} peth* vif* tap* tun* virbr* vnet* vboxnet* + + ${config.networking.dhcpcd.extraConfig} + ''; + + # Hook for emitting ip-up/ip-down events. + exitHook = pkgs.writeText "dhcpcd.exit-hook" + '' + #exec >> /var/log/dhcpcd 2>&1 + #set -x + + params="IFACE=$interface REASON=$reason" + + # only works when interface is wireless and wpa_supplicant has a control socket + # but we allow it to fail silently + ${optionalString config.networking.wireless.enable '' + params+=" $(${pkgs.wpa_supplicant}/sbin/wpa_cli -i$interface status 2>/dev/null | grep ssid | sed 's|^b|B|;s|ssid|SSID|' | xargs)" + ''} + + if [ "$reason" = BOUND -o "$reason" = REBOOT ]; then + # Restart ntpd. We need to restart it to make sure that it + # will actually do something: if ntpd cannot resolve the + # server hostnames in its config file, then it will never do + # anything ever again ("couldn't resolve ..., giving up on + # it"), so we silently lose time synchronisation. + ${config.systemd.package}/bin/systemctl try-restart ntpd.service + + ${config.systemd.package}/bin/systemctl start ip-up.target + fi + + #if [ "$reason" = EXPIRE -o "$reason" = RELEASE -o "$reason" = NOCARRIER ] ; then + # ${config.systemd.package}/bin/systemctl start ip-down.target + #fi + ''; + +in + +{ + + ###### interface + + options = { + + networking.dhcpcd.denyInterfaces = mkOption { + default = []; + description = '' + Disable the DHCP client for any interface whose name matches + any of the shell glob patterns in this list. The purpose of + this option is to blacklist virtual interfaces such as those + created by Xen, libvirt, LXC, etc. + ''; + }; + + networking.dhcpcd.extraConfig = mkOption { + default = ""; + description = '' + Literal string to append to the config file generated for dhcpcd. + ''; + }; + + }; + + + ###### implementation + + config = mkIf config.networking.useDHCP { + + systemd.services.dhcpcd = + { description = "DHCP Client"; + + wantedBy = [ "network.target" ]; + after = [ "systemd-udev-settle.service" ]; + + # Stopping dhcpcd during a reconfiguration is undesirable + # because it brings down the network interfaces configured by + # dhcpcd. So do a "systemctl restart" instead. + stopIfChanged = false; + + path = [ dhcpcd pkgs.nettools pkgs.openresolv ]; + + serviceConfig = + { Type = "forking"; + PIDFile = "/run/dhcpcd.pid"; + ExecStart = "@${dhcpcd}/sbin/dhcpcd dhcpcd --config ${dhcpcdConf}"; + ExecReload = "${dhcpcd}/sbin/dhcpcd --rebind"; + StandardError = "null"; + Restart = "always"; + }; + }; + + environment.systemPackages = [ dhcpcd ]; + + environment.etc = + [ { source = exitHook; + target = "dhcpcd.exit-hook"; + } + ]; + + powerManagement.resumeCommands = + '' + # Tell dhcpcd to rebind its interfaces if it's running. + ${config.systemd.package}/bin/systemctl reload dhcpcd.service + ''; + + }; + +} diff --git a/nixos/modules/services/networking/dhcpd.nix b/nixos/modules/services/networking/dhcpd.nix new file mode 100644 index 00000000000..43e0843cb97 --- /dev/null +++ b/nixos/modules/services/networking/dhcpd.nix @@ -0,0 +1,131 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.dhcpd; + + stateDir = "/var/lib/dhcp"; # Don't use /var/state/dhcp; not FHS-compliant. + + configFile = if cfg.configFile != null then cfg.configFile else pkgs.writeText "dhcpd.conf" + '' + default-lease-time 600; + max-lease-time 7200; + authoritative; + ddns-update-style ad-hoc; + log-facility local1; # see dhcpd.nix + + ${cfg.extraConfig} + + ${pkgs.lib.concatMapStrings + (machine: '' + host ${machine.hostName} { + hardware ethernet ${machine.ethernetAddress}; + fixed-address ${machine.ipAddress}; + } + '') + cfg.machines + } + ''; + +in + +{ + + ###### interface + + options = { + + services.dhcpd = { + + enable = mkOption { + default = false; + description = " + Whether to enable the DHCP server. + "; + }; + + extraConfig = mkOption { + default = ""; + example = " + option subnet-mask 255.255.255.0; + option broadcast-address 192.168.1.255; + option routers 192.168.1.5; + option domain-name-servers 130.161.158.4, 130.161.33.17, 130.161.180.1; + option domain-name \"example.org\"; + subnet 192.168.1.0 netmask 255.255.255.0 { + range 192.168.1.100 192.168.1.200; + } + "; + description = " + Extra text to be appended to the DHCP server configuration + file. Currently, you almost certainly need to specify + something here, such as the options specifying the subnet + mask, DNS servers, etc. + "; + }; + + configFile = mkOption { + default = null; + description = " + The path of the DHCP server configuration file. If no file + is specified, a file is generated using the other options. + "; + }; + + interfaces = mkOption { + default = ["eth0"]; + description = " + The interfaces on which the DHCP server should listen. + "; + }; + + machines = mkOption { + default = []; + example = [ + { hostName = "foo"; + ethernetAddress = "00:16:76:9a:32:1d"; + ipAddress = "192.168.1.10"; + } + { hostName = "bar"; + ethernetAddress = "00:19:d1:1d:c4:9a"; + ipAddress = "192.168.1.11"; + } + ]; + description = " + A list mapping ethernet addresses to IP addresses for the + DHCP server. + "; + }; + + }; + + }; + + + ###### implementation + + config = mkIf config.services.dhcpd.enable { + + jobs.dhcpd = + { description = "DHCP server"; + + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; + + script = + '' + mkdir -m 755 -p ${stateDir} + + touch ${stateDir}/dhcpd.leases + + exec ${pkgs.dhcp}/sbin/dhcpd -f -cf ${configFile} \ + -lf ${stateDir}/dhcpd.leases \ + ${toString cfg.interfaces} + ''; + }; + + }; + +} diff --git a/nixos/modules/services/networking/dnsmasq.nix b/nixos/modules/services/networking/dnsmasq.nix new file mode 100644 index 00000000000..b726493d421 --- /dev/null +++ b/nixos/modules/services/networking/dnsmasq.nix @@ -0,0 +1,70 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + cfg = config.services.dnsmasq; + dnsmasq = pkgs.dnsmasq; + + serversParam = concatMapStrings (s: "-S ${s} ") cfg.servers; + + dnsmasqConf = pkgs.writeText "dnsmasq.conf" '' + ${cfg.extraConfig} + ''; + +in + +{ + + ###### interface + + options = { + + services.dnsmasq = { + + enable = mkOption { + default = false; + description = '' + Whether to run dnsmasq. + ''; + }; + + servers = mkOption { + default = []; + example = [ "8.8.8.8" "8.8.4.4" ]; + description = '' + The parameter to dnsmasq -S. + ''; + }; + + extraConfig = mkOption { + type = types.string; + default = ""; + description = '' + Extra configuration directives that should be added to + <literal>dnsmasq.conf</literal> + ''; + }; + + }; + + }; + + + ###### implementation + + config = mkIf config.services.dnsmasq.enable { + + jobs.dnsmasq = + { description = "dnsmasq daemon"; + + startOn = "ip-up"; + + daemonType = "daemon"; + + exec = "${dnsmasq}/bin/dnsmasq -R ${serversParam} -o -C ${dnsmasqConf}"; + }; + + }; + +} diff --git a/nixos/modules/services/networking/ejabberd.nix b/nixos/modules/services/networking/ejabberd.nix new file mode 100644 index 00000000000..6d233e543e2 --- /dev/null +++ b/nixos/modules/services/networking/ejabberd.nix @@ -0,0 +1,135 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.ejabberd; + +in + +{ + + ###### interface + + options = { + + services.ejabberd = { + + enable = mkOption { + default = false; + description = "Whether to enable ejabberd server"; + }; + + spoolDir = mkOption { + default = "/var/lib/ejabberd"; + description = "Location of the spooldir of ejabberd"; + }; + + logsDir = mkOption { + default = "/var/log/ejabberd"; + description = "Location of the logfile directory of ejabberd"; + }; + + confDir = mkOption { + default = "/var/ejabberd"; + description = "Location of the config directory of ejabberd"; + }; + + virtualHosts = mkOption { + default = "\"localhost\""; + description = "Virtualhosts that ejabberd should host. Hostnames are surrounded with doublequotes and separated by commas"; + }; + + loadDumps = mkOption { + default = []; + description = "Configuration dump that should be loaded on the first startup"; + example = [ ./myejabberd.dump ]; + }; + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + environment.systemPackages = [ pkgs.ejabberd ]; + + jobs.ejabberd = + { description = "EJabberd server"; + + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; + + environment = { + PATH = "$PATH:${pkgs.ejabberd}/sbin:${pkgs.ejabberd}/bin:${pkgs.coreutils}/bin:${pkgs.bash}/bin:${pkgs.gnused}/bin"; + }; + + preStart = + '' + # Initialise state data + mkdir -p ${cfg.logsDir} + + if ! test -d ${cfg.spoolDir} + then + initialize=1 + cp -av ${pkgs.ejabberd}/var/lib/ejabberd /var/lib + fi + + if ! test -d ${cfg.confDir} + then + mkdir -p ${cfg.confDir} + cp ${pkgs.ejabberd}/etc/ejabberd/* ${cfg.confDir} + sed -e 's|{hosts, \["localhost"\]}.|{hosts, \[${cfg.virtualHosts}\]}.|' ${pkgs.ejabberd}/etc/ejabberd/ejabberd.cfg > ${cfg.confDir}/ejabberd.cfg + fi + + ejabberdctl --config-dir ${cfg.confDir} --logs ${cfg.logsDir} --spool ${cfg.spoolDir} start + + ${if cfg.loadDumps == [] then "" else + '' + if [ "$initialize" = "1" ] + then + # Wait until the ejabberd server is available for use + count=0 + while ! ejabberdctl --config-dir ${cfg.confDir} --logs ${cfg.logsDir} --spool ${cfg.spoolDir} status + do + if [ $count -eq 30 ] + then + echo "Tried 30 times, giving up..." + exit 1 + fi + + echo "Ejabberd daemon not yet started. Waiting for 1 second..." + count=$((count++)) + sleep 1 + done + + ${concatMapStrings (dump: + '' + echo "Importing dump: ${dump}" + + if [ -f ${dump} ] + then + ejabberdctl --config-dir ${cfg.confDir} --logs ${cfg.logsDir} --spool ${cfg.spoolDir} load ${dump} + elif [ -d ${dump} ] + then + for i in ${dump}/ejabberd-dump/* + do + ejabberdctl --config-dir ${cfg.confDir} --logs ${cfg.logsDir} --spool ${cfg.spoolDir} load $i + done + fi + '') cfg.loadDumps} + fi + ''} + ''; + + postStop = + '' + ejabberdctl --config-dir ${cfg.confDir} --logs ${cfg.logsDir} --spool ${cfg.spoolDir} stop + ''; + }; + + }; + +} diff --git a/nixos/modules/services/networking/firewall.nix b/nixos/modules/services/networking/firewall.nix new file mode 100644 index 00000000000..b24ac2d7032 --- /dev/null +++ b/nixos/modules/services/networking/firewall.nix @@ -0,0 +1,368 @@ +/* This module enables a simple firewall. + + The firewall can be customised in arbitrary ways by setting + ‘networking.firewall.extraCommands’. For modularity, the firewall + uses several chains: + + - ‘nixos-fw-input’ is the main chain for input packet processing. + + - ‘nixos-fw-log-refuse’ and ‘nixos-fw-refuse’ are called for + refused packets. (The former jumps to the latter after logging + the packet.) If you want additional logging, or want to accept + certain packets anyway, you can insert rules at the start of + these chain. + + - ‘nixos-fw-accept’ is called for accepted packets. If you want + additional logging, or want to reject certain packets anyway, you + can insert rules at the start of this chain. + +*/ + + + +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.networking.firewall; + + helpers = + '' + # Helper command to manipulate both the IPv4 and IPv6 tables. + ip46tables() { + iptables "$@" + ${optionalString config.networking.enableIPv6 '' + ip6tables "$@" + ''} + } + ''; + + kernelPackages = config.boot.kernelPackages; + + kernelHasRPFilter = kernelPackages.kernel.features.netfilterRPFilter or false; + kernelCanDisableHelpers = kernelPackages.kernel.features.canDisableNetfilterConntrackHelpers or false; + +in + +{ + + ###### interface + + options = { + + networking.firewall.enable = mkOption { + default = false; + description = + '' + Whether to enable the firewall. This is a simple stateful + firewall that blocks connection attempts to unauthorised TCP + or UDP ports on this machine. It does not affect packet + forwarding. + ''; + }; + + networking.firewall.logRefusedConnections = mkOption { + default = true; + description = + '' + Whether to log rejected or dropped incoming connections. + ''; + }; + + networking.firewall.logRefusedPackets = mkOption { + default = false; + description = + '' + Whether to log all rejected or dropped incoming packets. + This tends to give a lot of log messages, so it's mostly + useful for debugging. + ''; + }; + + networking.firewall.logRefusedUnicastsOnly = mkOption { + default = true; + description = + '' + If <option>networking.firewall.logRefusedPackets</option> + and this option are enabled, then only log packets + specifically directed at this machine, i.e., not broadcasts + or multicasts. + ''; + }; + + networking.firewall.rejectPackets = mkOption { + default = false; + description = + '' + If set, forbidden packets are rejected rather than dropped + (ignored). This means that an ICMP "port unreachable" error + message is sent back to the client. Rejecting packets makes + port scanning somewhat easier. + ''; + }; + + networking.firewall.trustedInterfaces = mkOption { + type = types.listOf types.string; + description = + '' + Traffic coming in from these interfaces will be accepted + unconditionally. + ''; + }; + + networking.firewall.allowedTCPPorts = mkOption { + default = []; + example = [ 22 80 ]; + type = types.listOf types.int; + description = + '' + List of TCP ports on which incoming connections are + accepted. + ''; + }; + + networking.firewall.allowedUDPPorts = mkOption { + default = []; + example = [ 53 ]; + type = types.listOf types.int; + description = + '' + List of open UDP ports. + ''; + }; + + networking.firewall.allowPing = mkOption { + default = false; + type = types.bool; + description = + '' + Whether to respond to incoming ICMPv4 echo requests + ("pings"). ICMPv6 pings are always allowed because the + larger address space of IPv6 makes network scanning much + less effective. + ''; + }; + + networking.firewall.checkReversePath = mkOption { + default = kernelHasRPFilter; + type = types.bool; + description = + '' + Performs a reverse path filter test on a packet. + If a reply to the packet would not be sent via the same interface + that the packet arrived on, it is refused. + + If using asymmetric routing or other complicated routing, + disable this setting and setup your own counter-measures. + + (needs kernel 3.3+) + ''; + }; + + networking.firewall.connectionTrackingModules = mkOption { + default = [ "ftp" ]; + example = [ "ftp" "irc" "sane" "sip" "tftp" "amanda" "h323" "netbios_sn" "pptp" "snmp" ]; + type = types.listOf types.string; + description = + '' + List of connection-tracking helpers that are auto-loaded. + The complete list of possible values is given in the example. + + As helpers can pose as a security risk, it is advised to + set this to an empty list and disable the setting + networking.firewall.autoLoadConntrackHelpers + + Loading of helpers is recommended to be done through the new + CT target. More info: + https://home.regit.org/netfilter-en/secure-use-of-helpers/ + ''; + }; + + networking.firewall.autoLoadConntrackHelpers = mkOption { + default = true; + type = types.bool; + description = + '' + Whether to auto-load connection-tracking helpers. + See the description at networking.firewall.connectionTrackingModules + + (needs kernel 3.5+) + ''; + }; + + networking.firewall.extraCommands = mkOption { + default = ""; + example = "iptables -A INPUT -p icmp -j ACCEPT"; + description = + '' + Additional shell commands executed as part of the firewall + initialisation script. These are executed just before the + final "reject" firewall rule is added, so they can be used + to allow packets that would otherwise be refused. + ''; + }; + + }; + + + ###### implementation + + # !!! Maybe if `enable' is false, the firewall should still be built + # but not started by default. However, currently nixos-rebuild + # doesn't deal with such Upstart jobs properly (it starts them if + # they are changed, regardless of whether the start condition + # holds). + config = mkIf cfg.enable { + + networking.firewall.trustedInterfaces = [ "lo" ]; + + environment.systemPackages = [ pkgs.iptables ]; + + boot.kernelModules = map (x: "nf_conntrack_${x}") cfg.connectionTrackingModules; + boot.extraModprobeConfig = optionalString (!cfg.autoLoadConntrackHelpers) '' + options nf_conntrack nf_conntrack_helper=0 + ''; + + assertions = [ { assertion = ! cfg.checkReversePath || kernelHasRPFilter; + message = "This kernel does not support rpfilter"; } + { assertion = cfg.autoLoadConntrackHelpers || kernelCanDisableHelpers; + message = "This kernel does not support disabling conntrack helpers"; } + ]; + + jobs.firewall = + { description = "Firewall"; + + startOn = "started network-interfaces"; + + path = [ pkgs.iptables ]; + + preStart = + '' + ${helpers} + + # Flush the old firewall rules. !!! Ideally, updating the + # firewall would be atomic. Apparently that's possible + # with iptables-restore. + ip46tables -D INPUT -j nixos-fw 2> /dev/null || true + for chain in nixos-fw nixos-fw-accept nixos-fw-log-refuse nixos-fw-refuse FW_REFUSE; do + ip46tables -F "$chain" 2> /dev/null || true + ip46tables -X "$chain" 2> /dev/null || true + done + + + # The "nixos-fw-accept" chain just accepts packets. + ip46tables -N nixos-fw-accept + ip46tables -A nixos-fw-accept -j ACCEPT + + + # The "nixos-fw-refuse" chain rejects or drops packets. + ip46tables -N nixos-fw-refuse + + ${if cfg.rejectPackets then '' + # Send a reset for existing TCP connections that we've + # somehow forgotten about. Send ICMP "port unreachable" + # for everything else. + ip46tables -A nixos-fw-refuse -p tcp ! --syn -j REJECT --reject-with tcp-reset + ip46tables -A nixos-fw-refuse -j REJECT + '' else '' + ip46tables -A nixos-fw-refuse -j DROP + ''} + + + # The "nixos-fw-log-refuse" chain performs logging, then + # jumps to the "nixos-fw-refuse" chain. + ip46tables -N nixos-fw-log-refuse + + ${optionalString cfg.logRefusedConnections '' + ip46tables -A nixos-fw-log-refuse -p tcp --syn -j LOG --log-level info --log-prefix "rejected connection: " + ''} + ${optionalString (cfg.logRefusedPackets && !cfg.logRefusedUnicastsOnly) '' + ip46tables -A nixos-fw-log-refuse -m pkttype --pkt-type broadcast \ + -j LOG --log-level info --log-prefix "rejected broadcast: " + ip46tables -A nixos-fw-log-refuse -m pkttype --pkt-type multicast \ + -j LOG --log-level info --log-prefix "rejected multicast: " + ''} + ip46tables -A nixos-fw-log-refuse -m pkttype ! --pkt-type unicast -j nixos-fw-refuse + ${optionalString cfg.logRefusedPackets '' + ip46tables -A nixos-fw-log-refuse \ + -j LOG --log-level info --log-prefix "rejected packet: " + ''} + ip46tables -A nixos-fw-log-refuse -j nixos-fw-refuse + + + # The "nixos-fw" chain does the actual work. + ip46tables -N nixos-fw + + # Perform a reverse-path test to refuse spoofers + # For now, we just drop, as the raw table doesn't have a log-refuse yet + ${optionalString (kernelHasRPFilter && cfg.checkReversePath) '' + if ! ip46tables -A PREROUTING -t raw -m rpfilter --invert -j DROP; then + echo "<2>failed to initialise rpfilter support" >&2 + fi + ''} + + # Accept all traffic on the trusted interfaces. + ${flip concatMapStrings cfg.trustedInterfaces (iface: '' + ip46tables -A nixos-fw -i ${iface} -j nixos-fw-accept + '')} + + # Accept packets from established or related connections. + ip46tables -A nixos-fw -m conntrack --ctstate ESTABLISHED,RELATED -j nixos-fw-accept + + # Accept connections to the allowed TCP ports. + ${concatMapStrings (port: + '' + ip46tables -A nixos-fw -p tcp --dport ${toString port} -j nixos-fw-accept + '' + ) cfg.allowedTCPPorts + } + + # Accept packets on the allowed UDP ports. + ${concatMapStrings (port: + '' + ip46tables -A nixos-fw -p udp --dport ${toString port} -j nixos-fw-accept + '' + ) cfg.allowedUDPPorts + } + + # Accept IPv4 multicast. Not a big security risk since + # probably nobody is listening anyway. + #iptables -A nixos-fw -d 224.0.0.0/4 -j nixos-fw-accept + + # Optionally respond to ICMPv4 pings. + ${optionalString cfg.allowPing '' + iptables -A nixos-fw -p icmp --icmp-type echo-request -j nixos-fw-accept + ''} + + # Accept all ICMPv6 messages except redirects and node + # information queries (type 139). See RFC 4890, section + # 4.4. + ${optionalString config.networking.enableIPv6 '' + ip6tables -A nixos-fw -p icmpv6 --icmpv6-type redirect -j DROP + ip6tables -A nixos-fw -p icmpv6 --icmpv6-type 139 -j DROP + ip6tables -A nixos-fw -p icmpv6 -j nixos-fw-accept + ''} + + ${cfg.extraCommands} + + # Reject/drop everything else. + ip46tables -A nixos-fw -j nixos-fw-log-refuse + + + # Enable the firewall. + ip46tables -A INPUT -j nixos-fw + ''; + + postStop = + '' + ${helpers} + ip46tables -D INPUT -j nixos-fw || true + #ip46tables -P INPUT ACCEPT + ''; + }; + + }; + +} diff --git a/nixos/modules/services/networking/flashpolicyd.nix b/nixos/modules/services/networking/flashpolicyd.nix new file mode 100644 index 00000000000..f5bc550ab5f --- /dev/null +++ b/nixos/modules/services/networking/flashpolicyd.nix @@ -0,0 +1,84 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.flashpolicyd; + + flashpolicyd = pkgs.stdenv.mkDerivation { + name = "flashpolicyd-0.6"; + + src = pkgs.fetchurl { + name = "flashpolicyd_v0.6.zip"; + url = "http://www.adobe.com/content/dotcom/en/devnet/flashplayer/articles/socket_policy_files/_jcr_content/articlePrerequistes/multiplefiles/node_1277808777771/file.res/flashpolicyd_v0.6%5B1%5D.zip"; + sha256 = "16zk237233npwfq1m4ksy4g5lzy1z9fp95w7pz0cdlpmv0fv9sm3"; + }; + + buildInputs = [ pkgs.unzip pkgs.perl ]; + + installPhase = "mkdir $out; cp -pr * $out/; chmod +x $out/*/*.pl"; + }; + + flashpolicydWrapper = pkgs.writeScriptBin "flashpolicyd" + '' + #! ${pkgs.stdenv.shell} + exec ${flashpolicyd}/Perl_xinetd/in.flashpolicyd.pl \ + --file=${pkgs.writeText "flashpolixy.xml" cfg.policy} \ + 2> /dev/null + ''; + +in + +{ + + ###### interface + + options = { + + services.flashpolicyd = { + + enable = mkOption { + default = false; + description = + '' + Whether to enable the Flash Policy server. This is + necessary if you want Flash applications to make + connections to your server. + ''; + }; + + policy = mkOption { + default = + '' + <?xml version="1.0"?> + <!DOCTYPE cross-domain-policy SYSTEM "/xml/dtds/cross-domain-policy.dtd"> + <cross-domain-policy> + <site-control permitted-cross-domain-policies="master-only"/> + <allow-access-from domain="*" to-ports="*" /> + </cross-domain-policy> + ''; + description = "The policy to be served. The default is to allow connections from any domain to any port."; + }; + + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + services.xinetd.enable = true; + + services.xinetd.services = singleton + { name = "flashpolicy"; + port = 843; + unlisted = true; + server = "${flashpolicydWrapper}/bin/flashpolicyd"; + }; + + }; + +} diff --git a/nixos/modules/services/networking/freenet.nix b/nixos/modules/services/networking/freenet.nix new file mode 100644 index 00000000000..a4bd2098986 --- /dev/null +++ b/nixos/modules/services/networking/freenet.nix @@ -0,0 +1,64 @@ +# NixOS module for Freenet daemon + +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.freenet; + varDir = "/var/lib/freenet"; + +in + +{ + + ### configuration + + options = { + + services.freenet = { + + enable = mkOption { + type = types.uniq types.bool; + default = false; + description = "Enable the Freenet daemon"; + }; + + nice = mkOption { + type = types.uniq types.int; + default = 10; + description = "Set the nice level for the Freenet daemon"; + }; + + }; + + }; + + ### implementation + + config = mkIf cfg.enable { + + systemd.services.freenet = { + description = "Freenet daemon"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig.ExecStart = "${pkgs.freenet}/bin/freenet"; + serviceConfig.User = "freenet"; + serviceConfig.UMask = "0007"; + serviceConfig.WorkingDirectory = varDir; + serviceConfig.Nice = cfg.nice; + }; + + users.extraUsers.freenet = { + group = "freenet"; + description = "Freenet daemon user"; + home = varDir; + createHome = true; + uid = config.ids.uids.freenet; + }; + + users.extraGroups.freenet.gid = config.ids.gids.freenet; + }; + +} diff --git a/nixos/modules/services/networking/git-daemon.nix b/nixos/modules/services/networking/git-daemon.nix new file mode 100644 index 00000000000..a7c7c206198 --- /dev/null +++ b/nixos/modules/services/networking/git-daemon.nix @@ -0,0 +1,112 @@ +{pkgs, config, ...}: +with pkgs.lib; +let + + cfg = config.services.gitDaemon; + gitUser = "git"; + +in +{ + + ###### interface + + options = { + services.gitDaemon = { + + enable = mkOption { + default = false; + description = '' + Enable Git daemon, which allows public hosting of git repositories + without any access controls. This is mostly intended for read-only access. + + You can allow write access by setting daemon.receivepack configuration + item of the repository to true. This is solely meant for a closed LAN setting + where everybody is friendly. + + If you need any access controls, use something else. + ''; + }; + + basePath = mkOption { + default = ""; + example = "/srv/git/"; + description = '' + Remap all the path requests as relative to the given path. For example, + if you set base-path to /srv/git, then if you later try to pull + git://example.com/hello.git, Git daemon will interpret the path as /srv/git/hello.git. + ''; + }; + + exportAll = mkOption { + default = false; + description = '' + Publish all directories that look like Git repositories (have the objects + and refs subdirectories), even if they do not have the git-daemon-export-ok file. + + If disabled, you need to touch .git/git-daemon-export-ok in each repository + you want the daemon to publish. + + Warning: enabling this without a repository whitelist or basePath + publishes every git repository you have. + ''; + }; + + repositories = mkOption { + default = []; + example = [ "/srv/git" "/home/user/git/repo2" ]; + description = '' + A whitelist of paths of git repositories, or directories containing repositories + all of which would be published. Paths must not end in "/". + + Warning: leaving this empty and enabling exportAll publishes all + repositories in your filesystem or basePath if specified. + ''; + }; + + listenAddress = mkOption { + default = ""; + example = "example.com"; + description = "Listen on a specific IP address or hostname."; + }; + + port = mkOption { + default = 9418; + description = "Port to listen on."; + }; + + options = mkOption { + default = ""; + description = "Extra configuration options to be passed to Git daemon."; + }; + + }; + }; + + ###### implementation + + config = mkIf cfg.enable { + + users.extraUsers = singleton + { name = gitUser; + uid = config.ids.uids.git; + description = "Git daemon user"; + }; + + users.extraGroups = singleton + { name = gitUser; + gid = config.ids.gids.git; + }; + + jobs.gitDaemon = { + name = "git-daemon"; + startOn = "ip-up"; + exec = "${pkgs.git}/bin/git daemon --reuseaddr " + + (optionalString (cfg.basePath != "") "--basepath=${cfg.basePath} ") + + (optionalString (cfg.listenAddress != "") "--listen=${cfg.listenAddress} ") + + "--port=${toString cfg.port} --user=${gitUser} --group=${gitUser} ${cfg.options} " + + "--verbose " + (optionalString cfg.exportAll "--export-all") + concatStringsSep " " cfg.repositories; + }; + + }; + +} diff --git a/nixos/modules/services/networking/gnunet.nix b/nixos/modules/services/networking/gnunet.nix new file mode 100644 index 00000000000..421c0d9bb69 --- /dev/null +++ b/nixos/modules/services/networking/gnunet.nix @@ -0,0 +1,148 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.gnunet; + + homeDir = "/var/lib/gnunet"; + + configFile = with cfg; pkgs.writeText "gnunetd.conf" + '' + [PATHS] + SERVICEHOME = ${homeDir} + + [ats] + WAN_QUOTA_IN = ${toString load.maxNetDownBandwidth} b + WAN_QUOTA_OUT = ${toString load.maxNetUpBandwidth} b + + [datastore] + QUOTA = ${toString fileSharing.quota} MB + + [transport-udp] + PORT = ${toString udp.port} + ADVERTISED_PORT = ${toString udp.port} + + [transport-tcp] + PORT = ${toString tcp.port} + ADVERTISED_PORT = ${toString tcp.port} + + ${extraOptions} + ''; + +in + +{ + + ###### interface + + options = { + + services.gnunet = { + + enable = mkOption { + default = false; + description = '' + Whether to run the GNUnet daemon. GNUnet is GNU's anonymous + peer-to-peer communication and file sharing framework. + ''; + }; + + fileSharing = { + quota = mkOption { + default = 1024; + description = '' + Maximum file system usage (in MiB) for file sharing. + ''; + }; + }; + + udp = { + port = mkOption { + default = 2086; # assigned by IANA + description = '' + The UDP port for use by GNUnet. + ''; + }; + }; + + tcp = { + port = mkOption { + default = 2086; # assigned by IANA + description = '' + The TCP port for use by GNUnet. + ''; + }; + }; + + load = { + maxNetDownBandwidth = mkOption { + default = 50000; + description = '' + Maximum bandwidth usage (in bits per second) for GNUnet + when downloading data. + ''; + }; + + maxNetUpBandwidth = mkOption { + default = 50000; + description = '' + Maximum bandwidth usage (in bits per second) for GNUnet + when downloading data. + ''; + }; + + hardNetUpBandwidth = mkOption { + default = 0; + description = '' + Hard bandwidth limit (in bits per second) when uploading + data. + ''; + }; + }; + + extraOptions = mkOption { + default = ""; + description = '' + Additional options that will be copied verbatim in `gnunet.conf'. + See `gnunet.conf(5)' for details. + ''; + }; + }; + + }; + + + ###### implementation + + config = mkIf config.services.gnunet.enable { + + users.extraUsers.gnunet = { + group = "gnunet"; + description = "GNUnet User"; + home = homeDir; + createHome = true; + uid = config.ids.uids.gnunet; + }; + + users.extraGroups.gnunet.gid = config.ids.gids.gnunet; + + # The user tools that talk to `gnunetd' should come from the same source, + # so install them globally. + environment.systemPackages = [ pkgs.gnunet ]; + + systemd.services.gnunet = { + description = "GNUnet"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + path = [ pkgs.gnunet pkgs.miniupnpc ]; + serviceConfig.ExecStart = "${pkgs.gnunet}/lib/gnunet/libexec/gnunet-service-arm -c ${configFile}"; + serviceConfig.User = "gnunet"; + serviceConfig.UMask = "0007"; + serviceConfig.WorkingDirectory = homeDir; + }; + + }; + +} diff --git a/nixos/modules/services/networking/gogoclient.nix b/nixos/modules/services/networking/gogoclient.nix new file mode 100644 index 00000000000..07c35e3cb3d --- /dev/null +++ b/nixos/modules/services/networking/gogoclient.nix @@ -0,0 +1,88 @@ +{pkgs, config, ...}: + +with pkgs.lib; + +let cfg = config.services.gogoclient; +in + +{ + + ###### interface + + options = { + services.gogoclient = { + enable = mkOption { + default = false; + type = types.bool; + description = '' + Enable the gogoclient ipv6 tunnel. + ''; + }; + autorun = mkOption { + default = true; + description = " + Switch to false to create upstart-job and configuration, + but not run it automatically + "; + }; + + username = mkOption { + default = ""; + description = " + Your Gateway6 login name, if any. + "; + }; + + password = mkOption { + default = ""; + type = types.string; + description = " + Path to a file (as a string), containing your gogonet password, if any. + "; + }; + + server = mkOption { + default = "anonymous.freenet6.net"; + example = "broker.freenet6.net"; + description = " + Used Gateway6 server. + "; + }; + }; + }; + + ###### implementation + + config = mkIf cfg.enable { + boot.kernelModules = [ "tun" ]; + + networking.enableIPv6 = true; + + systemd.services.gogoclient = { + description = "ipv6 tunnel"; + + after = [ "network.target" ]; + requires = [ "network.target" ]; + + unitConfig.RequiresMountsFor = "/var/lib/gogoc"; + + script = let authMethod = if cfg.password == "" then "anonymous" else "any"; in '' + mkdir -p -m 700 /var/lib/gogoc + cat ${pkgs.gogoclient}/share/${pkgs.gogoclient.name}/gogoc.conf.sample | \ + ${pkgs.gnused}/bin/sed \ + -e "s|^userid=|&${cfg.username}|" \ + -e "s|^passwd=|&${optionalString (cfg.password != "") "$(cat ${cfg.password})"}|" \ + -e "s|^server=.*|server=${cfg.server}|" \ + -e "s|^auth_method=.*|auth_method=${authMethod}|" \ + -e "s|^#log_file=|log_file=1|" > /var/lib/gogoc/gogoc.conf + cd /var/lib/gogoc + exec ${pkgs.gogoclient}/bin/gogoc -y -f /var/lib/gogoc/gogoc.conf + ''; + } // optionalAttrs cfg.autorun { + wantedBy = [ "ip-up.target" ]; + partOf = [ "ip-up.target" ]; + }; + + }; + +} diff --git a/nixos/modules/services/networking/gvpe.nix b/nixos/modules/services/networking/gvpe.nix new file mode 100644 index 00000000000..594a2e80f34 --- /dev/null +++ b/nixos/modules/services/networking/gvpe.nix @@ -0,0 +1,144 @@ +# GNU Virtual Private Ethernet + +{config, pkgs, ...}: + +let + inherit (pkgs.lib) mkOption mkIf; + + cfg = config.services.gvpe; + + finalConfig = if cfg.configFile != null then + cfg.configFile + else if cfg.configText != null then + pkgs.writeTextFile { + name = "gvpe.conf"; + text = cfg.configText; + } + else + throw "You must either specify contents of the config file or the config file itself for GVPE"; + + ifupScript = if cfg.ipAddress == null || cfg.subnet == null then + throw "Specify IP address and subnet (with mask) for GVPE" + else if cfg.nodename == null then + throw "You must set node name for GVPE" + else + (pkgs.writeTextFile { + name = "gvpe-if-up"; + text = '' + #! /bin/sh + + export PATH=$PATH:${pkgs.iproute}/sbin + + ip link set $IFNAME up + ip address add ${cfg.ipAddress} dev $IFNAME + ip route add ${cfg.subnet} dev $IFNAME + + ${cfg.customIFSetup} + ''; + executable = true; + }); + + exec = "${pkgs.gvpe}/sbin/gvpe -c /var/gvpe -D ${cfg.nodename} " + + " ${cfg.nodename}.pid-file=/var/gvpe/gvpe.pid" + + " ${cfg.nodename}.if-up=if-up" + + " &> /var/log/gvpe"; + + inherit (cfg) startOn stopOn; +in + +{ + options = { + services.gvpe = { + enable = mkOption { + default = false; + description = '' + Whether to run gvpe + ''; + }; + startOn = mkOption { + default = "started network-interfaces"; + description = '' + Condition to start GVPE + ''; + }; + stopOn = mkOption { + default = "stopping network-interfaces"; + description = '' + Condition to stop GVPE + ''; + }; + nodename = mkOption { + default = null; + description ='' + GVPE node name + ''; + }; + configText = mkOption { + default = null; + example = '' + tcp-port = 655 + udp-port = 655 + mtu = 1480 + ifname = vpn0 + + node = alpha + hostname = alpha.example.org + connect = always + enable-udp = true + enable-tcp = true + on alpha if-up = if-up-0 + on alpha pid-file = /var/gvpe/gvpe.pid + ''; + description = '' + GVPE config contents + ''; + }; + configFile = mkOption { + default = null; + example = "/root/my-gvpe-conf"; + description = '' + GVPE config file, if already present + ''; + }; + ipAddress = mkOption { + default = null; + description = '' + IP address to assign to GVPE interface + ''; + }; + subnet = mkOption { + default = null; + example = "10.0.0.0/8"; + description = '' + IP subnet assigned to GVPE network + ''; + }; + customIFSetup = mkOption { + default = ""; + description = '' + Additional commands to apply in ifup script + ''; + }; + }; + }; + config = mkIf cfg.enable { + jobs.gvpe = { + description = "GNU Virtual Private Ethernet node"; + + inherit startOn stopOn; + + preStart = '' + mkdir -p /var/gvpe + mkdir -p /var/gvpe/pubkey + chown root /var/gvpe + chmod 700 /var/gvpe + cp ${finalConfig} /var/gvpe/gvpe.conf + cp ${ifupScript} /var/gvpe/if-up + ''; + + inherit exec; + + respawn = true; + }; + }; +} diff --git a/nixos/modules/services/networking/hostapd.nix b/nixos/modules/services/networking/hostapd.nix new file mode 100644 index 00000000000..4edea12b6be --- /dev/null +++ b/nixos/modules/services/networking/hostapd.nix @@ -0,0 +1,163 @@ +{ config, pkgs, ... }: + +# TODO: +# +# asserts +# ensure that the nl80211 module is loaded/compiled in the kernel +# hwMode must be a/b/g +# channel must be between 1 and 13 (maybe) +# wpa_supplicant and hostapd on the same wireless interface doesn't make any sense +# perhaps an assertion that there is a dhcp server and a dns server on the IP address serviced by the hostapd? + +with pkgs.lib; + +let + + cfg = config.services.hostapd; + + configFile = pkgs.writeText "hostapd.conf" + '' + interface=${cfg.interface} + driver=${cfg.driver} + ssid=${cfg.ssid} + hw_mode=${cfg.hwMode} + channel=${toString cfg.channel} + + # logging (debug level) + logger_syslog=-1 + logger_syslog_level=2 + logger_stdout=-1 + logger_stdout_level=2 + + ctrl_interface=/var/run/hostapd + ctrl_interface_group=${cfg.group} + + ${if cfg.wpa then '' + wpa=1 + wpa_passphrase=${cfg.wpaPassphrase} + '' else ""} + + ${cfg.extraCfg} + '' ; + +in + +{ + ###### interface + + options = { + + services.hostapd = { + + enable = mkOption { + default = false; + description = '' + Enable putting a wireless interface into infrastructure mode, + allowing other wireless devices to associate with the wireless interface and do + wireless networking. A simple access point will enable hostapd.wpa, and + hostapd.wpa_passphrase, hostapd.ssid, dhcpd on the wireless interface to + provide IP addresses to the associated stations, and nat (from the wireless + interface to an upstream interface). + ''; + }; + + interface = mkOption { + default = ""; + example = "wlan0"; + description = '' + The interfaces <command>hostapd</command> will use. + ''; + }; + + driver = mkOption { + default = "nl80211"; + example = "hostapd"; + type = types.string; + description = "Which driver hostapd will use. Most things will probably use the default."; + }; + + ssid = mkOption { + default = "nixos"; + example = "mySpecialSSID"; + type = types.string; + description = "SSID to be used in IEEE 802.11 management frames."; + }; + + hwMode = mkOption { + default = "b"; + example = "g"; + type = types.string; + description = "Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g"; + }; + + channel = mkOption { + default = 7; + example = 11; + type = types.int; + description = + '' + Channel number (IEEE 802.11) + Please note that some drivers do not use this value from hostapd and the + channel will need to be configured separately with iwconfig. + ''; + }; + + group = mkOption { + default = "wheel"; + example = "network"; + type = types.string; + description = "members of this group can control hostapd"; + }; + + wpa = mkOption { + default = true; + description = "enable WPA (IEEE 802.11i/D3.0) to authenticate to the access point"; + }; + + wpaPassphrase = mkOption { + default = "my_sekret"; + example = "any_64_char_string"; + type = types.string; + description = + '' + WPA-PSK (pre-shared-key) passphrase. Clients will need this + passphrase to associate with this access point. Warning: This passphrase will + get put into a world-readable file in the nix store. + ''; + }; + + extraCfg = mkOption { + default = ""; + example = '' + auth_algo=0 + ieee80211n=1 + ht_capab=[HT40-][SHORT-GI-40][DSSS_CCK-40] + ''; + type = types.string; + description = "Extra configuration options to put in the hostapd.conf"; + }; + }; + }; + + + ###### implementation + + config = mkIf cfg.enable { + + environment.systemPackages = [ pkgs.hostapd ]; + + systemd.services.hostapd = + { description = "hostapd wireless AP"; + + path = [ pkgs.hostapd ]; + wantedBy = [ "network.target" ]; + + after = [ "${cfg.interface}-cfg.service" "nat.service" "bind.service" "dhcpd.service"]; + + serviceConfig = + { ExecStart = "${pkgs.hostapd}/bin/hostapd ${configFile}"; + Restart = "always"; + }; + }; + }; +} diff --git a/nixos/modules/services/networking/ifplugd.nix b/nixos/modules/services/networking/ifplugd.nix new file mode 100644 index 00000000000..df50e9807a9 --- /dev/null +++ b/nixos/modules/services/networking/ifplugd.nix @@ -0,0 +1,88 @@ +{pkgs, config, ...}: + +with pkgs.lib; + +let + + inherit (pkgs) ifplugd; + + cfg = config.networking.interfaceMonitor; + + # The ifplugd action script, which is called whenever the link + # status changes (i.e., a cable is plugged in or unplugged). We do + # nothing when a cable is unplugged. When a cable is plugged in, we + # restart dhclient, which will hopefully give us a new IP address + # if appropriate. + plugScript = pkgs.writeScript "ifplugd.action" + '' + #! ${pkgs.stdenv.shell} + iface="$1" + status="$2" + ${cfg.commands} + ''; + +in + +{ + + ###### interface + + options = { + + networking.interfaceMonitor.enable = mkOption { + default = false; + description = '' + If <literal>true</literal>, monitor Ethernet interfaces for + cables being plugged in or unplugged. When this occurs, the + <command>dhclient</command> service is restarted to + automatically obtain a new IP address. This is useful for + roaming users (laptops). + ''; + }; + + networking.interfaceMonitor.beep = mkOption { + default = false; + description = '' + If <literal>true</literal>, beep when an Ethernet cable is + plugged in or unplugged. + ''; + }; + + networking.interfaceMonitor.commands = mkOption { + default = ""; + description = '' + Shell commands to be executed when the link status of an + interface changes. On invocation, the shell variable + <varname>iface</varname> contains the name of the interface, + while the variable <varname>status</varname> contains either + <literal>up</literal> or <literal>down</literal> to indicate + the new status. + ''; + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + jobs.ifplugd = + { description = "Network interface connectivity monitor"; + + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; + + exec = + '' + ${ifplugd}/sbin/ifplugd --no-daemon --no-startup --no-shutdown \ + ${if config.networking.interfaceMonitor.beep then "" else "--no-beep"} \ + --run ${plugScript} + ''; + }; + + environment.systemPackages = [ ifplugd ]; + + }; + +} diff --git a/nixos/modules/services/networking/iodined.nix b/nixos/modules/services/networking/iodined.nix new file mode 100644 index 00000000000..1b3473ee0ee --- /dev/null +++ b/nixos/modules/services/networking/iodined.nix @@ -0,0 +1,87 @@ +# NixOS module for iodine, ip over dns daemon + +{ config, pkgs, ... }: + +with pkgs.lib; + +let + cfg = config.services.iodined; + + iodinedUser = "iodined"; + +in + +{ + + ### configuration + + options = { + + services.iodined = { + + enable = mkOption { + type = types.uniq types.bool; + default = false; + description = "Enable iodine, ip over dns daemon"; + }; + + client = mkOption { + type = types.uniq types.bool; + default = false; + description = "Start iodine in client mode"; + }; + + ip = mkOption { + type = types.uniq types.string; + default = ""; + description = "Assigned ip address or ip range"; + example = "172.16.10.1/24"; + }; + + domain = mkOption { + type = types.uniq types.string; + default = ""; + description = "Domain or subdomain of which nameservers point to us"; + example = "tunnel.mydomain.com"; + }; + + extraConfig = mkOption { + type = types.uniq types.string; + default = ""; + description = "Additional command line parameters"; + example = "-P mysecurepassword -l 192.168.1.10 -p 23"; + }; + + }; + + }; + + ### implementation + + config = mkIf cfg.enable { + environment.systemPackages = [ pkgs.iodine ]; + boot.kernelModules = [ "tun" ]; + + systemd.services.iodined = { + description = "iodine, ip over dns daemon"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig.ExecStart = "${pkgs.iodine}/sbin/iodined -f -u ${iodinedUser} ${cfg.extraConfig} ${cfg.ip} ${cfg.domain}"; + }; + + + users.extraUsers = singleton { + name = iodinedUser; + uid = config.ids.uids.iodined; + description = "Iodine daemon user"; + }; + users.extraGroups.iodined.gid = config.ids.gids.iodined; + + assertions = [{ assertion = if !cfg.client then cfg.ip != "" else true; + message = "cannot start iodined without ip set";} + { assertion = cfg.domain != ""; + message = "cannot start iodined without domain name set";}]; + + }; + +} diff --git a/nixos/modules/services/networking/ircd-hybrid/builder.sh b/nixos/modules/services/networking/ircd-hybrid/builder.sh new file mode 100644 index 00000000000..b8cb836db95 --- /dev/null +++ b/nixos/modules/services/networking/ircd-hybrid/builder.sh @@ -0,0 +1,31 @@ +source $stdenv/setup + +doSub() { + local src=$1 + local dst=$2 + ensureDir $(dirname $dst) + substituteAll $src $dst +} + +subDir=/ +for i in $scripts; do + if test "$(echo $i | cut -c1-2)" = "=>"; then + subDir=$(echo $i | cut -c3-) + else + dst=$out/$subDir/$((stripHash $i; echo $strippedName) | sed 's/\.in//') + doSub $i $dst + chmod +x $dst # !!! + fi +done + +subDir=/ +for i in $substFiles; do + if test "$(echo $i | cut -c1-2)" = "=>"; then + subDir=$(echo $i | cut -c3-) + else + dst=$out/$subDir/$((stripHash $i; echo $strippedName) | sed 's/\.in//') + doSub $i $dst + fi +done + +ensureDir $out/bin diff --git a/nixos/modules/services/networking/ircd-hybrid/control.in b/nixos/modules/services/networking/ircd-hybrid/control.in new file mode 100644 index 00000000000..312dfaada32 --- /dev/null +++ b/nixos/modules/services/networking/ircd-hybrid/control.in @@ -0,0 +1,26 @@ +#! @shell@ -e + +# Make sure that the environment is deterministic. +export PATH=@coreutils@/bin + +if test "$1" = "start"; then + if ! @procps@/bin/pgrep ircd; then + if @ipv6Enabled@; then + while ! @iproute@/sbin/ip addr | + @gnugrep@/bin/grep inet6 | + @gnugrep@/bin/grep global; do + sleep 1; + done; + fi; + rm -rf /home/ircd + mkdir -p /home/ircd + chown ircd: /home/ircd + cd /home/ircd + env - HOME=/homeless-shelter $extraEnv \ + @su@/bin/su ircd --shell=/bin/sh -c ' @ircdHybrid@/bin/ircd -configfile @out@/conf/ircd.conf </dev/null -logfile /home/ircd/ircd.log' 2>&1 >/var/log/ircd-hybrid.out + fi; +fi + +if test "$1" = "stop" ; then + @procps@/bin/pkill ircd; +fi; diff --git a/nixos/modules/services/networking/ircd-hybrid/default.nix b/nixos/modules/services/networking/ircd-hybrid/default.nix new file mode 100644 index 00000000000..cd82a41ef7a --- /dev/null +++ b/nixos/modules/services/networking/ircd-hybrid/default.nix @@ -0,0 +1,137 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.ircdHybrid; + + ircdService = pkgs.stdenv.mkDerivation rec { + name = "ircd-hybrid-service"; + scripts = [ "=>/bin" ./control.in ]; + substFiles = [ "=>/conf" ./ircd.conf ]; + inherit (pkgs) ircdHybrid coreutils su iproute gnugrep procps; + + ipv6Enabled = if config.networking.enableIPv6 then "true" else "false"; + + inherit (cfg) serverName sid description adminEmail + extraPort; + + cryptoSettings = + (optionalString (cfg.rsaKey != null) "rsa_private_key_file = \"${cfg.rsaKey}\";\n") + + (optionalString (cfg.certificate != null) "ssl_certificate_file = \"${cfg.certificate}\";\n"); + + extraListen = map (ip: "host = \""+ip+"\";\nport = 6665 .. 6669, "+extraPort+"; ") cfg.extraIPs; + + builder = ./builder.sh; + }; + +in + +{ + + ###### interface + + options = { + + services.ircdHybrid = { + + enable = mkOption { + default = false; + description = " + Enable IRCD. + "; + }; + + serverName = mkOption { + default = "hades.arpa"; + description = " + IRCD server name. + "; + }; + + sid = mkOption { + default = "0NL"; + description = " + IRCD server unique ID in a net of servers. + "; + }; + + description = mkOption { + default = "Hybrid-7 IRC server."; + description = " + IRCD server description. + "; + }; + + rsaKey = mkOption { + default = null; + example = /root/certificates/irc.key; + description = " + IRCD server RSA key. + "; + }; + + certificate = mkOption { + default = null; + example = /root/certificates/irc.pem; + description = " + IRCD server SSL certificate. There are some limitations - read manual. + "; + }; + + adminEmail = mkOption { + default = "<bit-bucket@example.com>"; + example = "<name@domain.tld>"; + description = " + IRCD server administrator e-mail. + "; + }; + + extraIPs = mkOption { + default = []; + example = ["127.0.0.1"]; + description = " + Extra IP's to bind. + "; + }; + + extraPort = mkOption { + default = "7117"; + description = " + Extra port to avoid filtering. + "; + }; + + }; + + }; + + + ###### implementation + + config = mkIf config.services.ircdHybrid.enable { + + users.extraUsers = singleton + { name = "ircd"; + description = "IRCD owner"; + group = "ircd"; + uid = config.ids.uids.ircd; + }; + + users.extraGroups.ircd.gid = config.ids.gids.ircd; + + jobs.ircd_hybrid = + { name = "ircd-hybrid"; + + description = "IRCD Hybrid server"; + + startOn = "started networking"; + stopOn = "stopping networking"; + + exec = "${ircdService}/bin/control start"; + }; + + }; + +} diff --git a/nixos/modules/services/networking/ircd-hybrid/ircd.conf b/nixos/modules/services/networking/ircd-hybrid/ircd.conf new file mode 100644 index 00000000000..bb22832dbdb --- /dev/null +++ b/nixos/modules/services/networking/ircd-hybrid/ircd.conf @@ -0,0 +1,1051 @@ +/* doc/example.conf - ircd-hybrid-7 Example configuration file + * Copyright (C) 2000-2006 Hybrid Development Team + * + * Written by ejb, wcampbel, db, leeh and others + * Other example configurations can be found in the source dir under + * etc/. + * + * $Id: example.conf 639 2006-06-01 14:12:21Z michael $ + */ + +/* IMPORTANT NOTES: + * + * auth {} blocks MUST be specified in order of precedence. The first one + * that matches a user will be used. So place spoofs first, then specials, + * then general access. + * + * Shell style (#), C++ style (//) and C style comments are supported. + * + * Files may be included by either: + * .include "filename" + * .include <filename> + * + * Times/durations are written as: + * 12 hours 30 minutes 1 second + * + * Valid units of time: + * month, week, day, hour, minute, second + * + * Valid units of size: + * megabyte/mbyte/mb, kilobyte/kbyte/kb, byte + * + * Sizes and times may be singular or plural. + */ + +/* EFNET NOTE: + * + * This config file is NOT suitable for EFNet. EFNet admins should use + * example.efnet.conf + */ + +/* + * serverinfo {}: contains information about the server. (OLD M:) + */ +serverinfo { + /* + * name: the name of our server. This cannot be changed at runtime. + */ + name = "@serverName@"; + + /* + * sid: a server's unique ID. This is three characters long and must + * be in the form [0-9][A-Z0-9][A-Z0-9]. The first character must be + * a digit, followed by 2 alpha-numerical letters. + * NOTE: The letters must be capitalized. This cannot be changed at runtime. + */ + sid = "@sid@"; + + /* + * description: the description of the server. '[' and ']' may not + * be used here for compatibility with older servers. + */ + description = "@description@"; + + /* + * network info: the name and description of the network this server + * is on. Shown in the 005 reply and used with serverhiding. + */ + network_name = "JustIRCNetwork"; + network_desc = "This is My Network"; + + /* + * hub: allow this server to act as a hub and have multiple servers + * connected to it. This may not be changed if there are active + * LazyLink servers. + */ + hub = no; + + /* + * vhost: the IP to bind to when we connect outward to ipv4 servers. + * This should be an ipv4 IP only, or "* for INADDR_ANY. + */ + #vhost = "192.169.0.1"; + + /* + * vhost6: the IP to bind to when we connect outward to ipv6 servers. + * This should be an ipv6 IP only, or "* for INADDR_ANY. + */ + #vhost6 = "3ffe:80e8:546::2"; + + /* max_clients: the maximum number of clients allowed to connect */ + max_clients = 512; + + /* + * rsa key: the path to the file containing our rsa key for cryptlink. + * + * Example command to store a 2048 bit RSA keypair in + * rsa.key, and the public key in rsa.pub: + * + * openssl genrsa -out rsa.key 2048 + * openssl rsa -in rsa.key -pubout -out rsa.pub + * chown <ircd-user>.<ircd.group> rsa.key rsa.pub + * chmod 0600 rsa.key + * chmod 0644 rsa.pub + */ + #rsa_private_key_file = "/usr/local/ircd/etc/rsa.key"; + + /* + * ssl certificate: the path to the file containing our ssl certificate + * for encrypted client connection. + * + * This assumes your private RSA key is stored in rsa.key. You + * MUST have an RSA key in order to generate the certificate + * + * openssl req -new -days 365 -x509 -key rsa.key -out cert.pem + * + * See http://www.openssl.org/docs/HOWTO/certificates.txt + * + * Please use the following values when generating the cert + * + * Organization Name: Network Name + * Organization Unit Name: changme.someirc.net + * Common Name: irc.someirc.net + * E-mail: you@domain.com + */ + #ssl_certificate_file = "/usr/local/ircd/etc/cert.pem"; + + @cryptoSettings@ +}; + +/* + * admin {}: contains admin information about the server. (OLD A:) + */ +admin { + name = "Anonymous Hero"; + description = "Main Server Administrator"; + email = "@adminEmail@"; +}; + +/* + * log {}: contains information about logfiles. + */ +log { + /* Do you want to enable logging to ircd.log? */ + use_logging = yes; + + /* + * logfiles: the logfiles to use for user connects, /oper uses, + * and failed /oper. These files must exist for logging to be used. + */ + fname_userlog = "/home/ircd/logs/userlog"; + fname_operlog = "/home/ircd/logs/operlog"; + fname_killlog = "/home/ircd/logs/kill"; + fname_klinelog = "/home/ircd/logs/kline"; + fname_glinelog = "/home/ircd/logs/gline"; + + /* + * log_level: the amount of detail to log in ircd.log. The + * higher, the more information is logged. May be changed + * once the server is running via /quote SET LOG. Either: + * L_CRIT, L_ERROR, L_WARN, L_NOTICE, L_TRACE, L_INFO or L_DEBUG + */ + log_level = L_INFO; +}; + +/* + * class {}: contains information about classes for users (OLD Y:) + */ +class { + /* name: the name of the class. classes are text now */ + name = "users"; + + /* + * ping_time: how often a client must reply to a PING from the + * server before they are dropped. + */ + ping_time = 90 seconds; + + /* + * number_per_ip: how many local users are allowed to connect + * from one IP (optional) + */ + number_per_ip = 10; + + /* + * max_local: how many local users are allowed to connect + * from one ident@host (optional) + */ + max_local = 50; + + /* + * max_global: network-wide limit of users per ident@host (optional) + */ + max_global = 50; + + /* + * max_number: the maximum number of users allowed in this class (optional) + */ + max_number = 10000; + + /* + * the following lines are optional and allow you to define + * how many users can connect from one /NN subnet + */ + /*cidr_bitlen_ipv4 = 24; + *cidr_bitlen_ipv6 = 120; + *number_per_cidr = 16;*/ + + /* + * sendq: the amount of data allowed in a clients queue before + * they are dropped. + */ + sendq = 100 kbytes; +}; + +class { + name = "opers"; + ping_time = 90 seconds; + number_per_ip = 10; + max_number = 100; + sendq = 100kbytes; +}; + +class { + name = "server"; + ping_time = 90 seconds; + + /* + * ping_warning: how fast a server must reply to a PING before + * a warning to opers is generated. + */ + ping_warning = 15 seconds; + + /* + * connectfreq: only used in server classes. Specifies the delay + * between autoconnecting to servers. + */ + connectfreq = 5 minutes; + + /* max number: the amount of servers to autoconnect to */ + max_number = 1; + + /* sendq: servers need a higher sendq as they send more data */ + sendq = 2 megabytes; +}; + +/* + * listen {}: contains information about the ports ircd listens on (OLD P:) + */ +listen { + /* + * port: the specific port to listen on. If no host is specified + * before, it will listen on all available IPs. + * + * Ports are separated via a comma, a range may be specified using ".." + */ + + /* port: listen on all available IPs, ports 6665 to 6669 */ + port = 6665 .. 6669; + + /* + * Listen on 192.168.0.1/6697 with ssl enabled and hidden from STATS P + * unless you are an administrator. + * + * NOTE: The "flags" directive has to come before "port". Always! + */ + #flags = hidden, ssl; + #host = "192.168.0.1"; + #port = 6697; + + /* + * host: set a specific IP/host the ports after the line will listen + * on. This may be ipv4 or ipv6. + */ + #host = "1.2.3.4"; + #port = 7000, 7001; + + #host = "3ffe:1234:a:b:c::d"; + #port = 7002; + + @extraListen@ +}; + +auth { + user = "*@*"; + class = "users"; + #flags = need_ident; +}; + +/* + * operator {}: defines ircd operators. (OLD O:) + * + * ircd-hybrid no longer supports local operators, privileges are + * controlled via flags. + */ +operator { + /* name: the name of the oper */ + /* NOTE: operator "opername"{} is also supported */ + name = "god"; + + /* + * user: the user@host required for this operator. CIDR is not + * supported. Multiple user="" lines are supported. + */ + user = "*god@*"; + user = "*@127.0.0.1"; + + /* + * password: the password required to oper. By default this will + * need to be encrypted using 'mkpasswd'. MD5 is supported. + */ + password = "iamoperator"; + + /* + * encrypted: controls whether the oper password above has been + * encrypted. (OLD CRYPT_OPER_PASSWORD now optional per operator) + */ + encrypted = no; + + /* + * rsa_public_key_file: the public key for this oper when using Challenge. + * A password should not be defined when this is used, see + * doc/challenge.txt for more information. + */ +# rsa_public_key_file = "/usr/local/ircd/etc/oper.pub"; + + /* class: the class the oper joins when they successfully /oper */ + class = "opers"; + + /* + * umodes: default usermodes opers get when they /oper. If defined, + * it will override oper_umodes settings in general {}. + * Available usermodes: + * + * +b - bots - See bot and drone flooding notices + * +c - cconn - Client connection/quit notices + * +D - deaf - Don't receive channel messages + * +d - debug - See debugging notices + * +f - full - See I: line full notices + * +G - softcallerid - Server Side Ignore for users not on your channels + * +g - callerid - Server Side Ignore (for privmsgs etc) + * +i - invisible - Not shown in NAMES or WHO unless you share a + * a channel + * +k - skill - See server generated KILL messages + * +l - locops - See LOCOPS messages + * +n - nchange - See client nick changes + * +r - rej - See rejected client notices + * +s - servnotice - See general server notices + * +u - unauth - See unauthorized client notices + * +w - wallop - See server generated WALLOPS + * +x - external - See remote server connection and split notices + * +y - spy - See LINKS, STATS, TRACE notices etc. + * +z - operwall - See oper generated WALLOPS + */ +# umodes = locops, servnotice, operwall, wallop; + + /* + * privileges: controls the activities and commands an oper is + * allowed to do on the server. All options default to no. + * Available options: + * + * global_kill: allows remote users to be /KILL'd (OLD 'O' flag) + * remote: allows remote SQUIT and CONNECT (OLD 'R' flag) + * remoteban: allows remote KLINE/UNKLINE + * kline: allows KILL, KLINE and DLINE (OLD 'K' flag) + * unkline: allows UNKLINE and UNDLINE (OLD 'U' flag) + * gline: allows GLINE (OLD 'G' flag) + * xline: allows XLINE (OLD 'X' flag) + * operwall: allows OPERWALL + * nick_changes: allows oper to see nickchanges (OLD 'N' flag) + * via usermode +n + * rehash: allows oper to REHASH config (OLD 'H' flag) + * die: allows DIE and RESTART (OLD 'D' flag) + * admin: gives admin privileges. admins + * may (un)load modules and see the + * real IPs of servers. + * hidden_admin: same as 'admin', but noone can recognize you as + * being an admin + * hidden_oper: not shown in /stats p (except for other operators) + */ + /* You can either use + * die = yes; + * rehash = yes; + * + * or in a flags statement i.e. + * flags = die, rehash; + * + * You can also negate a flag with ~ i.e. + * flags = ~remote; + * + */ + flags = global_kill, remote, kline, unkline, xline, + die, rehash, nick_changes, admin, operwall; +}; + +/* + * shared {}: users that are allowed to remote kline (OLD U:) + * + * NOTE: This can be effectively used for remote klines. + * Please note that there is no password authentication + * for users setting remote klines. You must also be + * /oper'd in order to issue a remote kline. + */ +shared { + /* + * name: the server the user must be on to set klines. If this is not + * specified, the user will be allowed to kline from all servers. + */ + name = "irc2.some.server"; + + /* + * user: the user@host mask that is allowed to set klines. If this is + * not specified, all users on the server above will be allowed to set + * a remote kline. + */ + user = "oper@my.host.is.spoofed"; + + /* + * type: list of what to share, options are as follows: + * kline - allow oper/server to kline + * tkline - allow temporary klines + * unkline - allow oper/server to unkline + * xline - allow oper/server to xline + * txline - allow temporary xlines + * unxline - allow oper/server to unxline + * resv - allow oper/server to resv + * tresv - allow temporary resvs + * unresv - allow oper/server to unresv + * locops - allow oper/server to locops - only used for servers that cluster + * all - allow oper/server to do all of the above (default) + */ + type = kline, unkline, resv; +}; + +/* + * kill {}: users that are not allowed to connect (OLD K:) + * Oper issued klines will be added to the specified kline config + */ +kill { + user = "bad@*.hacked.edu"; + reason = "Obviously hacked account"; +}; + +kill { + user = "^O[[:alpha:]]?[[:digit:]]+(x\.o|\.xo)$@^[[:alnum:]]{4}\.evilnet.org$"; + type = regex; +}; + +/* + * deny {}: IPs that are not allowed to connect (before DNS/ident lookup) + * Oper issued dlines will be added to the specified dline config + */ +deny { + ip = "10.0.1.0/24"; + reason = "Reconnecting vhosted bots"; +}; + +/* + * exempt {}: IPs that are exempt from deny {} and Dlines. (OLD d:) + */ +exempt { + ip = "192.168.0.0/16"; +}; + +/* + * resv {}: nicks and channels users may not use/join (OLD Q:) + */ +resv { + /* reason: the reason for the proceeding resv's */ + reason = "There are no services on this network"; + + /* resv: the nicks and channels users may not join/use */ + nick = "nickserv"; + nick = "chanserv"; + channel = "#services"; + + /* resv: wildcard masks are also supported in nicks only */ + reason = "Clone bots"; + nick = "clone*"; +}; + +/* + * gecos {}: The X: replacement, used for banning users based on + * their "realname". + */ +gecos { + name = "*sex*"; + reason = "Possible spambot"; +}; + +gecos { + name = "sub7server"; + reason = "Trojan drone"; +}; + +gecos { + name = "*http*"; + reason = "Spambot"; +}; + +gecos { + name = "^\[J[0o]hn Do[3e]\]-[0-9]{2,5}$"; + type = regex; +}; + +/* + * channel {}: The channel block contains options pertaining to channels + */ +channel { + /* + * disable_fake_channels: this option, if set to 'yes', will + * disallow clients to create or join channels that have one + * of the following ASCII characters in their name: + * + * 2 | bold + * 3 | mirc color + * 15 | plain text + * 22 | reverse + * 31 | underline + * 160 | non-breaking space + */ + disable_fake_channels = yes; + + /* + * restrict_channels: reverse channel RESVs logic, only reserved + * channels are allowed + */ + restrict_channels = no; + + /* + * disable_local_channels: prevent users from joining &channels. + */ + disable_local_channels = no; + + /* + * use_invex: Enable/disable channel mode +I, a n!u@h list of masks + * that can join a +i channel without an invite. + */ + use_invex = yes; + + /* + * use_except: Enable/disable channel mode +e, a n!u@h list of masks + * that can join a channel through a ban (+b). + */ + use_except = yes; + + /* + * use_knock: Allows users to request an invite to a channel that + * is locked somehow (+ikl). If the channel is +p or you are banned + * the knock will not be sent. + */ + use_knock = yes; + + /* + * knock_delay: The amount of time a user must wait between issuing + * the knock command. + */ + knock_delay = 1 minutes; + + /* + * knock_delay_channel: How often a knock to any specific channel + * is permitted, regardless of the user sending the knock. + */ + knock_delay_channel = 1 minute; + + /* + * burst_topicwho: enable sending of who set topic on topicburst + * default is yes + */ + burst_topicwho = yes; + + /* + * max_chans_per_user: The maximum number of channels a user can + * join/be on. + */ + max_chans_per_user = 25; + + /* quiet_on_ban: stop banned people talking in channels. */ + quiet_on_ban = yes; + + /* max_bans: maximum number of +b/e/I modes in a channel */ + max_bans = 1000; + + /* + * how many joins in how many seconds constitute a flood, use 0 to + * disable. +b opers will be notified (changeable via /set) + */ + join_flood_count = 100; + join_flood_time = 10 seconds; + + /* + * splitcode: The ircd will now check splitmode every few seconds. + * + * Either split users or split servers can activate splitmode, but + * both conditions must be met for the ircd to deactivate splitmode. + * + * You may force splitmode to be permanent by /quote set splitmode on + */ + + /* + * default_split_user_count: when the usercount is lower than this level, + * consider ourselves split. This must be set for automatic splitmode. + */ + default_split_user_count = 0; + + /* + * default_split_server_count: when the servercount is lower than this, + * consider ourselves split. This must be set for automatic splitmode. + */ + default_split_server_count = 0; + + /* split no create: disallow users creating channels on split. */ + no_create_on_split = yes; + + /* split: no join: disallow users joining channels at all on a split */ + no_join_on_split = no; +}; + +/* + * serverhide {}: The serverhide block contains the options regarding + * serverhiding + */ +serverhide { + /* + * flatten_links: this option will show all servers in /links appear + * that they are linked to this current server + */ + flatten_links = no; + + /* + * links_delay: how often to update the links file when it is + * flattened. + */ + links_delay = 5 minutes; + + /* + * hidden: hide this server from a /links output on servers that + * support it. This allows hub servers to be hidden etc. + */ + hidden = no; + + /* + * disable_hidden: prevent servers hiding themselves from a + * /links output. + */ + disable_hidden = no; + + /* + * hide_servers: hide remote servernames everywhere and instead use + * hidden_name and network_desc. + */ + hide_servers = no; + + /* + * Use this as the servername users see if hide_servers = yes. + */ + hidden_name = "*.hidden.com"; + + /* + * hide_server_ips: If this is disabled, opers will be unable to see servers + * ips and will be shown a masked ip, admins will be shown the real ip. + * + * If this is enabled, nobody can see a servers ip. *This is a kludge*, it + * has the side effect of hiding the ips everywhere, including logfiles. + * + * We recommend you leave this disabled, and just take care with who you + * give admin=yes; to. + */ + hide_server_ips = no; +}; + +/* + * general {}: The general block contains many of the options that were once + * compiled in options in config.h. The general block is read at start time. + */ +general { + /* + * gline_min_cidr: the minimum required length of a CIDR bitmask + * for IPv4 based glines + */ + gline_min_cidr = 16; + + /* + * gline_min_cidr6: the minimum required length of a CIDR bitmask + * for IPv6 based glines + */ + gline_min_cidr6 = 48; + + /* + * Whether to automatically set mode +i on connecting users. + */ + invisible_on_connect = yes; + + /* + * If you don't explicitly specify burst_away in your connect blocks, then + * they will default to the burst_away value below. + */ + burst_away = no; + + /* + * Show "actually using host <ip>" on /whois when possible. + */ + use_whois_actually = yes; + + /* + * Max time from the nickname change that still causes KILL + * automatically to switch for the current nick of that user. (seconds) + */ + kill_chase_time_limit = 90; + + /* + * If hide_spoof_ips is disabled, opers will be allowed to see the real IP of spoofed + * users in /trace etc. If this is defined they will be shown a masked IP. + */ + hide_spoof_ips = yes; + + /* + * Ignore bogus timestamps from other servers. Yes, this will desync + * the network, but it will allow chanops to resync with a valid non TS 0 + * + * This should be enabled network wide, or not at all. + */ + ignore_bogus_ts = no; + + /* + * disable_auth: completely disable ident lookups; if you enable this, + * be careful of what you set need_ident to in your auth {} blocks + */ + disable_auth = no; + + /* disable_remote_commands: disable users doing commands on remote servers */ + disable_remote_commands = no; + + /* + * tkline_expire_notices: enables or disables temporary kline/xline + * expire notices. + */ + tkline_expire_notices = no; + + /* + * default_floodcount: the default value of floodcount that is configurable + * via /quote set floodcount. This is the amount of lines a user + * may send to any other user/channel in one second. + */ + default_floodcount = 10; + + /* + * failed_oper_notice: send a notice to all opers on the server when + * someone tries to OPER and uses the wrong password, host or ident. + */ + failed_oper_notice = yes; + + /* + * dots_in_ident: the amount of '.' characters permitted in an ident + * reply before the user is rejected. + */ + dots_in_ident = 2; + + /* + * dot_in_ip6_addr: ircd-hybrid-6.0 and earlier will disallow hosts + * without a '.' in them. This will add one to the end. Only needed + * for older servers. + */ + dot_in_ip6_addr = no; + + /* + * min_nonwildcard: the minimum non wildcard characters in k/d/g lines + * placed via the server. klines hand placed are exempt from limits. + * wildcard chars: '.' ':' '*' '?' '@' '!' '#' + */ + min_nonwildcard = 4; + + /* + * min_nonwildcard_simple: the minimum non wildcard characters in + * gecos bans. wildcard chars: '*' '?' '#' + */ + min_nonwildcard_simple = 3; + + /* max_accept: maximum allowed /accept's for +g usermode */ + max_accept = 20; + + /* anti_nick_flood: enable the nickflood control code */ + anti_nick_flood = yes; + + /* nick flood: the nick changes allowed in the specified period */ + max_nick_time = 20 seconds; + max_nick_changes = 5; + + /* + * anti_spam_exit_message_time: the minimum time a user must be connected + * before custom quit messages are allowed. + */ + anti_spam_exit_message_time = 5 minutes; + + /* + * ts delta: the time delta allowed between server clocks before + * a warning is given, or before the link is dropped. all servers + * should run ntpdate/rdate to keep clocks in sync + */ + ts_warn_delta = 30 seconds; + ts_max_delta = 5 minutes; + + /* + * kline_with_reason: show the user the reason why they are k/d/glined + * on exit. May give away who set k/dline when set via tcm. + */ + kline_with_reason = yes; + + /* + * kline_reason: show this message to users on channel + * instead of the oper reason. + */ + kline_reason = "Connection closed"; + + /* + * reject_hold_time: wait this amount of time before disconnecting + * a rejected client. Use 0 to disable. + */ + reject_hold_time = 0; + + /* + * warn_no_nline: warn opers about servers that try to connect but + * we don't have a connect {} block for. Twits with misconfigured + * servers can get really annoying with this enabled. + */ + warn_no_nline = yes; + + /* + * stats_e_disabled: set this to 'yes' to disable "STATS e" for both + * operators and administrators. Doing so is a good idea in case + * there are any exempted (exempt{}) server IPs you don't want to + * see leaked. + */ + stats_e_disabled = no; + + /* stats_o_oper only: make stats o (opers) oper only */ + stats_o_oper_only = yes; + + /* stats_P_oper_only: make stats P (ports) oper only */ + stats_P_oper_only = yes; + + /* + * stats i oper only: make stats i (auth {}) oper only. set to: + * yes: show users no auth blocks, made oper only. + * masked: show users first matching auth block + * no: show users all auth blocks. + */ + stats_i_oper_only = yes; + + /* + * stats_k_oper_only: make stats k/K (klines) oper only. set to: + * yes: show users no auth blocks, made oper only + * masked: show users first matching auth block + * no: show users all auth blocks. + */ + stats_k_oper_only = yes; + + /* + * caller_id_wait: time between notifying a +g user that somebody + * is messaging them. + */ + caller_id_wait = 1 minute; + + /* + * opers_bypass_callerid: allows operators to bypass +g and message + * anyone who has it set (useful if you use services). + */ + opers_bypass_callerid = no; + + /* + * pace_wait_simple: time between use of less intensive commands + * (ADMIN, HELP, (L)USERS, VERSION, remote WHOIS) + */ + pace_wait_simple = 1 second; + + /* + * pace_wait: time between more intensive commands + * (INFO, LINKS, LIST, MAP, MOTD, STATS, WHO, wildcard WHOIS, WHOWAS) + */ + pace_wait = 10 seconds; + + /* + * short_motd: send clients a notice telling them to read the motd + * instead of forcing a motd to clients who may simply ignore it. + */ + short_motd = no; + + /* + * ping_cookie: require clients to respond exactly to a ping command, + * can help block certain types of drones and FTP PASV mode spoofing. + */ + ping_cookie = no; + + /* no_oper_flood: increase flood limits for opers. */ + no_oper_flood = yes; + + /* + * true_no_oper_flood: completely eliminate flood limits for opers + * and for clients with can_flood = yes in their auth {} blocks + */ + true_no_oper_flood = yes; + + /* oper_pass_resv: allow opers to over-ride RESVs on nicks/channels */ + oper_pass_resv = yes; + + /* + * idletime: the maximum amount of time a user may idle before + * they are disconnected + */ + idletime = 0; + + /* REMOVE ME. The following line checks you've been reading. */ + #havent_read_conf = 1; + + /* + * max_targets: the maximum amount of targets in a single + * PRIVMSG/NOTICE. Set to 999 NOT 0 for unlimited. + */ + max_targets = 4; + + /* + * client_flood: maximum amount of data in a clients queue before + * they are dropped for flooding. + */ + client_flood = 2560 bytes; + + /* + * message_locale: the default message locale + * Use "standard" for the compiled in defaults. + * To install the translated messages, go into messages/ in the + * source directory and run `make install'. + */ + message_locale = "standard"; + + /* + * usermodes configurable: a list of usermodes for the options below + * + * +b - bots - See bot and drone flooding notices + * +c - cconn - Client connection/quit notices + * +D - deaf - Don't receive channel messages + * +d - debug - See debugging notices + * +f - full - See I: line full notices + * +G - softcallerid - Server Side Ignore for users not on your channels + * +g - callerid - Server Side Ignore (for privmsgs etc) + * +i - invisible - Not shown in NAMES or WHO unless you share a + * a channel + * +k - skill - See server generated KILL messages + * +l - locops - See LOCOPS messages + * +n - nchange - See client nick changes + * +r - rej - See rejected client notices + * +s - servnotice - See general server notices + * +u - unauth - See unauthorized client notices + * +w - wallop - See server generated WALLOPS + * +x - external - See remote server connection and split notices + * +y - spy - See LINKS, STATS, TRACE notices etc. + * +z - operwall - See oper generated WALLOPS + */ + + /* oper_only_umodes: usermodes only opers may set */ + oper_only_umodes = bots, cconn, debug, full, skill, nchange, + rej, spy, external, operwall, locops, unauth; + + /* oper_umodes: default usermodes opers get when they /oper */ + oper_umodes = bots, locops, servnotice, operwall, wallop; + + /* + * servlink_path: path to 'servlink' program used by ircd to handle + * encrypted/compressed server <-> server links. + * + * only define if servlink is not in same directory as ircd itself. + */ + #servlink_path = "/usr/local/ircd/bin/servlink"; + + /* + * default_cipher_preference: default cipher to use for cryptlink when none is + * specified in connect block. + */ + #default_cipher_preference = "BF/168"; + + /* + * use_egd: if your system does not have *random devices yet you + * want to use OpenSSL and encrypted links, enable this. Beware - + * EGD is *very* CPU intensive when gathering data for its pool + */ +# use_egd = yes; + + /* + * egdpool_path: path to EGD pool. Not necessary for OpenSSL >= 0.9.7 + * which automatically finds the path. + */ +# egdpool_path = "/var/run/egd-pool"; + + + /* + * compression_level: level of compression for compressed links between + * servers. + * + * values are between: 1 (least compression, fastest) + * and: 9 (most compression, slowest). + */ +# compression_level = 6; + + /* + * throttle_time: the minimum amount of time between connections from + * the same ip. exempt {} blocks are excluded from this throttling. + * Offers protection against flooders who reconnect quickly. + * Set to 0 to disable. + */ + throttle_time = 10; +}; + +glines { + /* enable: enable glines, network wide temp klines */ + enable = yes; + + /* + * duration: the amount of time a gline will remain on your + * server before expiring + */ + duration = 1 day; + + /* + * logging: which types of rules you want to log when triggered + * (choose reject or block) + */ + logging = reject, block; + + /* + * NOTE: gline ACLs can cause a desync of glines throughout the + * network, meaning some servers may have a gline triggered, and + * others may not. Also, you only need insert rules for glines + * that you want to block and/or reject. If you want to accept and + * propagate the gline, do NOT put a rule for it. + */ + + /* user@host for rule to apply to */ + user = "god@I.still.hate.packets"; + /* server for rule to apply to */ + name = "hades.arpa"; + + /* + * action: action to take when a matching gline is found. options are: + * reject - do not apply the gline locally + * block - do not propagate the gline + */ + action = reject, block; + + user = "god@*"; + name = "*"; + action = block; +}; + diff --git a/nixos/modules/services/networking/minidlna.nix b/nixos/modules/services/networking/minidlna.nix new file mode 100644 index 00000000000..ea5bc8514f1 --- /dev/null +++ b/nixos/modules/services/networking/minidlna.nix @@ -0,0 +1,112 @@ +# Module for MiniDLNA, a simple DLNA server. + +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.minidlna; + + port = 8200; + +in + +{ + + ###### interface + + options = { + + services.minidlna.enable = mkOption { + type = types.bool; + default = false; + description = + '' + Whether to enable MiniDLNA, a simple DLNA server. It serves + media files such as video and music to DLNA client devices + such as televisions and media players. + ''; + }; + + services.minidlna.mediaDirs = mkOption { + type = types.listOf types.string; + default = []; + examples = [ "/data/media" "V,/home/alice/video" ]; + description = + '' + Directories to be scanned for media files. The prefixes + <literal>A,</literal>, <literal>V,</literal> and + <literal>P,</literal> restrict a directory to audio, video + or image files. The directories must be accessible to the + <literal>minidlna</literal> user account. + ''; + }; + + services.minidlna.config = mkOption { + type = types.lines; + description = "The contents of MiniDLNA's configuration file."; + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + # Running minidlna only makes sense for serving files to the + # outside, so open up the required ports by default. + networking.firewall.allowedTCPPorts = [ port ]; + networking.firewall.allowedUDPPorts = [ 1900 ]; # SSDP + + services.minidlna.config = + '' + port=${toString port} + friendly_name=NixOS Media Server + db_dir=/var/cache/minidlna + log_dir=/var/log/minidlna + inotify=yes + ${concatMapStrings (dir: '' + media_dir=${dir} + '') cfg.mediaDirs} + ''; + + users.extraUsers.minidlna = { + description = "MiniDLNA daemon user"; + group = "minidlna"; + uid = config.ids.uids.minidlna; + }; + + users.extraGroups.minidlna.gid = config.ids.gids.minidlna; + + systemd.services.minidlna = + { description = "MiniDLNA Server"; + + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + + preStart = + '' + mkdir -p /var/cache/minidlna /var/log/minidlna /run/minidlna + chown minidlna /var/cache/minidlna /var/log/minidlna /run/minidlna + ''; + + # FIXME: log through the journal rather than + # /var/log/minidlna. The -d flag does that, but also raises + # the log level to debug... + serviceConfig = + { User = "minidlna"; + Group = "nogroup"; + PermissionsStartOnly = true; + Type = "forking"; + PIDFile = "/run/minidlna/pid"; + ExecStart = + "@${pkgs.minidlna}/sbin/minidlna minidlna -P /run/minidlna/pid" + + " -f ${pkgs.writeText "minidlna.conf" cfg.config}"; + }; + }; + + }; + +} diff --git a/nixos/modules/services/networking/nat.nix b/nixos/modules/services/networking/nat.nix new file mode 100644 index 00000000000..9d62a764f06 --- /dev/null +++ b/nixos/modules/services/networking/nat.nix @@ -0,0 +1,104 @@ +# This module enables Network Address Translation (NAT). +# XXX: todo: support multiple upstream links +# see http://yesican.chsoft.biz/lartc/MultihomedLinuxNetworking.html + +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.networking.nat; + +in + +{ + + ###### interface + + options = { + + networking.nat.enable = mkOption { + default = false; + description = + '' + Whether to enable Network Address Translation (NAT). + ''; + }; + + networking.nat.internalIPs = mkOption { + example = [ "192.168.1.0/24" ] ; + description = + '' + The IP address ranges for which to perform NAT. Packets + coming from these networks and destined for the external + interface will be rewritten. + ''; + # Backward compatibility: this used to be a single range instead + # of a list. + apply = x: if isList x then x else [x]; + }; + + networking.nat.externalInterface = mkOption { + example = "eth1"; + description = + '' + The name of the external network interface. + ''; + }; + + networking.nat.externalIP = mkOption { + default = ""; + example = "203.0.113.123"; + description = + '' + The public IP address to which packets from the local + network are to be rewritten. If this is left empty, the + IP address associated with the external interface will be + used. + ''; + }; + + }; + + + ###### implementation + + config = mkIf config.networking.nat.enable { + + environment.systemPackages = [ pkgs.iptables ]; + + boot.kernelModules = [ "nf_nat_ftp" ]; + + jobs.nat = + { description = "Network Address Translation"; + + startOn = "started network-interfaces"; + + path = [ pkgs.iptables ]; + + preStart = + '' + iptables -t nat -F POSTROUTING + iptables -t nat -X + '' + + (concatMapStrings (network: + '' + iptables -t nat -A POSTROUTING \ + -s ${network} -o ${cfg.externalInterface} \ + ${if cfg.externalIP == "" + then "-j MASQUERADE" + else "-j SNAT --to-source ${cfg.externalIP}"} + '' + ) cfg.internalIPs) + + '' + echo 1 > /proc/sys/net/ipv4/ip_forward + ''; + + postStop = + '' + iptables -t nat -F POSTROUTING + ''; + }; + }; +} diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix new file mode 100644 index 00000000000..1d5682f5f3f --- /dev/null +++ b/nixos/modules/services/networking/networkmanager.nix @@ -0,0 +1,193 @@ +{ config, pkgs, ... }: + +with pkgs.lib; +with pkgs; + +let + cfg = config.networking.networkmanager; + + stateDirs = "/var/lib/NetworkManager /var/lib/dhclient"; + + configFile = writeText "NetworkManager.conf" '' + [main] + plugins=keyfile + + [keyfile] + ${optionalString (config.networking.hostName != "") '' + hostname=${config.networking.hostName} + ''} + + [logging] + level=WARN + ''; + + polkitConf = '' + [network-manager] + Identity=unix-group:networkmanager + Action=org.freedesktop.NetworkManager.* + ResultAny=yes + ResultInactive=no + ResultActive=yes + + [modem-manager] + Identity=unix-group:networkmanager + Action=org.freedesktop.ModemManager.* + ResultAny=yes + ResultInactive=no + ResultActive=yes + ''; + + ipUpScript = writeScript "01nixos-ip-up" '' + #!/bin/sh + if test "$2" = "up"; then + ${config.systemd.package}/bin/systemctl start ip-up.target + fi + ''; + + overrideNameserversScript = writeScript "02overridedns" '' + #!/bin/sh + ${optionalString cfg.overrideNameservers "${gnused}/bin/sed -i '/nameserver /d' /etc/resolv.conf"} + ${concatStrings (map (s: '' + ${optionalString cfg.appendNameservers + "${gnused}/bin/sed -i '/nameserver ${s}/d' /etc/resolv.conf" + } + echo 'nameserver ${s}' >> /etc/resolv.conf + '') config.networking.nameservers)} + ''; + +in { + + ###### interface + + options = { + + networking.networkmanager = { + + enable = mkOption { + default = false; + merge = mergeEnableOption; + description = '' + Whether to use NetworkManager to obtain an IP address and other + configuration for all network interfaces that are not manually + configured. If enabled, a group <literal>networkmanager</literal> + will be created. Add all users that should have permission + to change network settings to this group. + ''; + }; + + packages = mkOption { + default = [ ]; + description = '' + Extra packages that provide NetworkManager plugins. + ''; + merge = mergeListOption; + apply = list: [ networkmanager modemmanager wpa_supplicant ] ++ list; + }; + + overrideNameservers = mkOption { + default = false; + description = '' + If enabled, any nameservers received by DHCP or configured in + NetworkManager will be replaced by the nameservers configured + in the <literal>networking.nameservers</literal> option. This + option overrides the <literal>appendNameservers</literal> option + if both are enabled. + ''; + }; + + appendNameservers = mkOption { + default = false; + description = '' + If enabled, the name servers configured in the + <literal>networking.nameservers</literal> option will be appended + to the ones configured in NetworkManager or received by DHCP. + ''; + }; + + }; + }; + + + ###### implementation + + config = mkIf cfg.enable { + + assertions = [{ + assertion = config.networking.wireless.enable == false; + message = "You can not use networking.networkmanager with services.networking.wireless"; + }]; + + environment.etc = [ + { source = ipUpScript; + target = "NetworkManager/dispatcher.d/01nixos-ip-up"; + } + { source = configFile; + target = "NetworkManager/NetworkManager.conf"; + } + { source = "${networkmanager_openvpn}/etc/NetworkManager/VPN/nm-openvpn-service.name"; + target = "NetworkManager/VPN/nm-openvpn-service.name"; + } + { source = "${networkmanager_vpnc}/etc/NetworkManager/VPN/nm-vpnc-service.name"; + target = "NetworkManager/VPN/nm-vpnc-service.name"; + } + { source = "${networkmanager_openconnect}/etc/NetworkManager/VPN/nm-openconnect-service.name"; + target = "NetworkManager/VPN/nm-openconnect-service.name"; + } + ] ++ pkgs.lib.optional (cfg.overrideNameservers || cfg.appendNameservers) + { source = overrideNameserversScript; + target = "NetworkManager/dispatcher.d/02overridedns"; + }; + + environment.systemPackages = cfg.packages ++ [ + networkmanager_openvpn + networkmanager_vpnc + networkmanager_openconnect + ]; + + users.extraGroups = singleton { + name = "networkmanager"; + gid = config.ids.gids.networkmanager; + }; + + systemd.packages = cfg.packages; + + # Create an initialisation service that both starts + # NetworkManager when network.target is reached, + # and sets up necessary directories for NM. + systemd.services."networkmanager-init" = { + description = "NetworkManager initialisation"; + wantedBy = [ "network.target" ]; + partOf = [ "NetworkManager.service" ]; + wants = [ "NetworkManager.service" ]; + before = [ "NetworkManager.service" ]; + script = '' + mkdir -m 700 -p /etc/NetworkManager/system-connections + mkdir -m 755 -p ${stateDirs} + ''; + serviceConfig = { + Type = "oneshot"; + }; + }; + + # Turn off NixOS' network management + networking = { + useDHCP = false; + wireless.enable = false; + }; + + powerManagement.resumeCommands = '' + systemctl restart NetworkManager + ''; + + security.polkit.permissions = polkitConf; + + # openvpn plugin has only dbus interface + services.dbus.packages = cfg.packages ++ [ + networkmanager_openvpn + networkmanager_vpnc + networkmanager_openconnect + ]; + + services.udev.packages = cfg.packages; + }; +} diff --git a/nixos/modules/services/networking/ntpd.nix b/nixos/modules/services/networking/ntpd.nix new file mode 100644 index 00000000000..e5e164021d3 --- /dev/null +++ b/nixos/modules/services/networking/ntpd.nix @@ -0,0 +1,90 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + inherit (pkgs) ntp; + + stateDir = "/var/lib/ntp"; + + ntpUser = "ntp"; + + configFile = pkgs.writeText "ntp.conf" '' + # Keep the drift file in ${stateDir}/ntp.drift. However, since we + # chroot to ${stateDir}, we have to specify it as /ntp.drift. + driftfile /ntp.drift + + ${toString (map (server: "server " + server + " iburst\n") config.services.ntp.servers)} + ''; + + ntpFlags = "-c ${configFile} -u ${ntpUser}:nogroup -i ${stateDir}"; + +in + +{ + + ###### interface + + options = { + + services.ntp = { + + enable = mkOption { + default = true; + description = '' + Whether to synchronise your machine's time using the NTP + protocol. + ''; + }; + + servers = mkOption { + default = [ + "0.pool.ntp.org" + "1.pool.ntp.org" + "2.pool.ntp.org" + ]; + description = '' + The set of NTP servers from which to synchronise. + ''; + }; + + }; + + }; + + + ###### implementation + + config = mkIf config.services.ntp.enable { + + # Make tools such as ntpq available in the system path + environment.systemPackages = [ pkgs.ntp ]; + + users.extraUsers = singleton + { name = ntpUser; + uid = config.ids.uids.ntp; + description = "NTP daemon user"; + home = stateDir; + }; + + jobs.ntpd = + { description = "NTP Daemon"; + + wantedBy = [ "ip-up.target" ]; + partOf = [ "ip-up.target" ]; + + path = [ ntp ]; + + preStart = + '' + mkdir -m 0755 -p ${stateDir} + chown ${ntpUser} ${stateDir} + ''; + + exec = "ntpd -g -n ${ntpFlags}"; + }; + + }; + +} diff --git a/nixos/modules/services/networking/oidentd.nix b/nixos/modules/services/networking/oidentd.nix new file mode 100644 index 00000000000..a2a555a8ad1 --- /dev/null +++ b/nixos/modules/services/networking/oidentd.nix @@ -0,0 +1,44 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +{ + + ###### interface + + options = { + + services.oidentd.enable = mkOption { + default = false; + type = types.bool; + description = '' + Whether to enable ‘oidentd’, an implementation of the Ident + protocol (RFC 1413). It allows remote systems to identify the + name of the user associated with a TCP connection. + ''; + }; + + }; + + + ###### implementation + + config = mkIf config.services.oidentd.enable { + + jobs.oidentd = + { startOn = "started network-interfaces"; + daemonType = "fork"; + exec = "${pkgs.oidentd}/sbin/oidentd -u oidentd -g nogroup"; + }; + + users.extraUsers.oidentd = { + description = "Ident Protocol daemon user"; + group = "oidentd"; + uid = config.ids.uids.oidentd; + }; + + users.extraGroups.oidentd.gid = config.ids.gids.oidentd; + + }; + +} diff --git a/nixos/modules/services/networking/openfire.nix b/nixos/modules/services/networking/openfire.nix new file mode 100644 index 00000000000..d5c18c0675c --- /dev/null +++ b/nixos/modules/services/networking/openfire.nix @@ -0,0 +1,70 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + inherit (pkgs) jre openfire coreutils which gnugrep gawk gnused; + + extraStartDependency = + if config.services.openfire.usePostgreSQL then "and started postgresql" else ""; + +in + +{ + + ###### interface + + options = { + + services.openfire = { + + enable = mkOption { + default = false; + description = " + Whether to enable OpenFire XMPP server. + "; + }; + + usePostgreSQL = mkOption { + default = true; + description = " + Whether you use PostgreSQL service for your storage back-end. + "; + }; + + }; + + }; + + + ###### implementation + + config = mkIf config.services.openfire.enable ( + mkAssert (!(config.services.openfire.usePostgreSQL -> config.services.postgresql.enable)) " + openfire assertion failed + " { + + jobs.openfire = + { description = "OpenFire XMPP server"; + + startOn = "started networking ${extraStartDependency}"; + + script = + '' + export PATH=${jre}/bin:${openfire}/bin:${coreutils}/bin:${which}/bin:${gnugrep}/bin:${gawk}/bin:${gnused}/bin + export HOME=/tmp + mkdir /var/log/openfire || true + mkdir /etc/openfire || true + for i in ${openfire}/conf.inst/*; do + if ! test -f /etc/openfire/$(basename $i); then + cp $i /etc/openfire/ + fi + done + openfire start + ''; # */ + }; + + }); + +} diff --git a/nixos/modules/services/networking/openvpn.nix b/nixos/modules/services/networking/openvpn.nix new file mode 100644 index 00000000000..1e862591406 --- /dev/null +++ b/nixos/modules/services/networking/openvpn.nix @@ -0,0 +1,172 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.openvpn; + + inherit (pkgs) openvpn; + + makeOpenVPNJob = cfg: name: + let + + path = (getAttr "openvpn-${name}" config.systemd.services).path; + + upScript = '' + #! /bin/sh + export PATH=${path} + + # For convenience in client scripts, extract the remote domain + # name and name server. + for var in ''${!foreign_option_*}; do + x=(''${!var}) + if [ "''${x[0]}" = dhcp-option ]; then + if [ "''${x[1]}" = DOMAIN ]; then domain="''${x[2]}" + elif [ "''${x[1]}" = DNS ]; then nameserver="''${x[2]}" + fi + fi + done + + ${cfg.up} + ''; + + downScript = '' + #! /bin/sh + export PATH=${path} + ${cfg.down} + ''; + + configFile = pkgs.writeText "openvpn-config-${name}" + '' + errors-to-stderr + ${optionalString (cfg.up != "" || cfg.down != "") "script-security 2"} + ${cfg.config} + ${optionalString (cfg.up != "") "up ${pkgs.writeScript "openvpn-${name}-up" upScript}"} + ${optionalString (cfg.down != "") "down ${pkgs.writeScript "openvpn-${name}-down" downScript}"} + ''; + + in { + description = "OpenVPN instance ‘${name}’"; + + wantedBy = optional cfg.autoStart "multi-user.target"; + after = [ "network-interfaces.target" ]; + + path = [ pkgs.iptables pkgs.iproute pkgs.nettools ]; + + serviceConfig.ExecStart = "@${openvpn}/sbin/openvpn openvpn --config ${configFile}"; + serviceConfig.Restart = "always"; + }; + +in + +{ + + ###### interface + + options = { + + /* !!! Obsolete. */ + services.openvpn.enable = mkOption { + default = true; + description = "Whether to enable OpenVPN."; + }; + + services.openvpn.servers = mkOption { + default = {}; + + example = { + + server = { + config = '' + # Simplest server configuration: http://openvpn.net/index.php/documentation/miscellaneous/static-key-mini-howto.html. + # server : + dev tun + ifconfig 10.8.0.1 10.8.0.2 + secret /root/static.key + ''; + up = "ip route add ..."; + down = "ip route del ..."; + }; + + client = { + config = '' + client + remote vpn.example.org + dev tun + proto tcp-client + port 8080 + ca /root/.vpn/ca.crt + cert /root/.vpn/alice.crt + key /root/.vpn/alice.key + ''; + up = "echo nameserver $nameserver | ${pkgs.openresolv}/sbin/resolvconf -m 0 -a $dev"; + down = "${pkgs.openresolv}/sbin/resolvconf -d $dev"; + }; + + }; + + description = '' + Each attribute of this option defines an Upstart job to run an + OpenVPN instance. These can be OpenVPN servers or clients. + The name of each Upstart job is + <literal>openvpn-</literal><replaceable>name</replaceable>, + where <replaceable>name</replaceable> is the corresponding + attribute name. + ''; + + type = types.attrsOf types.optionSet; + + options = { + + config = mkOption { + type = types.string; + description = '' + Configuration of this OpenVPN instance. See + <citerefentry><refentrytitle>openvpn</refentrytitle><manvolnum>8</manvolnum></citerefentry> + for details. + ''; + }; + + up = mkOption { + default = ""; + type = types.string; + description = '' + Shell commands executed when the instance is starting. + ''; + }; + + down = mkOption { + default = ""; + type = types.string; + description = '' + Shell commands executed when the instance is shutting down. + ''; + }; + + autoStart = mkOption { + default = true; + type = types.bool; + description = "Whether this OpenVPN instance should be started automatically."; + }; + + }; + + }; + + }; + + + ###### implementation + + config = mkIf (cfg.servers != {}) { + + systemd.services = listToAttrs (mapAttrsFlatten (name: value: nameValuePair "openvpn-${name}" (makeOpenVPNJob value name)) cfg.servers); + + environment.systemPackages = [ openvpn ]; + + boot.kernelModules = [ "tun" ]; + + }; + +} diff --git a/nixos/modules/services/networking/prayer.nix b/nixos/modules/services/networking/prayer.nix new file mode 100644 index 00000000000..fb541bf101a --- /dev/null +++ b/nixos/modules/services/networking/prayer.nix @@ -0,0 +1,103 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + inherit (pkgs) prayer; + + cfg = config.services.prayer; + + stateDir = "/var/lib/prayer"; + + prayerUser = "prayer"; + prayerGroup = "prayer"; + + prayerExtraCfg = pkgs.writeText "extraprayer.cf" '' + prefix = "${prayer}" + var_prefix = "${stateDir}" + prayer_user = "${prayerUser}" + prayer_group = "${prayerGroup}" + sendmail_path = "/var/setuid-wrappers/sendmail" + + use_http_port ${cfg.port} + + ${cfg.extraConfig} + ''; + + prayerCfg = pkgs.runCommand "prayer.cf" { } '' + # We have to remove the http_port 80, or it will start a server there + cat ${prayer}/etc/prayer.cf | grep -v http_port > $out + cat ${prayerExtraCfg} >> $out + ''; + +in + +{ + + ###### interface + + options = { + + services.prayer = { + + enable = mkOption { + default = false; + description = '' + Whether to run the prayer webmail http server. + ''; + }; + + port = mkOption { + default = "2080"; + description = '' + Port the prayer http server is listening to. + ''; + }; + + extraConfig = mkOption { + default = "" ; + description = '' + Extra configuration. Contents will be added verbatim to the configuration file. + ''; + }; + }; + + }; + + + ###### implementation + + config = mkIf config.services.prayer.enable { + environment.systemPackages = [ prayer ]; + + users.extraUsers = singleton + { name = prayerUser; + uid = config.ids.uids.prayer; + description = "Prayer daemon user"; + home = stateDir; + }; + + users.extraGroups = singleton + { name = prayerGroup; + gid = config.ids.gids.prayer; + }; + + jobs.prayer = + { name = "prayer"; + + startOn = "startup"; + + preStart = + '' + mkdir -m 0755 -p ${stateDir} + chown ${prayerUser}.${prayerGroup} ${stateDir} + ''; + + daemonType = "daemon"; + + exec = "${prayer}/sbin/prayer --config-file=${prayerCfg}"; + }; + }; + +} diff --git a/nixos/modules/services/networking/privoxy.nix b/nixos/modules/services/networking/privoxy.nix new file mode 100644 index 00000000000..89c40c53157 --- /dev/null +++ b/nixos/modules/services/networking/privoxy.nix @@ -0,0 +1,95 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + inherit (pkgs) privoxy; + + stateDir = "/var/spool/privoxy"; + + privoxyUser = "privoxy"; + + privoxyFlags = "--no-daemon --user ${privoxyUser} ${privoxyCfg}"; + + privoxyCfg = pkgs.writeText "privoxy.conf" '' + listen-address ${config.services.privoxy.listenAddress} + logdir ${config.services.privoxy.logDir} + confdir ${privoxy}/etc + filterfile default.filter + + ${config.services.privoxy.extraConfig} + ''; + +in + +{ + + ###### interface + + options = { + + services.privoxy = { + + enable = mkOption { + default = false; + description = '' + Whether to run the machine as a HTTP proxy server. + ''; + }; + + listenAddress = mkOption { + default = "127.0.0.1:8118"; + description = '' + Address the proxy server is listening to. + ''; + }; + + logDir = mkOption { + default = "/var/log/privoxy" ; + description = '' + Location for privoxy log files. + ''; + }; + + extraConfig = mkOption { + default = "" ; + description = '' + Extra configuration. Contents will be added verbatim to the configuration file. + ''; + }; + }; + + }; + + + ###### implementation + + config = mkIf config.services.privoxy.enable { + + environment.systemPackages = [ privoxy ]; + + users.extraUsers = singleton + { name = privoxyUser; + uid = config.ids.uids.privoxy; + description = "Privoxy daemon user"; + home = stateDir; + }; + + jobs.privoxy = + { name = "privoxy"; + + startOn = "startup"; + + preStart = + '' + mkdir -m 0755 -p ${stateDir} + chown ${privoxyUser} ${stateDir} + ''; + + exec = "${privoxy}/sbin/privoxy ${privoxyFlags}"; + }; + + }; + +} diff --git a/nixos/modules/services/networking/quassel.nix b/nixos/modules/services/networking/quassel.nix new file mode 100644 index 00000000000..f3a4e457ec8 --- /dev/null +++ b/nixos/modules/services/networking/quassel.nix @@ -0,0 +1,96 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + quassel = pkgs.kde4.quasselDaemon; + cfg = config.services.quassel; + user = if cfg.user != null then cfg.user else "quassel"; +in + +{ + + ###### interface + + options = { + + services.quassel = { + + enable = mkOption { + default = false; + description = '' + Whether to run the Quassel IRC client daemon. + ''; + }; + + interface = mkOption { + default = "127.0.0.1"; + description = '' + The interface the Quassel daemon will be listening to. If `127.0.0.1', + only clients on the local host can connect to it; if `0.0.0.0', clients + can access it from any network interface. + ''; + }; + + portNumber = mkOption { + default = 4242; + description = '' + The port number the Quassel daemon will be listening to. + ''; + }; + + dataDir = mkOption { + default = ''/home/${user}/.config/quassel-irc.org''; + description = '' + The directory holding configuration files, the SQlite database and the SSL Cert. + ''; + }; + + user = mkOption { + default = null; + description = '' + The existing user the Quassel daemon should run as. If left empty, a default "quassel" user will be created. + ''; + }; + + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + users.extraUsers = mkIf (cfg.user == null) [ + { name = "quassel"; + description = "Quassel IRC client daemon"; + group = "quassel"; + uid = config.ids.uids.quassel; + }]; + + users.extraGroups = mkIf (cfg.user == null) [ + { name = "quassel"; + gid = config.ids.gids.quassel; + }]; + + jobs.quassel = + { description = "Quassel IRC client daemon"; + + startOn = "ip-up"; + + preStart = '' + mkdir -p ${cfg.dataDir} + chown ${user} ${cfg.dataDir} + ''; + + exec = '' + ${pkgs.su}/bin/su -s ${pkgs.stdenv.shell} ${user} \ + -c '${quassel}/bin/quasselcore --listen=${cfg.interface}\ + --port=${toString cfg.portNumber} --configdir=${cfg.dataDir}' + ''; + }; + + }; + +} diff --git a/nixos/modules/services/networking/radvd.nix b/nixos/modules/services/networking/radvd.nix new file mode 100644 index 00000000000..8d586ce6e46 --- /dev/null +++ b/nixos/modules/services/networking/radvd.nix @@ -0,0 +1,77 @@ +# Module for the IPv6 Router Advertisement Daemon. + +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.radvd; + + confFile = pkgs.writeText "radvd.conf" cfg.config; + +in + +{ + + ###### interface + + options = { + + services.radvd.enable = mkOption { + default = false; + description = + '' + Whether to enable the Router Advertisement Daemon + (<command>radvd</command>), which provides link-local + advertisements of IPv6 router addresses and prefixes using + the Neighbor Discovery Protocol (NDP). This enables + stateless address autoconfiguration in IPv6 clients on the + network. + ''; + }; + + services.radvd.config = mkOption { + example = + '' + interface eth0 { + AdvSendAdvert on; + prefix 2001:db8:1234:5678::/64 { }; + }; + ''; + description = + '' + The contents of the radvd configuration file. + ''; + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + environment.systemPackages = [ pkgs.radvd ]; + + jobs.radvd = + { description = "IPv6 Router Advertisement Daemon"; + + startOn = "started network-interfaces"; + + preStart = + '' + # !!! Radvd only works if IPv6 forwarding is enabled. But + # this should probably be done somewhere else (and not + # necessarily for all interfaces). + echo 1 > /proc/sys/net/ipv6/conf/all/forwarding + ''; + + exec = "${pkgs.radvd}/sbin/radvd -m syslog -s -C ${confFile}"; + + daemonType = "fork"; + }; + + }; + +} diff --git a/nixos/modules/services/networking/rdnssd.nix b/nixos/modules/services/networking/rdnssd.nix new file mode 100644 index 00000000000..f797206ad5c --- /dev/null +++ b/nixos/modules/services/networking/rdnssd.nix @@ -0,0 +1,48 @@ +# Module for rdnssd, a daemon that configures DNS servers in +# /etc/resolv/conf from IPv6 RDNSS advertisements. + +{ config, pkgs, ... }: + +with pkgs.lib; + +{ + + ###### interface + + options = { + + services.rdnssd.enable = mkOption { + default = false; + #default = config.networking.enableIPv6; + description = + '' + Whether to enable the RDNSS daemon + (<command>rdnssd</command>), which configures DNS servers in + <filename>/etc/resolv.conf</filename> from RDNSS + advertisements sent by IPv6 routers. + ''; + }; + + }; + + + ###### implementation + + config = mkIf config.services.rdnssd.enable { + + jobs.rdnssd = + { description = "RDNSS daemon"; + + # Start before the network interfaces are brought up so that + # the daemon receives RDNSS advertisements from the kernel. + startOn = "starting network-interfaces"; + + # !!! Should write to /var/run/rdnssd/resolv.conf and run the daemon under another uid. + exec = "${pkgs.ndisc6}/sbin/rdnssd --resolv-file /etc/resolv.conf -u root"; + + daemonType = "fork"; + }; + + }; + +} diff --git a/nixos/modules/services/networking/rpcbind.nix b/nixos/modules/services/networking/rpcbind.nix new file mode 100644 index 00000000000..00c958c5a4a --- /dev/null +++ b/nixos/modules/services/networking/rpcbind.nix @@ -0,0 +1,81 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + netconfigFile = { + target = "netconfig"; + source = pkgs.writeText "netconfig" '' + # + # The network configuration file. This file is currently only used in + # conjunction with the TI-RPC code in the libtirpc library. + # + # Entries consist of: + # + # <network_id> <semantics> <flags> <protofamily> <protoname> \ + # <device> <nametoaddr_libs> + # + # The <device> and <nametoaddr_libs> fields are always empty in this + # implementation. + # + udp tpi_clts v inet udp - - + tcp tpi_cots_ord v inet tcp - - + udp6 tpi_clts v inet6 udp - - + tcp6 tpi_cots_ord v inet6 tcp - - + rawip tpi_raw - inet - - - + local tpi_cots_ord - loopback - - - + unix tpi_cots_ord - loopback - - - + ''; + }; + +in + +{ + + ###### interface + + options = { + + services.rpcbind = { + + enable = mkOption { + default = false; + description = '' + Whether to enable `rpcbind', an ONC RPC directory service + notably used by NFS and NIS, and which can be queried + using the rpcinfo(1) command. `rpcbind` is a replacement for + `portmap`. + ''; + }; + + }; + + }; + + + ###### implementation + + config = mkIf config.services.rpcbind.enable { + + environment.systemPackages = [ pkgs.rpcbind ]; + + environment.etc = [ netconfigFile ]; + + systemd.services.rpcbind = + { description = "ONC RPC Directory Service"; + + wantedBy = [ "multi-user.target" ]; + + requires = [ "basic.target" ]; + after = [ "basic.target" ]; + + unitConfig.DefaultDependencies = false; # don't stop during shutdown + + serviceConfig.Type = "forking"; + serviceConfig.ExecStart = "@${pkgs.rpcbind}/bin/rpcbind rpcbind"; + }; + + }; + +} diff --git a/nixos/modules/services/networking/sabnzbd.nix b/nixos/modules/services/networking/sabnzbd.nix new file mode 100644 index 00000000000..8816ac0d2f8 --- /dev/null +++ b/nixos/modules/services/networking/sabnzbd.nix @@ -0,0 +1,52 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.sabnzbd; + inherit (pkgs) sabnzbd; + +in + +{ + + ###### interface + + options = { + services.sabnzbd = { + enable = mkOption { + default = false; + description = "Whether to enable the sabnzbd FTP server."; + }; + configFile = mkOption { + default = "/var/sabnzbd/sabnzbd.ini"; + description = "Path to config file. (You need to create this file yourself!)"; + }; + }; + }; + + + ###### implementation + + config = mkIf cfg.enable { + + users.extraUsers = + [ { name = "sabnzbd"; + uid = config.ids.uids.sabnzbd; + description = "sabnzbd user"; + home = "/homeless-shelter"; + } + ]; + + jobs.sabnzbd = + { description = "sabnzbd server"; + + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; + + exec = "${sabnzbd}/bin/sabnzbd -d -f ${cfg.configFile}"; + }; + + }; +} diff --git a/nixos/modules/services/networking/ssh/lshd.nix b/nixos/modules/services/networking/ssh/lshd.nix new file mode 100644 index 00000000000..d32fabbde24 --- /dev/null +++ b/nixos/modules/services/networking/ssh/lshd.nix @@ -0,0 +1,175 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + inherit (pkgs) lsh; + + cfg = config.services.lshd; + +in + +{ + + ###### interface + + options = { + + services.lshd = { + + enable = mkOption { + default = false; + description = '' + Whether to enable the GNU lshd SSH2 daemon, which allows + secure remote login. + ''; + }; + + portNumber = mkOption { + default = 22; + description = '' + The port on which to listen for connections. + ''; + }; + + interfaces = mkOption { + default = []; + description = '' + List of network interfaces where listening for connections. + When providing the empty list, `[]', lshd listens on all + network interfaces. + ''; + example = [ "localhost" "1.2.3.4:443" ]; + }; + + hostKey = mkOption { + default = "/etc/lsh/host-key"; + description = '' + Path to the server's private key. Note that this key must + have been created, e.g., using "lsh-keygen --server | + lsh-writekey --server", so that you can run lshd. + ''; + }; + + syslog = mkOption { + default = true; + description = ''Whether to enable syslog output.''; + }; + + passwordAuthentication = mkOption { + default = true; + description = ''Whether to enable password authentication.''; + }; + + publicKeyAuthentication = mkOption { + default = true; + description = ''Whether to enable public key authentication.''; + }; + + rootLogin = mkOption { + default = false; + description = ''Whether to enable remote root login.''; + }; + + loginShell = mkOption { + default = null; + description = '' + If non-null, override the default login shell with the + specified value. + ''; + example = "/nix/store/xyz-bash-10.0/bin/bash10"; + }; + + srpKeyExchange = mkOption { + default = false; + description = '' + Whether to enable SRP key exchange and user authentication. + ''; + }; + + tcpForwarding = mkOption { + default = true; + description = ''Whether to enable TCP/IP forwarding.''; + }; + + x11Forwarding = mkOption { + default = true; + description = ''Whether to enable X11 forwarding.''; + }; + + subsystems = mkOption { + default = [ ["sftp" "${pkgs.lsh}/sbin/sftp-server"] ]; + description = '' + List of subsystem-path pairs, where the head of the pair + denotes the subsystem name, and the tail denotes the path to + an executable implementing it. + ''; + }; + + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + jobs.lshd = + { description = "GNU lshd SSH2 daemon"; + + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; + + environment = + { LD_LIBRARY_PATH = config.system.nssModules.path; }; + + preStart = + '' + test -d /etc/lsh || mkdir -m 0755 -p /etc/lsh + test -d /var/spool/lsh || mkdir -m 0755 -p /var/spool/lsh + + if ! test -f /var/spool/lsh/yarrow-seed-file + then + # XXX: It would be nice to provide feedback to the + # user when this fails, so that they can retry it + # manually. + ${lsh}/bin/lsh-make-seed --sloppy \ + -o /var/spool/lsh/yarrow-seed-file + fi + + if ! test -f "${cfg.hostKey}" + then + ${lsh}/bin/lsh-keygen --server | \ + ${lsh}/bin/lsh-writekey --server -o "${cfg.hostKey}" + fi + ''; + + exec = with cfg; + '' + ${lsh}/sbin/lshd --daemonic \ + --password-helper="${lsh}/sbin/lsh-pam-checkpw" \ + -p ${toString portNumber} \ + ${if interfaces == [] then "" + else (concatStrings (map (i: "--interface=\"${i}\"") + interfaces))} \ + -h "${hostKey}" \ + ${if !syslog then "--no-syslog" else ""} \ + ${if passwordAuthentication then "--password" else "--no-password" } \ + ${if publicKeyAuthentication then "--publickey" else "--no-publickey" } \ + ${if rootLogin then "--root-login" else "--no-root-login" } \ + ${if loginShell != null then "--login-shell=\"${loginShell}\"" else "" } \ + ${if srpKeyExchange then "--srp-keyexchange" else "--no-srp-keyexchange" } \ + ${if !tcpForwarding then "--no-tcpip-forward" else "--tcpip-forward"} \ + ${if x11Forwarding then "--x11-forward" else "--no-x11-forward" } \ + --subsystems=${concatStringsSep "," + (map (pair: (head pair) + "=" + + (head (tail pair))) + subsystems)} + ''; + }; + + }; + +} diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix new file mode 100644 index 00000000000..d57eef860d2 --- /dev/null +++ b/nixos/modules/services/networking/ssh/sshd.nix @@ -0,0 +1,338 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.openssh; + cfgc = config.programs.ssh; + + nssModulesPath = config.system.nssModules.path; + + permitRootLoginCheck = v: + v == "yes" || + v == "without-password" || + v == "forced-commands-only" || + v == "no"; + + knownHosts = map (h: getAttr h cfg.knownHosts) (attrNames cfg.knownHosts); + + knownHostsFile = pkgs.writeText "ssh_known_hosts" ( + flip concatMapStrings knownHosts (h: + "${concatStringsSep "," h.hostNames} ${builtins.readFile h.publicKeyFile}" + ) + ); + + userOptions = { + + openssh.authorizedKeys = { + keys = mkOption { + type = types.listOf types.string; + default = []; + description = '' + A list of verbatim OpenSSH public keys that should be added to the + user's authorized keys. The keys are added to a file that the SSH + daemon reads in addition to the the user's authorized_keys file. + You can combine the <literal>keys</literal> and + <literal>keyFiles</literal> options. + ''; + }; + + keyFiles = mkOption { + default = []; + description = '' + A list of files each containing one OpenSSH public key that should be + added to the user's authorized keys. The contents of the files are + read at build time and added to a file that the SSH daemon reads in + addition to the the user's authorized_keys file. You can combine the + <literal>keyFiles</literal> and <literal>keys</literal> options. + ''; + }; + }; + + }; + + authKeysFiles = let + mkAuthKeyFile = u: { + target = "ssh/authorized_keys.d/${u.name}"; + mode = "0444"; + source = pkgs.writeText "${u.name}-authorized_keys" '' + ${concatStringsSep "\n" u.openssh.authorizedKeys.keys} + ${concatMapStrings (f: builtins.readFile f + "\n") u.openssh.authorizedKeys.keyFiles} + ''; + }; + usersWithKeys = attrValues (flip filterAttrs config.users.extraUsers (n: u: + length u.openssh.authorizedKeys.keys != 0 || length u.openssh.authorizedKeys.keyFiles != 0 + )); + in map mkAuthKeyFile usersWithKeys; + +in + +{ + + ###### interface + + options = { + + services.openssh = { + + enable = mkOption { + default = false; + description = '' + Whether to enable the OpenSSH secure shell daemon, which + allows secure remote logins. + ''; + }; + + forwardX11 = mkOption { + default = cfgc.setXAuthLocation; + description = '' + Whether to allow X11 connections to be forwarded. + ''; + }; + + allowSFTP = mkOption { + default = true; + description = '' + Whether to enable the SFTP subsystem in the SSH daemon. This + enables the use of commands such as <command>sftp</command> and + <command>sshfs</command>. + ''; + }; + + permitRootLogin = mkOption { + default = "without-password"; + check = permitRootLoginCheck; + description = '' + Whether the root user can login using ssh. Valid values are + <literal>yes</literal>, <literal>without-password</literal>, + <literal>forced-commands-only</literal> or + <literal>no</literal>. + ''; + }; + + gatewayPorts = mkOption { + default = "no"; + description = '' + Specifies whether remote hosts are allowed to connect to + ports forwarded for the client. See + <citerefentry><refentrytitle>sshd_config</refentrytitle> + <manvolnum>5</manvolnum></citerefentry>. + ''; + }; + + ports = mkOption { + default = [22]; + description = '' + Specifies on which ports the SSH daemon listens. + ''; + }; + + usePAM = mkOption { + default = true; + description = '' + Specifies whether the OpenSSH daemon uses PAM to authenticate + login attempts. + ''; + }; + + passwordAuthentication = mkOption { + default = true; + description = '' + Specifies whether password authentication is allowed. Note + that setting this value to <literal>false</literal> is most + probably not going to have the desired effect unless + <literal>usePAM</literal> is disabled as well. + ''; + }; + + challengeResponseAuthentication = mkOption { + default = true; + description = '' + Specifies whether challenge/response authentication is allowed. + ''; + }; + + hostKeys = mkOption { + default = + [ { path = "/etc/ssh/ssh_host_dsa_key"; + type = "dsa"; + bits = 1024; + } + { path = "/etc/ssh/ssh_host_ecdsa_key"; + type = "ecdsa"; + bits = 521; + } + ]; + description = '' + NixOS can automatically generate SSH host keys. This option + specifies the path, type and size of each key. See + <citerefentry><refentrytitle>ssh-keygen</refentrytitle> + <manvolnum>1</manvolnum></citerefentry> for supported types + and sizes. + ''; + }; + + authorizedKeysFiles = mkOption { + default = []; + description = "Files from with authorized keys are read."; + }; + + extraConfig = mkOption { + default = ""; + description = "Verbatim contents of <filename>sshd_config</filename>."; + }; + + knownHosts = mkOption { + default = {}; + type = types.loaOf types.optionSet; + description = '' + The set of system-wide known SSH hosts. + ''; + example = [ + { + hostNames = [ "myhost" "myhost.mydomain.com" "10.10.1.4" ]; + publicKeyFile = ./pubkeys/myhost_ssh_host_dsa_key.pub; + } + { + hostNames = [ "myhost2" ]; + publicKeyFile = ./pubkeys/myhost2_ssh_host_dsa_key.pub; + } + ]; + options = { + hostNames = mkOption { + type = types.listOf types.string; + default = []; + description = '' + A list of host names and/or IP numbers used for accessing + the host's ssh service. + ''; + }; + publicKeyFile = mkOption { + description = '' + The path to the public key file for the host. The public + key file is read at build time and saved in the Nix store. + You can fetch a public key file from a running SSH server + with the <literal>ssh-keyscan</literal> command. + ''; + }; + }; + }; + + }; + + users.extraUsers = mkOption { + options = [ userOptions ]; + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + users.extraUsers = singleton + { name = "sshd"; + uid = config.ids.uids.sshd; + description = "SSH privilege separation user"; + home = "/var/empty"; + }; + + environment.etc = authKeysFiles ++ [ + { source = "${pkgs.openssh}/etc/ssh/moduli"; + target = "ssh/moduli"; + } + { source = knownHostsFile; + target = "ssh/ssh_known_hosts"; + } + ]; + + systemd.services.sshd = + { description = "SSH Daemon"; + + wantedBy = [ "multi-user.target" ]; + + stopIfChanged = false; + + path = [ pkgs.openssh pkgs.gawk ]; + + environment.LD_LIBRARY_PATH = nssModulesPath; + environment.LOCALE_ARCHIVE = "/run/current-system/sw/lib/locale/locale-archive"; + + preStart = + '' + mkdir -m 0755 -p /etc/ssh + + ${flip concatMapStrings cfg.hostKeys (k: '' + if ! [ -f "${k.path}" ]; then + ssh-keygen -t "${k.type}" -b "${toString k.bits}" -f "${k.path}" -N "" + fi + '')} + ''; + + serviceConfig = + { ExecStart = + "${pkgs.openssh}/sbin/sshd " + + "-f ${pkgs.writeText "sshd_config" cfg.extraConfig}"; + Restart = "always"; + Type = "forking"; + KillMode = "process"; + PIDFile = "/run/sshd.pid"; + }; + }; + + networking.firewall.allowedTCPPorts = cfg.ports; + + security.pam.services = optional cfg.usePAM { name = "sshd"; startSession = true; showMotd = true; }; + + services.openssh.authorizedKeysFiles = + [ ".ssh/authorized_keys" ".ssh/authorized_keys2" "/etc/ssh/authorized_keys.d/%u" ]; + + services.openssh.extraConfig = + '' + PidFile /run/sshd.pid + + Protocol 2 + + UsePAM ${if cfg.usePAM then "yes" else "no"} + + AddressFamily ${if config.networking.enableIPv6 then "any" else "inet"} + ${concatMapStrings (port: '' + Port ${toString port} + '') cfg.ports} + + ${optionalString cfgc.setXAuthLocation '' + XAuthLocation ${pkgs.xorg.xauth}/bin/xauth + ''} + + ${if cfg.forwardX11 then '' + X11Forwarding yes + '' else '' + X11Forwarding no + ''} + + ${optionalString cfg.allowSFTP '' + Subsystem sftp ${pkgs.openssh}/libexec/sftp-server + ''} + + PermitRootLogin ${cfg.permitRootLogin} + GatewayPorts ${cfg.gatewayPorts} + PasswordAuthentication ${if cfg.passwordAuthentication then "yes" else "no"} + ChallengeResponseAuthentication ${if cfg.challengeResponseAuthentication then "yes" else "no"} + + PrintMotd no # handled by pam_motd + + AuthorizedKeysFile ${toString cfg.authorizedKeysFiles} + + ${flip concatMapStrings cfg.hostKeys (k: '' + HostKey ${k.path} + '')} + ''; + + assertions = [{ assertion = if cfg.forwardX11 then cfgc.setXAuthLocation else true; + message = "cannot enable X11 forwarding without setting xauth location";}]; + + }; + +} diff --git a/nixos/modules/services/networking/supybot.nix b/nixos/modules/services/networking/supybot.nix new file mode 100644 index 00000000000..fa8b7556de5 --- /dev/null +++ b/nixos/modules/services/networking/supybot.nix @@ -0,0 +1,88 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.supybot; + +in + +{ + + options = { + + services.supybot = { + + enable = mkOption { + default = false; + description = "Enable Supybot, an IRC bot"; + }; + + stateDir = mkOption { + # Setting this to /var/lib/supybot caused useradd to fail + default = "/home/supybot"; + description = "The root directory, logs and plugins are stored here"; + }; + + configFile = mkOption { + type = types.path; + description = '' + Path to a supybot config file. This can be generated by + running supybot-wizard. + + Note: all paths should include the full path to the stateDir + directory (backup conf data logs logs/plugins plugins tmp web). + ''; + }; + + }; + + }; + + + config = mkIf cfg.enable { + + environment.systemPackages = [ pkgs.pythonPackages.limnoria ]; + + users.extraUsers = singleton { + name = "supybot"; + uid = config.ids.uids.supybot; + group = "supybot"; + description = "Supybot IRC bot user"; + home = cfg.stateDir; + createHome = true; + }; + + users.extraGroups.supybot = { + name = "supybot"; + gid = config.ids.gids.supybot; + }; + + systemd.services.supybot = { + description = "Supybot, an IRC bot"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + path = [ pkgs.pythonPackages.limnoria ]; + preStart = '' + cd ${cfg.stateDir} + mkdir -p backup conf data plugins logs/plugins tmp web + ln -sf ${cfg.configFile} supybot.cfg + # This needs to be created afresh every time + rm -f supybot.cfg.bak + ''; + + serviceConfig = { + ExecStart = "${pkgs.pythonPackages.limnoria}/bin/supybot ${cfg.stateDir}/supybot.cfg"; + PIDFile = "/run/supybot.pid"; + User = "supybot"; + Group = "supybot"; + UMask = "0007"; + Restart = "on-abort"; + StartLimitInterval = "5m"; + StartLimitBurst = "1"; + }; + }; + + }; +} diff --git a/nixos/modules/services/networking/tcpcrypt.nix b/nixos/modules/services/networking/tcpcrypt.nix new file mode 100644 index 00000000000..48cb884f246 --- /dev/null +++ b/nixos/modules/services/networking/tcpcrypt.nix @@ -0,0 +1,78 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.networking.tcpcrypt; + +in + +{ + + ###### interface + + options = { + + networking.tcpcrypt.enable = mkOption { + default = false; + description = '' + Whether to enable opportunistic TCP encryption. If the other end + speaks Tcpcrypt, then your traffic will be encrypted; otherwise + it will be sent in clear text. Thus, Tcpcrypt alone provides no + guarantees -- it is best effort. If, however, a Tcpcrypt + connection is successful and any attackers that exist are + passive, then Tcpcrypt guarantees privacy. + ''; + }; + }; + + config = mkIf cfg.enable { + + users.extraUsers = singleton { + name = "tcpcryptd"; + uid = config.ids.uids.tcpcryptd; + description = "tcpcrypt daemon user"; + }; + + jobs.tcpcrypt = { + description = "tcpcrypt"; + + wantedBy = ["multi-user.target"]; + after = ["network-interfaces.target"]; + + path = [ pkgs.iptables pkgs.tcpcrypt pkgs.procps ]; + + preStart = '' + sysctl -n net.ipv4.tcp_ecn >/run/pre-tcpcrypt-ecn-state + sysctl -w net.ipv4.tcp_ecn=0 + + iptables -t raw -N nixos-tcpcrypt + iptables -t raw -A nixos-tcpcrypt -p tcp -m mark --mark 0x0/0x10 -j NFQUEUE --queue-num 666 + iptables -t raw -I PREROUTING -j nixos-tcpcrypt + + iptables -t mangle -N nixos-tcpcrypt + iptables -t mangle -A nixos-tcpcrypt -p tcp -m mark --mark 0x0/0x10 -j NFQUEUE --queue-num 666 + iptables -t mangle -I POSTROUTING -j nixos-tcpcrypt + ''; + + exec = "tcpcryptd -x 0x10"; + + postStop = '' + if [ -f /run/pre-tcpcrypt-ecn-state ]; then + sysctl -w net.ipv4.tcp_ecn=$(cat /run/pre-tcpcrypt-ecn-state) + fi + + iptables -t mangle -D POSTROUTING -j nixos-tcpcrypt || true + iptables -t raw -D PREROUTING -j nixos-tcpcrypt || true + + iptables -t raw -F nixos-tcpcrypt || true + iptables -t raw -X nixos-tcpcrypt || true + + iptables -t mangle -F nixos-tcpcrypt || true + iptables -t mangle -X nixos-tcpcrypt || true + ''; + }; + }; + +} diff --git a/nixos/modules/services/networking/tftpd.nix b/nixos/modules/services/networking/tftpd.nix new file mode 100644 index 00000000000..37935496c59 --- /dev/null +++ b/nixos/modules/services/networking/tftpd.nix @@ -0,0 +1,43 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +{ + + ###### interface + + options = { + + services.tftpd.enable = mkOption { + default = false; + description = '' + Whether to enable the anonymous FTP user. + ''; + }; + + services.tftpd.path = mkOption { + default = "/home/tftp"; + description = '' + Where the tftp server files are stored + ''; + }; + + }; + + + ###### implementation + + config = mkIf config.services.tftpd.enable { + + services.xinetd.enable = true; + + services.xinetd.services = singleton + { name = "tftp"; + protocol = "udp"; + server = "${pkgs.netkittftp}/sbin/in.tftpd"; + serverArgs = "${config.services.tftpd.path}"; + }; + + }; + +} diff --git a/nixos/modules/services/networking/unbound.nix b/nixos/modules/services/networking/unbound.nix new file mode 100644 index 00000000000..fb75b4ed069 --- /dev/null +++ b/nixos/modules/services/networking/unbound.nix @@ -0,0 +1,118 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.unbound; + + username = "unbound"; + + stateDir = "/var/lib/unbound"; + + access = concatMapStrings (x: " access-control: ${x} allow\n") cfg.allowedAccess; + + interfaces = concatMapStrings (x: " interface: ${x}\n") cfg.interfaces; + + forward = optionalString (length cfg.forwardAddresses != 0) + "forward-zone:\n name: .\n" + + concatMapStrings (x: " forward-addr: ${x}\n") cfg.forwardAddresses; + + confFile = pkgs.writeText "unbound.conf" + '' + server: + directory: "${stateDir}" + username: ${username} + # make sure unbound can access entropy from inside the chroot. + # e.g. on linux the use these commands (on BSD, devfs(8) is used): + # mount --bind -n /dev/random /etc/unbound/dev/random + # and mount --bind -n /dev/log /etc/unbound/dev/log + chroot: "${stateDir}" + # logfile: "${stateDir}/unbound.log" #uncomment to use logfile. + pidfile: "${stateDir}/unbound.pid" + verbosity: 1 # uncomment and increase to get more logging. + # listen on all interfaces, answer queries from the local subnet. + ${interfaces} + ${access} + ${forward} + ${cfg.extraConfig} + ''; + +in + +{ + + ###### interface + + options = { + + services.unbound = { + + enable = mkOption { + default = false; + description = " + Whether to enable the Unbound domain name server. + "; + }; + + allowedAccess = mkOption { + default = ["127.0.0.0/24"]; + description = " + What networks are allowed to use us as a resolver. + "; + }; + + interfaces = mkOption { + default = [ "127.0.0.0" "::1" ]; + description = " + What addresses the server should listen to. + "; + }; + + forwardAddresses = mkOption { + default = [ ]; + description = " + What servers to forward the queries to. + "; + }; + + extraConfig = mkOption { + default = ""; + description = " + Extra unbound config + "; + }; + + }; + + }; + + + ###### implementation + + config = mkIf config.services.unbound.enable { + environment.systemPackages = [ pkgs.unbound ]; + + users.extraUsers = singleton + { name = username; + uid = config.ids.uids.unbound; + description = "unbound daemon user"; + home = "/tmp"; + }; + + jobs.unbound = + { description = "Unbound name server job"; + + preStart = + '' + ${pkgs.coreutils}/bin/mkdir -p ${stateDir} + ''; + + daemonType = "fork"; + + exec = "${pkgs.unbound}/sbin/unbound -c ${confFile}"; + }; + + }; + +} diff --git a/nixos/modules/services/networking/vsftpd.nix b/nixos/modules/services/networking/vsftpd.nix new file mode 100644 index 00000000000..1b2432401de --- /dev/null +++ b/nixos/modules/services/networking/vsftpd.nix @@ -0,0 +1,137 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.vsftpd; + + inherit (pkgs) vsftpd; + + yesNoOption = p : name : + "${name}=${if p then "YES" else "NO"}"; + +in + +{ + + ###### interface + + options = { + + services.vsftpd = { + + enable = mkOption { + default = false; + description = "Whether to enable the vsftpd FTP server."; + }; + + anonymousUser = mkOption { + default = false; + description = "Whether to enable the anonymous FTP user."; + }; + + anonymousUserHome = mkOption { + default = "/home/ftp"; + description = "Path to anonymous user data."; + }; + + localUsers = mkOption { + default = false; + description = "Whether to enable FTP for local users."; + }; + + writeEnable = mkOption { + default = false; + description = "Whether any write activity is permitted to users."; + }; + + anonymousUploadEnable = mkOption { + default = false; + description = "Whether any uploads are permitted to anonymous users."; + }; + + anonymousMkdirEnable = mkOption { + default = false; + description = "Whether mkdir is permitted to anonymous users."; + }; + + chrootlocalUser = mkOption { + default = false; + description = "Whether local users are confined to their home directory."; + }; + + userlistEnable = mkOption { + default = false; + description = "Whether users are included."; + }; + + userlistDeny = mkOption { + default = false; + description = "Whether users are excluded."; + }; + + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + users.extraUsers = + [ { name = "vsftpd"; + uid = config.ids.uids.vsftpd; + description = "VSFTPD user"; + home = "/homeless-shelter"; + } + ] ++ pkgs.lib.optional cfg.anonymousUser + { name = "ftp"; + uid = config.ids.uids.ftp; + group = "ftp"; + description = "Anonymous FTP user"; + home = cfg.anonymousUserHome; + }; + + users.extraGroups = singleton + { name = "ftp"; + gid = config.ids.gids.ftp; + }; + + jobs.vsftpd = + { description = "vsftpd server"; + + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; + + preStart = + '' + # !!! Why isn't this generated in the normal way? + cat > /etc/vsftpd.conf <<EOF + ${yesNoOption cfg.anonymousUser "anonymous_enable"} + ${yesNoOption cfg.localUsers "local_enable"} + ${yesNoOption cfg.writeEnable "write_enable"} + ${yesNoOption cfg.anonymousUploadEnable "anon_upload_enable"} + ${yesNoOption cfg.anonymousMkdirEnable "anon_mkdir_write_enable"} + ${yesNoOption cfg.chrootlocalUser "chroot_local_user"} + ${yesNoOption cfg.userlistEnable "userlist_enable"} + ${yesNoOption cfg.userlistDeny "userlist_deny"} + background=NO + listen=YES + nopriv_user=vsftpd + secure_chroot_dir=/var/empty + EOF + + ${if cfg.anonymousUser then '' + mkdir -p -m 555 ${cfg.anonymousUserHome} + chown -R ftp:ftp ${cfg.anonymousUserHome} + '' else ""} + ''; + + exec = "${vsftpd}/sbin/vsftpd /etc/vsftpd.conf"; + }; + + }; + +} diff --git a/nixos/modules/services/networking/wakeonlan.nix b/nixos/modules/services/networking/wakeonlan.nix new file mode 100644 index 00000000000..1fc54986b16 --- /dev/null +++ b/nixos/modules/services/networking/wakeonlan.nix @@ -0,0 +1,56 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + interfaces = config.services.wakeonlan.interfaces; + + ethtool = "${pkgs.ethtool}/sbin/ethtool"; + + passwordParameter = password : if (password == "") then "" else + "sopass ${password}"; + + methodParameter = {method, password} : + if method == "magicpacket" then "wol g" + else if method == "password" then "wol s so ${passwordParameter password}" + else throw "Wake-On-Lan method not supported"; + + line = { interface, method ? "magicpacket", password ? "" }: '' + ${ethtool} -s ${interface} ${methodParameter {inherit method password;}} + ''; + + concatStrings = fold (x: y: x + y) ""; + lines = concatStrings (map (l: line l) interfaces); + +in +{ + + ###### interface + + options = { + + services.wakeonlan.interfaces = mkOption { + default = [ ]; + example = [ + { + interface = "eth0"; + method = "password"; + password = "00:11:22:33:44:55"; + } + ]; + description = '' + Interfaces where to enable Wake-On-LAN, and how. Two methods available: + "magickey" and "password". The password has the shape of six bytes + in hexadecimal separated by a colon each. For more information, + check the ethtool manual. + ''; + }; + + }; + + + ###### implementation + + config.powerManagement.powerDownCommands = lines; + +} diff --git a/nixos/modules/services/networking/websockify.nix b/nixos/modules/services/networking/websockify.nix new file mode 100644 index 00000000000..12042bbad6c --- /dev/null +++ b/nixos/modules/services/networking/websockify.nix @@ -0,0 +1,54 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let cfg = config.services.networking.websockify; in { + options = { + services.networking.websockify = { + enable = mkOption { + description = "Whether to enable websockify to forward websocket connections to TCP connections."; + + default = false; + + type = types.bool; + }; + + sslCert = mkOption { + description = "Path to the SSL certificate."; + type = types.path; + }; + + sslKey = mkOption { + description = "Path to the SSL key."; + default = cfg.sslCert; + defaultText = "config.services.networking.websockify.sslCert"; + type = types.path; + }; + + portMap = mkOption { + description = "Ports to map by default."; + default = {}; + type = types.attrsOf types.int; + }; + }; + }; + + config = mkIf cfg.enable { + systemd.services."websockify@" = { + description = "Service to forward websocket connections to TCP connections (from port:to port %I)"; + script = '' + IFS=':' read -a array <<< "$1" + ${pkgs.pythonPackages.websockify}/bin/websockify --ssl-only \ + --cert=${cfg.sslCert} --key=${cfg.sslKey} 0.0.0.0:''${array[0]} 0.0.0.0:''${array[1]} + ''; + scriptArgs = "%i"; + }; + + systemd.targets."default-websockify" = { + description = "Target to start all default websockify@ services"; + unitConfig."X-StopOnReconfiguration" = true; + wants = mapAttrsToList (name: value: "websockify@${name}:${toString value}.service") cfg.portMap; + wantedBy = [ "multi-user.target" ]; + }; + }; +} diff --git a/nixos/modules/services/networking/wicd.nix b/nixos/modules/services/networking/wicd.nix new file mode 100644 index 00000000000..8e012273216 --- /dev/null +++ b/nixos/modules/services/networking/wicd.nix @@ -0,0 +1,41 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +{ + + ###### interface + + options = { + + networking.wicd.enable = mkOption { + default = false; + description = '' + Whether to start <command>wicd</command>. Wired and + wireless network configurations can then be managed by + wicd-client. + ''; + }; + }; + + + ###### implementation + + config = mkIf config.networking.wicd.enable { + + environment.systemPackages = [pkgs.wicd]; + + jobs.wicd = + { startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; + + script = + "${pkgs.wicd}/sbin/wicd -f"; + }; + + services.dbus.enable = true; + services.dbus.packages = [pkgs.wicd]; + + }; + +} diff --git a/nixos/modules/services/networking/wpa_supplicant.nix b/nixos/modules/services/networking/wpa_supplicant.nix new file mode 100644 index 00000000000..dca398dd8be --- /dev/null +++ b/nixos/modules/services/networking/wpa_supplicant.nix @@ -0,0 +1,136 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.networking.wireless; + configFile = "/etc/wpa_supplicant.conf"; + + ifaces = + cfg.interfaces ++ + optional (config.networking.WLANInterface != "") config.networking.WLANInterface; + +in + +{ + + ###### interface + + options = { + + networking.WLANInterface = mkOption { + default = ""; + description = "Obsolete. Use <option>networking.wireless.interfaces</option> instead."; + }; + + networking.wireless = { + enable = mkOption { + default = false; + description = '' + Whether to start <command>wpa_supplicant</command> to scan for + and associate with wireless networks. Note: NixOS currently + does not generate <command>wpa_supplicant</command>'s + configuration file, <filename>${configFile}</filename>. You + should edit this file yourself to define wireless networks, + WPA keys and so on (see + <citerefentry><refentrytitle>wpa_supplicant.conf</refentrytitle> + <manvolnum>5</manvolnum></citerefentry>). + ''; + }; + + interfaces = mkOption { + default = []; + example = [ "wlan0" "wlan1" ]; + description = '' + The interfaces <command>wpa_supplicant</command> will use. If empty, it will + automatically use all wireless interfaces. (Note that auto-detection is currently + broken on Linux 3.4.x kernels. See http://github.com/NixOS/nixos/issues/10 for + further details.) + ''; + }; + + driver = mkOption { + default = "nl80211,wext"; + description = "Force a specific wpa_supplicant driver."; + }; + + userControlled = { + enable = mkOption { + default = false; + description = '' + Allow normal users to control wpa_supplicant through wpa_gui or wpa_cli. + This is useful for laptop users that switch networks a lot. + + When you want to use this, make sure ${configFile} doesn't exist. + It will be created for you. + + Currently it is also necessary to explicitly specify networking.wireless.interfaces. + ''; + }; + + group = mkOption { + default = "wheel"; + example = "network"; + type = types.string; + description = "Members of this group can control wpa_supplicant."; + }; + }; + }; + }; + + + ###### implementation + + config = mkIf cfg.enable { + + environment.systemPackages = [ pkgs.wpa_supplicant ]; + + services.dbus.packages = [ pkgs.wpa_supplicant ]; + + jobs.wpa_supplicant = + { description = "WPA Supplicant"; + + wantedBy = [ "network.target" ]; + after = [ "systemd-udev-settle.service" ]; + + path = [ pkgs.wpa_supplicant ]; + + preStart = '' + touch -a ${configFile} + chmod 600 ${configFile} + '' + optionalString cfg.userControlled.enable '' + if [ ! -s ${configFile} ]; then + echo "ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=${cfg.userControlled.group}" >> ${configFile} + echo "update_config=1" >> ${configFile} + fi + ''; + + script = + '' + ${if ifaces == [] then '' + for i in $(cd /sys/class/net && echo *); do + DEVTYPE= + source /sys/class/net/$i/uevent + if [ "$DEVTYPE" = "wlan" -o -e /sys/class/net/$i/wireless ]; then + ifaces="$ifaces''${ifaces:+ -N} -i$i" + fi + done + '' else '' + ifaces="${concatStringsSep " -N " (map (i: "-i${i}") ifaces)}" + ''} + exec wpa_supplicant -s -u -D${cfg.driver} -c ${configFile} $ifaces + ''; + }; + + powerManagement.resumeCommands = + '' + ${config.systemd.package}/bin/systemctl try-restart wpa_supplicant + ''; + + assertions = [{ assertion = !cfg.userControlled.enable || cfg.interfaces != []; + message = "user controlled wpa_supplicant needs explicit networking.wireless.interfaces";}]; + + }; + +} diff --git a/nixos/modules/services/networking/xinetd.nix b/nixos/modules/services/networking/xinetd.nix new file mode 100644 index 00000000000..626183b810f --- /dev/null +++ b/nixos/modules/services/networking/xinetd.nix @@ -0,0 +1,158 @@ +{ config, pkgs, ... }: + +with pkgs.lib; + +let + + cfg = config.services.xinetd; + + inherit (pkgs) xinetd; + + configFile = pkgs.writeText "xinetd.conf" + '' + defaults + { + log_type = SYSLOG daemon info + log_on_failure = HOST + log_on_success = PID HOST DURATION EXIT + ${cfg.extraDefaults} + } + + ${concatMapStrings makeService cfg.services} + ''; + + makeService = srv: + '' + service ${srv.name} + { + protocol = ${srv.protocol} + ${optionalString srv.unlisted "type = UNLISTED"} + ${optionalString (srv.flags != "") "flags = ${srv.flags}"} + socket_type = ${if srv.protocol == "udp" then "dgram" else "stream"} + ${if srv.port != 0 then "port = ${toString srv.port}" else ""} + wait = ${if srv.protocol == "udp" then "yes" else "no"} + user = ${srv.user} + server = ${srv.server} + ${optionalString (srv.serverArgs != "") "server_args = ${srv.serverArgs}"} + ${srv.extraConfig} + } + ''; + +in + +{ + + ###### interface + + options = { + + services.xinetd.enable = mkOption { + default = false; + description = '' + Whether to enable the xinetd super-server daemon. + ''; + }; + + services.xinetd.extraDefaults = mkOption { + default = ""; + type = types.string; + description = '' + Additional configuration lines added to the default section of xinetd's configuration. + ''; + }; + + services.xinetd.services = mkOption { + default = []; + description = '' + A list of services provided by xinetd. + ''; + + type = types.listOf types.optionSet; + + options = { + + name = mkOption { + type = types.string; + example = "login"; + description = "Name of the service."; + }; + + protocol = mkOption { + type = types.string; + default = "tcp"; + description = + "Protocol of the service. Usually <literal>tcp</literal> or <literal>udp</literal>."; + }; + + port = mkOption { + type = types.int; + default = 0; + example = 123; + description = "Port number of the service."; + }; + + user = mkOption { + type = types.string; + default = "nobody"; + description = "User account for the service"; + }; + + server = mkOption { + type = types.string; + example = "/foo/bin/ftpd"; + description = "Path of the program that implements the service."; + }; + + serverArgs = mkOption { + type = types.string; + default = ""; + description = "Command-line arguments for the server program."; + }; + + flags = mkOption { + type = types.string; + default = ""; + description = ""; + }; + + unlisted = mkOption { + type = types.bool; + default = false; + description = '' + Whether this server is listed in + <filename>/etc/services</filename>. If so, the port + number can be omitted. + ''; + }; + + extraConfig = mkOption { + type = types.string; + default = ""; + description = "Extra configuration-lines added to the section of the service."; + }; + + }; + + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + jobs.xinetd = + { description = "xinetd server"; + + startOn = "started network-interfaces"; + stopOn = "stopping network-interfaces"; + + path = [ xinetd ]; + + exec = "xinetd -syslog daemon -dontfork -stayalive -f ${configFile}"; + }; + + }; + +} |