at 21.11-pre 46 kB view raw
1{ config, options, lib, pkgs, utils, ... }: 2 3with lib; 4with utils; 5 6let 7 8 cfg = config.networking; 9 interfaces = attrValues cfg.interfaces; 10 hasVirtuals = any (i: i.virtual) interfaces; 11 hasSits = cfg.sits != { }; 12 hasBonds = cfg.bonds != { }; 13 14 slaves = concatMap (i: i.interfaces) (attrValues cfg.bonds) 15 ++ concatMap (i: i.interfaces) (attrValues cfg.bridges) 16 ++ concatMap (i: attrNames (filterAttrs (name: config: ! (config.type == "internal" || hasAttr name cfg.interfaces)) i.interfaces)) (attrValues cfg.vswitches); 17 18 slaveIfs = map (i: cfg.interfaces.${i}) (filter (i: cfg.interfaces ? ${i}) slaves); 19 20 rstpBridges = flip filterAttrs cfg.bridges (_: { rstp, ... }: rstp); 21 22 needsMstpd = rstpBridges != { }; 23 24 bridgeStp = optional needsMstpd (pkgs.writeTextFile { 25 name = "bridge-stp"; 26 executable = true; 27 destination = "/bin/bridge-stp"; 28 text = '' 29 #!${pkgs.runtimeShell} -e 30 export PATH="${pkgs.mstpd}/bin" 31 32 BRIDGES=(${concatStringsSep " " (attrNames rstpBridges)}) 33 for BRIDGE in $BRIDGES; do 34 if [ "$BRIDGE" = "$1" ]; then 35 if [ "$2" = "start" ]; then 36 mstpctl addbridge "$BRIDGE" 37 exit 0 38 elif [ "$2" = "stop" ]; then 39 mstpctl delbridge "$BRIDGE" 40 exit 0 41 fi 42 exit 1 43 fi 44 done 45 exit 1 46 ''; 47 }); 48 49 # We must escape interfaces due to the systemd interpretation 50 subsystemDevice = interface: 51 "sys-subsystem-net-devices-${escapeSystemdPath interface}.device"; 52 53 addrOpts = v: 54 assert v == 4 || v == 6; 55 { options = { 56 address = mkOption { 57 type = types.str; 58 description = '' 59 IPv${toString v} address of the interface. Leave empty to configure the 60 interface using DHCP. 61 ''; 62 }; 63 64 prefixLength = mkOption { 65 type = types.addCheck types.int (n: n >= 0 && n <= (if v == 4 then 32 else 128)); 66 description = '' 67 Subnet mask of the interface, specified as the number of 68 bits in the prefix (<literal>${if v == 4 then "24" else "64"}</literal>). 69 ''; 70 }; 71 }; 72 }; 73 74 routeOpts = v: 75 { options = { 76 address = mkOption { 77 type = types.str; 78 description = "IPv${toString v} address of the network."; 79 }; 80 81 prefixLength = mkOption { 82 type = types.addCheck types.int (n: n >= 0 && n <= (if v == 4 then 32 else 128)); 83 description = '' 84 Subnet mask of the network, specified as the number of 85 bits in the prefix (<literal>${if v == 4 then "24" else "64"}</literal>). 86 ''; 87 }; 88 89 via = mkOption { 90 type = types.nullOr types.str; 91 default = null; 92 description = "IPv${toString v} address of the next hop."; 93 }; 94 95 options = mkOption { 96 type = types.attrsOf types.str; 97 default = { }; 98 example = { mtu = "1492"; window = "524288"; }; 99 description = '' 100 Other route options. See the symbol <literal>OPTIONS</literal> 101 in the <literal>ip-route(8)</literal> manual page for the details. 102 ''; 103 }; 104 105 }; 106 }; 107 108 gatewayCoerce = address: { inherit address; }; 109 110 gatewayOpts = { ... }: { 111 112 options = { 113 114 address = mkOption { 115 type = types.str; 116 description = "The default gateway address."; 117 }; 118 119 interface = mkOption { 120 type = types.nullOr types.str; 121 default = null; 122 example = "enp0s3"; 123 description = "The default gateway interface."; 124 }; 125 126 metric = mkOption { 127 type = types.nullOr types.int; 128 default = null; 129 example = 42; 130 description = "The default gateway metric/preference."; 131 }; 132 133 }; 134 135 }; 136 137 interfaceOpts = { name, ... }: { 138 139 options = { 140 name = mkOption { 141 example = "eth0"; 142 type = types.str; 143 description = "Name of the interface."; 144 }; 145 146 tempAddress = mkOption { 147 type = types.enum (lib.attrNames tempaddrValues); 148 default = cfg.tempAddresses; 149 defaultText = literalExample ''config.networking.tempAddresses''; 150 description = '' 151 When IPv6 is enabled with SLAAC, this option controls the use of 152 temporary address (aka privacy extensions) on this 153 interface. This is used to reduce tracking. 154 155 See also the global option 156 <xref linkend="opt-networking.tempAddresses"/>, which 157 applies to all interfaces where this is not set. 158 159 Possible values are: 160 ${tempaddrDoc} 161 ''; 162 }; 163 164 useDHCP = mkOption { 165 type = types.nullOr types.bool; 166 default = null; 167 description = '' 168 Whether this interface should be configured with dhcp. 169 Null implies the old behavior which depends on whether ip addresses 170 are specified or not. 171 ''; 172 }; 173 174 ipv4.addresses = mkOption { 175 default = [ ]; 176 example = [ 177 { address = "10.0.0.1"; prefixLength = 16; } 178 { address = "192.168.1.1"; prefixLength = 24; } 179 ]; 180 type = with types; listOf (submodule (addrOpts 4)); 181 description = '' 182 List of IPv4 addresses that will be statically assigned to the interface. 183 ''; 184 }; 185 186 ipv6.addresses = mkOption { 187 default = [ ]; 188 example = [ 189 { address = "fdfd:b3f0:482::1"; prefixLength = 48; } 190 { address = "2001:1470:fffd:2098::e006"; prefixLength = 64; } 191 ]; 192 type = with types; listOf (submodule (addrOpts 6)); 193 description = '' 194 List of IPv6 addresses that will be statically assigned to the interface. 195 ''; 196 }; 197 198 ipv4.routes = mkOption { 199 default = []; 200 example = [ 201 { address = "10.0.0.0"; prefixLength = 16; } 202 { address = "192.168.2.0"; prefixLength = 24; via = "192.168.1.1"; } 203 ]; 204 type = with types; listOf (submodule (routeOpts 4)); 205 description = '' 206 List of extra IPv4 static routes that will be assigned to the interface. 207 ''; 208 }; 209 210 ipv6.routes = mkOption { 211 default = []; 212 example = [ 213 { address = "fdfd:b3f0::"; prefixLength = 48; } 214 { address = "2001:1470:fffd:2098::"; prefixLength = 64; via = "fdfd:b3f0::1"; } 215 ]; 216 type = with types; listOf (submodule (routeOpts 6)); 217 description = '' 218 List of extra IPv6 static routes that will be assigned to the interface. 219 ''; 220 }; 221 222 macAddress = mkOption { 223 default = null; 224 example = "00:11:22:33:44:55"; 225 type = types.nullOr (types.str); 226 description = '' 227 MAC address of the interface. Leave empty to use the default. 228 ''; 229 }; 230 231 mtu = mkOption { 232 default = null; 233 example = 9000; 234 type = types.nullOr types.int; 235 description = '' 236 MTU size for packets leaving the interface. Leave empty to use the default. 237 ''; 238 }; 239 240 virtual = mkOption { 241 default = false; 242 type = types.bool; 243 description = '' 244 Whether this interface is virtual and should be created by tunctl. 245 This is mainly useful for creating bridges between a host and a virtual 246 network such as VPN or a virtual machine. 247 ''; 248 }; 249 250 virtualOwner = mkOption { 251 default = "root"; 252 type = types.str; 253 description = '' 254 In case of a virtual device, the user who owns it. 255 ''; 256 }; 257 258 virtualType = mkOption { 259 default = if hasPrefix "tun" name then "tun" else "tap"; 260 defaultText = literalExample ''if hasPrefix "tun" name then "tun" else "tap"''; 261 type = with types; enum [ "tun" "tap" ]; 262 description = '' 263 The type of interface to create. 264 The default is TUN for an interface name starting 265 with "tun", otherwise TAP. 266 ''; 267 }; 268 269 proxyARP = mkOption { 270 default = false; 271 type = types.bool; 272 description = '' 273 Turn on proxy_arp for this device. 274 This is mainly useful for creating pseudo-bridges between a real 275 interface and a virtual network such as VPN or a virtual machine for 276 interfaces that don't support real bridging (most wlan interfaces). 277 As ARP proxying acts slightly above the link-layer, below-ip traffic 278 isn't bridged, so things like DHCP won't work. The advantage above 279 using NAT lies in the fact that no IP addresses are shared, so all 280 hosts are reachable/routeable. 281 282 WARNING: turns on ip-routing, so if you have multiple interfaces, you 283 should think of the consequence and setup firewall rules to limit this. 284 ''; 285 }; 286 287 }; 288 289 config = { 290 name = mkDefault name; 291 }; 292 293 # Renamed or removed options 294 imports = 295 let 296 defined = x: x != "_mkMergedOptionModule"; 297 in [ 298 (mkChangedOptionModule [ "preferTempAddress" ] [ "tempAddress" ] 299 (config: 300 let bool = getAttrFromPath [ "preferTempAddress" ] config; 301 in if bool then "default" else "enabled" 302 )) 303 (mkRenamedOptionModule [ "ip4" ] [ "ipv4" "addresses"]) 304 (mkRenamedOptionModule [ "ip6" ] [ "ipv6" "addresses"]) 305 (mkRemovedOptionModule [ "subnetMask" ] '' 306 Supply a prefix length instead; use option 307 networking.interfaces.<name>.ipv{4,6}.addresses'') 308 (mkMergedOptionModule 309 [ [ "ipAddress" ] [ "prefixLength" ] ] 310 [ "ipv4" "addresses" ] 311 (cfg: with cfg; 312 optional (defined ipAddress && defined prefixLength) 313 { address = ipAddress; prefixLength = prefixLength; })) 314 (mkMergedOptionModule 315 [ [ "ipv6Address" ] [ "ipv6PrefixLength" ] ] 316 [ "ipv6" "addresses" ] 317 (cfg: with cfg; 318 optional (defined ipv6Address && defined ipv6PrefixLength) 319 { address = ipv6Address; prefixLength = ipv6PrefixLength; })) 320 321 ({ options.warnings = options.warnings; options.assertions = options.assertions; }) 322 ]; 323 324 }; 325 326 vswitchInterfaceOpts = {name, ...}: { 327 328 options = { 329 330 name = mkOption { 331 description = "Name of the interface"; 332 example = "eth0"; 333 type = types.str; 334 }; 335 336 vlan = mkOption { 337 description = "Vlan tag to apply to interface"; 338 example = 10; 339 type = types.nullOr types.int; 340 default = null; 341 }; 342 343 type = mkOption { 344 description = "Openvswitch type to assign to interface"; 345 example = "internal"; 346 type = types.nullOr types.str; 347 default = null; 348 }; 349 }; 350 }; 351 352 hexChars = stringToCharacters "0123456789abcdef"; 353 354 isHexString = s: all (c: elem c hexChars) (stringToCharacters (toLower s)); 355 356 tempaddrValues = { 357 disabled = { 358 sysctl = "0"; 359 description = "completely disable IPv6 temporary addresses"; 360 }; 361 enabled = { 362 sysctl = "1"; 363 description = "generate IPv6 temporary addresses but still use EUI-64 addresses as source addresses"; 364 }; 365 default = { 366 sysctl = "2"; 367 description = "generate IPv6 temporary addresses and use these as source addresses in routing"; 368 }; 369 }; 370 tempaddrDoc = '' 371 <itemizedlist> 372 ${concatStringsSep "\n" (mapAttrsToList (name: { description, ... }: '' 373 <listitem> 374 <para> 375 <literal>"${name}"</literal> to ${description}; 376 </para> 377 </listitem> 378 '') tempaddrValues)} 379 </itemizedlist> 380 ''; 381 382in 383 384{ 385 386 ###### interface 387 388 options = { 389 390 networking.hostName = mkOption { 391 default = "nixos"; 392 # Only allow hostnames without the domain name part (i.e. no FQDNs, see 393 # e.g. "man 5 hostname") and require valid DNS labels (recommended 394 # syntax). Note: We also allow underscores for compatibility/legacy 395 # reasons (as undocumented feature): 396 type = types.strMatching 397 "^$|^[[:alnum:]]([[:alnum:]_-]{0,61}[[:alnum:]])?$"; 398 description = '' 399 The name of the machine. Leave it empty if you want to obtain it from a 400 DHCP server (if using DHCP). The hostname must be a valid DNS label (see 401 RFC 1035 section 2.3.1: "Preferred name syntax", RFC 1123 section 2.1: 402 "Host Names and Numbers") and as such must not contain the domain part. 403 This means that the hostname must start with a letter or digit, 404 end with a letter or digit, and have as interior characters only 405 letters, digits, and hyphen. The maximum length is 63 characters. 406 Additionally it is recommended to only use lower-case characters. 407 If (e.g. for legacy reasons) a FQDN is required as the Linux kernel 408 network node hostname (uname --nodename) the option 409 boot.kernel.sysctl."kernel.hostname" can be used as a workaround (but 410 the 64 character limit still applies). 411 ''; 412 }; 413 414 networking.fqdn = mkOption { 415 readOnly = true; 416 type = types.str; 417 default = if (cfg.hostName != "" && cfg.domain != null) 418 then "${cfg.hostName}.${cfg.domain}" 419 else throw '' 420 The FQDN is required but cannot be determined. Please make sure that 421 both networking.hostName and networking.domain are set properly. 422 ''; 423 defaultText = literalExample ''''${networking.hostName}.''${networking.domain}''; 424 description = '' 425 The fully qualified domain name (FQDN) of this host. It is the result 426 of combining networking.hostName and networking.domain. Using this 427 option will result in an evaluation error if the hostname is empty or 428 no domain is specified. 429 ''; 430 }; 431 432 networking.hostId = mkOption { 433 default = null; 434 example = "4e98920d"; 435 type = types.nullOr types.str; 436 description = '' 437 The 32-bit host ID of the machine, formatted as 8 hexadecimal characters. 438 439 You should try to make this ID unique among your machines. You can 440 generate a random 32-bit ID using the following commands: 441 442 <literal>head -c 8 /etc/machine-id</literal> 443 444 (this derives it from the machine-id that systemd generates) or 445 446 <literal>head -c4 /dev/urandom | od -A none -t x4</literal> 447 448 The primary use case is to ensure when using ZFS that a pool isn't imported 449 accidentally on a wrong machine. 450 ''; 451 }; 452 453 networking.enableIPv6 = mkOption { 454 default = true; 455 type = types.bool; 456 description = '' 457 Whether to enable support for IPv6. 458 ''; 459 }; 460 461 networking.defaultGateway = mkOption { 462 default = null; 463 example = { 464 address = "131.211.84.1"; 465 interface = "enp3s0"; 466 }; 467 type = types.nullOr (types.coercedTo types.str gatewayCoerce (types.submodule gatewayOpts)); 468 description = '' 469 The default gateway. It can be left empty if it is auto-detected through DHCP. 470 It can be specified as a string or an option set along with a network interface. 471 ''; 472 }; 473 474 networking.defaultGateway6 = mkOption { 475 default = null; 476 example = { 477 address = "2001:4d0:1e04:895::1"; 478 interface = "enp3s0"; 479 }; 480 type = types.nullOr (types.coercedTo types.str gatewayCoerce (types.submodule gatewayOpts)); 481 description = '' 482 The default ipv6 gateway. It can be left empty if it is auto-detected through DHCP. 483 It can be specified as a string or an option set along with a network interface. 484 ''; 485 }; 486 487 networking.defaultGatewayWindowSize = mkOption { 488 default = null; 489 example = 524288; 490 type = types.nullOr types.int; 491 description = '' 492 The window size of the default gateway. It limits maximal data bursts that TCP peers 493 are allowed to send to us. 494 ''; 495 }; 496 497 networking.nameservers = mkOption { 498 type = types.listOf types.str; 499 default = []; 500 example = ["130.161.158.4" "130.161.33.17"]; 501 description = '' 502 The list of nameservers. It can be left empty if it is auto-detected through DHCP. 503 ''; 504 }; 505 506 networking.search = mkOption { 507 default = []; 508 example = [ "example.com" "home.arpa" ]; 509 type = types.listOf types.str; 510 description = '' 511 The list of search paths used when resolving domain names. 512 ''; 513 }; 514 515 networking.domain = mkOption { 516 default = null; 517 example = "home.arpa"; 518 type = types.nullOr types.str; 519 description = '' 520 The domain. It can be left empty if it is auto-detected through DHCP. 521 ''; 522 }; 523 524 networking.useHostResolvConf = mkOption { 525 type = types.bool; 526 default = false; 527 description = '' 528 In containers, whether to use the 529 <filename>resolv.conf</filename> supplied by the host. 530 ''; 531 }; 532 533 networking.localCommands = mkOption { 534 type = types.lines; 535 default = ""; 536 example = "text=anything; echo You can put $text here."; 537 description = '' 538 Shell commands to be executed at the end of the 539 <literal>network-setup</literal> systemd service. Note that if 540 you are using DHCP to obtain the network configuration, 541 interfaces may not be fully configured yet. 542 ''; 543 }; 544 545 networking.interfaces = mkOption { 546 default = {}; 547 example = 548 { eth0.ipv4.addresses = [ { 549 address = "131.211.84.78"; 550 prefixLength = 25; 551 } ]; 552 }; 553 description = '' 554 The configuration for each network interface. If 555 <option>networking.useDHCP</option> is true, then every 556 interface not listed here will be configured using DHCP. 557 ''; 558 type = with types; attrsOf (submodule interfaceOpts); 559 }; 560 561 networking.vswitches = mkOption { 562 default = { }; 563 example = 564 { vs0.interfaces = { eth0 = { }; lo1 = { type="internal"; }; }; 565 vs1.interfaces = [ { name = "eth2"; } { name = "lo2"; type="internal"; } ]; 566 }; 567 description = 568 '' 569 This option allows you to define Open vSwitches that connect 570 physical networks together. The value of this option is an 571 attribute set. Each attribute specifies a vswitch, with the 572 attribute name specifying the name of the vswitch's network 573 interface. 574 ''; 575 576 type = with types; attrsOf (submodule { 577 578 options = { 579 580 interfaces = mkOption { 581 example = [ "eth0" "eth1" ]; 582 description = "The physical network interfaces connected by the vSwitch."; 583 type = with types; attrsOf (submodule vswitchInterfaceOpts); 584 }; 585 586 controllers = mkOption { 587 type = types.listOf types.str; 588 default = []; 589 example = [ "ptcp:6653:[::1]" ]; 590 description = '' 591 Specify the controller targets. For the allowed options see <literal>man 8 ovs-vsctl</literal>. 592 ''; 593 }; 594 595 openFlowRules = mkOption { 596 type = types.lines; 597 default = ""; 598 example = '' 599 actions=normal 600 ''; 601 description = '' 602 OpenFlow rules to insert into the Open vSwitch. All <literal>openFlowRules</literal> are 603 loaded with <literal>ovs-ofctl</literal> within one atomic operation. 604 ''; 605 }; 606 607 # TODO: custom "openflow version" type, with list from existing openflow protocols 608 supportedOpenFlowVersions = mkOption { 609 type = types.listOf types.str; 610 example = [ "OpenFlow10" "OpenFlow13" "OpenFlow14" ]; 611 default = [ "OpenFlow13" ]; 612 description = '' 613 Supported versions to enable on this switch. 614 ''; 615 }; 616 617 # TODO: use same type as elements from supportedOpenFlowVersions 618 openFlowVersion = mkOption { 619 type = types.str; 620 default = "OpenFlow13"; 621 description = '' 622 Version of OpenFlow protocol to use when communicating with the switch internally (e.g. with <literal>openFlowRules</literal>). 623 ''; 624 }; 625 626 extraOvsctlCmds = mkOption { 627 type = types.lines; 628 default = ""; 629 example = '' 630 set-fail-mode <switch_name> secure 631 set Bridge <switch_name> stp_enable=true 632 ''; 633 description = '' 634 Commands to manipulate the Open vSwitch database. Every line executed with <literal>ovs-vsctl</literal>. 635 All commands are bundled together with the operations for adding the interfaces 636 into one atomic operation. 637 ''; 638 }; 639 640 }; 641 642 }); 643 644 }; 645 646 networking.bridges = mkOption { 647 default = { }; 648 example = 649 { br0.interfaces = [ "eth0" "eth1" ]; 650 br1.interfaces = [ "eth2" "wlan0" ]; 651 }; 652 description = 653 '' 654 This option allows you to define Ethernet bridge devices 655 that connect physical networks together. The value of this 656 option is an attribute set. Each attribute specifies a 657 bridge, with the attribute name specifying the name of the 658 bridge's network interface. 659 ''; 660 661 type = with types; attrsOf (submodule { 662 663 options = { 664 665 interfaces = mkOption { 666 example = [ "eth0" "eth1" ]; 667 type = types.listOf types.str; 668 description = 669 "The physical network interfaces connected by the bridge."; 670 }; 671 672 rstp = mkOption { 673 default = false; 674 type = types.bool; 675 description = "Whether the bridge interface should enable rstp."; 676 }; 677 678 }; 679 680 }); 681 682 }; 683 684 networking.bonds = 685 let 686 driverOptionsExample = '' 687 { 688 miimon = "100"; 689 mode = "active-backup"; 690 } 691 ''; 692 in mkOption { 693 default = { }; 694 example = literalExample '' 695 { 696 bond0 = { 697 interfaces = [ "eth0" "wlan0" ]; 698 driverOptions = ${driverOptionsExample}; 699 }; 700 anotherBond.interfaces = [ "enp4s0f0" "enp4s0f1" "enp5s0f0" "enp5s0f1" ]; 701 } 702 ''; 703 description = '' 704 This option allows you to define bond devices that aggregate multiple, 705 underlying networking interfaces together. The value of this option is 706 an attribute set. Each attribute specifies a bond, with the attribute 707 name specifying the name of the bond's network interface 708 ''; 709 710 type = with types; attrsOf (submodule { 711 712 options = { 713 714 interfaces = mkOption { 715 example = [ "enp4s0f0" "enp4s0f1" "wlan0" ]; 716 type = types.listOf types.str; 717 description = "The interfaces to bond together"; 718 }; 719 720 driverOptions = mkOption { 721 type = types.attrsOf types.str; 722 default = {}; 723 example = literalExample driverOptionsExample; 724 description = '' 725 Options for the bonding driver. 726 Documentation can be found in 727 <link xlink:href="https://www.kernel.org/doc/Documentation/networking/bonding.txt" /> 728 ''; 729 730 }; 731 732 lacp_rate = mkOption { 733 default = null; 734 example = "fast"; 735 type = types.nullOr types.str; 736 description = '' 737 DEPRECATED, use `driverOptions`. 738 Option specifying the rate in which we'll ask our link partner 739 to transmit LACPDU packets in 802.3ad mode. 740 ''; 741 }; 742 743 miimon = mkOption { 744 default = null; 745 example = 100; 746 type = types.nullOr types.int; 747 description = '' 748 DEPRECATED, use `driverOptions`. 749 Miimon is the number of millisecond in between each round of polling 750 by the device driver for failed links. By default polling is not 751 enabled and the driver is trusted to properly detect and handle 752 failure scenarios. 753 ''; 754 }; 755 756 mode = mkOption { 757 default = null; 758 example = "active-backup"; 759 type = types.nullOr types.str; 760 description = '' 761 DEPRECATED, use `driverOptions`. 762 The mode which the bond will be running. The default mode for 763 the bonding driver is balance-rr, optimizing for throughput. 764 More information about valid modes can be found at 765 https://www.kernel.org/doc/Documentation/networking/bonding.txt 766 ''; 767 }; 768 769 xmit_hash_policy = mkOption { 770 default = null; 771 example = "layer2+3"; 772 type = types.nullOr types.str; 773 description = '' 774 DEPRECATED, use `driverOptions`. 775 Selects the transmit hash policy to use for slave selection in 776 balance-xor, 802.3ad, and tlb modes. 777 ''; 778 }; 779 780 }; 781 782 }); 783 }; 784 785 networking.macvlans = mkOption { 786 default = { }; 787 example = literalExample '' 788 { 789 wan = { 790 interface = "enp2s0"; 791 mode = "vepa"; 792 }; 793 } 794 ''; 795 description = '' 796 This option allows you to define macvlan interfaces which should 797 be automatically created. 798 ''; 799 type = with types; attrsOf (submodule { 800 options = { 801 802 interface = mkOption { 803 example = "enp4s0"; 804 type = types.str; 805 description = "The interface the macvlan will transmit packets through."; 806 }; 807 808 mode = mkOption { 809 default = null; 810 type = types.nullOr types.str; 811 example = "vepa"; 812 description = "The mode of the macvlan device."; 813 }; 814 815 }; 816 817 }); 818 }; 819 820 networking.sits = mkOption { 821 default = { }; 822 example = literalExample '' 823 { 824 hurricane = { 825 remote = "10.0.0.1"; 826 local = "10.0.0.22"; 827 ttl = 255; 828 }; 829 msipv6 = { 830 remote = "192.168.0.1"; 831 dev = "enp3s0"; 832 ttl = 127; 833 }; 834 } 835 ''; 836 description = '' 837 This option allows you to define 6-to-4 interfaces which should be automatically created. 838 ''; 839 type = with types; attrsOf (submodule { 840 options = { 841 842 remote = mkOption { 843 type = types.nullOr types.str; 844 default = null; 845 example = "10.0.0.1"; 846 description = '' 847 The address of the remote endpoint to forward traffic over. 848 ''; 849 }; 850 851 local = mkOption { 852 type = types.nullOr types.str; 853 default = null; 854 example = "10.0.0.22"; 855 description = '' 856 The address of the local endpoint which the remote 857 side should send packets to. 858 ''; 859 }; 860 861 ttl = mkOption { 862 type = types.nullOr types.int; 863 default = null; 864 example = 255; 865 description = '' 866 The time-to-live of the connection to the remote tunnel endpoint. 867 ''; 868 }; 869 870 dev = mkOption { 871 type = types.nullOr types.str; 872 default = null; 873 example = "enp4s0f0"; 874 description = '' 875 The underlying network device on which the tunnel resides. 876 ''; 877 }; 878 879 }; 880 881 }); 882 }; 883 884 networking.vlans = mkOption { 885 default = { }; 886 example = literalExample '' 887 { 888 vlan0 = { 889 id = 3; 890 interface = "enp3s0"; 891 }; 892 vlan1 = { 893 id = 1; 894 interface = "wlan0"; 895 }; 896 } 897 ''; 898 description = 899 '' 900 This option allows you to define vlan devices that tag packets 901 on top of a physical interface. The value of this option is an 902 attribute set. Each attribute specifies a vlan, with the name 903 specifying the name of the vlan interface. 904 ''; 905 906 type = with types; attrsOf (submodule { 907 908 options = { 909 910 id = mkOption { 911 example = 1; 912 type = types.int; 913 description = "The vlan identifier"; 914 }; 915 916 interface = mkOption { 917 example = "enp4s0"; 918 type = types.str; 919 description = "The interface the vlan will transmit packets through."; 920 }; 921 922 }; 923 924 }); 925 926 }; 927 928 networking.wlanInterfaces = mkOption { 929 default = { }; 930 example = literalExample '' 931 { 932 wlan-station0 = { 933 device = "wlp6s0"; 934 }; 935 wlan-adhoc0 = { 936 type = "ibss"; 937 device = "wlp6s0"; 938 mac = "02:00:00:00:00:01"; 939 }; 940 wlan-p2p0 = { 941 device = "wlp6s0"; 942 mac = "02:00:00:00:00:02"; 943 }; 944 wlan-ap0 = { 945 device = "wlp6s0"; 946 mac = "02:00:00:00:00:03"; 947 }; 948 } 949 ''; 950 description = 951 '' 952 Creating multiple WLAN interfaces on top of one physical WLAN device (NIC). 953 954 The name of the WLAN interface corresponds to the name of the attribute. 955 A NIC is referenced by the persistent device name of the WLAN interface that 956 <literal>udev</literal> assigns to a NIC by default. 957 If a NIC supports multiple WLAN interfaces, then the one NIC can be used as 958 <literal>device</literal> for multiple WLAN interfaces. 959 If a NIC is used for creating WLAN interfaces, then the default WLAN interface 960 with a persistent device name form <literal>udev</literal> is not created. 961 A WLAN interface with the persistent name assigned from <literal>udev</literal> 962 would have to be created explicitly. 963 ''; 964 965 type = with types; attrsOf (submodule { 966 967 options = { 968 969 device = mkOption { 970 type = types.str; 971 example = "wlp6s0"; 972 description = "The name of the underlying hardware WLAN device as assigned by <literal>udev</literal>."; 973 }; 974 975 type = mkOption { 976 type = types.enum [ "managed" "ibss" "monitor" "mesh" "wds" ]; 977 default = "managed"; 978 example = "ibss"; 979 description = '' 980 The type of the WLAN interface. 981 The type has to be supported by the underlying hardware of the device. 982 ''; 983 }; 984 985 meshID = mkOption { 986 type = types.nullOr types.str; 987 default = null; 988 description = "MeshID of interface with type <literal>mesh</literal>."; 989 }; 990 991 flags = mkOption { 992 type = with types; nullOr (enum [ "none" "fcsfail" "control" "otherbss" "cook" "active" ]); 993 default = null; 994 example = "control"; 995 description = '' 996 Flags for interface of type <literal>monitor</literal>. 997 ''; 998 }; 999 1000 fourAddr = mkOption { 1001 type = types.nullOr types.bool; 1002 default = null; 1003 description = "Whether to enable <literal>4-address mode</literal> with type <literal>managed</literal>."; 1004 }; 1005 1006 mac = mkOption { 1007 type = types.nullOr types.str; 1008 default = null; 1009 example = "02:00:00:00:00:01"; 1010 description = '' 1011 MAC address to use for the device. If <literal>null</literal>, then the MAC of the 1012 underlying hardware WLAN device is used. 1013 1014 INFO: Locally administered MAC addresses are of the form: 1015 <itemizedlist> 1016 <listitem><para>x2:xx:xx:xx:xx:xx</para></listitem> 1017 <listitem><para>x6:xx:xx:xx:xx:xx</para></listitem> 1018 <listitem><para>xA:xx:xx:xx:xx:xx</para></listitem> 1019 <listitem><para>xE:xx:xx:xx:xx:xx</para></listitem> 1020 </itemizedlist> 1021 ''; 1022 }; 1023 1024 }; 1025 1026 }); 1027 1028 }; 1029 1030 networking.useDHCP = mkOption { 1031 type = types.bool; 1032 default = true; 1033 description = '' 1034 Whether to use DHCP to obtain an IP address and other 1035 configuration for all network interfaces that are not manually 1036 configured. 1037 1038 Using this option is highly discouraged and also incompatible with 1039 <option>networking.useNetworkd</option>. Please use 1040 <option>networking.interfaces.&lt;name&gt;.useDHCP</option> instead 1041 and set this to false. 1042 ''; 1043 }; 1044 1045 networking.useNetworkd = mkOption { 1046 default = false; 1047 type = types.bool; 1048 description = '' 1049 Whether we should use networkd as the network configuration backend or 1050 the legacy script based system. Note that this option is experimental, 1051 enable at your own risk. 1052 ''; 1053 }; 1054 1055 networking.tempAddresses = mkOption { 1056 default = if cfg.enableIPv6 then "default" else "disabled"; 1057 type = types.enum (lib.attrNames tempaddrValues); 1058 description = '' 1059 Whether to enable IPv6 Privacy Extensions for interfaces not 1060 configured explicitly in 1061 <xref linkend="opt-networking.interfaces._name_.tempAddress" />. 1062 1063 This sets the ipv6.conf.*.use_tempaddr sysctl for all 1064 interfaces. Possible values are: 1065 1066 ${tempaddrDoc} 1067 ''; 1068 }; 1069 1070 }; 1071 1072 1073 ###### implementation 1074 1075 config = { 1076 1077 warnings = concatMap (i: i.warnings) interfaces; 1078 1079 assertions = 1080 (forEach interfaces (i: { 1081 # With the linux kernel, interface name length is limited by IFNAMSIZ 1082 # to 16 bytes, including the trailing null byte. 1083 # See include/linux/if.h in the kernel sources 1084 assertion = stringLength i.name < 16; 1085 message = '' 1086 The name of networking.interfaces."${i.name}" is too long, it needs to be less than 16 characters. 1087 ''; 1088 })) ++ (forEach slaveIfs (i: { 1089 assertion = i.ipv4.addresses == [ ] && i.ipv6.addresses == [ ]; 1090 message = '' 1091 The networking.interfaces."${i.name}" must not have any defined ips when it is a slave. 1092 ''; 1093 })) ++ (forEach interfaces (i: { 1094 assertion = i.tempAddress != "disabled" -> cfg.enableIPv6; 1095 message = '' 1096 Temporary addresses are only needed when IPv6 is enabled. 1097 ''; 1098 })) ++ (forEach interfaces (i: { 1099 assertion = (i.virtual && i.virtualType == "tun") -> i.macAddress == null; 1100 message = '' 1101 Setting a MAC Address for tun device ${i.name} isn't supported. 1102 ''; 1103 })) ++ [ 1104 { 1105 assertion = cfg.hostId == null || (stringLength cfg.hostId == 8 && isHexString cfg.hostId); 1106 message = "Invalid value given to the networking.hostId option."; 1107 } 1108 ]; 1109 1110 boot.kernelModules = [ ] 1111 ++ optional hasVirtuals "tun" 1112 ++ optional hasSits "sit" 1113 ++ optional hasBonds "bonding"; 1114 1115 boot.extraModprobeConfig = 1116 # This setting is intentional as it prevents default bond devices 1117 # from being created. 1118 optionalString hasBonds "options bonding max_bonds=0"; 1119 1120 boot.kernel.sysctl = { 1121 "net.ipv4.conf.all.forwarding" = mkDefault (any (i: i.proxyARP) interfaces); 1122 "net.ipv6.conf.all.disable_ipv6" = mkDefault (!cfg.enableIPv6); 1123 "net.ipv6.conf.default.disable_ipv6" = mkDefault (!cfg.enableIPv6); 1124 } // listToAttrs (flip concatMap (filter (i: i.proxyARP) interfaces) 1125 (i: [(nameValuePair "net.ipv4.conf.${replaceChars ["."] ["/"] i.name}.proxy_arp" true)])) 1126 // listToAttrs (forEach interfaces 1127 (i: let 1128 opt = i.tempAddress; 1129 val = tempaddrValues.${opt}.sysctl; 1130 in nameValuePair "net.ipv6.conf.${replaceChars ["."] ["/"] i.name}.use_tempaddr" val)); 1131 1132 # Capabilities won't work unless we have at-least a 4.3 Linux 1133 # kernel because we need the ambient capability 1134 security.wrappers = if (versionAtLeast (getVersion config.boot.kernelPackages.kernel) "4.3") then { 1135 ping = { 1136 source = "${pkgs.iputils.out}/bin/ping"; 1137 capabilities = "cap_net_raw+p"; 1138 }; 1139 } else { 1140 ping.source = "${pkgs.iputils.out}/bin/ping"; 1141 }; 1142 security.apparmor.policies."bin.ping".profile = lib.mkIf config.security.apparmor.policies."bin.ping".enable (lib.mkAfter '' 1143 /run/wrappers/bin/ping { 1144 include <abstractions/base> 1145 include <nixos/security.wrappers> 1146 rpx /run/wrappers/wrappers.*/ping, 1147 } 1148 /run/wrappers/wrappers.*/ping { 1149 include <abstractions/base> 1150 include <nixos/security.wrappers> 1151 r /run/wrappers/wrappers.*/ping.real, 1152 mrpx ${config.security.wrappers.ping.source}, 1153 capability net_raw, 1154 capability setpcap, 1155 } 1156 ''); 1157 1158 # Set the host and domain names in the activation script. Don't 1159 # clear it if it's not configured in the NixOS configuration, 1160 # since it may have been set by dhcpcd in the meantime. 1161 system.activationScripts.hostname = 1162 optionalString (cfg.hostName != "") '' 1163 hostname "${cfg.hostName}" 1164 ''; 1165 system.activationScripts.domain = 1166 optionalString (cfg.domain != null) '' 1167 domainname "${cfg.domain}" 1168 ''; 1169 1170 environment.etc.hostid = mkIf (cfg.hostId != null) 1171 { source = pkgs.runCommand "gen-hostid" { preferLocalBuild = true; } '' 1172 hi="${cfg.hostId}" 1173 ${if pkgs.stdenv.isBigEndian then '' 1174 echo -ne "\x''${hi:0:2}\x''${hi:2:2}\x''${hi:4:2}\x''${hi:6:2}" > $out 1175 '' else '' 1176 echo -ne "\x''${hi:6:2}\x''${hi:4:2}\x''${hi:2:2}\x''${hi:0:2}" > $out 1177 ''} 1178 ''; 1179 }; 1180 1181 # static hostname configuration needed for hostnamectl and the 1182 # org.freedesktop.hostname1 dbus service (both provided by systemd) 1183 environment.etc.hostname = mkIf (cfg.hostName != "") 1184 { 1185 text = cfg.hostName + "\n"; 1186 }; 1187 1188 environment.systemPackages = 1189 [ pkgs.host 1190 pkgs.iproute2 1191 pkgs.iputils 1192 pkgs.nettools 1193 ] 1194 ++ optionals config.networking.wireless.enable [ 1195 pkgs.wirelesstools # FIXME: obsolete? 1196 pkgs.iw 1197 ] 1198 ++ bridgeStp; 1199 1200 # The network-interfaces target is kept for backwards compatibility. 1201 # New modules must NOT use it. 1202 systemd.targets.network-interfaces = 1203 { description = "All Network Interfaces (deprecated)"; 1204 wantedBy = [ "network.target" ]; 1205 before = [ "network.target" ]; 1206 after = [ "network-pre.target" ]; 1207 unitConfig.X-StopOnReconfiguration = true; 1208 }; 1209 1210 systemd.services = { 1211 network-local-commands = { 1212 description = "Extra networking commands."; 1213 before = [ "network.target" ]; 1214 wantedBy = [ "network.target" ]; 1215 after = [ "network-pre.target" ]; 1216 unitConfig.ConditionCapability = "CAP_NET_ADMIN"; 1217 path = [ pkgs.iproute2 ]; 1218 serviceConfig.Type = "oneshot"; 1219 serviceConfig.RemainAfterExit = true; 1220 script = '' 1221 # Run any user-specified commands. 1222 ${cfg.localCommands} 1223 ''; 1224 }; 1225 }; 1226 services.mstpd = mkIf needsMstpd { enable = true; }; 1227 1228 virtualisation.vswitch = mkIf (cfg.vswitches != { }) { enable = true; }; 1229 1230 services.udev.packages = [ 1231 (pkgs.writeTextFile rec { 1232 name = "ipv6-privacy-extensions.rules"; 1233 destination = "/etc/udev/rules.d/98-${name}"; 1234 text = let 1235 sysctl-value = tempaddrValues.${cfg.tempAddresses}.sysctl; 1236 in '' 1237 # enable and prefer IPv6 privacy addresses by default 1238 ACTION=="add", SUBSYSTEM=="net", RUN+="${pkgs.bash}/bin/sh -c 'echo ${sysctl-value} > /proc/sys/net/ipv6/conf/%k/use_tempaddr'" 1239 ''; 1240 }) 1241 (pkgs.writeTextFile rec { 1242 name = "ipv6-privacy-extensions.rules"; 1243 destination = "/etc/udev/rules.d/99-${name}"; 1244 text = concatMapStrings (i: 1245 let 1246 opt = i.tempAddress; 1247 val = tempaddrValues.${opt}.sysctl; 1248 msg = tempaddrValues.${opt}.description; 1249 in 1250 '' 1251 # override to ${msg} for ${i.name} 1252 ACTION=="add", SUBSYSTEM=="net", RUN+="${pkgs.procps}/bin/sysctl net.ipv6.conf.${replaceChars ["."] ["/"] i.name}.use_tempaddr=${val}" 1253 '') (filter (i: i.tempAddress != cfg.tempAddresses) interfaces); 1254 }) 1255 ] ++ lib.optional (cfg.wlanInterfaces != {}) 1256 (pkgs.writeTextFile { 1257 name = "99-zzz-40-wlanInterfaces.rules"; 1258 destination = "/etc/udev/rules.d/99-zzz-40-wlanInterfaces.rules"; 1259 text = 1260 let 1261 # Collect all interfaces that are defined for a device 1262 # as device:interface key:value pairs. 1263 wlanDeviceInterfaces = 1264 let 1265 allDevices = unique (mapAttrsToList (_: v: v.device) cfg.wlanInterfaces); 1266 interfacesOfDevice = d: filterAttrs (_: v: v.device == d) cfg.wlanInterfaces; 1267 in 1268 genAttrs allDevices (d: interfacesOfDevice d); 1269 1270 # Convert device:interface key:value pairs into a list, and if it exists, 1271 # place the interface which is named after the device at the beginning. 1272 wlanListDeviceFirst = device: interfaces: 1273 if hasAttr device interfaces 1274 then mapAttrsToList (n: v: v//{_iName=n;}) (filterAttrs (n: _: n==device) interfaces) ++ mapAttrsToList (n: v: v//{_iName=n;}) (filterAttrs (n: _: n!=device) interfaces) 1275 else mapAttrsToList (n: v: v // {_iName = n;}) interfaces; 1276 1277 # Udev script to execute for the default WLAN interface with the persistend udev name. 1278 # The script creates the required, new WLAN interfaces interfaces and configures the 1279 # existing, default interface. 1280 curInterfaceScript = device: current: new: pkgs.writeScript "udev-run-script-wlan-interfaces-${device}.sh" '' 1281 #!${pkgs.runtimeShell} 1282 # Change the wireless phy device to a predictable name. 1283 ${pkgs.iw}/bin/iw phy `${pkgs.coreutils}/bin/cat /sys/class/net/$INTERFACE/phy80211/name` set name ${device} 1284 1285 # Add new WLAN interfaces 1286 ${flip concatMapStrings new (i: '' 1287 ${pkgs.iw}/bin/iw phy ${device} interface add ${i._iName} type managed 1288 '')} 1289 1290 # Configure the current interface 1291 ${pkgs.iw}/bin/iw dev ${device} set type ${current.type} 1292 ${optionalString (current.type == "mesh" && current.meshID!=null) "${pkgs.iw}/bin/iw dev ${device} set meshid ${current.meshID}"} 1293 ${optionalString (current.type == "monitor" && current.flags!=null) "${pkgs.iw}/bin/iw dev ${device} set monitor ${current.flags}"} 1294 ${optionalString (current.type == "managed" && current.fourAddr!=null) "${pkgs.iw}/bin/iw dev ${device} set 4addr ${if current.fourAddr then "on" else "off"}"} 1295 ${optionalString (current.mac != null) "${pkgs.iproute2}/bin/ip link set dev ${device} address ${current.mac}"} 1296 ''; 1297 1298 # Udev script to execute for a new WLAN interface. The script configures the new WLAN interface. 1299 newInterfaceScript = device: new: pkgs.writeScript "udev-run-script-wlan-interfaces-${new._iName}.sh" '' 1300 #!${pkgs.runtimeShell} 1301 # Configure the new interface 1302 ${pkgs.iw}/bin/iw dev ${new._iName} set type ${new.type} 1303 ${optionalString (new.type == "mesh" && new.meshID!=null) "${pkgs.iw}/bin/iw dev ${device} set meshid ${new.meshID}"} 1304 ${optionalString (new.type == "monitor" && new.flags!=null) "${pkgs.iw}/bin/iw dev ${device} set monitor ${new.flags}"} 1305 ${optionalString (new.type == "managed" && new.fourAddr!=null) "${pkgs.iw}/bin/iw dev ${device} set 4addr ${if new.fourAddr then "on" else "off"}"} 1306 ${optionalString (new.mac != null) "${pkgs.iproute2}/bin/ip link set dev ${device} address ${new.mac}"} 1307 ''; 1308 1309 # Udev attributes for systemd to name the device and to create a .device target. 1310 systemdAttrs = n: ''NAME:="${n}", ENV{INTERFACE}="${n}", ENV{SYSTEMD_ALIAS}="/sys/subsystem/net/devices/${n}", TAG+="systemd"''; 1311 in 1312 flip (concatMapStringsSep "\n") (attrNames wlanDeviceInterfaces) (device: 1313 let 1314 interfaces = wlanListDeviceFirst device wlanDeviceInterfaces.${device}; 1315 curInterface = elemAt interfaces 0; 1316 newInterfaces = drop 1 interfaces; 1317 in '' 1318 # It is important to have that rule first as overwriting the NAME attribute also prevents the 1319 # next rules from matching. 1320 ${flip (concatMapStringsSep "\n") (wlanListDeviceFirst device wlanDeviceInterfaces.${device}) (interface: 1321 ''ACTION=="add", SUBSYSTEM=="net", ENV{DEVTYPE}=="wlan", ENV{INTERFACE}=="${interface._iName}", ${systemdAttrs interface._iName}, RUN+="${newInterfaceScript device interface}"'')} 1322 1323 # Add the required, new WLAN interfaces to the default WLAN interface with the 1324 # persistent, default name as assigned by udev. 1325 ACTION=="add", SUBSYSTEM=="net", ENV{DEVTYPE}=="wlan", NAME=="${device}", ${systemdAttrs curInterface._iName}, RUN+="${curInterfaceScript device curInterface newInterfaces}" 1326 # Generate the same systemd events for both 'add' and 'move' udev events. 1327 ACTION=="move", SUBSYSTEM=="net", ENV{DEVTYPE}=="wlan", NAME=="${device}", ${systemdAttrs curInterface._iName} 1328 ''); 1329 }); 1330 }; 1331 1332}