Menu Zavrieť

OpenSER VoIP SIP so službami a prepojením na Cisco Call Managera

Cieľ:

Cieľom konfigurácie je rozbehnúť funkčný OpenSER VoIP server, ktorý bude vykonávať autentifikáciu používateľov a smerovanie SIP správ, ďalej služby typu event notification a presence. OpenSER bude prepojený na CCM za účelom zostavovania hovorov do telco siete. Infraštruktúra bude obsahovať aj Asterisk server, ktory bude ponúkať autentifikovaným používateľom služby ako IVR, VoiceMail, audio konferencie a iné. Predpokladá sa umiestnenie UA vo verejnej IP sieti, v privátnej IP sieti (za firewallom a jedným or viac NAT), volania z a do PSTN siete.

Stav:

  • migrácia na kamailio 3.x

 

 

Očakávaná architektúra

 

SIP arch

 

Pomocné linky:

 

 

Obsah

  1. inštalácia OpenSER-u 1.3.x na debiane
  2. Autentifikácia na MySQL
    1. Nastavenie DB MySQL
    2. Konfigurácia OpenSER aby použil MySQL
    3. Konfigurácia auntentifikácie pri registrácií – konfigurácia Registrar a Proxy
  3. Aliasy a ich používanie
  4. Riešenie prepojenia medzi doménami
  5. NAT Traversal
    1. TURN
    2. STUN
    3. RTPProxy
    4. MediaProxy
  6. Instant Messaging a Presence
  7. ENUM
  8. Smerovanie na Cisco Call Manager-a (CCM)

Inštalácia OpenSER

Inštalácia bez problémov z debian repozitára. Čistý OpenSER je hneď funkčný, na rozdiel od inštalácie na Ubuntu, ktorý pri default inštalácii hádže problém s radiusclientom.

Na spustenie služby je potrebné mať rozchodené DNS pre danú doménu napr.

; SIP VoIP katedry
voip                    A                       158.193.152.1
_sip._udp               SRV     0 1 5060        voip

Overenie cez dig.

C:\dig>dig -t SRV _sip._udp.kis.fri.uniza.sk

; <<>> DiG 9.3.2 <<>> -t SRV _sip._udp.kis.fri.uniza.sk
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 486
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 2

;; QUESTION SECTION:
;_sip._udp.kis.fri.uniza.sk.    IN      SRV

;; ANSWER SECTION:
_sip._udp.kis.fri.uniza.sk. 3600 IN     SRV     0 1 5060 voip.kis.fri.uniza.sk.

;; AUTHORITY SECTION:
kis.fri.uniza.sk.       3600    IN      NS      ns.kis.fri.uniza.sk.

;; ADDITIONAL SECTION:
voip.kis.fri.uniza.sk.  3600    IN      A       158.193.152.1
ns.kis.fri.uniza.sk.    3600    IN      A       158.193.152.1

;; Query time: 10 msec
;; SERVER: 158.193.152.1#53(158.193.152.1)
;; WHEN: Thu May 28 10:21:24 2009
;; MSG SIZE  rcvd: 134

 

a vložiť do konfiguráku openser.cfg parameter alias s menom danej domény, lebo ináč neprebehne registrácia a odpoveď servera je Too many hops

alias=kis.fri.uniza.sk

OpenSER beží ako služba, pri čistej inštalácii nie je problém sa registrovať sa na serveri (keďže autentifikácia je vypnutá).

Link na openser.cfg

Problémy

1.  Problém je registrovať sa zo sieti spoza NAT typu Linksys (WRT350N), spoza Cisco ASA nie je problém.

 

Autentifikácia na MySQL

Úloha je nakonfigurovať MySQL, ktorá bude držať autentifikačné údaje používateľov a bude ukladať lokalizačné údaje používateľov (nestrácame ich reštartom OpenSER servera).

Predpokladá sa nainštalovaný MySQL server:

apt-get install mysql-server

Autentifikáciu na DB v OpenSER-e vykonáva modul AUTH_DB.

Default parametere modulu AUTH_DB sú:

Defaul params AUTH_DB
Parameter    Default    Description    
db_url "mysql://openserro:openserro@localhost/openser" URL of the database
user_column "username" Name of the column holdingdomains of users 
domain_column "domain"   Name of the column holdingdomains of users     
password column "ha1" Name of the column holdingpasswords
password_column2 "ha1b" Name of the column holding pre-calculated HA1 strings that were calculated including the domain in the username.
calculate_ha1 0 (server assumes that ha1 strings are already calculated in the database) Tell the server whether it should expect plaintext passwords in the database
or not.
use_domain 0 (domains won’t be checked when looking up in the subscriber database) Use this parameter set to 1 if you have a multi-domain environment.
load_credentials "rpid" Specifies the credentials to be fetch from the database when the authentication is performed. The loaded credentials will be stored
in AVPs.

 

Pozn. z múdrej knihy ohľadne rozdielov medzi www_authorize a proxy_authorize

The AUTH_DB module exports two functions.
www_authorize(realm, table)
This function is used in the REGISTER authentication that occurs in accordance with RFC2617.
proxy_authorize(realm, table)
The function verifies credentials according to RFC2617 for the non-REGISTER requests. If the credentials are verified successfully, the credentials will be marked  as authorized.
You have to use www_authorize when your server is the endpoint of the request. Use proxy_authorize when the request’s final destination is not your server and you will forward the request ahead, actually working as a proxy.
The difference between www_authorize and proxy_authorize is that if the request’s end point is you (REGISTER) you use www_authorize.

