Thursday, April 18, 2019

Simple Albert laucher plugin for managing VPN's

For some reasons now switched to Linux laptop from Macbook. And as an amazing replacement for Alfred launcher found Albert.
It also have a powerful plugin system and simple workflows could be created really fast.
One of workflows I used to in Alfred is switch VPN's on/off directly from Alfred's interface. As it's all opensource, answer is quite simple - if you need something, write it.
So, as a small task during sickness wrote a plugin for toggling VPN's state, that are managed through NetworkManager.


Looks like this:


Code is simple and published here

Thursday, March 14, 2019

Simple Call ACL App for FusionPBX

Made a simple Call Access Control List application for FusionPBX

Idea is to have a set of rules, that will be match on Caller and Callee number to allow or reject this call.
As an example - simple limit certain extension to call only certain numbers. Or block some callers to call exact this extension.

All is done on regex-like simple patterns.

As an example in screen below, extension 902 (or any number contains 902) can't dial any number, unless it contains 901 (extension 901 as well)


Rules are applied in order.

This app now is a part of my fork of FusionPBX, but fully compatible with vanilla Fusion version 4.4

To install it

# cd /usr/src
# git clone -b 4.4 https://github.com/samael33/fusionpbx.git fusionpbx-samael
# cp -r fusionpbx-samael/app/call_acl /var/www/fusionpbx/app/
# mkdir -p /var/www/fusionpbx/resources/install/scripts/app/custom
# cp -r fusionpbx-samael/resources/install/scripts/app/custom/call_acl /var/www/fusionpbx/resources/install/scripts/app/custom
# cp -r fusionpbx-samael/resources/install/scripts/app/app_custom.lua /var/www/fusionpbx/resources/install/scripts/app/
# cp -r fusionpbx-samael/app/dialplans/resources/switch/conf/dialplan/041_call_acl.xml /var/www/fusionpbx/app/dialplans/resources/switch/conf/dialplan

(optional)
# chown -R www-data. /var/www/fusionpbx

FusionPBX Menu -> Advanced -> Upgrade -> Schema + App Defaults + Menu Defaults + Permission Defaults

Note, by default in Dialplan call_acl by default is disabled. Done this is mainly cause you don't want to enable it  on all domains. So, enable it per domain.

For cons - it's really heavy under high load and with big number of rules, cause heavily using regular expressions which are not super fast.

Wednesday, March 6, 2019

SIP/Kamaiio not-reachable endpoints and timers.

According to RFC3261 we have following mechanism of reliability:
(3 next blocks are taken from this book)


For non-INVITE transactions, a SIP timer, T1, is started by a UAC or a stateful proxy server when a new request is generated or sent. If no response to the request (as identified by a response containing the identical local tag, remote tag, Call-ID, and CSeq) is received when T1 expires, the request is resent. After a request is retransmitted, the next timer period is doubled until T2 is reached. 
If a provisional (informational class 1xx) response is received, the UAC or stateful proxy server immediately switches to timer T2. After that, the remaining retrans- missions occur at T2 intervals. This capped exponential backoff process is continued until a 64*T1, after which the request is declared dead. 


For an INVITE transaction, the retransmission scheme is slightly different. INVITEs are retransmitted starting at T1, and then the timer is doubled after each retransmission. The INVITE is retransmitted until 64*T1 after which the request is declared dead. After a provisional (1xx) response is received, the INVITE is never retransmitted. A stateful proxy must store a forwarded request or generated response message for 32 seconds. 

Suggested default values for T1 and T2 are 500 ms and 4 seconds, respectively. Timer T1 is supposed to be an estimate of the roundtrip time (RTT) in the network.

Main problem here is if remote side is dead, that we can get it after only 32 seconds. Which is too big, especially when we have some conditions like forward on not reachable. So, normally, decision is taken after not receiving provisional (1xx) response after 5 (or less) seconds. 

Kamailio has a fr_timer to control these type of behavior. By default, it's fully compatible with RFC. But it's not what we need. So, idea is to have fr_timer small initially and then - restore it on receiving provisional reply.

