{"id":557,"date":"2013-01-15T14:49:04","date_gmt":"2013-01-15T13:49:04","guid":{"rendered":""},"modified":"2018-11-01T00:46:12","modified_gmt":"2018-10-31T23:46:12","slug":"kamailio-call-establishment-permission-rules","status":"publish","type":"post","link":"https:\/\/nil.uniza.sk\/en\/kamailio-call-establishment-permission-rules\/","title":{"rendered":"Kamailio Call establishment permission rules"},"content":{"rendered":"<p>\n\tThis article talks about deploying permission control mechanism for call establishment in Kamailio SIP Proxy.<\/p>\n<p>\n\tIn many VoIP solutions, it is crutial to deploy numbering scheme and write down rules where users are\/aren&#39;t allowed to call.<br \/>\n\tOn top of that, a company can allow the people to call outside, for example to PSTN. The rules can change over time as well as the numbering scheme itself.<\/p>\n<p>\n\tThis increases the demand to maintain the numbering system and permission rules for system administrators in a easy-to-use way. It is not feasible to rewrite the configuration files all over again and again.<\/p>\n<p>\n\t&nbsp;<\/p>\n<p>\n\tThere is a module for Kamailio SIP server, called&nbsp;<a href=\"http:\/\/kamailio.org\/docs\/modules\/stable\/modules_k\/permissions.html\"><u><em>permissions<\/em><\/u><\/a>, which enables us to tell Kamailio to check every caller and callee info. Based on this info, Kamailio can decide if the call can be routed or not. The configuration is pretty easy and works for versions 3.3.x and 4.0.<\/p>\n<p>\n\t<strong>Changes for kamailio.cfg file:<\/strong><\/p>\n<p>\n\tFirst, we define a directive in the &quot;defined values&quot; section that we can use later to easily turn on\/off the permissions checking:<\/p>\n<pre>\r\n#!define WITH_PERMISSIONS<\/pre>\n<p>\n\tNext, in the modules section, we actually have to load the module (We don&#39;t need to install it. It is a part of default installation of Kamailio):<\/p>\n<pre>\r\n#!ifdef WITH_PERMISSIONS\r\nloadmodule &quot;permissions.so&quot;\r\n#!endif<\/pre>\n<p>\n\tIn the module parameters section we can define where the files that store the rules are:<\/p>\n<pre>\r\n#!ifdef WITH_PERMISSIONS\r\nmodparam(&quot;permissions&quot;,&quot;default_allow_file&quot;,&quot;\/etc\/kamailio\/rules.allow&quot;)\r\nmodparam(&quot;permissions&quot;,&quot;default_deny_file&quot;,&quot;\/etc\/kamailio\/rules.deny&quot;)\r\n#!endif<\/pre>\n<address>\n\tnote: these are not the default names of the files, so they have to be specified. See the documentation of the permissions module for more information.<\/address>\n<p>\n\tThe last step is to incorporate the module functionality to the routing logic. In the main routing block &quot;request_route&quot; you can add<\/p>\n<pre>\r\n#!ifdef\r\nroute(PERMISSIONS_AUTHORIZE);\r\n#!endif<\/pre>\n<p>\n\tright before <em>route(SIPOUT);<\/em> if you didn&#39;t alter the routing logic before. The new route itself looks like:<\/p>\n<pre>\r\nroute[PERMISSIONS_AUTHORIZE] {\r\n  #!ifdef WITH_PERMISSIONS\r\n  if(allow_routing())\r\n  {\r\n    xlog(&quot;L_NOTICE&quot;,&quot;Routing allowed for $fu calling $ru&quot;);\r\n  }\r\n  else\r\n  {\r\n    xlog(&quot;L_NOTICE&quot;,&quot;Routing denied for $fu calling $ru&quot;);\r\n    sl_send_reply(&quot;403&quot;,&quot;Routing Not Allowed&quot;);\r\n    exit;\r\n  }\r\n  #!endif\r\n}<\/pre>\n<p>\n\tAnd that&#39;s it! Now we have to create the files that will contain the permission rules. As we specified in the routing logic, we need files <em>\/etc\/kamailio\/rules.allow<\/em> and <em>\/etc\/kamailio\/rules.deny<\/em>.<\/p>\n<p>\n\tThis is an example of the allow file that comes with the Kamailio source code:<\/p>\n<pre>\r\n# SIP Express Router permissions module config file\r\n# Syntax:\r\n# from_list [EXCEPT from_list] : req_uri_list [EXCEPT req_uri_list]\r\n#\r\n# from_list and req_uri_list are comma separated expressions\r\n# Expressions are treated as case insensitive POSIX Extended Regular Expressions\r\n# Keyword ALL matches any expression.\r\n#\r\n# Examples:\r\n# ALL : &quot;^sip:361[0-9]*@abc.com$&quot; EXCEPT &quot;^sip:361[0-9]*3@abc.com$&quot;, &quot;^sip:361[0-9]*4@abc.com$&quot;\r\n#\r\n# &quot;^sip:3677[0-9]*@abc.com$&quot; : &quot;^sip:361[0-9]*@abc.com$&quot;\r\n#\r\n# ALL : ALL<\/pre>\n<p>\n\t&nbsp;<\/p>\n<p>\n\tAs you can see, single-line comments begin with &quot;#&quot; sign and the syntax is explained. Let&#39;s have a look at our example rule:<\/p>\n<p>\n\t&nbsp;<\/p>\n<pre>\r\n&quot;^sip:1[0-9]{3}@awesome_domain.com$&quot; EXCEPT &quot;^sip:1111@awesome_domain.com$&quot;, &quot;^sip:1112@awesome_domain.com$&quot; : &quot;^sip:2[0-9]{3}@awesome_domain.com&quot;<\/pre>\n<p>\n\tThis rule tells us that users from our awesome domain with numbers from &lt;1000-1999&gt; range (except numbers 1111 and 1112) are allowed to call to numbers &lt;2000-2999&gt;.<\/p>\n<p>\n\tNow examine this example:<\/p>\n<pre>\r\n&quot;^sip:hr-*@awesome_domain.com$&quot; : ALL EXCEPT &quot;^sip:the-boss@awesome_domain.com&quot;<\/pre>\n<p>\n\tThis states that HR department (with SIP URI hr-&#8230;&#8230;..@awesome_domain.com) is not limited in making calls, except they can&#39;t call the boss to fire him \ud83d\ude42<\/p>\n<p>\n\t&nbsp;<\/p>\n<p>\n\tThese two examples were from the allow file! The same syntax applies for the deny rules as well.<\/p>\n<p>\n\tA single rule<\/p>\n<pre>\r\nALL : ALL<\/pre>\n<p>\n\tin the deny file will deny all routing and you can only allow call you explicitly specify in the allow file.<\/p>\n<p>\n\tFor more information how the rules are treated and files evaluated, you should have a look at the documentation of permissions module, <a href=\"http:\/\/kamailio.org\/docs\/modules\/stable\/modules_k\/permissions.html#sec-call-routing\">this section<\/a> in particular.<\/p>\n<p>\n\t&nbsp;<\/p>\n<p>\n\tKamailio needs to be restarted in order for the new configuration to take effect. Restart is also necessary everytime the rules files change.<\/p>\n<pre>\r\nshell# \/etc\/init.d\/kamailio restart<\/pre>\n<p>\n\t&nbsp;<\/p>\n<p>\n\tThat concludes the configuration of Kamailio SIP server.<\/p>\n<p>\n\t&nbsp;<\/p>\n<p>\n\t&nbsp;<\/p>\n<p>\n\t&nbsp;<\/p>\n<p>\n\tWhat comes next is a consideration how to maintain the permission rules in the files. When Kamailio is running on a single node, it is not a problem to manage the rules simply by editing the files and restarting Kamailio. But what if many Kamailio instances run on many different nodes of a computer cluster to provide High Availability or Load Balancing? Or what if a computer breaks down and you lose the files? There is a need to keep the rules on some external storage (i.e. database) and configure cluster nodes to download them.<\/p>\n<p>\n\tThe next paragraph talks about ways how to do this. In the end the option I consider the best is explained more in depth as well as the configuration itself.<\/p>\n<p>\n\t&nbsp;<\/p>\n<p>\n\tOne option is to store the contents of the allow and deny files in the database. All that is required is a single table that would hold two rows (one for allow file and one for deny file). There are ways how to store text files in different database systems, like for example CLOB data type in Oracle. Mysql offers ways like using the LOAD DATA INFILE. Once the file contents are in database, all that remains is to write a script that will pull the data and save them in the local files on HDD. This can be done in many ways. Kamailio is capable of calling Lua scripting language. This language have resources of handling DB results and writing to local files (using modules SQLops, App_Lua and Rtimer). Using Lua would mean, that Kamailio itself would be responsible for downloading the files periodically. If Kamailio fails, files are not refreshed. (note: Keep in mind that if you are calling Lua script from Kamailio, the file which contains the script must belong to user running Kamailio). If you would like to keep it out of Kamailio, there is a possibility to call perl or python scripts directly from Linux, for example.<\/p>\n<p>\n\tDrawback of this solution is the fact that the whole content of the file is stored in one row od DB table. Once it is edited, the row has to be replaced by a new one.<\/p>\n<p>\n\tFrom the structure of the files we can see that it would be better to store the rules in database as 1 row = 1 rule. This would enable the administrator to add, remove or edit a single rule. Database can be accessed from many different systems, so creation of various interfaces for editing the rules is and easy task.<\/p>\n<p>\n\tLet&#39;s have a look how to do this. The following example works with Oracle DB which is accessed using UnixODBC, but changing the syntax to your DB system should not be a problem.<\/p>\n<p>\n\tWe can create a table permissions_rules that will look like this:<\/p>\n<pre>\r\nCREATE TABLE permissions_rules (\r\n  type VARCHAR2(1) default &#39;&#39; CONSTRAINT check_type CHECK (type IN (&#39;A&#39;,&#39;D&#39;)) NOT NULL,\r\n  rule VARCHAR2(300) NOT NULL,\r\n  last_change DATE NOT NULL\r\n);\r\nCREATE OR REPLACE TRIGGER permissions_rules_tr\r\nbefore insert on permissions_rules FOR EACH ROW\r\nBEGIN\r\n  :NEW.last_change:=sysdate;\r\nEND permissions_rules_tr;\r\n\/<\/pre>\n<p>\n\t&nbsp;<\/p>\n<p>\n\tThe column rule stores the specific rule and the column type holds the information whether the rule is of allow or deny type. Type can only have value of &quot;A&quot; or &quot;D&quot;. Trigger before insert on this table only inputs the current sysdate to the last column.<\/p>\n<p>\n\t&nbsp;<\/p>\n<p>\n\tFollowing python script is used to download the rules and construct the files. Python is a part of many Linux distributions. You need to install package python-pyodbc (for Debian\/Ubuntu) or pyodbc (for Fedora\/RedHat).<\/p>\n<address>\n\tnote: The installation and configuration of UnixODBC is not a part of this example. Many good tutorials can be found online and ODBC can be configured to access all DB systems.<\/address>\n<p>\n\tInstall pyodbc:<\/p>\n<pre>\r\n(for Debian\/Ubuntu) shell# apt-get install python-pyodbc\r\n(for Fedora\/RedHat) shell# yum install pyodbc<\/pre>\n<p>\n\tCreate a file named \/etc\/kamailio\/permissions_python.py:<\/p>\n<pre>\r\nimport pyodbc\r\ncnxn=pyodbc.connect(&#39;DSN=OracleSIPGateway;UID=sipgateway_cs_ro;PWD=1%2%3%DB&#39;)\r\ncursor1=cnxn.cursor()\r\ncursor2=cnxn.cursor()\r\n\r\n###first allow file rules\r\n#open file for writing\r\nf=open(&#39;\/etc\/kamailio\/rules.allow&#39;,&#39;w&#39;)\r\n\r\n#write some header stuff to the file.. like syntax etc.\r\nf.write(&quot;# SIP Express Router permissions module config file\\n# allowfile\\n# Syntax:\\n&quot;)\r\nf.write(&quot;# from_list [EXCEPT from_list] : req_uri_list [EXCEPT req_uri_list]\\n#\\n&quot;)\r\nf.write(&quot;# from_list and req_uri_list are comma separated expressions\\n&quot;)\r\nf.write(&quot;# Expressions are treated as case insensitive POSIX Extended Regular Expressions\\n&quot;)\r\nf.write(&quot;# Keyword ALL matches any expression.\\n#\\n&quot;)\r\nf.write(&quot;# Examples:\\n# ALL : \\&quot;^sip:361[0-9]*@abc.com$\\&quot; EXCEPT \\&quot;^sip:361[0-9]*3@abc.com$\\&quot;, \\&quot;^sip:361[0-9]*4@abc.com$\\&quot;\\n&quot;)\r\nf.write(&quot;#\\n# \\&quot;^sip:3677[0-9]*@abc.com$\\&quot; : \\&quot;^sip:361[0-9]*@abc.com$\\&quot;\\n#\\n# All : ALL\\n&quot;)\r\n\r\n#fetch rows and write them to file\r\nfor row in cursor1.execute(&quot;select rule from permissions_rules where type like &#39;A&#39;&quot;):\r\n    #you can do a lot of things with the rule before writing it to file.. for example syntaxt checking\r\n    f.write(row[0])\r\n    f.write(&#39;\\n&#39;)\r\n\r\nf.close()\r\n\r\n###the same for deny rules\r\nf=open(&#39;\/etc\/kamailio\/rules.deny&#39;,&#39;w&#39;)\r\n\r\n#write some header stuff to the file.. like syntax etc.\r\nf.write(&quot;# SIP Express Router permissions module config file\\n# denyfile\\n# Syntax:\\n&quot;)\r\nf.write(&quot;# from_list [EXCEPT from_list] : req_uri_list [EXCEPT req_uri_list]\\n#\\n&quot;)\r\nf.write(&quot;# from_list and req_uri_list are comma separated expressions\\n&quot;)\r\nf.write(&quot;# Expressions are treated as case insensitive POSIX Extended Regular Expressions\\n&quot;)\r\nf.write(&quot;# Keyword ALL matches any expression.\\n#\\n&quot;)\r\nf.write(&quot;# Examples:\\n# ALL : \\&quot;^sip:361[0-9]*@abc.com$\\&quot; EXCEPT \\&quot;^sip:361[0-9]*3@abc.com$\\&quot;, \\&quot;^sip:361[0-9]*4@abc.com$\\&quot;\\n&quot;)\r\nf.write(&quot;#\\n# \\&quot;^sip:3677[0-9]*@abc.com$\\&quot; : \\&quot;^sip:361[0-9]*@abc.com$\\&quot;\\n#\\n# All : ALL\\n&quot;)\r\n\r\nfor row in cursor2.execute(&quot;select rule from permissions_rules where type like &#39;D&#39;&quot;):\r\n    #again, syntax verification etc. is possible here\r\n    f.write(row[0])\r\n    f.write(&#39;\\n&#39;)\r\n\r\nf.close()\r\n\r\ncnxn.close()<\/pre>\n<p>\n\t&nbsp;<\/p>\n<p>\n\tNext thing to do is to create a bash script that will call this python code and in the end it will restart Kamailio.<\/p>\n<p>\n\tCreate file \/etc\/kamailio\/permissions_script.sh:<\/p>\n<pre>\r\n#!\/bin\/bash\r\n\r\necho &quot;Downloading Permissions rules and constructing files for Kamailio!&quot; &gt;&gt; \/var\/log\/syslog #use \/var\/log\/messages on Fedora\/RedHat\r\n\r\n#fire python script\r\npython \/etc\/kamailio\/permissions_python.py\r\n\r\n#if only one Kamailio instance is running in a cluster, check if it is on this node:\r\nstr=`\/etc\/init.d\/kamailio status`\r\nif [[ &quot;$str&quot; == *pid* ]]\r\nthen\r\n  #if this node is running Kamailio, restart it\r\n  echo &quot;Restarting Kamailio!&quot; &gt;&gt; \/var\/log\/syslog #use \/var\/log\/messages on Fedora\/RedHat\r\n  \/etc\/init.d\/kamailio restart;\r\nfi<\/pre>\n<div>\n\t&nbsp;And don&#39;t forget to add execute rights<\/div>\n<pre>\r\nshell# chmod +x \/etc\/kamailio\/permissions_script.sh<\/pre>\n<p>\n\tNow use <em>cron <\/em>to call this script when you desire. For example, in some setups it is sufficient for permissions rules to be refreshed every 12 hours.<\/p>\n<pre>\r\nshell# crontab -e<\/pre>\n<address>\n\tnote: you can change the cron default editor to your favorite one by shell command &quot;export EDITOR=your_editor&quot; \ud83d\ude42<\/address>\n<p>\n\tOnce you are at the cron edit screen, create your times:<\/p>\n<pre>\r\n0 7,19 * * * \/etc\/kamailio\/permissions_script.sh<\/pre>\n<p>\n\tThis will download permissions rules every day at 7:00 and 19:00. Good idea is to customize cron to call the script when the server load is lowest within a single day.<\/p>\n<p>\n\tAfter editing crontab, restart crond:<\/p>\n<pre>\r\nshell# \/etc\/init.d\/crond restart<\/pre>\n<p>\n\tAnd that&#39;s it. This will download the rules from the database and save them in your local files. The python script can be extended to verify the syntax of the rule and output some debug messages to syslog when opening the files or database connection.<\/p>\n<p>\n\tAnother great idea is to call this script before Kamailio starts. That can be achieved by modifying the \/etc\/init.d\/kamailio script, by adding line &quot;python \/etc\/kamailio\/permissions_python.py&quot; right in the beggining of the start() function.<\/p>\n<p>\n\t&nbsp;<\/p>\n<p>\n\t&nbsp;<\/p>\n<p>\n\tAs said before, there are many different ways how to interact with the database table and it&#39;s contents.<\/p>\n<p>\n\tLet&#39;s say that the administrator changes the content of a file locally and wants to populate the changes over all the nodes. Here is a small bash script that will allow him to upload new rules to database (while erasing all the old ones). This script also enables him to insert or remove a single rule from database (following the correct syntax) and check current contents of the database table.<\/p>\n<p>\n\tWe will name the script file &quot;SIPuser&quot;:<\/p>\n<p>\n\t&nbsp;<\/p>\n<pre>\r\n#!\/bin\/bash\r\n\r\ndomain=&quot;my_domain.com&quot;\r\ndbdsn=&quot;myDSNfromODBCconfig&quot;\r\ndbuser=&quot;Chewbacca&quot;\r\ndbpassword=&quot;port123&quot;\r\n\r\ncase &quot;$1&quot; in\r\n  permissions)\r\n    case &quot;$2&quot; in\r\n      add)\r\n        case &quot;$3&quot; in\r\n          allow)\r\n            type=&quot;A&quot;\r\n            ;;\r\n          deny)\r\n            type=&quot;D&quot;\r\n            ;;\r\n          *)\r\n            echo &quot;Incorrect rule specification&quot;\r\n            exit 1;\r\n            ;;\r\n        esac\r\n        #there can be rule validation here.. TODO\r\n        echo &quot;insert into permissions_rules(type,rule) values (&#39;$type&#39;,&#39;$4&#39;);&quot; | isql $dbdsn $dbuser $dbpassword &gt; \/dev\/null\r\n        echo &quot;Rule added to database!&quot;\r\n        ;;\r\n      rm)\r\n        case &quot;$3&quot; in\r\n          allow)\r\n            type=&quot;A&quot;\r\n            ;;\r\n          deny)\r\n            type=&quot;D&quot;\r\n            ;;\r\n          *)\r\n            echo &quot;Incorrect rule specification&quot;\r\n            exit 1;\r\n            ;;\r\n        esac\r\n        #there can be rule validation here.. TODO\r\n        echo &quot;delete from permissions_rules where type like &#39;$type&#39; and rule like &#39;$4&#39;;&quot; | isql $dbdsn $dbuser $dbpassword &gt; \/dev\/null\r\n        echo &quot;Rule removed from database!&quot;\r\n        ;;\r\n      show)\r\n        echo &quot;rules.allow rules in database:&quot;\r\n        echo &quot;select rule from permissions_rules where type like &#39;A&#39;;&quot; | isql $dbdsn $dbuser $dbpassword -du -b\r\n        echo\r\n        echo &quot;rules.deny rules in database:&quot;\r\n        echo &quot;select rule from permissions_rules where type like &#39;D&#39;;&quot; | isql $dbdsn $dbuser $dbpassword -du -b\r\n        ;;\r\n      upload)\r\n        echo &quot;caution: use this only on machine, where Kamailio is running in order to maintain file consistency!&quot;\r\n        read -p &quot;Are you sure you want to continue? [y\/N] &quot; decision\r\n        decision=`echo $decision | tr &#39;[A-Z]&#39; &#39;[a-z]&#39;`\r\n        if [ &quot;$decision&quot; == &quot;y&quot; ]; then\r\n          echo &quot;Removing old rules from DB.&quot;\r\n          echo &quot;delete from permissions_rules;&quot; | isql $dbdsn $dbuser $dbpassword &gt; \/dev\/null\r\n          echo &quot;Done.&quot;\r\n          #allow rules:\r\n          echo -n &quot;Parsing and uploading rules.allow file rules...&quot;\r\n          cat \/etc\/kamailio\/rules.allow | while read line\r\n          do\r\n            if [ &quot;${line:0:1}&quot; != &quot;#&quot; ]; then\r\n              echo &quot;insert into permissions_rules(type,rule) values(&#39;A&#39;,&#39;$line&#39;);&quot; | isql $dbdsn $dbuser $dbpassword &gt; \/dev\/null\r\n            fi\r\n          done\r\n          echo &quot;Allow rules uploaded!&quot;\r\n          #deny rules:\r\n          echo -n &quot;Parsing and uploading rules.deny file rules...&quot;\r\n          cat \/etc\/kamailio\/rules.deny | while read line\r\n          do\r\n            if [ &quot;${line:0:1}&quot; != &quot;#&quot; ]; then\r\n              echo &quot;insert into permissions_rules(type,rule) values(&#39;D&#39;,&#39;$line&#39;);&quot; | isql $dbdsn $dbuser $dbpassword &gt; \/dev\/null\r\n            fi\r\n          done\r\n          echo &quot;Deny rules uploaded!&quot;\r\n        else\r\n          echo\r\n        fi\r\n        ;;\r\n      *)\r\n       echo &quot;Incorect input.&quot;\r\n       exit 1;\r\n       ;;\r\n    esac\r\n    exit 0;\r\n    ;;\r\n  *)\r\n    echo &quot;Syntax:&quot;\r\n    echo &quot;  permissions:&quot;\r\n    echo &quot;    SIPuser permissions add &lt;allow|deny&gt; &#39;&lt;rule&gt;&#39;   ...  adds new rule &lt;rule&gt; of type allow or deny to the database&quot;\r\n    echo &quot;                                                         (don&#39;t forget to enclose the &lt;rule&gt; in \\&quot;&#39;\\&quot; signs)&quot;\r\n    echo &quot;    SIPuser permissions rm &lt;allow|deny&gt; &#39;&lt;rule&gt;&#39;    ...  removes rules &lt;rule&gt; of type allow or deny to the database&quot;\r\n    echo &quot;                                                         (don&#39;t forget to enclose the &lt;rule&gt; in \\&quot;&#39;\\&quot; signs)&quot;\r\n    echo &quot;    SIPuser permissions show            ...  shows the database stored rules&quot;\r\n    echo &quot;    SIPuser permissions upload          ...  uploads the rules stored in local rules.allow|deny files to the database&quot;\r\n    echo &quot;                                             (caution: use this only on machine, where Kamailio is running in order to maintain&quot;\r\n    echo &quot;                                              file consistency!)&quot;\r\n    echo\r\n    exit 2\r\n    ;;\r\nesac<\/pre>\n<p>\n\tThis script utilizes <em>isql<\/em> command, which is part of the ODBC package. This script is only a simple example of interaction with the database, but can be used for quick tasks. Surely other, for example web-based applications can be developed to edit contents of the database.<\/p>\n<p>\n\t&nbsp;<\/p>\n<p>\n\tIn this article I tried to talk about permission checking for call establishment in Kamailio SIP server and synchronization of permissions rules across multiple cluster nodes.<\/p>\n<p>\n\tBear in mind that this is NOT the only way of achieving the goal :). Any comments are welcome.<\/p>","protected":false},"excerpt":{"rendered":"<p>\n\tThis article talks about deploying permission control mechanism for call establishment in Kamailio SIP Proxy.<\/p>\n<p>\n\tIn many VoIP solutions, it is crutial to deploy numbering scheme and write down rules where users are\/aren&#39;t allowed to call.<br \/>\n\tOn top of that, a company can allow the people to call outside, for example to PSTN. The rules can change over time as well as the numbering scheme itself.<\/p>","protected":false},"author":449,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_seopress_robots_primary_cat":"","_seopress_titles_title":"","_seopress_titles_desc":"","_seopress_robots_index":"","_kad_blocks_custom_css":"","_kad_blocks_head_custom_js":"","_kad_blocks_body_custom_js":"","_kad_blocks_footer_custom_js":"","_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"footnotes":""},"categories":[781,685,771,677],"tags":[],"class_list":["post-557","post","type-post","status-publish","format-standard","hentry","category-kamailio-en","category-linux_-_howto-en","category-sip-en","category-ip-telephony-voip"],"taxonomy_info":{"category":[{"value":781,"label":"Kamailio"},{"value":685,"label":"Linux - HOWTO"},{"value":771,"label":"SIP"},{"value":677,"label":"VoIP"}]},"featured_image_src_large":false,"author_info":{"display_name":"","author_link":"https:\/\/nil.uniza.sk\/en\/author\/"},"comment_info":3,"category_info":[{"term_id":781,"name":"Kamailio","slug":"kamailio-en","term_group":0,"term_taxonomy_id":779,"taxonomy":"category","description":"","parent":771,"count":29,"filter":"raw","cat_ID":781,"category_count":29,"category_description":"","cat_name":"Kamailio","category_nicename":"kamailio-en","category_parent":771},{"term_id":685,"name":"Linux - HOWTO","slug":"linux_-_howto-en","term_group":0,"term_taxonomy_id":683,"taxonomy":"category","description":"","parent":0,"count":71,"filter":"raw","cat_ID":685,"category_count":71,"category_description":"","cat_name":"Linux - HOWTO","category_nicename":"linux_-_howto-en","category_parent":0},{"term_id":771,"name":"SIP","slug":"sip-en","term_group":0,"term_taxonomy_id":769,"taxonomy":"category","description":"","parent":0,"count":23,"filter":"raw","cat_ID":771,"category_count":23,"category_description":"","cat_name":"SIP","category_nicename":"sip-en","category_parent":0},{"term_id":677,"name":"VoIP","slug":"ip-telephony-voip","term_group":0,"term_taxonomy_id":675,"taxonomy":"category","description":"","parent":673,"count":3,"filter":"raw","cat_ID":677,"category_count":3,"category_description":"","cat_name":"VoIP","category_nicename":"ip-telephony-voip","category_parent":673}],"tag_info":false,"_links":{"self":[{"href":"https:\/\/nil.uniza.sk\/en\/wp-json\/wp\/v2\/posts\/557","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nil.uniza.sk\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nil.uniza.sk\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nil.uniza.sk\/en\/wp-json\/wp\/v2\/users\/449"}],"replies":[{"embeddable":true,"href":"https:\/\/nil.uniza.sk\/en\/wp-json\/wp\/v2\/comments?post=557"}],"version-history":[{"count":0,"href":"https:\/\/nil.uniza.sk\/en\/wp-json\/wp\/v2\/posts\/557\/revisions"}],"wp:attachment":[{"href":"https:\/\/nil.uniza.sk\/en\/wp-json\/wp\/v2\/media?parent=557"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nil.uniza.sk\/en\/wp-json\/wp\/v2\/categories?post=557"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nil.uniza.sk\/en\/wp-json\/wp\/v2\/tags?post=557"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}