30.01.2022

TLS

Немного о том, как настраивать tls_mgm.

TLS domain это обозначение настроек, которое никак не связано с доменами в SIP заголовках. Оно используется для того, что дать opensips возможность определить какие сертификаты использовать для входящих\исходящих соединений. Какие сертификаты (читай: какой TLSdomain) использовать при входящем звонке, Opensips определяет по SIP domain в (SNI) записи в сертификате присылаемом от звонящего, либо по сокету на который пришел запрос на соединение(звонок).

в качестве примера настроек можно выставить
tlsdomain: my_srv_domain,
ip match: “*”,
SIP domain: “*”
certificate: cert1.pem
private ket: privkey1.pem
остальные параметры по-умолчанию.
Таким образом все входящие соединения по TLS будут обработаны этими настройками. (cert1.pem и privkey1.pem это файлы полученные на unix системе certbot приложением).

Для исходящих соединений opensips будет смотреть через какой сокет отправляется звонок. Также можно выбрать TLSdomain через переменную в скрипте ().

8.08.2021

Kamailio TLS-UDP with dispatcher and used old openssl 1.0.2 (sslv2\3 support)

This project is how to convert TLS-UDP with kamailio. Problem is that modern Unix (Ubuntu and debian have only modern openssl library so it’s not support ssv2\3 protocol). To make it works you have to

  • do this steps at vanilla system.
  • get source of kamailio
  • for compiling using /make include_modules=”tls”/
  • rtpengine should be installed as usual
  • then everything should go as usual

Benefits from this configs is that working for inbound\outbound calls and use Dispatcher.
this is example of dispatcher file:

#
# dispatcher destination sets (groups)
#

# line format
# setid(int) destination(sip uri) flags(int,opt) priority(int,opt) attributes(str,opt)


1 sip:PEER1:5070;transport=udp 0 0 socket=udp:KAM_SOCKET_UDP:5070
1 sip:PERR2;transport=udp 0 0 socket=udp:KAM_SOcKET_UDP:5070

2 sip:TLS_CARRIER:5061;transport=tls 0 0 socket=tls:TLS_SOCKET_KAM:5061

Example of kamailio config you may get here.

#!KAMAILIO
#
############################################################
# *** Value defines - IDs used later in config
#!ifdef WITH_DEBUG
#!define DBGLEVEL 3
#!else
#!define DBGLEVEL 2
#!endif
#!define DS_LIST "/usr/local/etc/kamailio/dispatcher.list"
#!define LISTEN_UDP_PRIVATE udp:LOCAL_INTERFACE_IP:5070
#!define FLAG_FROM_ASTERISK 10
#!define FLAG_FROM_PEER 11


# - flags
#   FLT_ - per transaction (message) flags
#!define FLT_ACC 1
#!define FLT_ACCMISSED 2
#!define FLT_ACCFAILED 3
#!define FLT_NATS 5

#	FLB_ - per branch flags
#!define FLB_NATB 6
#!define FLB_NATSIPPING 7

####### Global Parameters #########

/* LOG Levels: 3=DBG, 2=INFO, 1=NOTICE, 0=WARN, -1=ERR, ... */
debug=DBGLEVEL

/* set to 'yes' to print log messages to terminal or use '-E' cli option */
log_stderror=no

memdbg=5
memlog=5

log_facility=LOG_LOCAL0
log_prefix="{$mt $hdr(CSeq) $ci} "

children=8

auto_aliases=no

server_signature=no

alias="DOMAIN_NAME"

listen=udp:LOCAL_INTERFACE_IP:5070
listen=tls:LOCAL_INTERFACE_IP:5061 advertise EXTERNAL_IP:5061

tcp_connection_lifetime=3605

tcp_max_connections=20000

tcp_accept_no_cl=yes

enable_tls=yes
tls_max_connections=20000

enable_sctp=no

####### Modules Section ########
mpath="/usr/local/lib64/kamailio/modules/"


