Categories
Blog Knowledge Base

Gamma’s Gateway migration and SIP issues

Over the last few weeks and possibly going on for a few more Gamma Telecom are migrating users from their MSX SBCs to their ‘new’ SWe SBCs, and as side effect of this change is that they now do not support non-symetrical nat translation of RTP traffic

Their previous SBCs and like many other carriers do not have an issue with this and in the words of Twilio’s notes below they support both methods

** When Symmetric RTP is enabled Twilio will detect where the remote RTP stream is coming from and start sending RTP to that destination instead of the one negotiated in the SDP. Please note that this setting is more vulnerable to RTP attacks.

When Symmetric RTP is disabled, Twilio will send RTP to the destination negotiated in the SDP. This setting is considered to be more secure and therefore recommended.

On making support calls to Gamma initially they just seem to tell users that the RTP is being sent from a port that isn’t specified in the SDP, and yes that is correct, But Gamma being Gamma and even though they will have had numerous calls they don’t go any further

It seems the problem is with the customer firewalls in particular pfSense:

By default, pfSense software rewrites the source port on all outgoing connections except for UDP port 500. Some operating systems do a poor job of source port randomization, if they do it at all. This makes IP address spoofing easier and makes it possible to fingerprint hosts behind the firewall from their outbound traffic. Rewriting the source port eliminates these potential (but unlikely) security vulnerabilities. Outbound NAT rules, including the automatic rules, will show  in the Static Port column on rules set to randomize the source port.

Source port randomization breaks some rare applications. The default Automatic Outbound NAT ruleset disables source port randomization for UDP 500 because it will almost always be broken by rewriting the source port. Outbound NAT rules which preserve the original source port are called Static Port rules and have  on the rule in the Static Port column. All other traffic has the source port rewritten by default.

To add a rule for a device which requires static source ports:

  • Navigate to Firewall > NATOutbound tab
  • Select Hybrid Outbound NAT rule generation
  • Click Save
  • Click  to add a new NAT rule to the top of the list
  • Configure the rule to match the traffic that requires static port, such as a source address of a PBX.
  • Check Static Port in the Translation section of the page
  • Click Save
  • Click Apply Changes

After making that change, the source port on outgoing traffic matching the rule will be preserved. **The best practice is to use strict rules when utilizing static port to avoid any potential conflict if two local hosts use the same source port to talk to the same remote server and port using the same external IP address.**

Personally I would just make this change for the UDP port range and not all UDP ports as this could cause problem with traffic such a port 5060 when multiple servers or phones are on a site.

We have also been made aware of another issue with respect to call diversion to external numbers. By deafault Asterisk and many other IP PBXs set a diversion header in the 181 message giving the device that diverted the call and reason. in most cases this will be the extension number so the header will look like:

 Diversion: <sip:477@aaa.bbb.ccc.ddd>;reason=unconditional

This seems to cause issues at Gamma and they reject the call as it seems they are setting the callerid from this info.

To overcome this issue for chan_sip set ‘send_diversion = no’ in the general setting of sip.conf or in the “Other SIP Settings” fields in the Advanced sip setting menu. For PJSIP add it to the pjsip.endpoint_custom_post.conf file as below.

[PJSIPTwilio](+)
send_diversion=no

[GRAMMA_TEST](+)
send_diversion=no

And this seems to solve the problem.

To be honest we have only seen the problem with Gamma trunks and having tested with other suppliers and found they are not affected.

Gammas reson for this is as follows: “After reviewing the divert packet, I can see in the message header that the Diversion header is set to divert to “477”. I would recommend to change this to the full CLI you wish to forward the call to as I believe the system is trying to call “477” which wouldn’t be classed as a valid number. The 603 error you are seeing from your side would be in relation to OFCOMS national number length violation.”

See the Packet below

Session Initiation Protocol (181)
    Status-Line: SIP/2.0 181 Call is being forwarded
        Status-Code: 181
        [Resent Packet: False]
        [Request Frame: 22149]
        [Response Time (ms): 187]
    Message Header
        Via: SIP/2.0/UDP xxx.yyy.aaa.zzz:5060;branch=z9hG4bK04B82da620259a59a1a;received=xxx.yyy.aaa.zzz;rport=5060
            Transport: UDP
            Sent-by Address: xxx.yyy.aaa.zzz
            Sent-by port: 5060
            Branch: z9hG4bK04B82da620259a59a1a
            Received: xxx.yyy.aaa.zzz
            RPort: 5060
        From: <sip:01234567890@xxx.yyy.aaa.zzz>;tag=gK0441ee4f
            SIP from address: sip:01234567890@xxx.yyy.aaa.zzz
            SIP from tag: gK0441ee4f
        To: <sip:07890123456@aaa.bbb.ccc.ddd>;tag=as24643c1b
            SIP to address: sip:07890123456@aaa.bbb.ccc.ddd
            SIP to tag: as24643c1b
        Call-ID: 71571273_130153708@xxx.yyy.aaa.zzz
        [Generated Call-ID: 71571273_130153708@xxx.yyy.aaa.zzz]
        CSeq: 321899 INVITE
            Sequence Number: 321899
            Method: INVITE
        Server: FPBX-16.0.40.7(18.9)
        Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY, INFO, PUBLISH, MESSAGE
        Supported: replaces, timer
        Session-Expires: 1800;refresher=uas
        Contact: <sip:07890123456@aaa.bbb.ccc.ddd:5060>
            Contact URI: sip:07890123456@aaa.bbb.ccc.ddd:5060
                Contact URI User Part: 07890123456
                Contact URI Host Part: aaa.bbb.ccc.ddd
                Contact URI Host Port: 5060
        Diversion: <sip:477@aaa.bbb.ccc.ddd>;reason=unconditional
        Content-Length: 0

Now the RFC says :

“When a diversion occurs, a Diversion header SHOULD be added to the forwarded request or forwarded 3xx response. The Diversion header MUST contain the Request-URI of the request prior to the diversion. The Diversion header SHOULD contain a reason that the diversion occurred.”

Which is what happens, Gamma seem to have confused what the diversion header does as they seem to assume its setting the diversion destination or outbound caller ID, Neither of which are the uses for the Diversion header.

‘I will add updates here as and when they become available.’

Categories
Blog Services Support

ISDN Switch Off 2025

It’s the biggest and most important modernisation of the public phone network ever, and your business needs to check and may need to make changes to ensure a smooth transition

In 2017 BT announced it intended to Switch Off ISDN and PSTN by the end of 2025. From September 2023 new ISDN lines will not be available for purchase. Businesses must make alternative plans and migrate all ISDN / PSTN channels or they will be without a telephony service. All equipment that currently uses the PSTN will stop working: such as alarms, elevator phones, EPOS machines, door entry systems etc