Nastavenie DB MySQL

Podpora autentifikácie na DB je riešená modulom mysql.so. Takže tento modul je potrebné vybrať z repozitára pri inštalácií alebo ho doinštalovať. Modul sa nachádza v adresari /usr/lib/openser/modules.

Predpokladá sa nainštalovaný OpenSER MySQL modul:

apt-get install openser-mysql-module

Ďalším predpokladom je existencia MySQL DB,ktorú nainštalujeme štandardne.

Pokiaľ sú splnené prerekvizity na staších verziách urobíme v DB potrebné tabuľky spustením dodávaného skriptu openser_mysql.sh.Novšie verzie ho nemajú a je potrebné vykonať úkony cez openserctl.

Zeditujeme súbor /etc/openser/openserctlrc aby zohľadňoval naše potreby

 

## your SIP domain
SIP_DOMAIN=kis.fri.uniza.sk

## database type: MYSQL, PGSQL, DB_BERKELEY, or DBTEXT, by default none is load$
# If you want to setup a database with openserdbctl, you must at least specify
# this parameter.
DBENGINE=MYSQL

## database host
DBHOST=localhost

## database name
DBNAME=openser

## database read/write user
DBRWUSER=openser

## password for database read/write user
DBRWPW="openserrw"

## database read only user
DBROUSER=openserro

## password for database read only user
DBROPW=openserro

## database super user
DBROOTUSER="root"

# Describe what additional tables to install. Valid values for the variables
# below are yes/no/ask. With ask (default) it will interactively ask the user
# for an answer, while yes/no allow for automated, unassisted installs.
#

# odkomentoval som, ocakavaminstalaciu tabuliek pre presence
# If to install tables for the modules in the EXTRA_MODULES variable.
INSTALL_EXTRA_TABLES=ask

# If to install presence related tables.
INSTALL_PRESENCE_TABLES=ask

## type of aliases used: DB - database aliases; UL - usrloc aliases ## - default: none
ALIASES_TYPE="DB"

## control engine: FIFO or UNIXSOCK
## - default FIFO
CTLENGINE="FIFO"

## path to FIFO file OSER_FIFO="/tmp/openser_fifo"

Teazr vytvoríme tabuľku

openserdbctl create 

Problém:

root@castor:/usr/lib/openser/openserctl# openserdbctl create
MySQL password for root:
INFO: test server charset
INFO: creating database openser ...
ERROR 1071 (42000) at line 2: Specified key was too long; max key length is 1000 bytes
ERROR: Creating core tables failed!

Po surfovaní na webe som vypátral, že problém je s kódovaním použitým v MySQL, a to konkrétne že používame UTF-8. Google dal aj linku na riešenie problému:

http://lists.openser.org/pipermail/devel/2008-March/012765.html

http://sourceforge.net/tracker/index.php?func=detail&aid=1605410&group_id=139143&atid=743020

 

Toto je problém, ktorý sa mi moc nedarií vyriešiť. Snažil som sa to obísť vytvorením DB openser s kódovaním UTF8 cez phpmyadmin a potom ručne naimportovať tabuľky cez sql skripty z adresára

/usr/share/openser/mysql

root@castor:/usr/share/openser/mysql# ls -al
total 104
drwxr-xr-x 2 root root 4096 May  5 11:14 .
drwxr-xr-x 4 root root   31 May  5 11:14 ..
-rw-r--r-- 1 root root 1004 Jul 21  2008 acc-create.sql
-rw-r--r-- 1 root root  465 Jul 21  2008 alias_db-create.sql
-rw-r--r-- 1 root root  768 Jul 21  2008 auth_db-create.sql
-rw-r--r-- 1 root root  597 Jul 21  2008 avpops-create.sql
-rw-r--r-- 1 root root  813 Jul 21  2008 carrierroute-create.sql
-rw-r--r-- 1 root root  327 Jul 21  2008 cpl-create.sql
-rw-r--r-- 1 root root  886 Jul 21  2008 dialog-create.sql
-rw-r--r-- 1 root root  312 Jul 21  2008 dispatcher-create.sql
-rw-r--r-- 1 root root  318 Jul 21  2008 domain-create.sql
-rw-r--r-- 1 root root  392 Jul 21  2008 domainpolicy-create.sql
-rw-r--r-- 1 root root  709 Jul 21  2008 group-create.sql
-rw-r--r-- 1 root root  680 Jul 21  2008 imc-create.sql
-rw-r--r-- 1 root root 1147 Jul 21  2008 lcr-create.sql
-rw-r--r-- 1 root root  590 Jul 21  2008 msilo-create.sql
-rw-r--r-- 1 root root  331 Jul 21  2008 pdt-create.sql
-rw-r--r-- 1 root root  672 Jul 21  2008 permissions-create.sql
-rw-r--r-- 1 root root 3196 Jul 21  2008 presence-create.sql
-rw-r--r-- 1 root root  891 Jul 21  2008 registrar-create.sql
-rw-r--r-- 1 root root 1534 Jul 21  2008 rls-create.sql
-rw-r--r-- 1 root root 3782 Jul 21  2008 serweb-create.sql
-rw-r--r-- 1 root root  741 Jul 21  2008 siptrace-create.sql
-rw-r--r-- 1 root root  620 Jul 21  2008 speeddial-create.sql
-rw-r--r-- 1 root root  128 Jul 21  2008 standard-create.sql
-rw-r--r-- 1 root root  425 Jul 21  2008 uri_db-create.sql
-rw-r--r-- 1 root root  903 Jul 21  2008 usrloc-create.sql

