mob next [ci-skip] [ci skip] [skip ci]

lastFile:vars/per-machine/rigel/yggdrasil/yggdrasil-secret/secret
This commit is contained in:
2025-10-31 13:53:49 +07:00
parent 4259d8014e
commit 69dad99729
36 changed files with 944 additions and 24 deletions

View File

@@ -12,56 +12,159 @@
...
}:
{
networking.firewall.allowedUDPPorts = [ 5060 ];
services.asterisk = {
enable = lib.mkDefault true;
confFiles = {
"logger.conf" = ''
[general]
dateformat = %F %T.%3q ; ISO 8601 date format with milliseconds
use_callids = yes
appendhostname = no
queue_log = yes
queue_log_to_file = no
queue_log_name = queue_log
queue_log_realtime_use_gmt = no
rotatestrategy = rotate
exec_after_rotate=gzip -9 $\{filename\}.2
[logfiles]
console => notice,warning,error
security => security
messages => notice,warning,error
full => notice,warning,error,verbose,dtmf,fax
syslog.local0 => notice,warning,error
'';
# Dial plan config
"extensions.conf" = ''
exten => 1001,1,Dial(PJSIP/user1,20)
exten => 1002,1,Dial(PJSIP/user2,20)
[from-internal]
exten => 100,1,Answer()
same => n,Wait(1)
same => n,Playback(hello-world)
same => n,Hangup()
exten => 6001,1,Dial(PJSIP/6001,20)
exten => 6002,1,Dial(PJSIP/6002,20)
exten => 8001,1,Dial(PJSIP/8001@kurogeek,20)
'';
"pjsip.conf" = ''
[transport-udp]
type=transport
protocol=udp
bind=0.0.0.0,[::]
bind=0.0.0.0
[transport-udp6]
type=transport
protocol=udp
bind=::
[endpoint_internal](!)
[kurogeek]
type=endpoint
context=from-kurogeek
disallow=all
allow=ulaw
allow=alaw
allow=g722
allow=gsm
aors=kurogeek
direct_media=no
[kurogeek]
type=aor
contact=sip:[fd79:fada:fbe9:8c5d:d899:932b:d36d:b8cc]
[kurogeek]
type=identify
endpoint=kurogeek
match=[fd79:fada:fbe9:8c5d:d899:932b:d36d:b8cc]
[6001]
type=endpoint
context=from-internal
disallow=all
allow=ulaw
allow=alaw
allow=g722
allow=gsm
auth=6001
aors=6001
direct_media=no
[auth_userpass](!)
[6001]
type=auth
auth_type=userpass
password=unsecurepassword
username=6001
[aor_dynamic](!)
[6001]
type=aor
max_contacts=1
max_contacts=1
[user1](endpoint_internal)
auth=user1
aors=user1
[user1](auth_userpass)
password=user1
username=user1
[user1](aor_dynamic)
[6002]
type=endpoint
context=from-internal
disallow=all
allow=ulaw
allow=alaw
allow=g722
allow=gsm
auth=6002
aors=6002
direct_media=no
[user2](endpoint_internal)
auth=user2
aors=user2
[user2](auth_userpass)
password=user2
username=user2
[user2](aor_dynamic)
[6002]
type=auth
auth_type=userpass
password=unsecurepassword
username=6002
[6002]
type=aor
max_contacts=1
'';
# "pjsip.conf" = ''
# [transport-udp6]
# type=transport
# protocol=udp
# bind=::
#
# [transport-udp]
# type=transport
# protocol=udp
# bind=0.0.0.0
#
# [endpoint_internal](!)
# type=endpoint
# context=from-internal
# disallow=all
# allow=ulaw
# allow=alaw
# allow=g722
# allow=gsm
#
# [auth_userpass](!)
# type=auth
# auth_type=userpass
#
# [aor_dynamic](!)
# type=aor
# max_contacts=1
#
# [user1](endpoint_internal)
# auth=user1
# aors=user1
# [user1](auth_userpass)
# password=user1
# username=user1
# [user1](aor_dynamic)
#
# [user2](endpoint_internal)
# auth=user2
# aors=user2
# [user2](auth_userpass)
# password=user2
# username=user2
# [user2](aor_dynamic)
# '';
};
};
};

View File