There are four options, all suitable for businesses ranging in size from as few as 3 employees to many thousands of employees. All you have to do is decide which is the best fit for you

Option 1: Adapt What You Have

Extend the life of your current phone system by connecting it to the internet. This is simply done by adding hardware known as a VoIP Gateway and a link known as a SIP Trunk, which uses your existing Internet connection. It’s easy, affordable, and users notice no difference – no new cables, no new handsets, no new training.

Option 2: Blend It All Together

Mix options 1, 2, and 3 to suit your needs. For example, an on-premise system at your head office, and a cloud-based system serving your remote sites. Or connect a cloud-based unified communications platform to an on-premise VoIP Gateway or SIP Trunk-powered system. Whatever the blend, enjoy the same seamlessly-integrated user experience.

Option 3: Upgrade What You Have

Replace your installed on-premise system with the latest feature-rich digital technology known as a Unified Communications (UC) Platform; this can be installed on your site as hardware or software, fully under your control. All your telephony now on the internet, but also seamlessly aligned with your email, messaging, and chat applications via an easy-to-use, easily accessible user interface. Plus, it can all be replicated on employees’ desktop computers, laptops and mobile devices for super-convenience.

Option 4: Migrate To The Cloud

Follow hundreds of millions of organisations worldwide by replacing your on-premise system with a powerful, cloud-powered Unified Communications (UC) solution. All your calls, email, chat, and messaging now via the internet; limitless ability to add the latest new features at will; and pay monthly, only for the services you use.

Sangoma have produced a useful Webinar: “How To Prepare For The Great British ISDN Switch Off”Webinar Recording: “How To Prepare For The Great British ISDN Switch Off”

If you have any questions or need advice email or call us.

Categories
Blog Knowledge Base

Ldap for FreePBX

Install and configure OpenLDAP server in FreePBX

Concept

Before diving into the installation and configuration, it’s better to know some terms used in LDAP.

Attribute

An attribute is a characteristic of an object. For example, an email of an account.

Object Class

An object class defines what attributes that object can have. For example, we define an object class, InetOrgPerson, it may contain displayName and mail attributes. Depends on the definition of object class, the attributes specified can be mandatory or optional.

Distinguished Name (DN)

Distinguished Name lets us uniquely identify the object. It is similar to the file path in a reverse order. For example, uid=JohnDoe,OU=People,DC=abc,DC=local is a DN

Entry

An entry is just an object. You define what object class this entry belongs to & each object class defines what attributes this object has. Each entry can belong to multiple object classes and need to have all mandatory attributes specified in all object classes it belongs to.

Schema

A schema contains the definitions of various attributes and object classes.

Domain Component (DC) & Organizational Unit (OU)

They are containers, contains object & let you manage objects in a hierarchy manner. People use them commonly.

OpenLDAP Installation

Install OpenLDAP related packages

sudo yum install openldap* -y
sudo systemctl start slapd
sudo systemctl enable slapd
sudo systemctl status slapd # Check service is started & enabled
● slapd.service - OpenLDAP Server Daemon
   Loaded: loaded (/usr/lib/systemd/system/slapd.service; enabled; vendor preset: disabled)
   Active: active (running) since Tue 2023-10-17 11:20:41 BST; 1 weeks 0 days ago
     Docs: man:slapd
           man:slapd-config
           man:slapd-hdb
           man:slapd-mdb
           file:///usr/share/doc/openldap-servers/guide.html
 Main PID: 1922 (slapd)
   CGroup: /system.slice/slapd.service
           └─1922 /usr/sbin/slapd -u ldap -h ldapi:/// ldap:///

Oct 24 16:46:06 testsystem.myserver.co.uk slapd[1922]: conn=1604 fd=22 ACCEPT from IP=192.168.1.202:45777 (IP=0.0.0.0:389)
Oct 24 16:46:06 testsystem.myserver.co.uk slapd[1922]: conn=1604 op=0 BIND dn="" method=128
Oct 24 16:46:06 testsystem.myserver.co.uk slapd[1922]: conn=1604 op=0 RESULT tag=97 err=0 text=
Oct 24 16:46:06 testsystem.myserver.co.uk slapd[1922]: conn=1604 op=1 SRCH base="dc=abc,dc=local" scope=2 deref=0 filter="(|(cn=*)(sn=*))"
Oct 24 16:46:06 testsystem.myserver.co.uk slapd[1922]: conn=1604 op=1 SEARCH RESULT tag=101 err=0 nentries=13 text=
Oct 24 16:46:06 testsystem.myserver.co.uk slapd[1922]: conn=1604 op=2 UNBIND
Oct 24 16:46:06 testsystem.myserver.co.uk slapd[1922]: conn=1604 fd=22 closed
Oct 24 16:46:49 testsystem.myserver.co.uk slapd[1922]: conn=1530 op=21 SRCH base="dc=abc,dc=local" scope=2 deref=0 filter="(cn=*)"
Oct 24 16:46:49 testsystem.myserver.co.uk slapd[1922]: conn=1530 op=21 SRCH attr=givenName title wWWHomePage telephoneNumber
Oct 24 16:46:49 testsystem.myserver.co.uk slapd[1922]: conn=1530 op=21 SEARCH RESULT tag=101 err=0 nentries=13 text=

OpenLDAP Configuration

Generate OpenLDAP password and save it

sudo slappasswd

Then, we will use ldapmodify to update /etc/openldap/slapd.d/cn=config/olcDatabase={2}hdb.ldif, which is our database config fileWe will create a file & customize and paste content below

vi db.ldif

Content you should paste: You should replace with your customized values

  1. olcSuffix (should be replaced by your domain, e.g. example.com -> dc=example,dc=com)
  2. olcRootDN (should be replaced by your domain admin name, can be any name you prefer, e.g. admin -> cn=admin,dc=abc,dc=local)
  3. olcRootPW (should be the password you generate above)
dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcSuffix
olcSuffix: dc=abc,dc=local

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcRootDN
olcRootDN: cn=admin,dc=abc,dc=local

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcRootPW
olcRootPW: {SSHA}xxxxx

Run this command to update.

sudo ldapmodify -Y External -H ldapi:/// -f db.ldif

Configuration of

/etc/openldap/slapd.d/cn=config/olcDatabase={2}hdb.ldif 

should now change to:

# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
# CRC32 9c010289
dn: olcDatabase={2}hdb
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: {2}hdb
olcDbDirectory: /var/lib/ldap
olcDbIndex: objectClass eq,pres
olcDbIndex: ou,cn,mail,surname,givenname eq,pres,sub
structuralObjectClass: olcHdbConfig
entryUUID: 6ceb0374-fb9c-103d-91a1-952174d1b37c
creatorsName: cn=config
createTimestamp: 20231010093751Z
olcSuffix: dc=abc,dc=local
olcRootDN: cn=admin,dc=abc,dc=local
olcRootPW:: encryped_password_here
entryCSN: 20221010095035.541034Z#000000#000#000000
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
modifyTimestamp: 20221010095035Z

