2026-04-16 19:48:27 +02:00
|
|
|
#!KAMAILIO
|
|
|
|
|
#
|
|
|
|
|
# Dotty Phone — Kamailio SIP Proxy
|
|
|
|
|
# Reiner Signaling-Proxy, kein Media-Handling.
|
|
|
|
|
# Zwei Accounts: tobias (Linphone iOS) und dotty (Mac Mini Asterisk)
|
|
|
|
|
#
|
|
|
|
|
|
|
|
|
|
####### Global Parameters #######
|
|
|
|
|
|
|
|
|
|
debug=2
|
|
|
|
|
log_stderror=yes
|
|
|
|
|
fork=yes
|
|
|
|
|
children=2
|
|
|
|
|
auto_aliases=no
|
|
|
|
|
|
|
|
|
|
# SIP Listen: TCP only (TLS via Traefik Reverse Proxy)
|
|
|
|
|
listen=tcp:0.0.0.0:5060
|
|
|
|
|
|
|
|
|
|
####### Modules Section #######
|
|
|
|
|
|
|
|
|
|
loadmodule "kex.so"
|
|
|
|
|
loadmodule "tm.so"
|
|
|
|
|
loadmodule "tmx.so"
|
|
|
|
|
loadmodule "sl.so"
|
|
|
|
|
loadmodule "rr.so"
|
|
|
|
|
loadmodule "pv.so"
|
|
|
|
|
loadmodule "maxfwd.so"
|
|
|
|
|
loadmodule "textops.so"
|
|
|
|
|
loadmodule "siputils.so"
|
|
|
|
|
loadmodule "xlog.so"
|
|
|
|
|
loadmodule "sanity.so"
|
|
|
|
|
loadmodule "usrloc.so"
|
|
|
|
|
loadmodule "registrar.so"
|
|
|
|
|
loadmodule "nathelper.so"
|
|
|
|
|
loadmodule "auth.so"
|
|
|
|
|
loadmodule "htable.so"
|
|
|
|
|
loadmodule "pike.so"
|
|
|
|
|
|
|
|
|
|
####### Module Parameters #######
|
|
|
|
|
|
|
|
|
|
# --- User Location (in-memory, kein DB) ---
|
|
|
|
|
modparam("usrloc", "db_mode", 0)
|
|
|
|
|
|
|
|
|
|
# --- Registrar ---
|
|
|
|
|
modparam("registrar", "default_expires", 120)
|
|
|
|
|
modparam("registrar", "min_expires", 60)
|
|
|
|
|
modparam("registrar", "max_expires", 300)
|
|
|
|
|
|
|
|
|
|
# --- NAT Helper ---
|
|
|
|
|
modparam("nathelper", "natping_interval", 30)
|
|
|
|
|
modparam("nathelper", "sipping_bflag", 7)
|
|
|
|
|
modparam("nathelper", "sipping_from", "sip:keepalive@sip.toppyr.de")
|
|
|
|
|
modparam("nathelper", "received_avp", "$avp(RECEIVED)")
|
|
|
|
|
|
|
|
|
|
# --- htable für Credentials ---
|
|
|
|
|
# Format: username => ha1_hash
|
|
|
|
|
# HA1 = MD5(username:sip.toppyr.de:password)
|
2026-04-16 21:26:22 +02:00
|
|
|
modparam("htable", "htable", "credentials=>size=4;")
|
2026-04-16 19:48:27 +02:00
|
|
|
|
|
|
|
|
# --- Credentials (HA1-Hashes) ---
|
|
|
|
|
# tobias (Linphone iOS): hash von tobias:sip.toppyr.de:8pjd6eskjKmCihsu
|
|
|
|
|
# dotty (Mac Mini): hash von dotty:sip.toppyr.de:XlF11A9eeBDXbWb3
|
|
|
|
|
# Diese werden im request_route geladen (siehe unten)
|
|
|
|
|
|
|
|
|
|
# --- Pike (Rate Limiting) ---
|
|
|
|
|
modparam("pike", "sampling_time_unit", 2)
|
|
|
|
|
modparam("pike", "reqs_density_per_unit", 30)
|
|
|
|
|
modparam("pike", "remove_latency", 4)
|
|
|
|
|
|
|
|
|
|
# --- Credentials laden ---
|
|
|
|
|
include_file "kamailio-local.cfg"
|
|
|
|
|
|
|
|
|
|
####### Routing Logic #######
|
|
|
|
|
|
|
|
|
|
request_route {
|
|
|
|
|
# --- Load Credentials on Startup ---
|
|
|
|
|
if ($sht(credentials=>tobias) == $null) {
|
|
|
|
|
$sht(credentials=>tobias) = "4190b31a0d1a3fde008eb04104f2dc31";
|
|
|
|
|
$sht(credentials=>dotty) = "1f044db626dc2f3d6c3865fa20ae130f";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# --- Max Forwards ---
|
|
|
|
|
if (!mf_process_maxfwd_header("10")) {
|
|
|
|
|
sl_send_reply("483", "Too Many Hops");
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# --- Sanity Check ---
|
|
|
|
|
if (!sanity_check("17895", "7")) {
|
|
|
|
|
xlog("L_WARN", "Malformed SIP from $si:$sp\n");
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# --- Rate Limiting ---
|
|
|
|
|
if (!pike_check_req()) {
|
|
|
|
|
xlog("L_WARN", "Pike blocked $si\n");
|
|
|
|
|
sl_send_reply("503", "Service Unavailable");
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# --- NAT Detection ---
|
|
|
|
|
if (nat_uac_test("19")) {
|
|
|
|
|
force_rport();
|
|
|
|
|
if (is_method("REGISTER")) {
|
|
|
|
|
fix_nated_register();
|
|
|
|
|
} else {
|
|
|
|
|
fix_nated_contact();
|
|
|
|
|
}
|
|
|
|
|
setbflag(7);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# --- REGISTER ---
|
|
|
|
|
if (is_method("REGISTER")) {
|
|
|
|
|
route(AUTH);
|
|
|
|
|
if (!save("location")) {
|
|
|
|
|
sl_send_reply("500", "Server Error");
|
|
|
|
|
}
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# --- Record-Route für Dialoge ---
|
|
|
|
|
if (is_method("INVITE|SUBSCRIBE")) {
|
|
|
|
|
record_route();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# --- In-Dialog Requests ---
|
|
|
|
|
if (has_totag()) {
|
|
|
|
|
if (loose_route()) {
|
|
|
|
|
if (isbflagset(7)) {
|
|
|
|
|
add_rr_param(";nat=yes");
|
|
|
|
|
}
|
|
|
|
|
route(RELAY);
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
# ACK ohne Route-Header
|
|
|
|
|
if (is_method("ACK")) {
|
|
|
|
|
if (t_check_trans()) {
|
|
|
|
|
route(RELAY);
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
sl_send_reply("404", "Not Found");
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# --- Authentifizierung für alles außer ACK/CANCEL ---
|
|
|
|
|
if (is_method("INVITE|MESSAGE|SUBSCRIBE|NOTIFY|OPTIONS")) {
|
|
|
|
|
route(AUTH);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# --- MESSAGE (SIP-Textnachricht) ---
|
|
|
|
|
if (is_method("MESSAGE")) {
|
|
|
|
|
if (!lookup("location")) {
|
|
|
|
|
sl_send_reply("404", "User Not Found");
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
route(RELAY);
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# --- INVITE ---
|
|
|
|
|
if (is_method("INVITE")) {
|
|
|
|
|
if (!lookup("location")) {
|
|
|
|
|
# Mac Mini offline
|
|
|
|
|
sl_send_reply("480", "Temporarily Unavailable");
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
route(RELAY);
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# --- CANCEL ---
|
|
|
|
|
if (is_method("CANCEL")) {
|
|
|
|
|
if (t_check_trans()) {
|
|
|
|
|
t_relay();
|
|
|
|
|
}
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# --- OPTIONS (Keepalive) ---
|
|
|
|
|
if (is_method("OPTIONS")) {
|
|
|
|
|
sl_send_reply("200", "OK");
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# --- Alles andere ---
|
|
|
|
|
route(RELAY);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# --- AUTH Route ---
|
|
|
|
|
route[AUTH] {
|
|
|
|
|
if ($sht(credentials=>$au) == $null) {
|
|
|
|
|
if (is_method("REGISTER")) {
|
|
|
|
|
www_challenge("sip.toppyr.de", "0");
|
|
|
|
|
} else {
|
|
|
|
|
proxy_challenge("sip.toppyr.de", "0");
|
|
|
|
|
}
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
if (is_method("REGISTER")) {
|
2026-04-16 21:26:22 +02:00
|
|
|
if (!pv_www_authenticate("sip.toppyr.de", "$sht(credentials=>$au)", "1")) {
|
2026-04-16 19:48:27 +02:00
|
|
|
www_challenge("sip.toppyr.de", "0");
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2026-04-16 21:26:22 +02:00
|
|
|
if (!pv_proxy_authenticate("sip.toppyr.de", "$sht(credentials=>$au)", "1")) {
|
2026-04-16 19:48:27 +02:00
|
|
|
proxy_challenge("sip.toppyr.de", "0");
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
consume_credentials();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# --- RELAY Route ---
|
|
|
|
|
route[RELAY] {
|
|
|
|
|
if (isbflagset(7)) {
|
|
|
|
|
add_rr_param(";nat=yes");
|
|
|
|
|
}
|
2026-04-16 21:55:41 +02:00
|
|
|
# Force TCP — Kamailio hat keinen UDP-Listener
|
|
|
|
|
if (!t_relay_to_tcp()) {
|
2026-04-16 19:48:27 +02:00
|
|
|
sl_send_reply("500", "Relay Error");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# --- Reply Route (NAT fix für Antworten) ---
|
|
|
|
|
onreply_route {
|
|
|
|
|
if (nat_uac_test("1")) {
|
|
|
|
|
fix_nated_contact();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# --- Failure Route ---
|
|
|
|
|
failure_route[FAIL_ROUTE] {
|
|
|
|
|
if (t_is_canceled()) {
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
}
|