@@ -0,0 +1,306 @@
{ clanLib, ... }:
{
_class = "clan.service";
manifest.name = "phonebox";
manifest.description = "";
manifest.categories = [ "System" ];
roles.default = {
interface =
{ lib, ... }:
{
options.ata-ethernet-iface = lib.mkOption {
type = lib.types.str;
description = "An Ethernet interface that connect to ATA box.";
};
};
perInstance =
{
roles,
settings,
...
}:
{
nixosModule =
{
lib,
config,
...
}:
let
user = "asterisk";
rtpPortFrom = 10000;
rtpPortTo = 20000;
ata-interface = settings.ata-ethernet-iface;
genServerSIPEndpoint =
{ hostname, address }:
''
[${hostname}](internal_endpoint)
aors=${hostname}
[${hostname}](ip_auth)
endpoint=${hostname}
match=[${address}]
[${hostname}](dynamiic_aor)
contact=sip:[${address}]
'';
genLocalSIPEndpoint =
{ localNumber }:
''
[${localNumber}](internal_endpoint)
aors=${localNumber}
auth=${localNumber}
[${localNumber}](userpass_auth)
username=${localNumber}
password=ENV(SIP_PASSWORD)
[${localNumber}](dynamiic_aor)
max_contacts=1
'';
genLocalExtenConf =
{ localNumber }:
''
exten => ${localNumber},1,Dial(PJSIP/${localNumber},20)
'';
genExtentConf =
{ prefixNumber, hostname }:
''
exten => _${prefixNumber}XXX,1,Dial(PJSIP/$${EXTEN:1}@${hostname},30)
'';
in
{
clan.core.vars.generators.phonebox = {
files = {
server-prefix-number.secret = false;
ata-local-number.secret = false;
ata-password = {
owner = user;
group = user;
secret = true;
};
};
prompts = {
server-prefix-number = {
persist = true;
type = "line";
description = "Server prefix number: the first number of [X000]";
};
ata-local-number = {
persist = true;
type = "line";
description = "Local suffix number: 3 last number of [0XXX]";
};
ata-password = {
persist = true;
type = "hidden";
description = "Password for SIP registration.";
};
};
script = ''
cat $prompts/server-prefix-number > $out/server-prefix-number
cat $prompts/ata-local-number > $out/ata-local-number
cat $prompts/ata-password > $out/ata-password
'';
};
systemd.services.asterisk.serviceConfig = {
LoadCredential = [
"sip_password_filepath:${config.clan.core.vars.generators.phonebox.files.ata-password.path}"
];
Environment = [
"SIP_PASSWORD=%d/sip_password_filepath"
];
};
networking.interfaces = {
${ata-interface} = {
useDHCP = false;
ipv4.addresses = [
{
address = "192.168.254.1";
prefixLength = 24;
}
];
};
};
services.dnsmasq = {
enable = true;
settings = {
bind-interfaces = true;
# enable-ra = true;
domain-needed = true;
domain = "localhost";
dhcp-range = [
"192.168.254.100,192.168.254.100,255.255.255.0,24h"
];
dhcp-option = [
"3,192.168.254.1"
];
interface = [ ata-interface ];
};
};
services.nginx = {
enable = true;
virtualHosts = {
"_" = {
locations."/" = {
proxyPass = "http://192.168.254.100";
};
};
};
};
networking.firewall.allowedUDPPortRanges = [
{
from = rtpPortFrom;
to = rtpPortTo;
}
];
networking.firewall.allowedUDPPorts = [
53
67
5060
];
networking.firewall.allowedTCPPorts = [
53
80
];
services.asterisk = {
enable = lib.mkDefault true;
confFiles =
let
machines = lib.attrNames roles.default.machines;
nodes = builtins.foldl' (
nodes: name:
nodes
++ [
{
hostname = name;
address = clanLib.vars.getPublicValue {
flake = config.clan.core.settings.directory;
machine = name;
generator = "yggdrasil";
file = "yggdrasil-ip";
default = null;
};
prefixNumber = clanLib.vars.getPublicValue {
flake = config.clan.core.settings.directory;
machine = name;
generator = "phonebox";
file = "server-prefix-number";
default = null;
};
localNumber = clanLib.vars.getPublicValue {
flake = config.clan.core.settings.directory;
machine = name;
generator = "phonebox";
file = "ata-local-number";
default = null;
};
}
]
) [ ] machines;
in
{
"logger.conf" = ''
[general]
dateformat = %F %T.%3q ; ISO 8601 date format with milliseconds
use_callids = yes
appendhostname = no
queue_log = yes
queue_log_to_file = no
queue_log_name = queue_log
queue_log_realtime_use_gmt = no
rotatestrategy = rotate
exec_after_rotate=gzip -9 $\{filename\}.2
[logfiles]
console => notice,warning,error
security => security
messages => notice,warning,error
full => notice,warning,error,verbose,dtmf,fax
syslog.local0 => notice,warning,error
'';
# Dial plan config
"extensions.conf" =
let
serverConf = builtins.foldl' (
config: node: config ++ (genExtentConf node.prefixNumber node.hostname)
) "" nodes;
in
''
[from-internal]
exten => 100,1,Answer()
same => n,Playback(hello-world)
same => n,Hangup()
''
+ (genLocalExtenConf config.clan.core.vars.generators.phonebox.files.ata-local-number.value)
+ serverConf;
"rtp.conf" = ''
[general]
rtpstart=${rtpPortFrom}
rtpend=${rtpPortTo}
'';
"pjsip.conf" =
let
serverConf = builtins.foldl' (
conf: node: conf ++ (genServerSIPEndpoint node.hostname node.address)
) "" nodes;
in
''
[transport-udp]
type=transport
protocol=udp
bind=0.0.0.0
[transport-udp6]
type=transport
protocol=udp
bind=::
[base_endpoint](!)
type=endpoint
disallow=all
allow=ulaw,alaw,g722,gsm
direct_media=no
[internal_endpoint](!,base_endpoint)
context=from-internal
[userpass_auth](!)
type=auth
auth_type=userpass
[ip_auth](!)
type=identify
endpoint=external
[dynamiic_aor](!)
type=aor
''
+ (genLocalSIPEndpoint config.clan.core.vars.generators.phonebox.files.ata-local-number)
+ serverConf;
};
};
};
};
};
}

View File

@@ -0,0 +1,18 @@
{ lib, ... }:
let
module = ./default.nix;
in
{
clan.modules = {
phonebox = module;
};
perSystem =
{ ... }:
{
clan.nixosTests.service-phonebox = {
imports = [ ./tests/vm/default.nix ];
clan.modules."@clan/phonebox" = module;
};
};
}

View File

@@ -0,0 +1,41 @@
{
pkgs,
...
}:
{
name = "service-phonebox";
clan = {
directory = ./.;
inventory = {
machines.server = { };
instances = {
phonebox-test = {
module.name = "@clan/phonebox";
module.input = "self";
roles.default.machines."server".settings = {
ata-ethernet-iface = "enp2s0";
};
};
};
};
};
nodes = {
server = {
services.asterisk = {
};
};
};
testScript = ''
start_all()
server.wait_for_unit("asterisk")
# Check that garage is running
server.succeed("systemctl status asterisk")
'';
}