príkazom:

 mysql -u root -p openser < sckript_XY.sql

problém je že neviem ktoré všetky tabs pre ktoré moduly budem potrebovať. Šiel som zaradom až kým som nedošiel na skript 

mysql -u root -p openser < registrar-create.sql

Chyba

ERROR 1071 (42000) at line 2: Specified key was too long; max key length is 1000 bytes

sa objavuje zas.

 

Skúšam ďalšie riešenie, kde urobím DB openser manuálne cez phpmyadmin v sada latin2 (tá by teoreticky mala prejsť podľa komentárov na webe), skript openserctl neurobí nič lebo vyhlási chybu, že databáza je už vytvorená. Robím teda manuálny import tabuliek z

/usr/share/openser/mysql

 skúšam len prvé dve najdôležitejšie, a to

root@castor:/usr/share/openser/mysql# mysql -u root -p openser < standard-create.sql
Enter password:
root@castor:/usr/share/openser/mysql# mysql -u root -p openser < registrar-create.sql
Enter password:

Zdá sa, že to prebehlo. Nezabudnúť nastaviť role používateľov openser s heslom a openserro na prístup k DB (opravenia).

Pozn.: Dopad použitej znakovej sady zatiaľ neviem posúdiť.

 Importujem takmer všetky moduly nakoľko sa mi väčšina zdá dôležitá z hľadiska budúceho nasadenia servera, popis modulov pre 1.3 v manuáli tu.

 

Konfigurácia OpenSER aby použil MySQL

1. odkomentuj modul mysql.so aby ho openser začal používať

loadmodule "mysql.so"

2. Odkomentuj moduly, ktoré zabezpečujú autentifikáciu

loadmodule "auth.so"
loadmodule "auth_db.so"

3. Odkomentuj parametre modulu

modparam("usrloc", "db_mode", 2)

a zakomentuj

#modparam("usrloc", "db_mode", 0)

 

kde parametre sú:

The usrloc module can utilize database for persistent contact storage. If you use database, your contacts will survive machine restarts or SW crashes. The disadvantage is that accessing database can be very time consuming. Therefore, usrloc module implements four database accessing modes:

  • 0 - This disables database completely. Only memory will be used. Contacts will not survive restart. Use this value if you need a really fast usrloc and contact persistence is not necessary or is provided by other means.

  • 1 - Write-Through scheme. All changes to usrloc are immediately reflected in database too. This is very slow, but very reliable. Use this scheme if speed is not your priority but need to make sure that no registered contacts will be lost during crash or reboot.

  • 2 - Write-Back scheme. This is a combination of previous two schemes. All changes are made to memory and database synchronization is done in the timer. The timer deletes all expired contacts and flushes all modified or new contacts to database. Use this scheme if you encounter high-load peaks and want them to process as fast as possible. The mode will not help at all if the load is high all the time. Also, latency of this mode is much lower than latency of mode 1, but slightly higher than latency of mode 0.

  • 3 - DB-Only scheme. No memory cache is kept, all operations being directly performed with the database. The timer deletes all expired contacts from database - cleans after clients that didn't un-register or re-register. The mode is useful if you configure more servers sharing the same DB without any replication at SIP level. The mode may be slower due the high number of DB operation. For example NAT pinging is a killer since during each ping cycle all nated contact are loaded from the DB; The lack of memory caching also disable the location watcher registration (in will not work with PA module) and disable the statistics exports.

a

modparam("auth_db", "calculate_ha1", yes)
modparam("auth_db", "password_column", "password")
Pozn. V prípade, že je problém s connectom na DB sa openser správa divne, usera autentifikuje a 
zároveň openserctl hádže problém s fifo.

ERROR: Error opening OpenSER's FIFO /tmp/openser_fifo
ERROR: Make sure you have the line 'modparam("mi_fifo", "fifo_name", "/tmp/openser_fifo")' in your config
ERROR: and also have loaded the mi_fifo module.

Konfigurácia auntentifikácie pri registrácií – konfigurácia Registrar.

Vložiť kód do openser.cfg alebo odkomentovať už existujúci.

Autentifikácia Proxy autentifikácie, ak volajúci je z local domény

if (!(method=="REGISTER") && from_uri==myself)
        {
                if (!proxy_authorize("", "subscriber")) {
                        proxy_challenge("", "0");
                        exit;
                }
                if (!check_from()) {
                        sl_send_reply("403","Forbidden auth ID");
                        exit;
                }

                consume_credentials();
                # caller authenticated
        }

a autentifikácie pri registrácii na registrar

if (is_method("REGISTER"))
        {
                # authenticate the REGISTER requests (uncomment to enable auth)
                if (!www_authorize("", "subscriber"))
                {
                        www_challenge("", "0");
                        exit;
                }
                ##
                if (!check_to())
                {
                        sl_send_reply("403","Forbidden auth ID");
                        exit;
                }

                if (!save("location"))
                        sl_reply_error();

                exit;
        }

 Overenie odregistrovaním a zaregistrovaním klienta, ak všetko funguje login musí byť fail ak daný user nie je v DB vytvorený.

 Pozn. Problém s vytvorením usera cez openserctl

openserctl add 1000 password 1000@voffice.com.br

 kde hádže chybu:

openserctl add 1000 password 1000@voffice.com.br
ERROR 1045 (28000): Access denied for user 'openserro'@'localhost' (using password: YES)
ERROR: user '1000' already exists

