summary refs log tree commit diff
path: root/nixos/modules/services/networking
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/services/networking')
-rw-r--r--nixos/modules/services/networking/amuled.nix78
-rw-r--r--nixos/modules/services/networking/avahi-daemon.nix144
-rw-r--r--nixos/modules/services/networking/bind.nix152
-rw-r--r--nixos/modules/services/networking/bitlbee.nix123
-rw-r--r--nixos/modules/services/networking/chrony.nix118
-rw-r--r--nixos/modules/services/networking/cntlm.nix115
-rw-r--r--nixos/modules/services/networking/ddclient.nix127
-rw-r--r--nixos/modules/services/networking/dhclient.nix111
-rw-r--r--nixos/modules/services/networking/dhcpcd.nix143
-rw-r--r--nixos/modules/services/networking/dhcpd.nix131
-rw-r--r--nixos/modules/services/networking/dnsmasq.nix70
-rw-r--r--nixos/modules/services/networking/ejabberd.nix135
-rw-r--r--nixos/modules/services/networking/firewall.nix368
-rw-r--r--nixos/modules/services/networking/flashpolicyd.nix84
-rw-r--r--nixos/modules/services/networking/freenet.nix64
-rw-r--r--nixos/modules/services/networking/git-daemon.nix112
-rw-r--r--nixos/modules/services/networking/gnunet.nix148
-rw-r--r--nixos/modules/services/networking/gogoclient.nix88
-rw-r--r--nixos/modules/services/networking/gvpe.nix144
-rw-r--r--nixos/modules/services/networking/hostapd.nix163
-rw-r--r--nixos/modules/services/networking/ifplugd.nix88
-rw-r--r--nixos/modules/services/networking/iodined.nix87
-rw-r--r--nixos/modules/services/networking/ircd-hybrid/builder.sh31
-rw-r--r--nixos/modules/services/networking/ircd-hybrid/control.in26
-rw-r--r--nixos/modules/services/networking/ircd-hybrid/default.nix137
-rw-r--r--nixos/modules/services/networking/ircd-hybrid/ircd.conf1051
-rw-r--r--nixos/modules/services/networking/minidlna.nix112
-rw-r--r--nixos/modules/services/networking/nat.nix104
-rw-r--r--nixos/modules/services/networking/networkmanager.nix193
-rw-r--r--nixos/modules/services/networking/ntpd.nix90
-rw-r--r--nixos/modules/services/networking/oidentd.nix44
-rw-r--r--nixos/modules/services/networking/openfire.nix70
-rw-r--r--nixos/modules/services/networking/openvpn.nix172
-rw-r--r--nixos/modules/services/networking/prayer.nix103
-rw-r--r--nixos/modules/services/networking/privoxy.nix95
-rw-r--r--nixos/modules/services/networking/quassel.nix96
-rw-r--r--nixos/modules/services/networking/radvd.nix77
-rw-r--r--nixos/modules/services/networking/rdnssd.nix48
-rw-r--r--nixos/modules/services/networking/rpcbind.nix81
-rw-r--r--nixos/modules/services/networking/sabnzbd.nix52
-rw-r--r--nixos/modules/services/networking/ssh/lshd.nix175
-rw-r--r--nixos/modules/services/networking/ssh/sshd.nix338
-rw-r--r--nixos/modules/services/networking/supybot.nix88
-rw-r--r--nixos/modules/services/networking/tcpcrypt.nix78
-rw-r--r--nixos/modules/services/networking/tftpd.nix43
-rw-r--r--nixos/modules/services/networking/unbound.nix118
-rw-r--r--nixos/modules/services/networking/vsftpd.nix137
-rw-r--r--nixos/modules/services/networking/wakeonlan.nix56
-rw-r--r--nixos/modules/services/networking/websockify.nix54
-rw-r--r--nixos/modules/services/networking/wicd.nix41
-rw-r--r--nixos/modules/services/networking/wpa_supplicant.nix136
-rw-r--r--nixos/modules/services/networking/xinetd.nix158
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}";
+      };
+
+  };
+
+}