...
route[ON_START_TRANSACTION] {
    t_set_fr(INVITE_TIMEOUT, 2000);
    route(REAY);
}
...
reply_route {
   ...
    if(status =~ "1[0-9][0-9]") {
        # Not set INVITE TIMEOUT here to prevent possible custom values
        t_set_fr(0, 30000);
    }
   ...
}

failure_route {
    ....
    # Restore timers if was reset.
    t_set_fr(INVITE_TIMEOUT, 2000);
    ....
    route(TRY_NEXT_DESTINATION);
}
...

Friday, August 3, 2018

Bulk Import Extensions/Devices to FusionPBX

FusionPBX is a really great software. So, community is constantly expanding it possibilities and adding new features.
On of these expands - app for bulk import extensions/devices/voicemails from CSV file.


Idea is quite simple - you upload CSV file, it's being processed and shows you a preview where you can select which field corresponding to which row (or column) of the file.

Installation is quite simple. I've made it in my fork of FusionPBX, but it's fully compatible with original one.

On your server

cd /usr/src

# If you're using 4.2 of FusionPBX - replace 4.4 with 4.2 below, 
#  but point, only 4.4 version is supported now
git clone -b 4.4 https://github.com/samael33/fusionpbx fusionpbx-samael 

mv fusionpbx-samael/app/bulk_import_extensions /var/www/fusionpbx/app
chown -R www-data:www-data /var/www/fusionpbx/app/bulk_import_extensions
rm -r fusionpbx-samael

::
Log into the FusionPBX webpage
Advanced -> Upgrade
Menu Defaults and Permission Defaults.
Log out and back in.

Monday, July 2, 2018

Phonebook app for FusionPBX

No secret, that FusionPBX has it's own AddressBook named Contacts. But I actually found it too heavy for a simple app for provisioning phones. And lack of organizing.
Quick googling found this app by DigiDaz. I've been using it a while, but found way it's organized with groups a bit strange.
I redesigned it (I'd say redo around 70-80% of code) and comes up with my version of it.
So, new version of FusionPBX Phonebook app.
1. Supports Yealink, Cisco (via XML_Directory_Service), Snom. Adding new formats is quite simple.
2. More focus on security, as other apps requite auth and normally does it with API key mechanism build into FusionPBX. If you want to stay without auth, you can set variable Phonebook - Auth (text) to False in Default Settings.

For Cisco XML directory need to change default nginx profile, as Cisco does not support HTTPS unless it's Cisco singed certificates.

/etc/nginx/sites-enabled/fusionpbx
...
server {
        listen 80;
        server_name fusionpbx;
        if ($uri !~* ^.*(provision|phonebook\/directory).*$) {
                rewrite ^(.*) https://$host$1 permanent;
                break;
        }
...

Example of how to put this in template for Cisco can be found here.
For Yealink - same as described in video in original post.
For Snom - add this lines at your FusionPBX template

<!-- Phonebook Support via app -->
{if isset($snom_phonebook_url)}
{fetch file=''|cat:$snom_phonebook_url|cat:'&vendor=snom'}
{/if}

For every template use corresponding variables in Device (or Domain/Global) settings.

App itself could be found for both 4.4 and 4.2 versions of FusionPBX.

Wednesday, April 11, 2018

FreeSwitch - call through registered extension

Sometimes with SIP PBX you have a trunk, that registers on PBX. Most common example - various gateways.
Asterisk has a simple solution for this (as in Asterisk difference between trunk and extension is more cosmetic, than functional), but FreeSWITCH uses concept of gateways.

But it's a very powerful system. So we will make bridge statement by ourselves.

Adoption for FusionPBX.

condition - destination_number - ^(\d{10,20})$
action - set - reged_ext=username_of_extension
action - set - num_to_dial=$1
action - bridge - {absolute_codec_string='${outbound_codec_prefs}'}${regex(${sofia_contact(${reged_ext}@${domain_name})}|(^\w+/\w+)/|%1)}/sip:${num_to_dial}@${regex(${sofia_contact(${reged_ext}@${domain_name})}|(\d+.\d+.\d+.\d+:\d+.*)|%1)}


Original source (rus)