#loadmodule "db_mysql.so"
loadmodule "kex.so"
loadmodule "corex.so"
loadmodule "tm.so"
loadmodule "pike.so"
loadmodule "htable.so"
loadmodule "nathelper.so"
loadmodule "tmx.so"
loadmodule "sl.so"
loadmodule "rr.so"
loadmodule "pv.so"
loadmodule "maxfwd.so"
#loadmodule "registrar"
#loadmodule "usrloc.so"
loadmodule "textops.so"
loadmodule "textopsx.so"
loadmodule "dialog.so"
loadmodule "tls.so"
loadmodule "siputils.so"
loadmodule "xlog.so"
loadmodule "sanity.so"
loadmodule "ctl.so"
loadmodule "cfg_rpc.so"
loadmodule "acc.so"
loadmodule "counters.so"
loadmodule "dispatcher.so"
loadmodule "outbound.so"
loadmodule "rtpengine.so"
loadmodule "path.so"


####Module Specific Parameters####
modparam("rr", "enable_double_rr", 1)

modparam("tls", "config", "/etc/kamailio/tls.cfg")
modparam("path", "use_received", 1)


modparam("acc", "log_flag", FLT_ACC)
modparam("acc", "failed_transaction_flag", FLT_ACCFAILED)
modparam("acc", "log_extra", "src_user=$fU;src_domain=$fd;dst_ouser=$tU;dst_user=$rU;dst_domain=$rd;src_ip=$si")

modparam("rtpengine", "rtpengine_sock", "udp:127.0.0.1:2223")
modparam("pike", "sampling_time_unit", 2)
modparam("pike", "reqs_density_per_unit", 16)
modparam("pike", "remove_latency", 4)
modparam("htable", "htable", "ipban=>size=8;autoexpire=300;")


modparam("dispatcher", "list_file", DS_LIST)
#modparam("dispatcher", "db_url", DBURL)
modparam("dispatcher", "table_name", "dispatcher")
modparam("dispatcher", "flags", 2)
modparam("dispatcher", "ds_ping_reply_codes", "class=2;code=480;code=404")
modparam("dispatcher", "ds_probing_mode", 1)
modparam("dispatcher", "ds_ping_reply_codes", "class=2;code=480;code=404")
modparam("dispatcher", "force_dst", 1)
modparam("dispatcher", "ds_ping_interval", 20)
modparam("dispatcher", "ds_ping_from", "sip:keepalive@smsglobal.com")
modparam("dispatcher", "ds_ping_reply_codes", "class=2;code=480;code=404")
modparam("nathelper", "received_avp", "$avp(s:rcv)")


###Routing Logic

request_route {

	# per request initial checks
	route(REQINIT);
	
	# CANCEL processing
	if (is_method("CANCEL")) {
		if (t_check_trans()) {
			route(RELAY);
		}
		exit;
	}

	# handle retransmissions
	if (!is_method("ACK")) {
		if(t_precheck_trans()) {
			t_check_trans();
			exit;
		}
		t_check_trans();
	}

        route(CHECK_SOURCE_IP);

	# handle requests within SIP dialogs
	route(WITHINDLG);

	### only initial requests (no To tag)

	# record routing for dialog forming requests (in case they are routed)
	# - remove preloaded route headers
	remove_hf("Route");
	if (is_method("INVITE|SUBSCRIBE")) {
		record_route();
	}

	# account only INVITEs
	if (is_method("INVITE")) {
		setflag(FLT_ACC); # do accounting
	}

	# handle presence related requests
	route(PRESENCE);

	# handle registrations
	route(REGISTRAR);

	if ($rU==$null) {
		# request with no Username in RURI
		sl_send_reply("484","Address Incomplete");
		exit;
	}

	# dispatch destinations
	route(DISPATCH);
}


route[RELAY] {
    if (is_method("INVITE")) {
        if(!t_is_set("failure_route")) {
            t_on_failure("MANAGE_FAILURE");
        }
    }

    if (isflagset(FLAG_FROM_PEER)) {
	    xlog("L_INFO","seems call from $si goig from PEER");
	    
    } else {
            
            xlog("L_INFO","Relaying TO TLS\n ");
    }


    if (!t_relay()) {
            sl_reply_error();
    }
    #exit;

}

# Per SIP request initial checks
route[REQINIT] {
	if (!mf_process_maxfwd_header("10")) {
		sl_send_reply("483","Too Many Hops");
		exit;
	}

	if(!sanity_check("1511", "7")) {
		xlog("Malformed SIP message from $si:$sp\n");
		exit;
	}
	force_rport();
	
	if(src_ip!=myself) {
		if($sht(ipban=>$si)!=$null) {
			# ip is already blocked
			xdbg("request from blocked IP - $rm from $fu (IP:$si:$sp)\n");
			exit;
		}
		if (!pike_check_req()) {
			xlog("L_ALERT","ALERT: pike blocking $rm from $fu (IP:$si:$sp)\n");
			$sht(ipban=>$si) = 1;
			exit;
		}
	}

	if($ua =~ "friendly|scanner|sipcli|sipvicious|VaxSIPUserAgent") {
		# silent drop for scanners - uncomment next line if want to reply
		# sl_send_reply("200", "OK");
		exit;
	}
	if(is_method("OPTIONS") && uri==myself && $rU==$null) {
		sl_send_reply("200","Keepalive");
		exit;
	}



}

