Lighttpd: mod_access

October 12th, 2017

lighttpd_logo I faced a problem when it was needed to allow access to certain url (x.x.x.x/zabbix/) for 2 fixed IP-addresses and one /16 subnet, and deny to anybody else.

The old examples from the official documentation worked not so perfect as I wanted https://redmine.lighttpd.net/boards/2/topics/1279
But the users helped me in the same topic.

This is how it’s done:

$HTTP["url"] =~ "^/zabbix/" {
    $HTTP["remoteip"] == "55.222.0.0/16" {
    }
    else $HTTP["remoteip"] == "11.22.33.44" {
    }
    else $HTTP["remoteip"] == "55.66.77.88" {
    }
    else $HTTP["remoteip"] != "" {  # (dummy match everything)
        url.access-deny = ( "" )
    }
}

Now anybody accessing /zabbix/ will get “403” error except 11.22.33.44 , 55.66.77.88 and 55.222.0.0/16.

OpenSIPS battle: REGISTER requests vs permissions module

October 12th, 2017

UPDATE: this post restricts access based on source IP address. A new article shows how to restrict access (registrations) based on username.

Sutuation: you have to check the source address of REGISTER messages, going to your OpenSIPS server and decide wether to allow them or to deny.

Use permissions module for this.

You can use it in two variants:

1. with OpenSIPS’ text config files register.allow and register.deny (similar to Unix hosts.allow and hosts.deny).
In this case you should use module’s function ‘allow_register

Example of blocking REGISTERs from 10.145.13.49 IP address:

register.deny file:

ALL : "^sip:.*10\.145\.13\.49"
ALL : "^sip:.*0*10\.145\.0*13\.0*49"   # this is to prevent bypassing
                                       # by the insertion of one or more '0' in the IP address

register.allow file is empty (allow everything except those in .deny file).

OpenSIPS script snippet:

	if ( is_method("REGISTER") ) {
		if (allow_register("register")) {
			save("location");
			exit;
		} else {
			sl_send_reply("403", "Forbidden registration from your IP v2");
			exit;
		}
	}

But this method has one big disadvantage – you need to restart OpenSIPS each time you edit register.allow/register.deny.
OpenSIPS ‘permissions’ module has a MI function ‘address_reload‘ but it reloads the table (see below), not the allow/deny files.
So, it’s more cool to use the second variant, go on reading!..

2. with DB table ‘address‘.
In this case you should use modules’ function ‘check_address

– register.allow and register.deny files are empty.
– add entries to ‘address’ table. In our case we’re using not real SQL DB but dbtext. So, this is how ‘/etc/opensips/dbtext/address’ file looks like:

voip-pbx-sbc ~ # cat /etc/opensips/dbtext/address 
id(int,auto) grp(int) ip(string) mask(int) port(int) proto(string) pattern(string,null) context_info(string,null)
1:0:10.84.2.0:24:0:any
2:0:10.145.13.5:32:0:any
3:0:10.145.13.49:32:0:any
4:0:10.145.14.0:24:0:any

WARNING: every time you add any new table, do not forget to add it’s version to another table ‘version’:

voip-pbx-sbc ~ # cat /etc/opensips/dbtext/version 
table_name(string) table_version(int) 
dispatcher:8
load_balancer:2
address:5

Firstly, I haven’t done it, and that’s why OpenSIPS could not start and I had this message in the system log:

ERROR:core:db_check_table_version: invalid version 0 for table address found, expected 5

So, the script snippet with the ‘check_address’ function:

	if ( is_method("REGISTER") ) {

		if(check_address("0","$si","0","any")) {
			save("location");
			exit;
		} else {
			sl_send_reply("403", "Forbidden registration from your IP v2");
			exit;
		}

	}

And here’s the magic! You may add IP-addresses or subnets to your DB or dbtext file and then run a MI command ‘address_reload‘ without restarting your high-loaded OpenSIPS.

Now the policy is “if address is in the table – allow it, otherwise block”. Look at the images below.

IP is not in the table – REGISTER is forbidden:

IP has been added to dbtext table and table reloaded – registrations passed successfully:

You can also look the table’s contents with MI commands ‘opensipsctl fifo address_dump‘ and ‘opensipsctl fifo subnet_dump‘.

UPD: OpenSIPS core developer’s answer to my question http://lists.opensips.org/pipermail/users/2017-October/038169.html .

Asterisk: count active calls on certain peers

October 8th, 2017

Let’s imagine that you have a number of peers – both internal users and trunks with VoIP providers.
And you need to count active calls on trunks only. Or even on trunks with some concrete provider, but not the total ‘core show calls’. As an example, you may need to pass that integer to Zabbix.