Apply some commonly used schema. The 2nd & 3rd schema allow us to create an object with InetOrgPerson & ShadowAccount which we will use to create an user

sudo ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif
sudo ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/nis.ldif
sudo ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif

OpenLDAP Verification

Create objects, Organizational Unit and group

Create a file, entries.ldif, and add below content which

  1. create a user, john
  2. assign john to 2 groups, john & Engineering
dn: dc=abc,dc=local
dc: abc
objectClass: top
objectClass: domain

dn: ou=People,dc=abc,dc=local
objectClass: organizationalUnit
ou: People

dn: ou=Groups,dc=abc,dc=local
objectClass: organizationalUnit
ou: Groups

dn: cn=Engineering,ou=Groups,dc=abc,dc=local
cn: Engineering
objectClass: posixGroup
gidNumber: 32452
memberUid: John

dn: uid=John,ou=People,dc=abc,dc=local
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: John
sn: Doe
givenName: John
cn: John Doe
displayName: John Ho
uidNumber: 32452
gidNumber: 32452
loginShell: /bin/bash
homeDirectory: /home/John
shadowMin: 0
shadowMax: 2
shadowWarning: 1
userPassword: {CRYPT}x
shadowLastChange: 19261
dn: cn=john,ou=Groups,dc=abc,dc=local
cn: John
objectClass: posixGroup
gidNumber: 32452
memberUid: John

Apply the content

ldapadd -x -W -D "cn=admin,dc=abc,dc=local" -f entries.ldif

Test querying LDAP

Query all entries

ldapsearch -D cn="admin,dc=abc,dc=local" -W -b "dc=abc,dc=local"
[root@testsystem ldapservice]# ldapsearch -D cn="admin,dc=abc,dc=local" -W -b "dc=abc,dc=local"
Enter LDAP Password: 
# extended LDIF
#
# LDAPv3
# base <dc=abc,dc=local> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# abc.local
dn: dc=abc,dc=local
dc: abc
objectClass: top
objectClass: domain

# People, abc.local
dn: ou=People,dc=abc,dc=local
objectClass: organizationalUnit
ou: People

# Groups, abc.local
dn: ou=Groups,dc=abc,dc=local
objectClass: organizationalUnit
ou: Groups

Change account password (Optional)

The account we created above uses a password, {CRYPT}x, which we obviously don’t want it to be, so we change the password as below

sudo ldappasswd -x -D cn=admin,dc=abc,dc=local -W -S uid=john,ou=People,dc=abc,dc=local

Now we have to create a script to extract the data

The contact data we want is in the mysql database on Freepbx, This is the asterisk database and the data is across a few tables.

The basic concept that we extract the info from the db and remove add or update the entries in the ldap database.

Bash Scripts

First we have a file for the variables and passwords ‘fldapconfig.sh’

# LDAP Server Connection Details
LDAP_SERVER="ldap://server:port"
LDAP_BINDDN="cn=admin,dc=abc,dc=local"
LDAP_BINDPW="ldappassword"
DB_HOST="localhost"
DB_USER="username"
DB_PASSWORD="mysqlsecret"
DB_NAME="asterisk"

# LDAP Entry Details
BASE_DN="dc=abc,dc=local"
BASE_OU="ou=People"

# Files
rem_file="/tmp/rem.txt"
add_file="/tmp/add.txt"
chg_file="/tmp/chg.txt"

Now the code. I accept no responsibility for it, Its a mess but it does what it says. There is bound to be a better way but with the timescale I had i needed something quick and as such its dirty. each section is distinct so shouldnt be hard to clean up.

The file fpbxldap.sh

#!/bin/bash

#Script file to add delete and modify ladp database for freeepbx contact manager 
#Copyright (C) 2023  Ian Plain Cyber-cottage.co.uk
#
#This program is free software; you can redistribute it and/or
#modify it under the terms of the GNU General Public License
#as published by the Free Software Foundation; either version 2
#of the License, or (at your option) any later version.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

source fldapconfig.sh

# LDAP Entry Details
#BASE_DN="dc=abc,dc=local"
#BASE_OU="ou=People"

# Search for the LDAP entries ad file them
CURRENT_TELEPHONE_NUMBER=$(ldapsearch -x -D "$LDAP_BINDDN" -w "$LDAP_BINDPW" -H "$LDAP_SERVER" -b "$BASE_OU,$BASE_DN" telephoneNumber | awk -F ',|=|: ' '/dn:/ {print $3}')
echo "$CURRENT_TELEPHONE_NUMBER" |grep -w -v  "People" > /tmp/ldapdb.txt


# Query to execute
QUERY="SELECT asterisk.contactmanager_entry_numbers.number as 'telephoneNumber', asterisk.contactmanager_group_entries.displayname as 'cn', asterisk.contactmanager_group_entries.fname as 'givenName', COALESCE(NULLIF(asterisk.contactmanager_group_entries.lname, ''), '-')  AS 'sn', asterisk.contactmanager_entry_numbers.type as 'o', asterisk.contactmanager_groups.name as 'dir'
FROM asterisk.contactmanager_entry_numbers  
INNER JOIN asterisk.contactmanager_group_entries ON asterisk.contactmanager_entry_numbers.entryid=asterisk.contactmanager_group_entries.id  
INNER JOIN asterisk.contactmanager_groups ON asterisk.contactmanager_groups.id=asterisk.contactmanager_group_entries.groupid 
WHERE asterisk.contactmanager_entry_numbers.number REGEXP '^[0-9]*$' AND asterisk.contactmanager_group_entries.displayname REGEXP '[:alpha:]'
;"

# Output file
OUTPUT_FILE="/tmp/fpbxdb.txt"

# Run the MySQL query and save the result to the output file
mysql -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASSWORD" "$DB_NAME" -N -e "$QUERY" | sed 's/\t/,/g' > "$OUTPUT_FILE"

#Split out just the names
cat /tmp/fpbxdb.txt |awk -F ',' '{print $2" - "$5}' > /tmp/fpxname.txt
cat /tmp/fpbxdb.txt |awk -F ',' '{print $2" - "$5","$1}' > /tmp/fpxnumna.txt


# Assign filenames to variables
listB_file="/tmp/ldapdb.txt"
listA_file="/tmp/fpxname.txt"

# Check if the files exist
if [ ! -f "$listA_file" ]; then
    echo "File $listA_file does not exist."
    exit 1
fi
if [ ! -f "$listB_file" ]; then
    echo "File $listB_file does not exist."
    exit 1
fi

#Bit of a hack here that adds an entry to empty file, as AWK doesnt like empty files.. Thsi was quick a fix
if [ -s "$listA_file" ]; then
  echo "The file is not empty."