route[CHECK_SOURCE_IP] {
    if(ds_is_from_list("1")) {
            setflag(FLAG_FROM_ASTERISK);
    } else {
            setflag(FLAG_FROM_PEER);
    }
}

# Handle requests within SIP dialogs
route[WITHINDLG] {
	if (has_totag()) {
		# sequential request withing a dialog should
		# take the path determined by record-routing
		if (loose_route()) {
			if (is_method("BYE")) {
				setflag(FLT_ACC); # do accounting ...
				setflag(FLT_ACCFAILED); # ... even if the transaction fails
			}
			route(RELAY);
		} else {
			if (is_method("SUBSCRIBE") && uri == myself) {
				# in-dialog subscribe requests
				exit;
			}
			if ( is_method("ACK") ) {
				if ( t_check_trans() ) {
					# non loose-route, but stateful ACK;
					# must be ACK after a 487 or e.g. 404 from upstream server
					t_relay();
					exit;
				} else {
					# ACK without matching transaction ... ignore and discard.
					exit;
				}
			}
			sl_send_reply("404","Not here");
		}
		exit;
	}
}

# Handle SIP registrations
route[REGISTRAR] {
	if(!is_method("REGISTER"))
		return;

	sl_send_reply("404", "Not Acceptable");
	exit;
}

# Presence server route
route[PRESENCE] {
	if(!is_method("PUBLISH|SUBSCRIBE"))
		return;

	sl_send_reply("404", "Not Acceptable");
	exit;
}

# Dispatch requests
route[DISPATCH] {
        # round robin dispatching on gateways group '1'
        # record routing for dialog forming requests (in case they are routed)
        # - remove preloaded route headers
        remove_hf("Route");
        if (is_method("INVITE|REFER")) {
                record_route();
                if (has_body("application/sdp")) {
                    if (rtpengine_offer()) {
                            t_on_reply("1");
                    }
                } else {
                    t_on_reply("2");
                }

                if (isflagset(FLAG_FROM_PEER)) {
		    xlog("L_INFO","Call from $si seems from PEER");
                    if(!ds_select_domain("1", "4")) {
                            send_reply("404", "No destination");
                            exit;
                    }

                }

                if (isflagset(FLAG_FROM_ASTERISK)) {
		    xlog("L_INFO","Call from $si seems from ASTERISK");
                    if(!ds_select_domain("2", "4")) {

                            send_reply("404", "No destination");
                            exit;
                    }
		    xlog("L_INFO","Call from $si seems from ASTERISK [$du] [$ru]");
		    
                }
		    

		    xlog("L_INFO","DESTINATION is $du");
        }

        if (is_method("ACK") && has_body("application/sdp")) {
                rtpengine_answer("force");
        }

        route(RELAY);
}


failure_route[RTF_DISPATCH] {
	if (t_is_canceled()) {
		exit;
	}
	# next DST - only for 500 or local timeout
	if (t_check_status("500")
			or (t_branch_timeout() and !t_branch_replied())) {
		if(ds_next_dst()) {
			xdbg("--- SCRIPT: retrying to <$ru> via <$du> (attrs: $xavp(_dsdst_=>attrs))\n");
			t_on_failure("RTF_DISPATCH");
			route(RELAY);
			exit;
		}
	}
}

onreply_route[1] {
        if (has_body("application/sdp")) {
                rtpengine_answer("force");
        }
}

onreply_route[2] {
        if (has_body("application/sdp")) {
                rtpengine_offer("force");
        }
}

24.09.2020

TCP\TLS NAT Zoiper

Столкнулся с проблемой, когда через sip прокси (opensips) не проходили пакеты (OPTIONS, NOTIFY, INVITE) в сторону uac при использовании TCP и TLS протоколов. при TLS opensips ругался 477/Send Error, при использовании TCP – 408 timeout. И действительно пакеты с opensips уходили, но не доходили до UAC.