Riešenie: skontroluj, či heslá nastavené v súbore /etc/openser/openserctlrc sú také isté ako si nastavil cez phpMyAdmin v oprávneniach.

Pridanie nového používateľa

openserctl add temp temp temp@temp.sk
new user 'temp' added

ak sa do SIP UA nastavia dané hodnoty a doméne účtu, server nás autentifikuje. Cez ngrep alebo log daného SIP UA (napr. Xlite) uvidíme výmenu popísanú v call flow diagrame pre registráciu.

 

Openeser.cfg konfig s povoleným a funkčným MySQL.

 

Používanie aliasov

Aliasy umožňujú mať k SIP účtom priradené alterntívne mená. Použijeme ukladanie aliasov do DB.

Riešenie:

Odkomentuj modul, ktorý pracuje s aliasmi

loadmodule "alias_db.so"

nastav parametre modulu pristupu do DB

# ----- alias_db params -----
/* uncomment the following lines if you want to enable the DB based
   aliases */
modparam("alias_db", "db_url","mysql://openser:openserrw@localhost/openser")

 Zapni v konf skripte prehľadávanie alias tabuľky pri volaniach:

# apply DB based aliases (uncomment to enable)
        alias_db_lookup("dbaliases");

kde z manuálu na funkciu sa dozvedáme jej funkciu:

alias_db_lookup(table_name)

The function takes the R-URI and search to see whether it is an alias or not. If it is an alias for a local user, the R-URI is replaced with user’s SIP uri.

The function returns TRUE if R-URI is alias and it was replaced by user’s SIP uri.

Meaning of the parameters is as follows:

  •  table_name – the name of the table where to search for alias.

This function can be used from REQUEST_ROUTE, FAILURE_ROUTE.

 Vytvorenie aliasu

Máme vytvorených dvoch používateľov palo a 1760, sú online a registrovaný:

openserctl ul show Domain:: location table=512 records=2 max_slot=1
        AOR:: 1760
                Contact:: sip:1760@158.193.139.204:5060 Q=
                        Expires:: 11
                        Callid:: 130816788-7101012296@158.193.139.204
                        Cseq:: 3
                        User-agent:: Voip Phone 1.0
                        State:: CS_SYNC
                        Flags:: 0
                        Cflag:: 0
                        Socket:: udp:158.193.152.1:5060
                        Methods:: 4294967295
        AOR:: palo
                Contact:: sip:palo@158.193.139.182:5060 Q=
                        Expires:: 11
                        Callid:: 26864123715-36200102262@158.193.139.182
                        Cseq:: 23
                        User-agent:: Voip Phone 1.0
                        State:: CS_SYNC
                        Flags:: 0
                        Cflag:: 0
                        Socket:: udp:158.193.152.1:5060
                        Methods:: 4294967295

Používateľovy 1760 som urobil db alias 100i:

 openserctl alias_db add 100@kis.fri.uniza.sk 1760@kis.fri.uniza.sk

a overíme

  openserctl  alias_db show 100@kis.fri.uniza.sk      
+-----------------------+
| SIP-ID                |
+-----------------------+
| 1760@kis.fri.uniza.sk |
+-----------------------+

Skúška smerovania volania na alias

Podľapopisu funkcie hore môžem volať usera 100, volanie príde na server, ten prehľadá medzi používatemi usera 100 ak nenájde, prehľadá aj aliasi v DB, ak nájde alias, prepíše Request URI na oroginal SIP adresu volaného

Volanie na 100:

Pozn. konfigurácia OpenSER je default, drobne som si upravil ak prebehne alias_db_lookup aby prilepil pole do hlavičky "db alias lookup". Toto potom nájdeme v modifikovanej správe INVITE

if (alias_db_lookup("dbaliases"))
        {
            append_hf("P-hint: db alias lookup\r\n");
        }

Pozn.: append_hf() z modulu textops

 

Prvý invite od palo@kis na 100@kis došiel na server s 100@kis R-URI (nepodstatné správy vynechávam)

 INVITE sip:100@kis.fri.uniza.sk SIP/2.0.
Via: SIP/2.0/UDP 158.193.139.182:5060;branch=z9hG4bK20468687413340650;rport.
From: palo <sip:palo@kis.fri.uniza.sk>;tag=72072903.
To: "100" <sip:100@kis.fri.uniza.sk>.
Call-ID: 27341358711-46590103309@158.193.139.182.
CSeq: 1 INVITE.
Contact: <sip:palo@158.193.139.182:5060>.
max-forwards: 70.
supported: replaces.
user-agent: Voip Phone 1.0.
Allow: INVITE, ACK, OPTIONS, BYE, CANCEL, REFER, NOTIFY, SUBSCRIBE, PRACK, UPDAT
E.
Content-Type: application/sdp.
Content-Length: 292.

 a po prechode cez server už ide už pozmenená správa na 1760@kis

INVITE sip:1760@158.193.139.204:5060 SIP/2.0.
Record-Route: <sip:158.193.152.1;lr=on>.
Via: SIP/2.0/UDP 158.193.152.1;branch=z9hG4bKcddc.c31a94f3.0.
Via: SIP/2.0/UDP 158.193.139.182:5060;branch=z9hG4bK158413909698224823;rport=506
0.
From: palo <sip:palo@kis.fri.uniza.sk>;tag=7939949.
To: "100" <sip:100@kis.fri.uniza.sk>.
Call-ID: 22421469446-13181109094@158.193.139.182.
CSeq: 2 INVITE.
Contact: <sip:palo@158.193.139.182:5060>.
max-forwards: 69.
supported: replaces.
user-agent: Voip Phone 1.0.
Allow: INVITE, ACK, OPTIONS, BYE, CANCEL, REFER, NOTIFY, SUBSCRIBE, PRACK, UPDAT
E.
Content-Type: application/sdp.
Content-Length: 292.
P-hint: db alias lookup

 openser.cfg s mysql a overenými a funkčnými aliasmi v mysql.