root@pbx:~# asterisk -C /etc/asterisk/asterisk.conf -rx 'sip show inuse' 
Setting max files open to 1000
* Peer name               In use          Limit           
104                       0/0/0           10              
107                       0/0/0           10              
100                       0/0/0           10                            
voip-isp-london1          1/0/0           6      
voip-isp-london2          2/1/0           6      
root@pbx:~# 

In fact, all magic is done with grep and especially awk tool. Firstly, you need to grep ‘voip-isp’, then extract the second column (is done with awk ‘{print $2}’ ) and then extract the first digit from three ones (e.g. 2 from 2/1/0).
At this point, you’ll get a list of integers, one per line, corresponding to number of active calls on each grepped trunk.
Now it’s time to summarize them, and the best way to do it is also awk! (is done with awk -F\/ ‘{sum += $1} END {print sum}’ )

root@pbx:~# asterisk -C /etc/asterisk/asterisk.conf -rx 'sip show inuse' | grep voip | awk '{print $2}' | awk -F\/ '{sum += $1} END {print sum}'
3

PBX backup script

September 5th, 2017
#!/bin/bash

#***************************************#
#*****http://alexeyka.zantsev.com/******#
#***************************************#

BACKUP_DIR=/home/user/PBX_BACKUPS
TAR="/bin/tar -czf"
DATE=$(date +%Y-%m-%d)
CDRDAY=$(date +%d)
SQLDUMP="/usr/bin/mysqldump"
SRVNAME=pbx_

#------------------------------------------------
# function for backup routine
bkuper ()
{
	# 1. cd to dir
	cd $BACKUP_DIR
	mkdir BACKUP

	# 2. copy mission-critical shit
	for i in /etc/asterisk/ /etc/lighttpd/lighttpd.conf /etc/odbc.ini /etc/odbcinst.ini /var/scripts/ ;
	do
		/bin/cp -r $i BACKUP/
	done

	# 3. CDR SQL dump on 28 day monthly
	if [ $CDRDAY == 28 ]
	then
		$SQLDUMP -u root -pRoOtPaSsWoRd db_asterisk_cdr > BACKUP/db_asterisk_cdr.$DATE.sql
	fi

	# 4. archivate
	$TAR $SRVNAME$DATE.tar.gz BACKUP/

	# 5. delete shit
	/bin/rm -rf BACKUP/
}
#------------------------------------------------

# fire!
if [ -d $BACKUP_DIR ]
    then
	bkuper
    else
	/bin/mkdir $BACKUP_DIR
	bkuper
fi

# remove older than 30 days old backups
find $BACKUP_DIR -type f -name "*z" -mtime +30 -execdir rm -f {} \;

exit $?

Debian 9, MariaDB, ODBC

August 11th, 2017

Debian switched from MySQL to MariaDB since release 9.
And as for now (2017-august-11) it seems that there is no ODBC package for MariaDB connection.

You need to download connector manually from MariaDB website. I tried 3.0.1 (beta) and it didn’t work for me, so I used latest stable (as for now, 2.0.15).

Just download gzipped tar file (not source), unpack it and place libmaodbc.so to /usr/lib/x86_64-linux-gnu/odbc/

After that your odbcinst.ini should look like this:

[MariaDB]
Description=MariaDB
Driver=/usr/lib/x86_64-linux-gnu/odbc/libmaodbc.so   
Setup=/usr/lib/x86_64-linux-gnu/odbc/libmdbodbc.so   
FileUsage=1
UsageCount=1
# not sure if we need 'Setup' at all. As I understood, it's for GUI tool and as you see, 
# I steel have a wrong lib here :) but now everything works

If you’re in a hurry, you may configure your server right now. But there’s a second part of the story.

As it was my first practice with Debian 9, MariaDB and ODBC connection for it, I haven’t know exactly what packages do I need. It seemed to be clear that some package names will be different in contrast to Debian 8/MySQL+ODBC.

That’s why I installed odbc-mdbtools, thinking that “MDB” means “MariaDB” :-)
Nothing worked, and “isql -v %connector name% %DB user% %DB pass%” command showed that “File not found”. I was confused!

It was my fault that I haven’t read the package description, relying on package name only.

And then, after some hours of research (including my monologue at Linuxquestions) I configured MariaDB + ODBC.

Debian 9: webserver notes

July 30th, 2017

Debian 9.1 Stretch (stable).