else
  echo "foobar" > /tmp/fpxname.txt
fi

if [ -s "$listB_file" ]; then
  echo "The file is not empty."
else
 echo "barfoo" > /tmp/ldapdb.txt
fi

# Compare the two files and echo names in List A but not in List B
awk 'NR==FNR{a[$0]++; next} !a[$0]' "$listB_file" "$listA_file"  > /tmp/add.txt
awk 'NR==FNR{a[$0]++; next} !a[$0]' "$listA_file" "$listB_file"  > /tmp/rem.txt

#lets delete the entries
# Loop through each line in the input file and run the command
while IFS= read -r REM_FILTER; do
    # Run the specified command on each line
echo "$REM_FILTER deleted from Ldap" >> /tmp/remlog.txt
ldapdelete -x -D "$LDAP_BINDDN" -w "$LDAP_BINDPW" -H "$LDAP_SERVER"  "cn=$REM_FILTER,$BASE_OU,$BASE_DN"
done < "$rem_file"

echo  "Done-------" >> /tmp/remlog.txt

#delete the previous ldif files
rm -f /tmp/adding.ldif
rm -f /tmp/modify.ldif

#lets add the entries
# Loop through each line in the input file and run the command
while IFS= read -r ADD_FILTER; do
# Run the specified command on each line
# echo  $ADD_FILTER |awk -F ' - ' '{print $1; print $2}'
ms_cn="$(echo  $ADD_FILTER |awk -F ' - ' '{print $1}')"
ms_o="$(echo  $ADD_FILTER |awk -F ' - ' '{print $2}')"

# Query to execute
QUERY="SELECT asterisk.contactmanager_entry_numbers.number as 'telephoneNumber',  COALESCE(NULLIF(asterisk.contactmanager_group_entries.lname, ''), '-')  AS 'sn' 
FROM asterisk.contactmanager_entry_numbers
INNER JOIN asterisk.contactmanager_group_entries ON asterisk.contactmanager_entry_numbers.entryid=asterisk.contactmanager_group_entries.id
INNER JOIN asterisk.contactmanager_groups ON asterisk.contactmanager_groups.id=asterisk.contactmanager_group_entries.groupid
WHERE asterisk.contactmanager_entry_numbers.type = '$ms_o' AND asterisk.contactmanager_group_entries.displayname = '$ms_cn'
;"