Riešenie prepojenia medzi doménami

Aby nedochádzalo k zneužitu nášho servera pre anonymizáciu iných alebo ako výstup do telco siete.

Pozn.
Funkcie sú z modulu DOMAIN
is_from_local(), which verifies if the FROM header field contains one of the domains managed by our proxy
is_uri_host_local(), replaces the uri==myself instruction

- skusky ukazali, ze sa mi tieto funkcie nespravali korektne, problem je mozno aj v tom ze nas
stroj ma mnohe DNS zaznamy a reverz ukazuje do blba,

INVITE z nasej domeny KIS na ineho v domene KIS koncil v route logic route(23) ako 403 Forbiden

Tu treba vyriešiť kto môže volať koho. Štandardne chceme povoliť aby naši používatelia mohli volať naším (in<=>in), naší iným v iných doménach (in=>out), iní odinakiaľ nám (out=>in), ale nechceme aby volali iný iným cez náš server a používali ho ako relay. Plus samo chceme riešiť aby sa naši pri volaní a registrácii autentifikovali. Pri štrukturovanie conf skriptu som sa inšpiroval z knihy Building Telephony Systems with OpenSER.
 

Najprv poriešime spracovávanie správ, ak príde REGISTER spracuje to logika definovaná v route(12), ak iná správa, spracujeme ju v logike route(13)

if (is_method("REGISTER")) {
                # autentifikacia registracie
                route(12);
        } else {
                route(13);
        }

 

#-------------------------------
#
# -- registracia -- route (12)
#
#-------------------------------


route [12]{
        ## kontrola na autentifikaciu registracie
        sl_send_reply("100","Trying");
                # authenticate the REGISTER requests (uncomment to enable auth)
                if (!www_authorize("", "subscriber"))
                {
                        # druhy param je qop, quality of protection
                        # 1 pouzi v digets qop
                        # 0 nepouzi, v priapade ak neviem ci qop phone podporuje alebo nie

                        www_challenge("", "0");
                        exit;
                }
                ##
                if (!check_to())
                {
                        sl_send_reply("403","Forbidden auth ID");
                        exit;
                }

                if (!save("location"))
                        sl_reply_error();

                exit;
}

v route 13 kontrolujeme či je správa z lokálnej domény alebo nie, a či je Request URI lokal or nie

 

#-------------------------------
#
# -- ine spravy ako Invite -- route (13)
#
#-------------------------------

route[13]{
        ## Non-Register request handler
        #if (is_from_local()) na nasom serveri nefungovalo..invite s touto podmienkou
        # skoncil na 403 Forbiden, musel som zamenit za from_uri...
        if (from_uri==myself)
        {
                # From an internal domain -> check the credentials and FROM
                if (!proxy_authorize("","subscriber")) {
                        proxy_challenge("","0");
                        exit;
                } else if (!check_from()) {
                        sl_send_reply("403", "Forbidden, use From=ID");
                        exit;
                }
                consume_credentials();

                ## apply DB based aliases (uncomment to enable)
                alias_db_lookup("dbaliases");

                # je Request URI domace or nie?
                # if (is_uri_host_local()) na nasom serveri nefungovalo..               # invite s touto podmienkou               # skoncil na 403 Forbiden, musel som zamenit za from_uri...  
      if (uri==myself){
                        # -- Inbound to Inbound
                        route(20);
                } else {
                        # -- Inbound to outbound
                        route(21);
                }
        } else  {
                # From an external domain -> do not check credentials
                #Verify aliases, if found replace R-URI.
                alias_db_lookup("dbaliases");

                if (is_uri_host_local()) {
                        #-- Outbound to inbound
                        route(22);
                } else {
                        # -- Outbound to outbound
                        route(23);
                }
        }
}

 Volanie domácich na domácich, route(20)

#-------------------------------
#
# domaci na domaceho
# inbound to inbound
#
#-------------------------------

route[20]{
        # from an internal domain -> inbound
        # Native SIP destinations are handled using the location table

        append_hf("P-hint: inbound->inbound \r\n");

        if (!lookup("location")) {
                sl_send_reply("404", "Not Found");
                exit;
        }
        route(1);
}

Volanie domácich na cudzích route (21)

#-------------------------------
#
# domaci na cudzieho
# inbound to outbound
#
#-------------------------------
route[21]{
        # from an internal domain -> outbound
        # Simply route the call outbound using DNS search

        append_hf("P-hint: inbound->outbound \r\n");
        route(1);
}

Volanie cudzích domácim, route(22)

#-------------------------------
#
# cudzi na domaceho
# outbound to inbound
#
#-------------------------------
route[22]{
        # From an external domain -> inbound
        append_hf("P-hint: outbound->inbound\r\n");

        #Verify aliases, if found replace R-URI.
        alias_db_lookup("dbaliases");

        if (!lookup("location")) {
                sl_send_reply("404", "Not Found");
                exit;
        }
        route(1);
}

Volanie cudzích cudzím, route (23)

 
#-------------------------------
#
# cudzi na cudzieho cezo mna
# outbound to outbound relay
# zakazane
#
#-------------------------------