If your Apache2 does not execute PHP code (even when PHP is already installed) check if a package ‘libapache2-mod-php7.0‘ is installed. Seems to be easy and obvious, but I faced this problem with Debian 9.

Linux: manual bandwidth limiting

May 26th, 2017

Emulate your network interface bandwidth in both directions:

tc qdisc add dev venet0 handle 1: root htb default 11
tc class add dev venet0 parent 1: classid 1:1 htb rate 1kbps
tc class add dev venet0 parent 1:1 classid 1:11 htb rate 1kbps

Show rules:

tc -d qdisc
tc -s qdisc

Delete certain rule and all rules respectively:

tc class del dev venet0 parent 1:1 classid 1:11 htb rate 1kbps
tc qdisc del dev venet0 root

Linux: run a command with a time limit

May 18th, 2017

Need to run tcpdump at night writing to a pcap file? Not a problem with a crond.
Need to stop it after 10 minutes? One more crond task initiating something like ‘ps aux | grep [t]cpd’, parsing it PID and killing it? No!

timeout 10m tcpdump -v -pnni eth0 udp src port 5060 and dst port 5060 and host 10.11.7.1 -w pbx_`date +%F_%H-%M`.pcap

timeout – a nice GNU coreutil.

SIP debugging: catch only certain types of messages

May 18th, 2017

Let’s say you need to catch INVITEs only. In this case do:
ngrep -q -W byline -d eth0 INVITE\ sip

‘-W byline’ means to print each SIP packet in readable text mode, line by line
‘-q’ means to be quiet, not to print packet reception hash marks. Without this option your screen will fill up with ###### signs between captured types of packets.
‘-d eth0’ it’s clear
‘INVITE\ sip’ means show INVITEs only. Be careful: if you type ‘INVITE’ word only, you’ll catch nearly every SIP packet, as not only INVITE requests contain the word ‘INVITE’. For example a reply for OPTION request also contains this word among allowed mwthods described in the ‘Allow:’ header field.

And each INVITE request has a request-line like
INVITE sip:123@dmn.co...
I mean starting with ‘INVITE’ word, following space and following ‘sip’ word.

Asterisk 13: list of modules to be used

March 10th, 2017

This list is not as short as it could be. But it still took much time to form it.

[modules]

autoload=no

preload => res_http_websocket.so
preload => res_odbc.so
preload => cdr_odbc.so

load => bridge_builtin_features.so
load => bridge_softmix.so
load => cdr_adaptive_odbc.so
load => res_config_odbc.so
load => codec_alaw.so
load => codec_g722.so
load => codec_ulaw.so
load => format_wav.so
load => format_gsm.so
load => chan_sip.so
load => res_ael_share.so
load => res_musiconhold.so
load => res_monitor.so
load => res_sorcery_config.so
load => res_srtp.so
load => res_rtp_multicast.so 
load => res_sorcery_realtime.so
load => res_pjproject.so
load => res_rtp_asterisk.so
load => res_timing_timerfd.so
load => res_agi.so
load => res_security_log.so
load => res_limit.so
load => res_sorcery_astdb.so
load => res_sorcery_memory.so
load => res_sorcery_memory_cache.so
load => app_stack.so
load => app_cdr.so
load => app_dial.so
load => app_mixmonitor.so
load => app_queue.so
load => app_read.so
load => app_stack.so
load => app_playback.so
load => app_system.so
load => app_macro.so
load => app_queue.so
load => app_confbridge.so
load => app_system.so
load => bridge_simple.so
load => app_bridgewait.so
load => func_strings.so
load => func_callerid.so
load => func_channel.so
load => func_cdr.so
load => func_global.so
load => func_logic.so
load => pbx_ael.so
load => func_periodic_hook.so
load => func_strings.so

In case of using chan_sip your modules.conf may look like this:

[modules]

autoload=no

load => app_dial.so
load => app_cdr.so
load => app_read.so
load => app_stack.so
load => app_verbose.so

load => cdr_csv.so

;load => chan_local.so
load => chan_sip.so

load => codec_alaw.so
load => codec_g729.so
load => codec_a_mu.so
load => codec_adpcm.so
load => codec_resample.so

load => format_wav.so

load => func_callerid.so
load => func_cdr.so
load => func_channel.so
load => func_curl.so
load => func_cut.so
load => func_logic.so
load => func_strings.so
load => func_timeout.so

load => pbx_ael.so

load => res_ael_share.so
load => res_agi.so
load => res_clialiases.so
load => res_rtp_asterisk.so
load => res_timing_timerfd.so

;load => bridge_simple.so
load => bridge_softmix.so