159 lines
5.5 KiB
Nix
159 lines
5.5 KiB
Nix
|
{ config, lib, pkgs, ... }:
|
||
|
|
||
|
with lib;
|
||
|
let
|
||
|
cfg = config.fudo.system;
|
||
|
|
||
|
portMappingOpts = { name, ... }: {
|
||
|
options = with types; {
|
||
|
internal-port = mkOption {
|
||
|
type = port;
|
||
|
description = "Port on localhost to recieve traffic";
|
||
|
};
|
||
|
external-port = mkOption {
|
||
|
type = port;
|
||
|
description = "External port on which to listen for traffic.";
|
||
|
};
|
||
|
protocols = mkOption {
|
||
|
type = listOf str;
|
||
|
description =
|
||
|
"Protocols for which to forward ports. Default is tcp-only.";
|
||
|
default = [ "tcp" ];
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
in {
|
||
|
options.fudo.system = with types; {
|
||
|
internal-port-map = mkOption {
|
||
|
type = attrsOf (submodule portMappingOpts);
|
||
|
description =
|
||
|
"Sets of external ports to internal (i.e. localhost) ports to forward.";
|
||
|
default = { };
|
||
|
example = {
|
||
|
sshmap = {
|
||
|
internal-port = 2222;
|
||
|
external-port = 22;
|
||
|
protocol = "udp";
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
config = mkIf (cfg.internal-port-map != { }) {
|
||
|
# FIXME: FUCK ME THIS IS WAY HARDER THAN IT SHOULD BE
|
||
|
# boot.kernel.sysctl = mkIf (cfg.internal-port-map != { }) {
|
||
|
# "net.ipv4.conf.all.route_localnet" = "1";
|
||
|
# };
|
||
|
|
||
|
# fudo.system.services.forward-internal-ports = let
|
||
|
# ip-line = op: src-port: target-port: protocol: ''
|
||
|
# ${ipt} -t nat -${op} PREROUTING -p ${protocol} --dport ${
|
||
|
# toString src-port
|
||
|
# } -j REDIRECT --to-ports ${toString target-port}
|
||
|
# ${ipt} -t nat -${op} OUTPUT -p ${protocol} -s lo --dport ${
|
||
|
# toString src-port
|
||
|
# } -j REDIRECT --to-ports ${toString target-port}
|
||
|
# '';
|
||
|
|
||
|
# ip-forward-line = ip-line "I";
|
||
|
|
||
|
# ip-unforward-line = ip-line "D";
|
||
|
|
||
|
# traceOut = obj: builtins.trace obj obj;
|
||
|
|
||
|
# concatMapAttrsToList = f: attrs: concatLists (mapAttrsToList f attrs);
|
||
|
|
||
|
# portmap-entries = concatMapAttrsToList (name: opts:
|
||
|
# map (protocol: {
|
||
|
# src = opts.external-port;
|
||
|
# target = opts.internal-port;
|
||
|
# protocol = protocol;
|
||
|
# }) opts.protocols) cfg.internal-port-map;
|
||
|
|
||
|
# make-entries = f: { src, target, protocol, ... }: f src target protocol;
|
||
|
|
||
|
# forward-entries = map (make-entries ip-forward-line) portmap-entries;
|
||
|
|
||
|
# unforward-entries = map (make-entries ip-unforward-line) portmap-entries;
|
||
|
|
||
|
# forward-ports-script = pkgs.writeShellScript "forward-internal-ports.sh"
|
||
|
# (concatStringsSep "\n" forward-entries);
|
||
|
|
||
|
# unforward-ports-script =
|
||
|
# pkgs.writeShellScript "unforward-internal-ports.sh"
|
||
|
# (concatStringsSep "\n"
|
||
|
# (map (make-entries ip-unforward-line) portmap-entries));
|
||
|
# in {
|
||
|
# wantedBy = [ "multi-user.target" ];
|
||
|
# after = [ "firewall.service" "nat.service" ];
|
||
|
# type = "oneshot";
|
||
|
# description = "Rules for forwarding external ports to local ports.";
|
||
|
# execStart = "${forward-ports-script}";
|
||
|
# execStop = "${unforward-ports-script}";
|
||
|
# requiredCapabilities =
|
||
|
# [ "CAP_DAC_READ_SEARCH" "CAP_NET_ADMIN" "CAP_NET_RAW" ];
|
||
|
# };
|
||
|
|
||
|
# networking.firewall = let
|
||
|
# iptables = "ip46tables";
|
||
|
# ip-forward-line = protocols: internal: external:
|
||
|
# concatStringsSep "\n" (map (protocol: ''
|
||
|
# ${iptables} -t nat -I PREROUTING -p ${protocol} --dport ${
|
||
|
# toString external
|
||
|
# } -j REDIRECT --to-ports ${toString internal}
|
||
|
# ${iptables} -t nat -I OUTPUT -s lo -p ${protocol} --dport ${
|
||
|
# toString external
|
||
|
# } -j REDIRECT --to-ports ${toString internal}
|
||
|
# '') protocols);
|
||
|
|
||
|
# ip-unforward-line = protocols: internal: external:
|
||
|
# concatStringsSep "\n" (map (protocol: ''
|
||
|
# ${iptables} -t nat -D PREROUTING -p ${protocol} --dport ${
|
||
|
# toString external
|
||
|
# } -j REDIRECT --to-ports ${toString internal}
|
||
|
# ${iptables} -t nat -D OUTPUT -s lo -p ${protocol} --dport ${
|
||
|
# toString external
|
||
|
# } -j REDIRECT --to-ports ${toString internal}
|
||
|
# '') protocols);
|
||
|
# in {
|
||
|
# enable = true;
|
||
|
|
||
|
# extraCommands = concatStringsSep "\n" (mapAttrsToList (name: opts:
|
||
|
# ip-forward-line opts.protocols opts.internal-port opts.external-port)
|
||
|
# cfg.internal-port-map);
|
||
|
|
||
|
# extraStopCommands = concatStringsSep "\n" (mapAttrsToList (name: opts:
|
||
|
# ip-unforward-line opts.protocols opts.internal-port opts.external-port)
|
||
|
# cfg.internal-port-map);
|
||
|
# };
|
||
|
|
||
|
# networking.nat.forwardPorts =
|
||
|
# let portmaps = (attrValues opts.external-port);
|
||
|
# in concatMap (opts:
|
||
|
# map (protocol: {
|
||
|
# destination = "127.0.0.1:${toString opts.internal-port}";
|
||
|
# sourcePort = opts.external-port;
|
||
|
# proto = protocol;
|
||
|
# }) opts.protocols) (attrValues cfg.internal-port-map);
|
||
|
|
||
|
# services.xinetd = mkIf ((length (attrNames cfg.internal-port-map)) > 0) {
|
||
|
# enable = true;
|
||
|
# services = let
|
||
|
# svcs = mapAttrsToList (name: opts: opts // { name = name; })
|
||
|
# cfg.internal-port-map;
|
||
|
# svcs-protocols = concatMap
|
||
|
# (svc: map (protocol: svc // { protocol = protocol; }) svc.protocols)
|
||
|
# svcs;
|
||
|
# in map (opts: {
|
||
|
# name = opts.name;
|
||
|
# unlisted = true;
|
||
|
# port = opts.external-port;
|
||
|
# server = "${pkgs.coreutils}/bin/false";
|
||
|
# extraConfig = "redirect = localhost ${toString opts.internal-port}";
|
||
|
# protocol = opts.protocol;
|
||
|
# }) svcs-protocols;
|
||
|
# };
|
||
|
};
|
||
|
}
|