route[23]{
        # From an external domain -> outbound
        # we are not accepting these calls

        append_hf("P-hint: outbound->outbound \r\n");
        sl_send_reply("403","Forbidden");
        exit;
}

openser.cfg s rozchodenou interdomain routing.

 NAT traversal

Riešenia STUN alebo TURN

TURN

TURN doplňuje STUN a umiestňuje tzv. Probe do cesty signalizácii a aj media streamu. Toto Probe v podstate je akýmsi ukončovacím bodom pre médiá pre oba koncové body. Keďže daný Probe, ktorý klientovi preposiela médiá (RTP) je ten istý, ktorý pomohol klientovi určiť jeho verejnú adresu a port, o problém symetrického NAT je tým pádom postarané.

TURN riešenie nad debianom som nenašiel (11.6.2009).

OpenSER a STUN

STUN popísané, otestované a funkčné v článku. Vyžaduje SIP klienta aby ho podporoval, pri zostavovaní hovoru je väčšie oneskorenie kvôli STUN výmene správ. Nevyžaduje konfiguráciu OpenSER.

 Problém

Je tu však problém v správaní klienta, najme pokiaľ sa pouziva Softphone a máme na PC viac IP adries a rozhraní, ako napr. na nasledujúcom obr. kde mám na PC okrem svojho ethernet rozhrania vmware rozhrania (kvôli vmware server), MS loop kvôli dynagen a podobne.

V takomto prípade, keďže SIP UA je v privátnej sieti za NAT, musí UA cez STUN zistiť svoju verejnú IP. Toto funguje a ako máme aj z následujúcej INVITE správy vypísané SDP c a o pole je nastavená verejná IP zistená cez STUN, to je korektné.

Problém je však pri zakladaní hovorov, kde je v generovanej INVITE správe popis SDP relácie a ako média pre audio je tam uvedený zoznam alterntív IPčiek, a žial, privátna je hneď prvá, a verejná, zistená cez stun až posledná (žlté pole a zelené). Pri volaní sa zakladá RTP stream nesprávne a podľa typu volania nieje audio dostupné, alebo len v jednom smere, typicky z spoza NAT na verejný segement ale nie naopak. Nezistil som ako to v BRIA a Eyebeam zmeniť RTP nastavenia zatiaľ.

 INVITE sip:4323@kis.fri.uniza.sk SIP/2.0.
Via: SIP/2.0/UDP 192.168.10.108:10860;branch=z9hG4bK-d8754z-54076831111b285e-1---d8754z-;rport.
Max-Forwards: 70.
Contact: <sip:1760@158.193.152.64:6749>.
To: "4323"<sip:4323@kis.fri.uniza.sk>.
From: "1760"<sip:1760@kis.fri.uniza.sk>;tag=cc62304b.
Call-ID: OWExZDJmMTNiMDhjYzU2NGViOGY4Mjg5OWM1ZTc5NTk..
CSeq: 1 INVITE.
Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO.
Content-Type: application/sdp.
User-Agent: X-Lite release 1100l stamp 47546.
Content-Length: 627.
.
v=0.
o=- 4 2 IN IP4 158.193.152.64.
s=CounterPath X-Lite 3.0.
c=IN IP4 158.193.152.64.
t=0 0.
m=audio 6759 RTP/AVP 107 119 100 106 0 105 98 8 3 101.
a=alt:1 5 : lIMy6RHf exve4e2w 192.168.10.108 26428.
a=alt:2 4 : L8cDRAbT VVgXePRm 169.254.51.3 26428.
a=alt:3 3 : IKlen3mB vjQU+1gH 192.168.66.1 26428.
a=alt:4 2 : 3ky6ujUg NIuz7oMi 192.168.6.1 26428.
a=alt:5 1 : Nqlz89U3 6srQFBMW 158.193.152.64 6759.
a=fmtp:101 0-15.
a=rtpmap:107 BV32/16000.
a=rtpmap:119 BV32-FEC/16000.
a=rtpmap:100 SPEEX/16000.
a=rtpmap:106 SPEEX-FEC/16000.
a=rtpmap:105 SPEEX-FEC/8000.
a=rtpmap:98 iLBC/8000.
a=rtpmap:101 telephone-event/8000.
a=sendrecv.

POZN. Riešenie vyzeralo triviálne jednoduché, žiedné trápenie s OpenSER.cfg. Realita popísaná výššie spôsobila, že po pár hodinách skúšania a snifovania prechádzam na testovanie ďalšieho riešenia a to Far-end riešenie cez RTP Proxy, nakoľko iné podobné riešenie známe ako MediaProxy nemá v debiane ešte implementáciu a zatiaľ sa chcem vyhnúť kompilácii balíčkov.

 

OpenSER a RTPproxy

  1. http://www.voip-info.org/wiki/view/RTPProxy
  2. http://en.wikipedia.org/wiki/TURN
  3. OpenSER v1.2.x and RTPProxy
  4. NatHelper Openser 1.3.x module

RTPproxy je vysokovýkonný software pre RTP streamy, ktorý dokáže spolupracovať s SER a OpenSER (v súčasnosti aj Kamailio a OpenSIPS). Pôvodne bol vytvorený pre správu NAT traversal ale prakticky môže fungovať tak ako media relay aj ako brána pre RTP sessions medi IPv4 a IPv6 sieťami. Bol vyvinutý Maximom Sobolevom.
RTPproxy má zopár vychytávok, ako napríklad správa na diaľku alebo podpora škálovateľných distribuovaných SIP sietí. Modul „NATHELPER“ integrovaný do SER a OpenSER SIP proxy software dovoľuje použitie viacerých inštancií RTPproxy bežiacich na vzdialených počítačoch pre zvýšenie spoľahlivosti a rozloženie záťaže. Software taktiež podporuje video relay a nahrávanie RTP sessions.