# Run the MySQL query and save the result to the output file
ms_query=$(mysql -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASSWORD" "$DB_NAME" -N -e "$QUERY")

ms_telephoneNumber=$(echo $ms_query | awk '{print $1}')
ms_sn=$(echo $ms_query | awk '{print $2}')

echo "dn: cn=$ms_cn - $ms_o,ou=People,dc=abc,dc=local" >> /tmp/adding.ldif
echo "cn: $ms_cn - $ms_o" >> /tmp/adding.ldif
echo "givenName: $ms_cn - $ms_o" >> /tmp/adding.ldif
echo "sn: $ms_sn" >> /tmp/adding.ldif
echo "telephonenumber: $ms_telephoneNumber" >> /tmp/adding.ldif
echo "objectclass: inetOrgPerson" >> /tmp/adding.ldif
echo "objectclass: top" >> /tmp/adding.ldif
echo ""  >> /tmp/adding.ldif
echo "cn: $ms_cn - $ms_o , $ms_telephoneNumber  added to Ldap" >> /tmp/addlog.txt
done < "$add_file"

#Lets run the ldif command
ldapadd -x  -D "$LDAP_BINDDN" -w "$LDAP_BINDPW" -H "$LDAP_SERVER"   -f /tmp/adding.ldif >> /tmp/addlog.txt

echo  "Done-------" >> /tmp/addlog.txt

#OK now we are going to compare freepbx and ldap entries and update as required.

#lets get the current ldap names and numbers 
ldapsearch -x -D "cn=admin,dc=abc,dc=local" -w "r1v3rp1g5" -b "ou=People,dc=abc,dc=local"  | awk -v OFS=',' '{split($0,a,": ")} /^cn:/{cn=a[2]} /^telephoneNumber:/{telephoneNumber=a[2]; print cn,telephoneNumber}' > /tmp/ldapcsv.txt

awk 'NR==FNR{a[$0]++; next} !a[$0]' /tmp/ldapcsv.txt   /tmp/fpxnumna.txt > /tmp/chg.txt
chg_file="/tmp/chg.txt"

# Loop through each line in the input file and run the command
while IFS= read -r CHG_FILTER; do
# Run the specified command on each line
# echo  $CHG_FILTER |awk -F ',' '{print $1; print $2}'
ms_cn="$(echo  $CHG_FILTER |awk -F ',' '{print $1}')"
ms_telephoneNumber="$(echo  $CHG_FILTER |awk -F ',' '{print $2}')"

echo "Changing telephoneNumber to $ms_telephoneNumber"
echo "dn: cn=$ms_cn,$BASE_OU,$BASE_DN" >> /tmp/modify.ldif
echo "changetype: modify" >> /tmp/modify.ldif
echo "replace: telephoneNumber" >> /tmp/modify.ldif
echo "telephoneNumber: $ms_telephoneNumber" >> /tmp/modify.ldif
echo ""  >> /tmp/modify.ldif

echo "$CHG_FILTER  changed in Ldap" >> /tmp/chglog.txt
done < "$chg_file"

ldapmodify -x -D "$LDAP_BINDDN" -w "$LDAP_BINDPW" -H "$LDAP_SERVER" -f /tmp/modify.ldif  >> /tmp/modify.ldif

echo  "Done-------" >> /tmp/chglog.txt

Example phone configurations for Sangoma S series and Gigaset.

Gigaset example

Sangoma S Series example

Im sure this will work with other systems that support Ldap directories

Categories
Blog Knowledge Base Products and services Support

Changes to help reduce smishing and SMS fraud

UK regulators have implemented changes to help reduce smishing and SMS fraud incidents.

As a reminder, effective immediately, application-to-person (A2P) SMS messages sent to the UK from Alphanumeric Sender IDs that contain special characters will be blocked. 

The following characters are allowed:

  • A to Z (upper and lowercase)
  • 0 to 9 
  • – (dash)
  • _ (underscore)
  • ‘ ‘ (space)
  • & (ampersand) 

Any special characters outside of the list above will be blocked (example: “+” or “@”).

Effective October 31, 2023, application-to-person (A2P) SMS messages sent to the UK from the following list of generic Alphanumeric Sender IDs will be blocked.

Note: Combinations of these generic Alphanumeric Sender IDs are allowed (for example, “Smith Bank” or “Border Control” are both allowed.
 

1TimePin2FAAcceptAccessAccountActiveAdmin
AdviseAlertAllowAllowanceAppAppointmentApprove
ApprovedAuthAuthMSGAuthoriseAuthSMSAwareBank
BankingBillBillingCallCardCautionCertify
CheckCloudOTPCodeCollectCollectionConfirmContact
ControlCourierDelayDeliverDeliveryDiscountEnergy
FraudHelpInfoInfoSMSISAKeyLoan
LoginLogisticsLogMeInLogonMalwareMessageMobile
MortgageMSGMsgAuthNetworkNoReplyNotifyOneTimePin
OrderOTPOTPSMSPackageParcelPayPayment
PinPinCodePostProtocolPurchaseRatifyRebate
ReceiptRefundReminderRepaymentReplyRespondSave
SavingSavingsScamScheduleSecureSecurityService
ShippingSignSigninSignonSMSSMSAuthSMSCode
SMSInfoSMSOTPSMSVerifySupportSystemTextTrace
TrackTrackingTrustTXTUpdateUpdatesValidate
VerifyVerifySMSVerifyMeVirusWarnWarningWinner

What do you need to do?

Avoid using special characters in your Alphanumeric Sender IDs and use a non-generic Alphanumeric Sender ID to send messages in the UK to avoid message disruption following the steps below:

  1. If you’re using a Messaging Service, update your generic Alphanumeric Sender ID by reviewing your suppliers guide on Using Alphanumeric Sender ID with Messaging Services.
  2. If you’re specifying your Alphanumeric Sender ID directly in your API request, update the “From” parameter in your application code with a non-generic Alphanumeric Sender ID.

What if you don’t take action?

There’s no action for you to take. SMS messages sent to the UK from generic Alphanumeric Sender IDs or Sender IDs that contain special characters will be blocked and return an error code.

Categories
Blog Gigaset Special Offers

Gigasets Bundle of Joy

We’re thrilled to present an exclusive opportunity to transform your communication experience – introducing the Gigaset Bundle of Joy Promotion! Elevate your connectivity with the ultimate combination of an N670 IP base station and 2 R650H handsets, all at an unbeatable price. Don’t miss out on this fantastic deal, available until October 31st 2023.

The N670 Base features include

  • Supports up to 20 users (increase to 250 via license)
  • Single cell system, upgradable with licenses
  • Supports up to 8 simultaneous calls
  • Zero-touch configuration via auto-provisioning

The R650 Handset features include

  • Large 1.8″ TFT display
  • IP65 dust & water resistant
  • Vibration & flashing alerts
  • Handsfree and 2.5mm headset connection
  • Phonebook up to 200 entries

Seamless Connectivity

The N670 IP Base Station offers seamless connectivity for crystal-clear communication. Experience exceptional voice quality and reliability, ensuring conversations are always top-notch.

Exceptional Mobility

Whether you’re looking to create a simple single cell solution, or a future-proof package which can be scaled to accommodate up to 20,000 handsets**, this bundle can be scaled as your customers’ business grows. With support for the S650H, SL750H and Maxwell C handsets too, it can be adapted to suit each individual user requirements.

Unmatched Value

This bundle, with 30% off RRP, offers exceptional value for an advanced communication setup. Equip workspaces with state-of-the-art devices without breaking the bank.

Call 01225580025 or Email for your pricing.

Categories
Applications Blog Knowledge Base Products and services

Transcribing voicemails to text with Amazon AWS

For this project we are going to use the Amazon AWS Transcribe service, AWS Transcribe is a cloud-based speech recognition service that converts audio recordings into accurate text transcripts. It uses advanced machine learning algorithms to identify different speakers and punctuation, while also supporting a variety of audio formats and languages. AWS Transcribe can transcribe audio from sources such as phone calls, video recordings, and live streams, making it a versatile tool thats idealy suited for voicemail transcription, The service is highly scalable and cost-effective.

We will say that we used to use Google’s Text to speech engine for thsi but over time I would have expected quality of transcription to have improved, But with Google this is not the case, and I expect this is because they possibly use “predictive” text to speech and not sample all the words as this example below shows, This is the same audio fed to Google and AWS

Amazon AWS Transcribe

Um, this is Ian. I’d like to order some pizza for tomorrow, please. We would like to order a pepperoni pizza and a mozzarella pizza that’s for  tomorrow at five PM. Thank you.

Google Speech to Text

like to order some pizza for tomorrow please would like to order a pepperoni pizza and a mozzarella Pizza Hut for tomorrow at 5 a.m. thank you

As can be seen google misses words and adds others, As you can imagine this isnt what you want with speech transcription.

So we have switched out old script to use AWS.

For this project on Freepbx you need a few extra applications added and a amazon aws account, setting this up is not covered here as you should already have knowledge of this if you are here.

The extra apps are , aws , jq , sox

to get aws :

curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip -qq awscliv2.zip
./aws/install

Then you need to configure as 'root' and as 'asterisk', so:
aws configure
fill out your aws key and token as well as the region your bucket is in 
Then repeat as 'asterisk' so
su asterisk
aws configure
and fill out same details.

for jq and sox, just yum install xxx as you would for any other program.

Next you need the asterisk dialplan added to the extensions_custom.conf

[vmail2text]
exten => _XXXX,1,Set(__EXTTOCALL=${EXTEN})
exten => _XXXX,n,Noop(${EXTTOCALL})
exten => _XXXX,n,Goto(s,1)

exten => s,1,Answer()  ; Listen to ringing for 1 seconds
exten => s,n,Set(AGC(rx)=8000)
exten => s,n,Set(DENOISE(rx)=on)
exten => s,n,Noop(${EXTTOCALL} , ${DIALSTATUS} , ${SV_DIALSTATUS})
exten => s,n,GotoIf($["${DIALSTATUS}"="BUSY"]?busy:bnext)
exten => s,n(busy),Set(greeting=busy)
exten => s,n,Goto(carryon)
exten => s,n(bnext),GotoIf($["${DIALSTATUS}"="NOANSWER"]?unavail:unext)
exten => s,n(unavail),Set(greeting=unavail)
exten => s,n,Goto(carryon)
exten => s,n(unext),Set(greeting=unavail)
exten => s,n,Goto(carryon)

exten => s,n(carryon),Set(origmailbox=${EXTTOCALL})
exten => s,n,Set(msg=${STAT(e,${ASTSPOOLDIR}/voicemail/default/${origmailbox}/${greeting}.wav)})
exten => s,n,Set(__start=0)
exten => s,n,Set(__end=0)
exten => s,n,NoOp(${UNIQUEID})
exten => s,n,Set(origdate=${STRFTIME(${EPOCH},,%a %b %d %r %Z %G)})
exten => s,n,Set(origtime=${EPOCH})
exten => s,n,Set(callerchan=${CHANNEL})
exten => s,n,Set(callerid=${CALLERID(num)})
exten => s,n,Set(origmailbox=${origmailbox})
exten => s,n,Answer()
exten => s,n,GotoIf($["${msg}"="1"]?msgy:msgn)
exten => s,n(msgy),Playback(${ASTSPOOLDIR}/voicemail/default/${origmailbox}/${greeting});(local/catreq/how_did)
exten => s,n,Goto(beep)
exten => s,n(msgn),Playback(vm-intro)
exten => s,n(beep),System(/bin/touch /var/lib/asterisk/sounds/catline/${UNIQUEID}.wav)
exten => s,n,Playback(beep)
exten => s,n,Set(__start=${EPOCH})
exten => s,n,Record(catline/${UNIQUEID}.wav,3,60,kaqu)
exten => s,n,Playback(beep)
exten => s,n,Hangup()
exten => h,1,Noop(${start} ${end})
exten => h,n,GotoIf($["${start}"!="0"]?ok:end)
exten => h,n(ok),Set(end=${EPOCH})
exten => h,n,Set(duration=${MATH(${end}-${start},int)})
exten => h,n,System(/usr/local/sbin/vmailprox.sh "${callerchan}" ${callerid} "${origdate}" ${origtime} ${origmailbox} ${UNIQUEID} ${duration})
exten => h,n(end),Noop(finished)

as can be seen this dialplan records a file and then runs the vmailprox.sh script. This script collects the variables and passes them over to the main script and exits after doing so, this is so channels aren’t held while transcription takes place. (Thats the plan anyway)

#!/bin/sh
callerchan=$1
callerid=$2
origdate=$3
origtime=$4
origmailbox=$5
origdir=$6
duration=$7
export callerchan
export callerid
export origdate
export origtime
export origmailbox
export origdir
export duration

nohup /usr/local/sbin/quietvmail.sh &
exit

Main script

#!/bin/sh
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
S3_BUCKET="YOURS3BUCKET"
DIRPATH=/var/spool/asterisk/voicemail/default/
#callerchan=$1
#callerid=$2
#origdate=$3
#origtime=$4
#origmailbox=$5
#origdir=$6
#duration=$7
counter=1
sleep 4

FILENUM=$(/bin/ls ${DIRPATH}${origmailbox}/INBOX |/bin/grep txt | /usr/bin/wc -l)

##Added to allow 999 messages
if  (( $FILENUM <= 9 ));
then
FILENAME=msg000${FILENUM}
elif (( $FILENUM <= 99 ));
then
FILENAME=msg00${FILENUM}
else
FILENAME=msg0${FILENUM}
fi

IN=$(/bin/grep "${origmailbox}=" /etc/asterisk/voicemail.conf)
set -- "$IN"
IFS=","; declare -a Array=($*)
email=${Array[2]}

/bin/echo "[message]" >> ${DIRPATH}${origmailbox}/INBOX/${FILENAME}.txt
/bin/echo origmailbox=${origmailbox} >> ${DIRPATH}${origmailbox}/INBOX/${FILENAME}.txt
/bin/echo "context=demo" >> ${DIRPATH}${origmailbox}/INBOX/${FILENAME}.txt
/bin/echo "macrocontext=" >> ${DIRPATH}${origmailbox}/INBOX/${FILENAME}.txt
/bin/echo "exten=s" >> ${DIRPATH}${origmailbox}/INBOX/${FILENAME}.txt
/bin/echo "priority=11" >> ${DIRPATH}${origmailbox}/INBOX/${FILENAME}.txt
/bin/echo callerchan=${callerchan} >> ${DIRPATH}${origmailbox}/INBOX/${FILENAME}.txt
/bin/echo callerid=${callerid} >> ${DIRPATH}${origmailbox}/INBOX/${FILENAME}.txt
/bin/echo origdate=${origdate} >> ${DIRPATH}${origmailbox}/INBOX/${FILENAME}.txt
/bin/echo origtime=${origtime} >> ${DIRPATH}${origmailbox}/INBOX/${FILENAME}.txt
/bin/echo msg_id=${origtime}-00000001  >> ${DIRPATH}${origmailbox}/INBOX/${FILENAME}.txt
/bin/echo "flag="  >> ${DIRPATH}${origmailbox}/INBOX/${FILENAME}.txt
/bin/echo "category=" >> ${DIRPATH}${origmailbox}/INBOX/${FILENAME}.txt
/bin/echo "duration=${duration}" >> ${DIRPATH}${origmailbox}/INBOX/${FILENAME}.txt

    /bin/nice /usr/bin/lame -b 16 -m m -q 9-resample /var/lib/asterisk/sounds/catline/${origdir}.wav  /tmp/${origdir}.mp3

    # Create a string based on the current date and time
    current_date_time="$(date +%Y-%m-%d_%H-%M-%S)"

    # Upload to the S3 Bucket

    aws --debug --profile default s3 cp /tmp/${origdir}.mp3 s3://$S3_BUCKET/$current_date_time

    # Start the transcription job
    output=$(aws --profile default transcribe start-transcription-job \
    --transcription-job-name $current_date_time \
    --language-code en-GB \
    --media-format mp3 \
    --media MediaFileUri=s3://$S3_BUCKET/$current_date_time \
    --output-bucket-name $S3_BUCKET)

    # Wait for the transcription to finish
    JOB_COMPLETED=false
    while [ "$JOB_COMPLETED" = false ]; do
        JOB_STATUS=$(aws --profile default transcribe get-transcription-job \
            --transcription-job-name $current_date_time \
            --query 'TranscriptionJob.TranscriptionJobStatus' \
            --output text)
            
        if [ "$JOB_STATUS" = "FAILED" ]; then
                JOB_COMPLETED=true
                SHORT_CALL=yes
                /bin/echo "$JOB_STATUS"    >> /tmp/logfile.txt
                break
        fi

        if [ "$JOB_STATUS" = "COMPLETED" ]; then
                /bin/echo "$JOB_STATUS"    >> /tmp/logfile.txt
                JOB_COMPLETED=true
        else

        ((counter++))
        sleep 5
        echo $counter    >> /tmp/logfile.txt
        /bin/echo "$JOB_STATUS"    >> /tmp/logfile.txt
                
                if [ "$counter" -eq  "15" ]; then
                JOB_STAUS=COMPLETED
                JOB_COMPLETED=true
                SHORT_CALL=yes
                break
                fi
        fi
    done


    # Get the transcription result
    aws s3 --profile default cp s3://$S3_BUCKET/$current_date_time.json /tmp/$current_date_time.json 

    # Get the transcription result
    FILTERED=$(jq -r '.results.transcripts[].transcript' /tmp/$current_date_time.json)
                   
        # append result of transcription
        if [ -z "$FILTERED" ]
        then
          echo "(AWS was unable to recognize any speech in audio data.)" >> /tmp/${origdir}.txt
        else
          echo "$FILTERED" >> /tmp/${origdir}.txt
          sed -i 's/ Um,/ /gI' /tmp/${origdir}.txt
        fi

voicemailbody=$(cat "/tmp/${origdir}.txt")

# echo "body ${voicemailbody}"

/bin/cp /var/lib/asterisk/sounds/catline/${origdir}.wav ${DIRPATH}${origmailbox}/INBOX/${FILENAME}.wav

echo -e "You have a new voicemail from ${callerid} it was left on ${origdate} and is ${duration} seconds long,\nThe message left,\n\n${voicemailbody}\n\nTranscribed by the Amazon AWS Transcribe service\n" | /bin/mail -s "A new voicemail has arrived from ${callerid}" -a "/tmp/${origdir}.mp3" "$email"

/bin/rm -f /tmp/${origdir}.mp3
/bin/rm -f /tmp/${origdir}.txt
aws --profile default transcribe delete-transcription-job --transcription-job-name $current_date_time

Then to pass calls to this and not normal voicemail, In Freepbx create a Custom Destination as “vmail2text,s,1” and if you require certain queues to go to specific mailboxes for example 2000 one like “vmail2text,2000,1” so calls will be sent to mailbox 2000 and teh transcriptions will be sent to the email address linked to that extension

Then in extensions that want to use transcription set the “Optional Destinations” in the advanced tab to the custom destination.

Users also can listen to voicemail normally from their handset or the ucp.

These scripts arent only useful for voicemail then can be used fro questionnaire lines and booking lines, anywhere you want to speed up the handling of voice messages. We will soon be looking at ways of integrating this with Whatsapp so transcriptions can be sent to your mobile.

If you have any further questions please email.

Categories
Blog

Missed call Notification

This new module does what it says, Users get an email notification of a missed call on their handset. With this module, either the PBX admin or the user can configure email notifications for whenever they miss a call.

A new menu entry will appear in the Applications menu which lists the Missed Call status for all the users on the system that have an email address defined in User Management.

This free module allows the sending of Missed call notifications to the user’s configured email address, on following events – 

  • Missed Internal call
  • Missed External call
  • Missed from Queue call
  • Missed from Ring Group call.

To change notifications types, the Admin can use User Management where they can edit users notification settings:

Or the user can do this themselves using the UCP, or once set up,

There are also dialable feature codes to enable or disable notifications on a per-extension basis, by default these are set to:
Missed Call Notification Activate *56
Missed Call Notification Deactivate *57
Missed Call Notification Toggle *58

This is a useful addition to FreePBX and can see situations where this would be really useful. Hotel reception desks for example.

Categories
Blog FreePBX Products and services Software

FreeStats

FreeStats is a re-write and expansion of the original call center stats package from Asternic giving it a fresh look and some additional features requested by users including CDRs, Search and Administrator login.

The statistics are now ‘live’ as the system uses mysql storage of queue records and not the parsing of the logfile that in the case of the original package had to be “Cron’d”

The screenshots of the package here show the refreshed user interface and additional pages.

The Search function lets you search the DB for the call uniqueID or callerID number then displaying all items in the queue logs and the realtime page is rewritten to work with modern Asterisk versions and the updated versions of AMI and Ajam for control of agents.

The package for downloading includes full installation instructions that can be viewed here and sql file for creating the mysql DB. An additional option is to limit access to the application by changing the config.php so that the Administrator logins can be used for allowing access to the system.

The code is opensource and your free to make changes or if you like it consider buying me a coffee.

Download the Source here

Categories
Blog FreePBX Software

A Web based call management package for small Hotels and Serviced offices

FreeHMS is a web based call management package for small Hotels, Guest Houses and managed offices. It is designed to work with FreePBX and Asterisk.

It allows owners to bill guests or users for the phone usage allowing guests to make calls, setup wakeup calls and access voicemail. Rooms are initially blocked from calling other rooms but can call Admin extensions with out being checked in. When a room is checked in they can make trunk calls and set up wakeup calls. When checking out any wakeup calls are removed and the voicemail is defaulted and all Voicemail messages are deleted.

Setting up the system is simple for Installer with minimal changes to the dialplan which are included in the custom configuration file. The system can be set to any language as all text is from a single configuration file which also includes currency and tax rate for billing. Users are created in FreePBX user admin so are easily changed and added.

Call rates are set using the rates page only available to the Admin users

Administration is simple and password controlled using the ‘User Managment’ module of Freepbx so changes to rates and rooms can only be carried out by the admin users, Reception users can log guests in and out, Create Bills and mark rooms for cleaning as well as set or cancel wakeup calls, The Housekeeping login only allows setting of rooms clean or not*. If a room is not marked as clean then that room cannot be checked in.

The software is fully web based and can be used on PC, Mac, Tablet or even smartphone.

The software is opensource and can be customised to suit most customers.

Features Include:

Checkin /Checkout

Billing : Rates are set by the admin user only, Bill can printed with relevant sales tax added.

Cleaning : Rooms are marked unclean on checkout and can only be checked in when marked as clean by reception or the cleaning staff. A cleaning list can be printed off for stall without a tablet or smartphone.

The software is here to download  and as its released as OSS you can modify and extend it as you wish

If you just want the software its free to download,  Limited email support will be available, All we ask is if you add a feature or make a change let us have it so everyone can benefit from it.

Finally if there is a feature you want let us know how we can work with you to make it come about.

If you do download and like it, maybe think about buying me a coffee

Categories
Asterisk Support Blog Elastix Support FreePBX Knowledge Base Security

Keeping the Bots out and allowing your friends in

Since this post was originally written things have advanced, FreePBX has an integrated firewall with intrusion detection using Fail2Ban, and this should always be enabled even if system is on premise.

Another major step forward in protection is APIBAN this is a client program that helps prevent unwanted SIP traffic by identifying addresses of known bad actors before they attack your system. Bad bots are collected through globally deployed honeypots. To use APIBAN you will need a key these are obtained from here . More details on API ban are here if you are interested in using it in different situations.

To simplify installation on Freepbx based systems I have simple script that downloads and install it, this can be downloaded here or from the command line of the server as follows:

wget https://freeaccesspublic.s3.eu-west-2.amazonaws.com/apiban.sh
Make it an executable : chmod +x  apiban.sh
then run the script : ./apiban.sh your_api_key

If you dont add your APIKEY on the command line vi will open and you can add it manually. The script will then initially run the client which will take a few seconds to download the initial set of bots, then it will add a line to the crontab file and restart the cron daemon. the timing of the cronjob is randomised to be between every 4 and 22 minutes.

We have seen many Bots attacking Asterisk servers, Interestingly its not always good old sipvicious anymore but a Windows program called sipcli and originating mainly from the US and Germany.

Normally our iptables firewalls are updated but for some reason these keep getting through, So we have now based rules on the User-Agent in iptables as well

Here are a few examples to get rid of many of the favourites

-A INPUT -p udp -m udp --dport 5060 -m string --string "User-Agent: friendly-scanner" --algo bm --to 65535 -j DROP
-A INPUT -p udp -m udp --dport 5060 -m string --string "User-Agent: sipcli" --algo bm --to 65535 -j DROP
-A INPUT -p udp -m udp --dport 5060 -m string --string "User-Agent: sipvicious" --algo bm --to 65535 -j DROP
-A INPUT -p udp -m udp --dport 5060 -m string --string "User-Agent: VaxSIPUserAgent" --algo bm --to 65535 -j DROP

For Freepbx format add following to the Firewalls custom rules


-A fpbxreject -p udp --dport 5060:5261 -m string --string "REGISTER sip:server.domain.co.uk" --algo bm -j ACCEPT
-A fpbxreject -p udp --dport 5060:5261 -m string --string "REGISTER sip:" --algo bm -j DROP
-A fpbxreject -p tcp --dport 5060:5261 -m string --string "REGISTER sip:server.domain.co.uk" --algo bm -j ACCEPT
-A fpbxreject -p tcp --dport 5060:5261 -m string --string "REGISTER sip:" --algo bm -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "sip:a'or'3=3--@" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: PolycomSoundPointIP SPIP_550 UA 3.3.2.0413" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: Avaya IP Phone 1120E" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: Cisco-SIPGateway/IOS-15.2.4.M5" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: PolycomVVX-VVX_401-UA5.4.1.18405" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: eyeBeam release 3006o stamp 17551" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: owenee" --algo bm --to 65535 -j DROP
-A fpbxreject -p tcp -m tcp --dport 5060:5261 -m string --string "User-Agent: owenee" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: Custom" --algo bm --to 65535 -j DROP
-A fpbxreject -p tcp -m tcp --dport 5060:5261 -m string --string "User-Agent: Custom" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: SIP" --algo bm --to 65535 -j DROP
-A fpbxreject -p tcp -m tcp --dport 5060:5261 -m string --string "User-Agent: SIP" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: gazllove" --algo bm --to 65535 -j DROP
-A fpbxreject -p tcp -m tcp --dport 5060:5261 -m string --string "User-Agent: gazllove" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: pplsip" --algo bm --to 65535 -j DROP
-A fpbxreject -p tcp -m tcp --dport 5060:5261 -m string --string "User-Agent: pplsip" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: sipcli" --algo bm --to 65535 -j DROP
-A fpbxreject -p tcp -m tcp --dport 5060:5261 -m string --string "User-Agent: sipcli" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: sipvicious" --algo bm --to 65535 -j DROP
-A fpbxreject -p tcp -m tcp --dport 5060:5261 -m string --string "User-Agent: sipvicious" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: sip-scan" --algo bm --to 65535 -j DROP
-A fpbxreject -p tcp -m tcp --dport 5060:5261 -m string --string "User-Agent: sip-scan" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: sipsak" --algo bm --to 65535 -j DROP
-A fpbxreject -p tcp -m tcp --dport 5060:5261 -m string --string "User-Agent: sipsak" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: sundayddr" --algo bm --to 65535 -j DROP
-A fpbxreject -p tcp -m tcp --dport 5060:5261 -m string --string "User-Agent: sundayddr" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: friendly-scanner" --algo bm --to 65535 -j DROP
-A fpbxreject -p tcp -m tcp --dport 5060:5261 -m string --string "User-Agent: friendly-scanner" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: iWar" --algo bm --to 65535 -j DROP
-A fpbxreject -p tcp -m tcp --dport 5060:5261 -m string --string "User-Agent: iWar" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: CSipSimple" --algo bm --to 65535 -j DROP
-A fpbxreject -p tcp -m tcp --dport 5060:5261 -m string --string "User-Agent: CSipSimple" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: SIVuS" --algo bm --to 65535 -j DROP
-A fpbxreject -p tcp -m tcp --dport 5060:5261 -m string --string "User-Agent: SIVuS" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: Gulp" --algo bm --to 65535 -j DROP
-A fpbxreject -p tcp -m tcp --dport 5060:5261 -m string --string "User-Agent: Gulp" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: sipv" --algo bm --to 65535 -j DROP
-A fpbxreject -p tcp -m tcp --dport 5060:5261 -m string --string "User-Agent: sipv" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: smap" --algo bm --to 65535 -j DROP
-A fpbxreject -p tcp -m tcp --dport 5060:5261 -m string --string "User-Agent: smap" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: friendly-request" --algo bm --to 65535 -j DROP
-A fpbxreject -p tcp -m tcp --dport 5060:5261 -m string --string "User-Agent: friendly-request" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: VaxIPUserAgent" --algo bm --to 65535 -j DROP
-A fpbxreject -p tcp -m tcp --dport 5060:5261 -m string --string "User-Agent: VaxIPUserAgent" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: VaxSIPUserAgent" --algo bm --to 65535 -j DROP
-A fpbxreject -p tcp -m tcp --dport 5060:5261 -m string --string "User-Agent: VaxSIPUserAgent" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: siparmyknife" --algo bm --to 65535 -j DROP
-A fpbxreject -p tcp -m tcp --dport 5060:5261 -m string --string "User-Agent: siparmyknife" --algo bm --to 65535 -j DROP
-A fpbxreject -p udp -m udp --dport 5060:5261 -m string --string "User-Agent: Test" --algo bm --to 65535 -j DROP
-A fpbxreject -p tcp -m tcp --dport 5060:5261 -m string --string "User-Agent: Test" --algo bm --to 65535 -j DROP

Also its worth adding these ranges as little good will ever come from them

# Ponytelecom ranges
-A INPUT -s 62.210.0.0/16 -j DROP
-A INPUT -s 195.154.0.0/16 -j DROP
-A INPUT -s 212.129.0.0/18 -j DROP
-A INPUT -s 62.4.0.0/19 -j DROP
-A INPUT -s 212.83.128.0/19 -j DROP
-A INPUT -s 212.83.160.0/19 -j DROP
-A INPUT -s 212.47.224.0/19 -j DROP
-A INPUT -s 163.172.0.0/16 -j DROP
-A INPUT -s 51.15.0.0/16 -j DROP
-A INPUT -s 151.115.0.0/16 -j DROP

# VITOX TELECOM
-A INPUT -s 77.247.109.0/255.255.255.0 -p udp -j DROP 
-A INPUT -s 185.53.88.0/24 -p udp -j DROP 
-A INPUT -s 185.53.89.0/24 -p udp -j DROP 
-A INPUT -s 37.49.224.0/24 -p udp -j DROP 
-A INPUT -s 37.49.230.0/24 -p udp -j DROP 
-A INPUT -s 37.49.231.0/24 -p udp -j DROP 
-A INPUT -s 77.247.110.0/255.255.255.0 -p udp -j DROP