1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7
8let
9 inherit (lib)
10 mkEnableOption
11 mkIf
12 mkOption
13 optionalString
14 types
15 ;
16
17 cfg = config.services.bird;
18 caps = [
19 "CAP_NET_ADMIN"
20 "CAP_NET_BIND_SERVICE"
21 "CAP_NET_RAW"
22 ];
23in
24{
25 ###### interface
26 options = {
27 services.bird = {
28 enable = mkEnableOption "BIRD Internet Routing Daemon";
29 package = lib.mkPackageOption pkgs "bird3" { };
30 config = mkOption {
31 type = types.lines;
32 description = ''
33 BIRD Internet Routing Daemon configuration file.
34 <http://bird.network.cz/>
35 '';
36 };
37 autoReload = mkOption {
38 type = types.bool;
39 default = true;
40 description = ''
41 Whether bird should be automatically reloaded when the configuration changes.
42 '';
43 };
44 checkConfig = mkOption {
45 type = types.bool;
46 default = true;
47 description = ''
48 Whether the config should be checked at build time.
49 When the config can't be checked during build time, for example when it includes
50 other files, either disable this option or use `preCheckConfig` to create
51 the included files before checking.
52 '';
53 };
54 preCheckConfig = mkOption {
55 type = types.lines;
56 default = "";
57 example = ''
58 echo "cost 100;" > include.conf
59 '';
60 description = ''
61 Commands to execute before the config file check. The file to be checked will be
62 available as `bird.conf` in the current directory.
63
64 Files created with this option will not be available at service runtime, only during
65 build time checking.
66 '';
67 };
68 };
69 };
70
71 imports = [
72 (lib.mkRemovedOptionModule [ "services" "bird2" ]
73 "Use services.bird instead. bird3 is the new default bird package. You can choose to remain with bird2 by setting the service.bird.package option."
74 )
75 (lib.mkRemovedOptionModule [ "services" "bird6" ] "Use services.bird instead")
76 ];
77
78 ###### implementation
79 config = mkIf cfg.enable {
80 environment.systemPackages = [ cfg.package ];
81
82 environment.etc."bird/bird.conf".source = pkgs.writeTextFile {
83 name = "bird";
84 text = cfg.config;
85 derivationArgs.nativeBuildInputs = lib.optional cfg.checkConfig cfg.package;
86 checkPhase = optionalString cfg.checkConfig ''
87 ln -s $out bird.conf
88 ${cfg.preCheckConfig}
89 bird -d -p -c bird.conf
90 '';
91 };
92
93 systemd.services.bird = {
94 description = "BIRD Internet Routing Daemon";
95 wantedBy = [ "multi-user.target" ];
96 reloadTriggers = lib.optional cfg.autoReload config.environment.etc."bird/bird.conf".source;
97 serviceConfig = {
98 Type = "forking";
99 Restart = "on-failure";
100 User = "bird";
101 Group = "bird";
102 ExecStart = "${lib.getExe' cfg.package "bird"} -c /etc/bird/bird.conf";
103 ExecReload = "${lib.getExe' cfg.package "birdc"} configure";
104 ExecStop = "${lib.getExe' cfg.package "birdc"} down";
105 RuntimeDirectory = "bird";
106 CapabilityBoundingSet = caps;
107 AmbientCapabilities = caps;
108 ProtectSystem = "full";
109 ProtectHome = "yes";
110 ProtectKernelTunables = true;
111 ProtectControlGroups = true;
112 PrivateTmp = true;
113 PrivateDevices = true;
114 SystemCallFilter = "~@cpu-emulation @debug @keyring @module @mount @obsolete @raw-io";
115 MemoryDenyWriteExecute = "yes";
116 };
117 };
118 users = {
119 users.bird = {
120 description = "BIRD Internet Routing Daemon user";
121 group = "bird";
122 isSystemUser = true;
123 };
124 groups.bird = { };
125 };
126 };
127
128 meta = {
129 maintainers = with lib.maintainers; [ herbetom ];
130 };
131}