Debian má vlastný RTPproxy balíček udržovaný debian tímom. Inštalácia popísaná u nás na serveri tu.

Na základe liniek a návodov spomenutých na začiatku ideme na openser.cfg

 

Treba načítať nathelper module do openser.

loadmodule "nathelper.so"

 Nastavenie parametrov modulu

# -- nathelper
#modparam("nathelper", "rtpproxy_sock", "udp:127.0.0.1:7890")
# pouzijem unix sock modparam("nathelper", "rtpproxy_sock", "unix:/var/run/rtpproxy/rtpproxy.sock")

Spôsob prepojenia/komunikácie medzi OpenSER a RTPProxy. Ja skúsim ísť cez unix sock.

modparam("nathelper", "natping_interval", 20) 

Definuje čas medzi intervalmi NAT pingov z SIP servera na všetkých zaregistrovaných UA v sekundách.

 

modparam("nathelper", "ping_nated_only", 1) 

Ak je nastavený param na 1, budú sa pingať len tie kontakty, ktoré majú nastavený príznak "behind_NAT" v lokačnej DB.

modparam("nathelper", "sipping_bflag", 7)

Ako budeme identtifikovať, akým flagom, NATované kontakty, na ktoré budeme robiť NATping.

 modparam("nathelper", "sipping_from", "sip:pinger@kis.fri.uniza.sk") 

Nastav SIP URI ktoré bude použité pri NATpingoch.

 

Ďalej nastav akým flagom budú kontakty spoza nat značené v usrloc (user location)

modparam("usrloc", "nat_bflag", 6)

Pozn. AVP = Attribute-Value-Pair .

Ďalej nastav aby registrar a nathelper ukladali URI, ktorá obsahuje prijaté parametre o IP, porte a protokole do AVP

modparam("registrar|nathelper", "received_avp", "$avp(i:42)")

kde $avp  je pseudopremenná OpenSER


AVPs

$(avp(id)[N]) – represents the value of N-th AVP identified by ‘id’.

The ‘id’ can be:

  • ”[si]:name” – name is the id of an AVP; ‘s’ and ‘i’ specifies if the id is string or integer. If missing, it is considered to be string.

  • “name” – the name is an AVP alias

Note: By default AVP created during initial message is available in “failure_route[]” but not in “onreply_route[]”. To get the last is needed: modparam("tm", "onreply_avp_mode", 1)


 Pridanie logiky do skriptu:

na začiatku skriptu pred has_to_tag vkladám volania na route[30], ktorá zistí či sme za NAT:

#-------------------------------
#
# -- detekcia NAT
#
#-------------------------------
route[30]{
force_rport();
        if (nat_uac_test("19")) {
                if (method=="REGISTER") {
                        fix_nated_register();
                } else {
                        fix_nated_contact();
                };
                setflag(5);
        };
} 

kde funkcia nat_uac_test() testuje, či je UAC za NAT


nat_uac_test(flags)

Tries to guess if client’s request originated behind a nat. The parameter determines what heuristics is used.

Meaning of the flags is as follows:

* 1 – Contact header field is searched for occurrence of RFC1918 addresses.
*
2 – the "received" test is used: address in Via is compared against source IP address of signaling
*
4 – Top Most VIA is searched for occurrence of RFC1918 addresses
*
8 – SDP is searched for occurrence of RFC1918 addresses
*
16 – test if the source port is different from the port in Via

All flags can be bitwise combined, the test returns true if any of the tests identified a NAT.

This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE.


a funkcia  fix_nated_register();  v prípade správy register uloži do AVP prijaté parametre


fix_nated_register()

The function creates a URI consisting of the source IP, port, and protocol and stores the URI in an Attribute-Value-Pair. The URI will be appended as "received" parameter to Contact in 200 OK and registrar will store it in the received cloumn in the location table.

Note: You have to set the received_avp parameter of the nathelper module and the registrar module (both module parameters must have the same value) to use this function.


a funkcia fix_nated_contact() pri inej správe ako register prepíše zdrojovú adresu a port spoza nat.


Rewrites Contact HF to contain request’s source address:port.

This function can be used from REQUEST_ROUTE, ONREPLY_ROUTE, BRANCH_ROUTE.


 

Ďalej do spracovávania logiky REGISTER pridáme

