From b006dee9f876ddf48fdd732ecf2beaae24fdbc44 Mon Sep 17 00:00:00 2001 From: Victor Seva Date: Wed, 17 Jun 2020 13:44:47 +0200 Subject: [PATCH] TT#68855 add support for permanent registrations Change-Id: I7852a92cb000a42ea4c32dcb8af4edf0ade14ad8 --- README | 20 ++++++ bin/check.sh | 77 ++++++++++++-------- bin/config_debug.pl | 7 +- bin/create_registrations.pl | 135 ++++++++++++++++++++++++++++++++++++ bin/scenario.pl | 2 +- bin/update_peer_host.pl | 4 +- bin/update_perm_reg.pl | 77 ++++++++++++++++++++ lib/Sipwise/API.pm | 67 +++++++++++++++++- 8 files changed, 354 insertions(+), 35 deletions(-) create mode 100755 bin/create_registrations.pl create mode 100755 bin/update_perm_reg.pl diff --git a/README b/README index 94f02551..83a1a5fb 100644 --- a/README +++ b/README @@ -84,6 +84,7 @@ And can optionally include: - speeddial.yml - peer.yml - trusted.yml + - registration.yml Test file syntax (XXXX_test.yml.tt2 files): @@ -367,6 +368,25 @@ testuser1002@spce.test: src_ip: 127.126.0.1 +registration.yml file syntax: +----------------------------- + +This is used for permanent registrations, lb has two extra sockets defined: + $yaml->{kamailio}{lb}{extra_sockets}->{test} = "udp:127.2.0.1:5064"; + $yaml->{kamailio}{lb}{extra_sockets}->{other} = "udp:127.3.0.1:5074"; + +socket has to be one of those two, and path has to have socket param with +the same value + +testuser1003@spce.test: + - nat: false + contact: sip:127.3.0.5:8008 + socket: sip:127.3.0.1:5074 + path: + q: 0.5 + expires: 1977-07-26 23:47:37 + + prefs.json file syntax: ---------------------- diff --git a/bin/check.sh b/bin/check.sh index a4285738..48987b15 100755 --- a/bin/check.sh +++ b/bin/check.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright: 2013-2016 Sipwise Development Team +# Copyright: 2013-2020 Sipwise Development Team # # 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 @@ -181,6 +181,12 @@ create_voip() { echo "$(date) - Cannot create domain subscribers" exit 1 fi + + if [ -f "${SCEN_CHECK_DIR}/registration.yml" ]; then + echo "$(date) - Creating permanent registrations" + "${BIN_DIR}/create_registrations.pl" \ + "${SCEN_CHECK_DIR}/registration.yml" + fi } # $1 prefs yml file @@ -240,6 +246,34 @@ create_voip_prefs() { fi } +delete_locations() { + local f + local sub + + for f in ${SCEN_CHECK_DIR}/callee.csv ${SCEN_CHECK_DIR}/caller.csv; do + for sub in $(uniq "${f}" | grep "${DOMAIN}" | cut -d\; -f1 | xargs); do + ngcp-kamctl proxy fifo ul.rm location "${sub}@${DOMAIN}" >/dev/null + # delete possible banned user + ngcp-kamcmd lb htable.delete auth "${sub}@${DOMAIN}::auth_count" + done + done + + # check what's in the DDBB + f=$(mysql --defaults-extra-file="${SIPWISE_EXTRA_CNF}" \ + kamailio -e 'select count(*) from location;' -s -r | head) + if [ "${f}" != "0" ]; then + echo "$(date) Cleaning location table" + sub=$(mysql --defaults-extra-file="${SIPWISE_EXTRA_CNF}" \ + -e 'select concat(username, "@", domain) as user from kamailio.location;' \ + -r -s | head| uniq|xargs) + for f in $sub; do + ngcp-kamctl proxy fifo ul.rm location "${f}" >/dev/null + done + mysql --defaults-extra-file="${SIPWISE_EXTRA_CNF}" \ + -e 'delete from kamailio.location;' || true + fi +} + # $1 domain delete_voip() { /usr/bin/ngcp-delete-domain "$1" >/dev/null 2>&1 @@ -290,34 +324,12 @@ delete_voip() { echo "$(date) - Deleting soundsets" "${BIN_DIR}/create_soundsets.pl" -delete "${SCEN_CHECK_DIR}/soundsets.yml" fi -} -delete_locations() { - local f - local sub - - for f in ${SCEN_CHECK_DIR}/callee.csv ${SCEN_CHECK_DIR}/caller.csv; do - for sub in $(uniq "${f}" | grep "${DOMAIN}" | cut -d\; -f1 | xargs); do - ngcp-kamctl proxy fifo ul.rm location "${sub}@${DOMAIN}" >/dev/null - # delete possible banned user - ngcp-kamcmd lb htable.delete auth "${sub}@${DOMAIN}::auth_count" - done - done - - # check what's in the DDBB - f=$(mysql --defaults-extra-file="${SIPWISE_EXTRA_CNF}" \ - kamailio -e 'select count(*) from location;' -s -r | head) - if [ "${f}" != "0" ]; then - echo "$(date) Cleaning location table" - sub=$(mysql --defaults-extra-file="${SIPWISE_EXTRA_CNF}" \ - -e 'select concat(username, "@", domain) as user from kamailio.location;' \ - -r -s | head| uniq|xargs) - for f in $sub; do - ngcp-kamctl proxy fifo ul.rm location "${f}" >/dev/null - done - mysql --defaults-extra-file="${SIPWISE_EXTRA_CNF}" \ - -e 'delete from kamailio.location;' || true + if [ -f "${SCEN_CHECK_DIR}/registration.yml" ]; then + echo "$(date) - Deleting registrations" + "${BIN_DIR}/create_registrations.pl" -delete "${SCEN_CHECK_DIR}/registration.yml" fi + delete_locations } release_appearance() { @@ -423,6 +435,8 @@ get_ip() { fi peer_host=$(grep "$1" "${SCEN_CHECK_DIR}/scenario.csv"|cut -d\; -f4| tr -d '\n') foreign_dom=$(grep "$1" "${SCEN_CHECK_DIR}/scenario.csv"|cut -d\; -f5| tr -d '\n') + registration=$(grep "$1" "${SCEN_CHECK_DIR}/scenario.csv"|cut -d\; -f6| tr -d '\n') + subscriber=$(grep "$1" "${SCEN_CHECK_DIR}/scenario.csv"|cut -d\; -f7| tr -d '\n') } copy_logs() { @@ -468,7 +482,6 @@ run_sipp() { echo "$(date) - create ${LOG_DIR}" mkdir -p "${LOG_DIR}" - delete_locations if [ "${PROFILE}" = "PRO" ] ; then release_appearance fi @@ -510,6 +523,14 @@ run_sipp() { echo "$(date) - foreign domain detected... using 5060 port" PORT="5060" fi + if [ "${registration}" == "permanent" ]; then + echo "$(date) - Update permanent reg:${subscriber} ${ip}:${PORT} info" + if ! "${BIN_DIR}/update_perm_reg.pl" \ + "${subscriber}" "${ip}" "${PORT}"; + then + error_helper "$(date) - error updating peer info" 15 + fi + fi if [ -f "${SCEN_CHECK_DIR}/${base}_reg.xml" ]; then echo "$(date) - Register ${base} ${ip}:${PORT}-${MPORT}" diff --git a/bin/config_debug.pl b/bin/config_debug.pl index 47d71b02..74d3acbe 100755 --- a/bin/config_debug.pl +++ b/bin/config_debug.pl @@ -108,10 +108,9 @@ else $yaml = LoadFile($file_yaml); $yaml->{kamailio}{lb}{cfgt} = 'yes'; $yaml->{kamailio}{lb}{dns}{use_dns_cache} = 'off'; - if($children > 0) - { - $yaml->{kamailio}{proxy}{children} = $children; - } + $yaml->{kamailio}{lb}{extra_sockets}->{test} = "udp:127.2.0.1:5064"; + $yaml->{kamailio}{lb}{extra_sockets}->{other} = "udp:127.3.0.1:5074"; + $yaml->{kamailio}{proxy}{children} = $children if($children > 0); $yaml->{kamailio}{proxy}{cfgt} = 'yes'; $yaml->{sems}{cfgt} = 'yes'; $yaml->{sems}{debug} = 'yes'; diff --git a/bin/create_registrations.pl b/bin/create_registrations.pl new file mode 100755 index 00000000..d5519d33 --- /dev/null +++ b/bin/create_registrations.pl @@ -0,0 +1,135 @@ +#!/usr/bin/perl +# +# Copyright: 2013-2016 Sipwise Development Team +# +# 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 3 of the License, or +# (at your option) any later version. +# +# This package 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. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# On Debian systems, the complete text of the GNU General +# Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". +# +use strict; +use warnings; + +use English; +use Getopt::Long; +use Cwd 'abs_path'; +use Config::Tiny; +use Sipwise::API qw(all); +use YAML::XS qw(DumpFile LoadFile); + +my $config = Config::Tiny->read('/etc/default/ngcp-api'); +my $opts; +if ($config) { + $opts = {}; + $opts->{host} = $config->{_}->{NGCP_API_IP}; + $opts->{port} = $config->{_}->{NGCP_API_PORT}; + $opts->{sslverify} = $config->{_}->{NGCP_API_SSLVERIFY}; +} +my $api = Sipwise::API->new($opts); +$opts = $api->opts; +my $del = 0; + +sub usage { + return "Usage:\n$PROGRAM_NAME registrations.yml\n". + "Options:\n". + " -delete\n". + " -d debug\n". + " -h this help\n"; +} +my $help = 0; +GetOptions ("h|help" => \$help, + "d|debug" => \$opts->{verbose}, + "delete" => \$del) + or die("Error in command line arguments\n".usage()); + +die(usage()) unless (!$help); +die("Error: wrong number of arguments\n".usage()) unless ($#ARGV == 0); + +sub delete_regs +{ + my $subscriber = shift; + my $domain = shift; + my $subs_id = $api->check_subscriber_exists({ + domain => $domain, + username => $subscriber}); + if($subs_id) { + my $count = $api->delete_subscriber_registration($subs_id); + print "${subscriber}[${subs_id}] deleted ${count} regs\n"; + } + + return; +} + +sub create_regs +{ + my $subscriber = shift; + my $domain = shift; + my $subs_id = $api->check_subscriber_exists({ + domain => $domain, + username => $subscriber}); + my $data = shift; + if($subs_id) { + foreach my $r (@{$data}) + { + $r->{subscriber_id} = $subs_id; + my $id = $api->create_subscriber_registration($r); + print "registration: ${subscriber}[${subs_id}] created [${id}]\n"; + } + } + else { + die("Error: No subscriber ${subscriber}\@${domain} found"); + } + + return; +} + +sub do_delete +{ + my $r = shift; + + foreach my $key (keys %{$r}) + { + my @fields = split /@/, $key; + delete_regs($fields[0], $fields[1]); + } + return; +} + +sub do_create { + my $r = shift; + + foreach my $key (keys %{$r}) + { + print "processing ${key}\n"; + my @fields = split /@/, $key; + my $reg = $r->{$key}; + create_regs($fields[0], $fields[1], $reg); + } + return; +} + +sub main { + my $r = shift; + + if ($del) { + print "delete registrations\n" unless $opts->{debug}; + return do_delete($r); + } else { + print "create registrations\n" unless $opts->{debug}; + return do_create($r); + } +} +my $path = abs_path($ARGV[0]); +print "loading ${path}\n"; +main(LoadFile($path)); diff --git a/bin/scenario.pl b/bin/scenario.pl index 3788f4d9..149e0e36 100755 --- a/bin/scenario.pl +++ b/bin/scenario.pl @@ -151,7 +151,7 @@ sub generate $auth = "[authentication username=$_->{username} password=$_->{password}]"; $csv_data = [$_->{username}, $_->{number}, $auth, $_->{domain}, $test_uuid, $_->{'pbx_extension'}]; $csv->{callee}->print($io_callee, $csv_data); - $csv_data = ["sipp_scenario_responder".sprintf("%02i", $res_id).".xml", $_->{proto}, $_->{ip}, $_->{peer_host}, $_->{foreign}]; + $csv_data = ["sipp_scenario_responder".sprintf("%02i", $res_id).".xml", $_->{proto}, $_->{ip}, $_->{peer_host}, $_->{foreign}, $_->{register}, $_->{username}."@".$_->{domain}]; $csv->{scenario}->print($io_scenario, $csv_data); if($_->{register} eq "yes" && $_->{active} eq "yes") { diff --git a/bin/update_peer_host.pl b/bin/update_peer_host.pl index 14e7a2c9..e422a95c 100755 --- a/bin/update_peer_host.pl +++ b/bin/update_peer_host.pl @@ -57,7 +57,9 @@ die("Wrong number of arguments\n".usage()) unless ($#ARGV == 0); my $data = {}; $data->{ip} = $ip unless !defined($ip); $data->{port} = $port unless !defined($port); -die("ip or port option has to be set\n".usage()) unless defined($data); +if (!defined($data->{ip}) && !defined($data->{port})) { + die("ip or port option has to be set\n".usage()) +} sub do_update { my $host_id = $api->check_peeringserver_exists({ name => $ARGV[0] }); diff --git a/bin/update_perm_reg.pl b/bin/update_perm_reg.pl new file mode 100755 index 00000000..dc17b6a3 --- /dev/null +++ b/bin/update_perm_reg.pl @@ -0,0 +1,77 @@ +#!/usr/bin/perl +# +# Copyright: 2020 Sipwise Development Team +# +# 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 3 of the License, or +# (at your option) any later version. +# +# This package 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. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# On Debian systems, the complete text of the GNU General +# Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". +# +use strict; +use warnings; + +use English; +use Getopt::Long; +use Cwd 'abs_path'; +use Config::Tiny; +use Sipwise::API qw(all); + +my $config = Config::Tiny->read('/etc/default/ngcp-api'); +my $opts; +if ($config) { + $opts = {}; + $opts->{host} = $config->{_}->{NGCP_API_IP}; + $opts->{port} = $config->{_}->{NGCP_API_PORT}; + $opts->{sslverify} = $config->{_}->{NGCP_API_SSLVERIFY}; +} +my $api = Sipwise::API->new($opts); +$opts = $api->opts; + +sub usage { + return "Usage:\n$PROGRAM_NAME [-h]" . + " subscriber IP PORT\n"; +} + +my $help = 0; +GetOptions ("h|help" => \$help, + "d|debug" => \$opts->{verbose}) + or die("Error in command line arguments\n".usage()); + +die(usage()) unless (!$help); +die("Wrong number of arguments\n".usage()) unless ($#ARGV == 2); + +my $data = {ip=> $ARGV[1], port=>$ARGV[2]}; +my ($subscriber, $domain) = split /@/, $ARGV[0]; + +sub do_update { + my $subs_id = $api->check_subscriber_exists({ + domain => $domain, + username => $subscriber}); + if(!$subs_id) { + die("Error: No subscriber ${subscriber}\@${domain} found"); + } + my $regs = $api->get_subscriber_registrations($subs_id); + foreach my $r (@{$regs}) { + print "registration[$r->{id}]: $r->{contact}\n"; + if($r->{contact} =~ m/sip:$data->{ip}:/) { + $r->{contact} = "sip:". $data->{ip}. ":" . $data->{port}; + $api->set_subscriber_registration($r->{id}, $r) or + die("Can't update permanent registration $r->{id}"); + print "registration for ${ARGV[0]}[$r->{id}] updated to $r->{contact}\n"; + } + } + return; +} + +do_update(); diff --git a/lib/Sipwise/API.pm b/lib/Sipwise/API.pm index 67eb3380..c23ae1d2 100644 --- a/lib/Sipwise/API.pm +++ b/lib/Sipwise/API.pm @@ -52,7 +52,7 @@ sub _get_id { my ($baseurl, $location) = @_; my $id; - ($id) = ($location =~ m/\Q$baseurl\E(\d+)/); + ($id) = ($location =~ m/\Q$baseurl\E(.+)/); return $id; } @@ -561,6 +561,71 @@ sub get_subscriber_trusted_sources { return $self->_get_content(undef, $urldata); } +sub check_subscriber_registration_exists { + my ($self, $data) = @_; + my $urldata = '/api/subscriberregistrations/'; + my $collection_id = 'ngcp:subscriberregistrations'; + + return $self->_exists($data, $urldata, $collection_id); +} + +sub create_subscriber_registration { + my ($self, $data) = @_; + my $urldata = '/api/subscriberregistrations/'; + + return $self->_create($data, $urldata); +} + +sub get_subscriber_registration { + my ($self, $id) = @_; + my $urldata = "/api/subscriberregistrations/${id}"; + my $collection_id = 'ngcp:subscriberregistrations'; + + return $self->_get_content(undef, $urldata); +} + +sub get_subscriber_registrations { + my ($self, $subs_id) = @_; + my $urldata = '/api/subscriberregistrations/'; + my $collection_id = 'ngcp:subscriberregistrations'; + + my $collection = $self->_get_content({subscriber_id=>$subs_id}, $urldata); + my $res = []; + if (defined $collection && $collection->{total_count} > 0) { + return $collection->{_embedded}->{$collection_id}; + } + return $res; +} + +sub set_subscriber_registration { + my ($self, $id, $data) = @_; + my $urldata = "/api/subscriberregistrations/${id}"; + my $collection_id = 'ngcp:subscriberregistrations'; + + return $self->_set_content($data, $urldata); +} + +sub delete_subscriber_registration { + my ($self, $subs_id) = @_; + my $urldata = '/api/subscriberregistrations/'; + my $collection_id = 'ngcp:subscriberregistrations'; + + my $collection = $self->_get_content(undef, $urldata); + my $count = 0; + if (defined $collection && $collection->{total_count} > 0) { + my $data = $collection->{_embedded}->{$collection_id}; + foreach my $r (@{$data}) { + if ($r->{subscriber_id} eq $subs_id) { + if($self->_delete(${urldata}.$r->{id})) { + $count++; + } + + } + } + } + return $count; +} + sub create_subscriber { my ($self, $data) = @_; my $urldata = '/api/subscribers/';