######## DoS prevention module ########
|
|
# Default "order" is "deny,allow".
|
|
# So if there is no data from DB request will be permitted by default.
|
|
#
|
|
loadmodule "ipops.so"
|
|
modparam("htable", "htable", "acl=>initval=-1;autoexpire=7200")
|
|
|
|
#!trydef ACL_MESSAGE_DENY "Rejected by ACL"
|
|
#!trydef ACL_CODE_DENY "603"
|
|
#!trydef ACL_ORDER_ALLOW_DENY "allow,deny"
|
|
#!trydef ACL_IP_ADDR_ANY "0.0.0.0/0"
|
|
|
|
#!trydef IP_REGEX "[0-9]{1,3}\.[0-9]{1,3}.[0-9]{1,3}\.[0-9]{1,3}"
|
|
|
|
## Route for ACL functionality
|
|
route[ACL_CHECK] {
|
|
|
|
# If packet came from platform or from 4 class MERA, do not check it
|
|
if (isflagset(FLAG_INTERNALLY_SOURCED) || isflagset(FLAG_TRUSTED_SOURCE) ) {
|
|
xlog("L_DEBUG", "$ci|ACL|Trusted source IP($si) ignoring");
|
|
return;
|
|
}
|
|
|
|
|
|
if (isflagset(FLAG_IS_REPLY)) {
|
|
$var(sip-packet) = $rs;
|
|
} else {
|
|
$var(sip-packet) = $rm;
|
|
}
|
|
|
|
# FIX for BYE method with IP instead of REALM in From, take REALM from To header
|
|
if ($fd =~ IP_REGEX) {
|
|
xlog("L_WARNING","$ci|ACL-realm|Fix for $var(sip-packet) with IP in from URI: use to-domain");
|
|
$var(realm) = $td;
|
|
} else {
|
|
$var(realm) = $fd;
|
|
}
|
|
|
|
$var(acl-realm-request) = "false";
|
|
$var(acl-device-request) = "false";
|
|
|
|
$var(realm-decision) = $sht(acl=>$var(realm)/$si);
|
|
|
|
if ($var(realm-decision) == -1) { # we do not have cached decision
|
|
$var(acl-realm-request) = "true";
|
|
} else if ($var(realm-decision) == 1 ){ # We have cached decision, let's use it
|
|
xlog("L_INFO", "$ci|ACL|$var(sip-packet) from $si is permitted by ACL for $var(realm)\n");
|
|
} else {
|
|
if (!isflagset(FLAG_IS_REPLY)) {
|
|
sl_send_reply(ACL_CODE_DENY, ACL_MESSAGE_DENY);
|
|
}
|
|
xlog("L_INFO", "$ci|ACL|$var(sip-packet) from $si is rejected by ACL for $var(realm)\n");
|
|
exit;
|
|
}
|
|
|
|
if (not_empty("$fU")) {
|
|
if ($fd =~ IP_REGEX) {
|
|
xlog("L_WARNING","$ci|ACL-device|Fix for $var(sip-packet) with IP in from URI: use to-domain");
|
|
$var(device) = $fU + "@" + $td;
|
|
} else {
|
|
$var(device) = $fU + "@" + $fd;
|
|
}
|
|
$var(device-decision) = $sht(acl=>$var(device)/$si);
|
|
|
|
if ($var(device-decision) == -1) { # we do not have cached decision
|
|
$var(acl-device-request) = "true";
|
|
} else if ($var(device-decision) == 1 ){ # We have cached decision, let's use it
|
|
xlog("L_INFO", "$ci|ACL|$var(sip-packet) from $si is permitted by ACL for $var(device)\n");
|
|
} else {
|
|
if (!isflagset(FLAG_IS_REPLY)) {
|
|
sl_send_reply(ACL_CODE_DENY, ACL_MESSAGE_DENY);
|
|
}
|
|
xlog("L_INFO", "$ci|ACL|$var(sip-packet) from $si is rejected by ACL for $var(device)\n");
|
|
exit;
|
|
}
|
|
}
|
|
|
|
|
|
if ($var(acl-realm-request) == "true" || $var(acl-device-request) == "true") {
|
|
if (not_empty("$fU"))
|
|
$var(query) = "{'Event-Category': 'acl', 'Event-Name': 'query', 'Entity': '" + $var(device) + "', 'With-Realm': " + $var(acl-realm-request) + "}";
|
|
else
|
|
$var(query) = "{'Event-Category': 'acl', 'Event-Name': 'query', 'Entity': '" + $var(realm) + "'}";
|
|
xlog("L_DBG", "$ci|ACL log|Query: $var(query)");
|
|
sl_send_reply("100", "Attempting K query");
|
|
if (kazoo_query("frontier", "sbc_config", $var(query), "$var(acl-response)")) {
|
|
xlog("L_DBG", "$ci|ACL log|Response: $var(acl-response)");
|
|
|
|
kazoo_json($var(acl-response), "Realm.Order", "$var(acl-realm-order)");
|
|
kazoo_json($var(acl-response), "Realm.CIDR", "$var(acl-realm-cidr)");
|
|
kazoo_json($var(acl-response), "Device.Order", "$var(acl-device-order)");
|
|
kazoo_json($var(acl-response), "Device.CIDR", "$var(acl-device-cidr)");
|
|
kazoo_json($var(acl-response), "Device.User-Agent", "$var(acl-device-ua)");
|
|
|
|
} else {
|
|
xlog("L_ERROR","$ci|ACL log|DB is unreachable");
|
|
$sht(acl=>$var(device)/$si) = 1;
|
|
xlog("L_INFO", "$ci|ACL|$var(sip-packet) from $si is permitted by ACL for $var(device)\n");
|
|
return;
|
|
}
|
|
|
|
route(ACL_CHECK_REALM);
|
|
if (not_empty("$fU")) {
|
|
route(ACL_CHECK_DEVICE);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
# Check ORDER setting for REALM
|
|
route[ACL_CHECK_REALM] {
|
|
if (not_empty("$var(acl-realm-order)")) {
|
|
if ($var(acl-realm-order) == ACL_ORDER_ALLOW_DENY) {
|
|
route(ACL_CHECK_REALM_ALLOW);
|
|
} else {
|
|
route(ACL_CHECK_REALM_DENY);
|
|
}
|
|
} else {
|
|
xlog("L_INFO","$ci|ACL-realm|undefined Order in response for $var(realm)");
|
|
$sht(acl=>$var(realm)/$si) = 1;
|
|
xlog("L_INFO", "$ci|ACL|$var(sip-packet) from $si is permitted by ACL for $var(realm)\n");
|
|
}
|
|
}
|
|
|
|
route[ACL_CHECK_REALM_ALLOW] {
|
|
if (not_empty("$var(acl-realm-cidr)")) {
|
|
$var(i) = 0;
|
|
kazoo_json($var(acl-response), "Realm.CIDR[$var(i)]", "$var(record)");;
|
|
while(not_empty("$var(record)")) {
|
|
xlog("L_INFO", "$ci|ACL-realm|checking if $si is in $var(record)");
|
|
if (($var(record) == ACL_IP_ADDR_ANY) || is_in_subnet("$si", $var(record))) {
|
|
$sht(acl=>$var(realm)/$si) = 1;
|
|
xlog("L_INFO", "$ci|ACL|$var(sip-packet) from $si is permitted by ACL for $var(realm)\n");
|
|
return;
|
|
}
|
|
$var(i) = $var(i) + 1;
|
|
kazoo_json($var(acl-response), "Realm.CIDR[$var(i)]", "$var(record)");;
|
|
}
|
|
} else {
|
|
xlog("L_INFO", "$ci|ACL-realm|undefined CIDR in response for $var(realm)");
|
|
}
|
|
# Remember in CACHE and DENY
|
|
$sht(acl=>$var(realm)/$si) = 0;
|
|
if (!isflagset(FLAG_IS_REPLY)) {
|
|
sl_send_reply(ACL_CODE_DENY, ACL_MESSAGE_DENY);
|
|
}
|
|
xlog("L_INFO", "$ci|ACL|$var(sip-packet) from $si is rejected by ACL for $var(realm)\n");
|
|
exit;
|
|
}
|
|
|
|
route[ACL_CHECK_REALM_DENY] {
|
|
$var(size) = $(kzR{kz.json,Realm.CIDR.length});
|
|
if (not_empty("$var(acl-realm-cidr)")) {
|
|
$var(i) = 0;
|
|
kazoo_json($var(acl-response), "Realm.CIDR[$var(i)]", "$var(record)");;
|
|
while(not_empty("$var(record)")) {
|
|
xlog("L_INFO", "$ci|ACL-realm|checking if $si is in $var(record)");
|
|
if (($var(record) == ACL_IP_ADDR_ANY) || is_in_subnet("$si", $var(record))) {
|
|
$sht(acl=>$var(realm)/$si) = 0;
|
|
if (!isflagset(FLAG_IS_REPLY)) {
|
|
sl_send_reply(ACL_CODE_DENY, ACL_MESSAGE_DENY);
|
|
}
|
|
xlog("L_INFO", "$ci|ACL|$var(sip-packet) from $si is rejected by ACL for $var(realm)\n");
|
|
exit;
|
|
}
|
|
$var(i) = $var(i) + 1;
|
|
kazoo_json($var(acl-response), "Realm.CIDR[$var(i)]", "$var(record)");;
|
|
}
|
|
} else {
|
|
xlog("L_INFO", "$ci|ACL-realm|undefined CIDR in response for $var(realm)");
|
|
}
|
|
# Remember in CACHE and ALLOW
|
|
$sht(acl=>$var(realm)/$si) = 1;
|
|
xlog("L_INFO", "$ci|ACL|$var(sip-packet) from $si is permitted by ACL for $var(realm)\n");
|
|
return;
|
|
}
|
|
|
|
# Check ORDER setting for DEVICE
|
|
route[ACL_CHECK_DEVICE] {
|
|
if (not_empty("$var(acl-device-order)")) {
|
|
if ($var(acl-device-order) == ACL_ORDER_ALLOW_DENY) {
|
|
route(ACL_CHECK_DEVICE_ALLOW);
|
|
} else {
|
|
route(ACL_CHECK_DEVICE_DENY);
|
|
}
|
|
} else {
|
|
xlog("L_INFO","$ci|ACL-device|undefined Order in response for $var(device)");
|
|
$sht(acl=>$var(device)/$si) = 1;
|
|
xlog("L_INFO", "$ci|ACL|$var(sip-packet) from $si is permitted by ACL for $var(device)\n");
|
|
}
|
|
}
|
|
|
|
route[ACL_CHECK_DEVICE_ALLOW] {
|
|
if (!not_empty("$var(acl-device-ua)") || (not_empty("$var(acl-device-ua)") && $ua =~ $var(acl-device-ua))) {
|
|
if (not_empty("$var(acl-device-cidr)")) {
|
|
$var(i) = 0;
|
|
kazoo_json($var(acl-response), "Device.CIDR[$var(i)]", "$var(record)");;
|
|
while(not_empty("$var(record)")) {
|
|
xlog("L_INFO", "$ci|ACL-realm|checking if $si is in $var(record)");
|
|
if (($var(record) == ACL_IP_ADDR_ANY) || is_in_subnet("$si", $var(record))) {
|
|
$sht(acl=>$var(device)/$si) = 1;
|
|
xlog("L_INFO", "$ci|ACL|$var(sip-packet) from $si is permitted by ACL for $var(device)\n");
|
|
return;
|
|
}
|
|
$var(i) = $var(i) + 1;
|
|
kazoo_json($var(acl-response), "Device.CIDR[$var(i)]", "$var(record)");;
|
|
}
|
|
} else {
|
|
xlog("L_INFO", "$ci|ACL-realm|undefined CIDR in response for $var(device)");
|
|
}
|
|
}
|
|
# Remember in CACHE and DENY
|
|
$sht(acl=>$var(device)/$si) = 0;
|
|
if (!isflagset(FLAG_IS_REPLY)) {
|
|
sl_send_reply(ACL_CODE_DENY, ACL_MESSAGE_DENY);
|
|
}
|
|
xlog("L_INFO", "$ci|ACL|$var(sip-packet) from $si is rejected by ACL for $var(device)\n");
|
|
exit;
|
|
}
|
|
|
|
route[ACL_CHECK_DEVICE_DENY] {
|
|
if (not_empty("$var(acl-device-ua)") && !($ua =~ $var(acl-device-ua))) {
|
|
$sht(acl=>$var(device)/$si) = 0;
|
|
if (!isflagset(FLAG_IS_REPLY)) {
|
|
sl_send_reply(ACL_CODE_DENY, ACL_MESSAGE_DENY);
|
|
}
|
|
xlog("L_INFO", "$ci|ACL|$var(sip-packet) from $si is rejected by ACL for $var(device)\n");
|
|
exit;
|
|
}
|
|
|
|
if (not_empty("$var(acl-device-cidr)")) {
|
|
$var(i) = 0;
|
|
kazoo_json($var(acl-response), "Device.CIDR[$var(i)]", "$var(record)");;
|
|
while(not_empty("$var(record)")) {
|
|
xlog("L_INFO", "$ci|ACL-device|checking if $si is in $var(record)");
|
|
if (($var(record) == ACL_IP_ADDR_ANY) || is_in_subnet("$si", $var(record))) {
|
|
$sht(acl=>$var(device)/$si) = 0;
|
|
if (!isflagset(FLAG_IS_REPLY)) {
|
|
sl_send_reply(ACL_CODE_DENY, ACL_MESSAGE_DENY);
|
|
}
|
|
xlog("L_INFO", "$ci|ACL|$var(sip-packet) from $si is rejected by ACL for $var(device)\n");
|
|
exit;
|
|
}
|
|
$var(i) = $var(i) + 1;
|
|
kazoo_json($var(acl-response), "Device.CIDR[$var(i)]", "$var(record)");;
|
|
}
|
|
} else {
|
|
xlog("L_INFO", "$ci|ACL-device|undefined CIDR in response for $var(device)");
|
|
}
|
|
# Remember in CACHE and ALLOW
|
|
$sht(acl=>$var(device)/$si) = 1;
|
|
xlog("L_INFO", "$ci|ACL|$var(sip-packet) from $si is permitted by ACL for $var(device)\n");
|
|
return;
|
|
}
|