Причина была в использовании STUN, если его отключить на Zoiper то связь работает хорошо в обе стороны.

20.06.2017

Тестирование Kamailio и multidomain сертификата ssl

Как подключить к Камалио самоподписанный multidomain сертификат.

Как обычно источники: Статья 1, Статья 2

Смысл простой, я так понял это можно сделать добавив extensions в сертификат, а это в свою очередь определяется в файлике openssl.conf

Находим секцию REQ в openssl.conf проверяем, что x509_extensions не закомментирован:

[req]
...
x509_extensions = v3_ca

Затем добавляем секцию v3_ca и указываем в ней следующее:

[v3_ca]
...
subjectAltName = @alt_names
[alt_names]
DNS.1 = example.com
DNS.2 = www.example.com
DNS.3 = example.co.uk
DNS.4 = www.example.co.uk

У меня сработало и сертификат стал иметь несколько доменных зон, что крайне удобно когда использует DNS файловер.

Проверить, кстати, можно очень просто после создания запроса на сертификат, выполните

openssl req -text -noout -in <запрос_сертификата>.csr

И если увидите, что-то подобное, то можно генерировать сертификат.

Certificate Request:
    Data:
        Version: 0 (0x0)
        Subject: C=DE, ST=Germany, L=City, O=Company, OU=Organisation-Unit, CN=server1.example.com/emailAddress=alias@example.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (4096 bit)
                Modulus (4096 bit):
[...]
                Exponent: 65537 (0x10001)
        Attributes:
        Requested Extensions:
            X509v3 Basic Constraints:
                CA:FALSE
            X509v3 Key Usage:
                Digital Signature, Non Repudiation, Key Encipherment
            X509v3 Subject Alternative Name:
                DNS:server1.example.com, DNS:mail.example.com, DNS:www.example.com
, DNS:www.sub.example.com, DNS:mx.example.com, DNS:support.example.com
    Signature Algorithm: sha1WithRSAEncryption
[...]

значит всё удалось.

16.06.2017

TLS. Kamailio. Asterisk. Настройка

Схема которую планировали реализовать:

Client1 —<TLS>— Kamailio —<UDP>— Asterisk —<UDP>— Kamailio —<TLS>— <Client2>

Что почитать перед тем как настраивать, это сразу несколько позиций, они обязательно вам пригодятся, ибо быстро сделать даже такую простую схему без понимания принципа не получится. А может и получится, но останутся дыры.

  1. Документация TLS модуля для Камалио 4.4 – прекрасно описывается как создать сертификат без получения и т.д.
  2. ssldump -Nn покажет обмен внутри протокола ssl кто кому какие сертификаты посылает
  3. howto kamailio and tls

Теперь непосредственно, то как работает TLS в двух словах.

  1. создать центра сертификации – CA
  2. подписать им сертификат для Камалио
  3. скопировать в подписанный сертификат приватный ключь, этот на всякий случай
  4. создать сертификат для sip-клиента
  5. скопировать приватный ключ в сертификат т.к. некоторые сип клиенты не имеют возможность для указания отдельно приватного ключа в настройках
  6. вынести конфигурацию tls в отдельный файл
  7. далее прописать в calist.pem сертификат CA. Это нужно чтобы камалио получив сертификат от клиента проверил его CA в своем списке и если СА в доверенных, то одобрить сертификат (при этом неважно откуда звонит клиент и какой домен (CN) указан в сертификате
  8. Повесить камалио на lts : listen:tls:ip_address:5061
  9. подключить к своему клиенту сертификат.
  10. клиент будет проверять сертификат поэтому, в виндоус нужно добавить в доверенные центры сертификации ваш сертификат CA, который вы создавали в самом начале.
  11. в сертификате Камалио обязательно должен быть указан CN соответствующий домену Камалио, либо его IP адресу если домена как такогово нет.
  12. В настройках камалио нужно оставить только verify_certificate = yes, require_certificate = no. Если поставить оба значения, то у меня ситуация выглядела так: Во время звонка при передаче ACK сообщения sip-клиент создавал новое соединение TLS и оно было отказывалось работать, потому, что не совпадали CN ожидаемые sip-клиентом и указанные в сертификате. Не стал разбираться дальше почему так происходит.

Настройка на данном этапе завершена, сертификат проверяется, т.е. использовать левый сертификат не получится.