route [12]{

        ## kontrola na autentifikaciu registracie
        sl_send_reply("100","Trying");

                # authenticate the REGISTER requests (uncomment to enable auth)
                # odkomentoval - 28.5.09
                if (!www_authorize("", "subscriber"))
                {
                        # druhy param je qop, quality of protection
                        # 1 pouzi v digets qop
                        # 0 nepouzi, v priapade ak neviem ci qop phone podporuje alebo nie

                        www_challenge("", "0");
                        exit;
                }
                
                if (isflagset(5)) {
#setbflag(6);
# if you want OPTIONS natpings uncomment next
setbflag(7);
};

                ##                 if (!check_to())                 {                         sl_send_reply("403","Forbidden auth ID");                         exit;                 }                 #save("location");                 if (!save("location"))                         sl_reply_error();                 exit; }

Update Route[1]

route[1] {
        
        if (subst_uri('/(sip:.*);nat=yes/\1/')){
                setbflag(6);
        };

        if (isflagset(5)||isbflagset(6)) {
                route(31);
        }
# for INVITEs enable some additional helper routes
        if (is_method("INVITE")) {
                t_on_branch("2");
                t_on_reply("2");
                t_on_failure("1");
        }

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

 a v route[31] zadefinujem vynutenie alebo ukon4enie rtpproxy

route[31]{
        f (is_method("BYE|CANCEL")) {
                unforce_rtp_proxy();
        } else if (is_method("INVITE")){
                force_rtp_proxy();
                t_on_failure("1");
        };
        if (isflagset(5))
                search_append('Contact:.*sip:[^>[:cntrl:]]*', ';nat=yes');
        t_on_reply("1");
}

a ešte zadefinovať on_reply_route(1)

onreply_route[1] {

        if ((isflagset(5) || isbflagset(6)) && status=~"(183)|(2[0-9][0-9])") {
                force_rtp_proxy();
        }
        search_append('Contact:.*sip:[^>[:cntrl:]]*', ';nat=yes');

        if (isbflagset(6)) {
                fix_nated_contact();
        }
        exit;
}

 

Ďalej musíme zrušiť použitie rtpproy ak zlyha volanie vo failure_route()

failure_route[1] {
        if (isbflagset(6) || isflagset(5)) {                 unforce_rtp_proxy();         } 

        if (t_was_cancelled()) {
                exit;
        }
}

Poznámka:

Super, volanie je úspešné (volanie z mbt na UA na notebooku), RTP média tečie oboma smermi

 

MediaProxy

Openser má vlastný projekt na media proxy server na adrese http://mediaproxy.ag-projects.com a vlastný modul mediaproxy, ktorý rieši spoluprácu OpenSer a Mediaproxy.

 

Instant Messaging a Presence

Odkomentuj moduly, ktoré robia presence

/* uncomment the next two lines for presence server support
   NOTE: a DB (like mysql) module must be also loaded */
loadmodule "presence.so"
loadmodule "presence_xml.so"

a nastav parametre pre presence

# ----- presence params -----
/* uncomment the following lines if you want to enable presence */
modparam("presence|presence_xml", "db_url",mysql://openser:openserrw@localhost/openser")
modparam("presence_xml", "force_active", 1)
modparam("presence", "server_address", "sip:159.193.15ľ.1:5060")

V treťom riadku nastav IP adresu servera.

a v pripade openser 1.3.x je priamo v default konfiguráku časť na presence, odkomentujeme, vyskúšame:

/* uncomment the following lines if you want to enable presence */
                        if (is_method("SUBSCRIBE") && $rd == "your.server.ip.address") {
                              # in-dialog subscribe requests
                              route(2);
                              exit;
                        }

a dalej v cfg okomentuj prvy if a zakomentuj sl_send_reply 503

/* uncomment this if you want to enable presence server
           and comment the next 'if' block
           NOTE: uncomment also the definition of route[2] from  below */
        if( is_method("PUBLISH|SUBSCRIBE"))
                        route(2);

        #if (is_method("PUBLISH"))
        #{
        #       sl_send_reply("503", "Service Unavailable");
        #       exit;
        #}

a odkomentuj celú predpripravnú logiku v route (2)

/* uncomment the whole following route for enabling presence
   NOTE: do not forget to enable the call of this route from the main
     route */
route[2]
{
        if (!t_newtran())
        {
                sl_reply_error();
                exit;
        };

        if(is_method("PUBLISH"))
        {
                handle_publish();
                t_release();
        }
        else
        if( is_method("SUBSCRIBE"))
        {
                handle_subscribe();
                t_release();
        }

        exit;
}
Pozn. Testovanie na UA eyebeam a bria

pri default odkoment to ukaze v brii stav eyebeam usera, ale nie v eyebeam, ide poslat spravu z eyebeam na briu ale nie naopak

LInk na kamailio presence

Enum

Link: module doc.

 

Načítaj modul enum

#enum modul
loadmodule "enum.so

nastav parametre modulu

# enum params
modparam("enum","domain_suffix","e164.arpa.")

 Smerovanie na Cisco Call Manager-a (CCM)

Skontrolujem kam ide cieľ, či je to klapka or zilinske cislo

if(uri=~"^sip:[0-9]{4}@.*"){
                if(!uri=~"^sip:176[0-9]@.*"){

                # INVITE na Call Manager
                append_hf("P-hint: in ccm\r\n");

                #ccm berie plne uri s narodnym a lokal prefixom
                prefix("42141513");
                route(5);
                #exit;
                };
        };

        # lokalne volania na zilinske cisla cez 0 von na ZA
        # ktore zacinaju cislom 0 a su dlhe max 9 znakov
        # pridam prefix SVK + ZA a presmerujem na CCM
        if(uri=~"^sip:[0-9]{7,14}@.*"){
                # INVITE na Call Manager
                append_hf("P-hint: in ccm\r\n");
                append_hf("P-hint: ZA volania \r\n");
                #ccm berie plne uri s narodnym a lokal prefixom
                prefix("42141");
                route(5);
        };
 

 

 

a potom volám Call managera cez route [5]

#-------------------------------
#
# -- forward na CCM
#
#-------------------------------

route[5]{
    rewritehostport("IP_ADRESA_CCM:PORT_NA_KTOROM_POCUVA");
    route(1);
}

 

 

 

Rate this post

Pridaj komentár

Vaša e-mailová adresa nebude zverejnená. Vyžadované polia sú označené *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

The reCAPTCHA verification period has expired. Please reload the page.