| @ -0,0 +1,84 @@ | |||||
| version: 2 | |||||
| workflows: | |||||
| version: 2 | |||||
| build_branch: | |||||
| jobs: | |||||
| - build_centos7 | |||||
| build_release: | |||||
| jobs: | |||||
| - build_centos7: | |||||
| filters: | |||||
| tags: | |||||
| only: /^\d+\.\d+\.\d+$/ | |||||
| branches: | |||||
| ignore: /.*/ | |||||
| jobs: | |||||
| build_centos7: | |||||
| docker: | |||||
| - image: offical2600hz/metapackager:1.0-centos-7 | |||||
| user: circleci | |||||
| shell: /bin/bash --login | |||||
| working_directory: /home/circleci/2600hz/the_app | |||||
| environment: | |||||
| CIRCLE_ARTIFACTS: /tmp/circleci-artifacts | |||||
| CIRCLE_TEST_REPORTS: /tmp/circleci-test-results | |||||
| BASH_ENV: "/home/circleci/2600hz/.bashrc" | |||||
| BUILD_ROOT: "/home/circleci/2600hz/packager" | |||||
| CORE_ROOT: "/home/circleci/2600hz/the_app" | |||||
| BUILD_SOURCES: "/home/circleci/2600hz/packager/SOURCES" | |||||
| BUILD_RPMS: "/home/circleci/2600hz/packager/RPMS" | |||||
| APP_DIR: "/home/circleci/2600hz/the_app" | |||||
| steps: | |||||
| - checkout | |||||
| - run: | |||||
| name: Setting up Directories | |||||
| command: | | |||||
| APP=${CIRCLE_PROJECT_REPONAME#meta-} | |||||
| echo -e "export APP=${APP}\n" >> $BASH_ENV | |||||
| - run: | |||||
| name: Generating version info | |||||
| command: | | |||||
| cd $BUILD_ROOT | |||||
| VERSION=$(./version) | |||||
| RELEASE=$(./release) | |||||
| PACKAGE_NAME=$(./package_name) | |||||
| echo "export PACKAGE_NAME=${PACKAGE_NAME}" >> $BASH_ENV | |||||
| echo "export VERSION=${VERSION}" >> $BASH_ENV | |||||
| echo "export RELEASE=${RELEASE}" >> $BASH_ENV | |||||
| PACKAGE_NAME=$(./package_name) | |||||
| echo "export PACKAGE_NAME=${PACKAGE_NAME}" >> $BASH_ENV | |||||
| echo "build version for ${PACKAGE_NAME} version: ${VERSION} release: ${RELEASE}" | |||||
| - run: | |||||
| name: Generating CHANGELOG and VERSION files | |||||
| command: | | |||||
| cd $BUILD_ROOT | |||||
| echo " - generate build version and changelog" | |||||
| ./package_docs | |||||
| - run: | |||||
| name: Preparing source for packaging | |||||
| command: | | |||||
| echo " - preparing source" | |||||
| cp -R ${APP_DIR}/* ${BUILD_SOURCES}/ | |||||
| cd $BUILD_SOURCES | |||||
| echo " - removing files that should not be packaged in the source tar" | |||||
| rm -rf ${BUILD_SOURCES}/.??* | |||||
| rm -rf ${BUILD_SOURCES}/doc* | |||||
| rm -rf ${BUILD_SOURCES}/*.md | |||||
| echo " - creating the source tar" | |||||
| cd $BUILD_ROOT | |||||
| ARTIFACTS_NAME=${PACKAGE_NAME}-${VERSION} | |||||
| mkdir -p ${ARTIFACTS_NAME} | |||||
| cp -r ${BUILD_SOURCES}/* ${ARTIFACTS_NAME}/. | |||||
| tar -cf ${ARTIFACTS_NAME}.tar ${ARTIFACTS_NAME} | |||||
| cp ${ARTIFACTS_NAME}.tar ${BUILD_SOURCES}/. | |||||
| - run: | |||||
| name: Building package | |||||
| command: | | |||||
| cd $BUILD_ROOT | |||||
| ./build | |||||
| - store_artifacts: | |||||
| path: /home/circleci/2600hz/packager/RPMS | |||||
| @ -0,0 +1,86 @@ | |||||
| name: kazoo-configs-kamailio | |||||
| base_branch: origin/4.3 | |||||
| base_core: null | |||||
| template: spec.tmpl | |||||
| package: | |||||
| centos7: | |||||
| name: kazoo-configs-kamailio | |||||
| group: Productivity/Telephony | |||||
| license: MPL1.1 | |||||
| build_arch: noarch | |||||
| build_requires: | |||||
| - rpm-build | |||||
| summary: Kazoo specific configuration for Kamailio | |||||
| description: | | |||||
| The Kazoo platform uses Kamailio to provide SIP services | |||||
| as well as dispatch requests to FreeSWITCH. This package | |||||
| is an elaborate Kamailio configuration based on 'roles' that | |||||
| configure and perform these actions. If you need help you | |||||
| can contact us via the dev mailing list or on IRC at #2600hz | |||||
| on FreeNode. | |||||
| dist: .el7.centos | |||||
| requires: | |||||
| sudo: {} | |||||
| source: '%{_build_tar}' | |||||
| prep: '%setup -q' | |||||
| install: | | |||||
| mkdir -p %{buildroot}/etc/kazoo | |||||
| cp -r kamailio %{buildroot}/etc/kazoo | |||||
| cp CHANGELOG VERSION %{buildroot}/etc/kazoo/kamailio | |||||
| chmod +x %{buildroot}/etc/kazoo/kamailio/db_scripts/*.sh | |||||
| find %{buildroot}/etc/kazoo/kamailio -type f > filelist.txt | |||||
| sed -i 's#%{buildroot}##g' filelist.txt | |||||
| to_replace="local.cfg tls.cfg" | |||||
| for NOREPLACE in ${to_replace} | |||||
| do | |||||
| sed -i "s!/etc/kazoo/kamailio/$NOREPLACE!%config(noreplace) /etc/kazoo/kamailio/$NOREPLACE!g" filelist.txt | |||||
| done | |||||
| cat filelist.txt | |||||
| mkdir -p %{buildroot}/usr/sbin | |||||
| cp -r system/sbin/* %{buildroot}/usr/sbin | |||||
| chmod +x %{buildroot}/usr/sbin/* | |||||
| mkdir -p %{buildroot}/etc/rsyslog.d | |||||
| rm -rf system/rsyslog.d/1-default-config-override.conf | |||||
| rm -rf system/rsyslog.d/5-rate-limits.conf | |||||
| cp -r system/rsyslog.d/*.conf %{buildroot}/etc/rsyslog.d | |||||
| mkdir -p %{buildroot}/etc/logrotate.d | |||||
| cp -r system/logrotate.d/*.conf %{buildroot}/etc/logrotate.d | |||||
| mkdir -p %{buildroot}/etc/security/limits.d | |||||
| cp -r system/security/limits.d/*.conf %{buildroot}/etc/security/limits.d | |||||
| mkdir -p %{buildroot}/usr/lib/systemd/system | |||||
| cp system/systemd/* %{buildroot}/usr/lib/systemd/system | |||||
| files: | |||||
| doc: | |||||
| - CHANGELOG | |||||
| - VERSION | |||||
| list: filelist.txt | |||||
| dir: /etc/kazoo/kamailio | |||||
| config: | |||||
| - mode: noreplace | |||||
| path: /etc/rsyslog.d/*kamailio* | |||||
| - mode: noreplace | |||||
| path: /etc/logrotate.d/*kamailio* | |||||
| - mode: noreplace | |||||
| path: /etc/security/limits.d/*kamailio* | |||||
| path: | |||||
| - /usr/sbin/kazoo-kamailio | |||||
| - /usr/lib/systemd/system/kazoo-kamailio.service | |||||
| post: systemctl -q enable kazoo-kamailio.service | |||||
| preun: '%{?systemd_preun kazoo-kamailio.service}' | |||||
| postun: '%{?systemd_postun kazoo-kamailio.service}' | |||||
| url: 'http://www.2600hz.org' | |||||
| vendor: 2600Hz | |||||
| metapackage: | |||||
| - | |||||
| name: meta-kazoo-kamailio | |||||
| package: kazoo-configs-kamailio | |||||
| type: required | |||||
| branch: '4.3' | |||||
| @ -1,80 +1,349 @@ | |||||
| # kazoo-configs | |||||
| Kazoo Configuration Files for Software We Use | |||||
| ``` | |||||
| @###+` | |||||
| ;# +@;'@@: | |||||
| +@@@' ##`` #' | |||||
| `@@'.'@, .@.```## + | |||||
| @:..`#@` #@````#@ `@@@, | |||||
| @'`.``@@ .@'`` ;@ :@@`@@+ | |||||
| #@`````@@@@` ,@: '@# ;@' | |||||
| +@`````:,.```````@@@@' ,@` | |||||
| '+` :@``````````` `', #@ | |||||
| ,@@@#: +@.`````````` ` @: | |||||
| @#.,@@@#@;```````` ``. ` +@` | |||||
| #@..``.'@,```````` .., ` @+ | |||||
| @#``````.```````` ` #@ :+: | |||||
| :@;````.```````` `@##@@@@@` | |||||
| +@,``````````` ,@+:.` @; | |||||
| #@````````` ,::::,:: ` `+@ | |||||
| #@.``````` .:,` `,, `` `@. | |||||
| #@`````` ,:` `, . `,@@. | |||||
| .@;````` ., , ``.` '@@` | |||||
| ++#@@@@.``` `:` . `` `+@+ | |||||
| @#':,.```` ,` .` `````'@: | |||||
| .@```````` , . ``````:@` | |||||
| :@``` ` `.. `. .```````.@, | |||||
| '@ `` . .`: ,` ````````.@@#'` | |||||
| .:;;:, +@@+. ` .` , ```````...+@@#; | |||||
| #@@@@@ .'@@#'. , ````.``..``.,@# | |||||
| @:``,@` `.#@; . ```.`:``..````## | |||||
| '@@` ,@``` @, #@+ @+ ` ````.```,.````#' | |||||
| :@@'@# +@``` ## #@;@@; #@ . ````````:.``.,@: | |||||
| :@#.`.@# ##`` `#@ #@. `+@: +@;` ` `````````'+#@@@@` | |||||
| @,..`,@#`:@,` ` ,@; #@, `@,@@, . ` ``````.``##+;,.` | |||||
| @+````.@@@@.```` @@@@, '@@@` ` ` ``````...;@` | |||||
| +@`````,:.`` ` ` `,:` #@' . ` ``````...`+@ | |||||
| ,@.`````````` ` ` @#+ ` `` `````````..::@' | |||||
| . @:````````` `. ``,@'@` .,: ```````````````......:.'@: | |||||
| :@@+: :@#```````` `.` +@:@+'#@@@#. ``````````````......:..`#@. | |||||
| @#'@@@#@#```````` ., '@@@@@;+@@#` ``````````````......:,....@@ | |||||
| #@.``.:+#```````` +#:. @@@:` ````````,``````.....`;:.....+@` | |||||
| @;`````````````` ` `:@@`,, ```````.,````.......;+@#;`.,@' | |||||
| .@#```````````` `,::,. `` ` +@; .:```````.````......,'#;,#@@+@@ | |||||
| ,@#``````````` ,:,.```.,, .` #@+` `,:`````````....`,;,#' .'@@` | |||||
| .@#```````` :,` `,` ``. #@+# `` ##+;,````````.:::,.#@ . | |||||
| .@#``````` :` .` ```.#@;@, ```@@;@#;:::::;'++,....#@ | |||||
| ,@,````` :` .` `````@;`@@; ,@@. #'``...#@+@#....;@` | |||||
| '@````` .. . ```````++ +@+@@` #@````+@` ,@'`..,@` | |||||
| `;+#@```` : ` ``````'@+; .@+ #@````## '@:.`'@, | |||||
| .+#@@@',``` `. .```````,'@@@@+, ;@.``,@. #@+@@+` | |||||
| '@',. `.`` ,` ````````.``.,'@' .@:.`#@ @@'. | |||||
| +@```` ` `.. , ````.```..````## @@@@@' .` | |||||
| +@``` `` .`, , ``.`,``..````## `.,::` | |||||
| +@ `` ` . , ```,.``..````@+ | |||||
| '@@#', ` `` ````````,.:'#@@' | |||||
| .:+@@@+ ` ```````.;@@@#;, | |||||
| .#@` . ``````..'@,` | |||||
| :@. ` ``````..`+; | |||||
| +@, ` ``````...,#+ | |||||
| +@:`` ` ``````....::@+ | |||||
| +@, , `` ``````....,,.,@# | |||||
| #@, `` ``` ````````....`;...:@# | |||||
| :@, . `````````````.....:,....:@: | |||||
| @@ .: `````````````.....,;`....#@ | |||||
| :@. ,'@@#: ``````.``````.....,+@@+;.,@; | |||||
| @@@@@+:@@: ```````..````.....,+@:'@@@@@ | |||||
| #;, @+,`` ``````.,````.....:'#` .;#. | |||||
| @.`,, ```````````....,;,.@` | |||||
| ;@ .,,````````..``,;:..`@' | |||||
| #@ ++':,,...,:;'+.....#@ | |||||
| @: +@#@#,,,,,,#@+@#....;@` | |||||
| ,@. +@; @;````'@` ,@#....@, | |||||
| .@@' +@; #@````#@ ,@#`'@@. | |||||
| '@@@; ;@.```@' :@@@'` | |||||
| `''` `@.`..@. :+. | |||||
| @+';+@` | |||||
| #@@@@@ | |||||
| # Manual Setup Guide for Kamailio with PostgreSQL for Kazoo/2600Hz | |||||
| This guide will help you manually set up a Kamailio Session Border Controller (SBC) with PostgreSQL for Kazoo/2600Hz. Since the 2600hz provided database for kamailio (Kazoo_DB) is not open source, we have to replace it with PostgreSQL. | |||||
| This is an improvement anyway, as KazooDB has issues with presence/BLF at larger scales without putting it on a ramdisk. | |||||
| ## Overview | |||||
| The Kamailio SBC acts as the entry point for SIP traffic in a Kazoo platform. It handles tasks like: | |||||
| - SIP signaling management | |||||
| - Load balancing | |||||
| - Security and authentication | |||||
| - Registration handling | |||||
| ## Prerequisites | |||||
| - Debian/Ubuntu system (Debian 11 Bullseye recommended), or RHEL 8/9 (Almalinux, Rocky Linux, etc.) | |||||
| - Basic understanding of SIP, PostgreSQL, and Kazoo | |||||
| ## 1. PostgreSQL Installation | |||||
| #### Debian: | |||||
| ```bash | |||||
| # Add PostgreSQL repository | |||||
| apt-key add https://www.postgresql.org/media/keys/ACCC4CF8.asc | |||||
| echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/postgresql.list | |||||
| # Update and install PostgreSQL 13 | |||||
| apt update | |||||
| apt install -y postgresql-13 postgresql-client-13 postgresql-contrib-13 \ | |||||
| python3-psycopg2 postgresql-server-dev-13 | |||||
| ``` | |||||
| #### RHEL: | |||||
| ```bash | |||||
| dnf module enable postgresql:13 # RHEL 8 | |||||
| dnf module enable postgresql:16 # RHEL 9 | |||||
| dnf install postgresql-server | |||||
| ``` | |||||
| ## 2. PostgreSQL Configuration | |||||
| Initialize the config (only required on RHEL, Debian does it during installation): | |||||
| ```bash | |||||
| postgresql-setup --initdb | |||||
| ``` | |||||
| Edit PostgreSQL configuration files: | |||||
| ### Configure PostgreSQL access | |||||
| Edit `pg_hba.conf` to allow access of the DB on 127.0.0.1 with password: | |||||
| #### Debian: | |||||
| ```bash | |||||
| nano /etc/postgresql/13/main/pg_hba.conf | |||||
| ``` | |||||
| #### RHEL: | |||||
| ```bash | |||||
| nano /var/lib/pgsql/data/pg_hba.conf | |||||
| ``` | |||||
| Add this line: | |||||
| ``` | |||||
| # IPv4 local connections: | |||||
| host all all 127.0.0.1/32 password | |||||
| ``` | |||||
| ### Configure main PostgreSQL settings: | |||||
| #### Debian: | |||||
| ```bash | |||||
| nano /etc/postgresql/13/main/postgresql.conf | |||||
| ``` | |||||
| #### RHEL: | |||||
| ```bash | |||||
| nano /var/lib/pgsql/data/postgresql.conf | |||||
| ``` | |||||
| ##### Key settings to update: | |||||
| ```conf | |||||
| # Basic settings | |||||
| listen_addresses = '127.0.0.1' | |||||
| port = 5432 | |||||
| # Memory | |||||
| shared_buffers = 512MB | |||||
| max_connections = 400 | |||||
| superuser_reserved_connections = 10 | |||||
| # For Kamailio performance | |||||
| datestyle = 'iso, dmy' | |||||
| timezone = 'UTC' | |||||
| ``` | |||||
| Restart PostgreSQL: | |||||
| #### Debian: | |||||
| ```bash | |||||
| systemctl restart postgresql@13-main | |||||
| ``` | |||||
| #### RHEL: | |||||
| ```bash | |||||
| systemctl restart postgresql | |||||
| ``` | |||||
| ## 3. Kamailio Installation | |||||
| ### Add Kamailio Repository | |||||
| #### Debian: | |||||
| ```bash | |||||
| apt-key add https://deb.kamailio.org/kamailiodebkey.gpg | |||||
| echo "deb http://deb.kamailio.org/kamailio55 bullseye main" > /etc/apt/sources.list.d/kamailio.list | |||||
| echo "deb-src http://deb.kamailio.org/kamailio55 bullseye main" >> /etc/apt/sources.list.d/kamailio.list | |||||
| apt update | |||||
| ``` | |||||
| #### RHEL: | |||||
| Add the repository: | |||||
| ```bash | |||||
| yum config-manager --add-repo https://rpm.kamailio.org/centos/kamailio.repo | |||||
| ``` | |||||
| Enable the correct version repo: | |||||
| ```bash | |||||
| nano /etc/yum.repos.d/kamailio.repo | |||||
| ``` | |||||
| Disable the "latest" repo by setting it to `enabled=0`. | |||||
| Enable the `5.5.7` repo by setting `enabled=1`. | |||||
| ### Install Kamailio Packages | |||||
| #### Debian: | |||||
| ```bash | |||||
| apt install -y kamailio kamailio-postgres-modules kamailio-kazoo-modules \ | |||||
| kamailio-outbound-modules kamailio-presence-modules kamailio-tls-modules \ | |||||
| kamailio-utils-modules kamailio-websocket-modules kamailio-extra-modules \ | |||||
| kamailio-xmpp-modules | |||||
| ``` | |||||
| #### RHEL: | |||||
| (All these Kamailio modules aren't strictly necessary, but they don't take up much space and you may want to use some later for custom scenarios.) | |||||
| ```bash | |||||
| dnf install kamailio kamailio-auth-ephemeral kamailio-auth-xkeys kamailio-carrierroute kamailio-cnxcc kamailio-cpl kamailio-crypto kamailio-debugsource kamailio-dialplan kamailio-dmq_userloc kamailio-evapi kamailio-gzcompress kamailio-http_async_client kamailio-http_client kamailio-ims kamailio-jansson kamailio-json kamailio-kazoo kamailio-lcr kamailio-ldap kamailio-lost kamailio-lua kamailio-lwsc kamailio-outbound kamailio-perl kamailio-phonenum kamailio-postgresql kamailio-presence kamailio-python kamailio-rabbitmq kamailio-regex kamailio-rtjson kamailio-ruby kamailio-sctp kamailio-secfilter kamailio-sipcapture-daemon-config kamailio-sipdump kamailio-sipjson kamailio-snmpstats kamailio-sqlang kamailio-sqlite kamailio-statsd kamailio-tcpops kamailio-tls kamailio-unixodbc kamailio-utils kamailio-uuid kamailio-websocket kamailio-xhttp-pi kamailio-xmlops kamailio-xmlrpc kamailio-xmpp | |||||
| ``` | |||||
| ## 4. Database Setup for Kamailio | |||||
| Create kamailio database and user: | |||||
| ```bash | |||||
| sudo -u postgres psql -c "CREATE DATABASE kamailio;" | |||||
| sudo -u postgres psql -c "CREATE USER kamailio WITH PASSWORD 'your_secure_password';" | |||||
| sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE kamailio TO kamailio;" | |||||
| ``` | |||||
| ## 5. Kazoo Configuration | |||||
| ### Clone Kamailio Configuration Repository | |||||
| ```bash | |||||
| mkdir -p /etc/kazoo | |||||
| git clone https://github.com/kazoo-classic/kazoo-configs-kamailio.git /etc/kazoo | |||||
| ``` | |||||
| ### Initialize Kamailio Database | |||||
| ```bash | |||||
| # Create necessary directories | |||||
| mkdir -p /etc/kazoo/kamailio/db | |||||
| chown kamailio:kamailio /etc/kazoo/kamailio -R | |||||
| # Initialize Kamailio database | |||||
| sudo -u postgres psql -U kamailio -d postgres://kamailio:your_secure_password@127.0.0.1/kamailio \ | |||||
| -f /etc/kazoo/kamailio/db_scripts/kamailio_initdb_postgres.sql | |||||
| ``` | |||||
| ## 6. Configure Kamailio | |||||
| ### System Configuration | |||||
| Create/edit the Kamailio system config: | |||||
| #### Debian: | |||||
| ```bash | |||||
| nano /etc/default/kamailio | |||||
| ``` | |||||
| Add the recommended values: | |||||
| ```conf | |||||
| # Kamailio startup options | |||||
| SHM_MEMORY=64 | |||||
| PKG_MEMORY=8 | |||||
| DUMP_CORE=no | |||||
| CFGFILE=/etc/kazoo/kamailio/kamailio.cfg | |||||
| ``` | |||||
| #### RHEL: | |||||
| ```bash | |||||
| nano /lib/systemd/system/kamailio.service | |||||
| ``` | |||||
| Change this line: | |||||
| ``` | |||||
| Environment='CFGFILE=/etc/kamailio/kamailio.cfg' | |||||
| ``` | |||||
| to this: | |||||
| ``` | |||||
| Environment='CFGFILE=/etc/kazoo/kamailio/kamailio.cfg' | |||||
| ``` | |||||
| Reload the systemd service file: | |||||
| ```bash | |||||
| systemctl daemon-reload | |||||
| ``` | |||||
| ### Create Local Configuration | |||||
| Edit the local configuration file for Kamailio: | |||||
| ```bash | |||||
| nano /etc/kazoo/kamailio/local.cfg | |||||
| ``` | |||||
| Uncomment the roles you want to enable near the top of the file. | |||||
| Set your server information: | |||||
| ```conf | |||||
| #!substdef "!MY_HOSTNAME!sbc.z1.your-domain.com!g" | |||||
| #!substdef "!MY_IP_ADDRESS!YOUR_SBC_IP_ADDRESS!g" | |||||
| ``` | |||||
| Point AMQP at your RabbitMQ Server. You can add more zones and secondary/terniary urls: | |||||
| ```conf | |||||
| #!substdef "!MY_AMQP_ZONE!z1!g" | |||||
| #!substdef "!MY_AMQP_URL!zone=z1;amqp://guest:guest@rabbitmq.your-domain.com:5672!g" | |||||
| ``` | |||||
| Configure your postgres connection | |||||
| ```conf | |||||
| #!trydef KZ_DB_MODULE postgres | |||||
| #!substdef "!KAMAILIO_DBMS!postgres!g" | |||||
| #!substdef "!KAZOO_DB_URL!postgres://kamailio:your_secure_password@127.0.0.1/kamailio!g" | |||||
| ``` | |||||
| Set your SIP bindings: | |||||
| ```conf | |||||
| #!substdef "!UDP_SIP!udp:MY_IP_ADDRESS:5060!g" | |||||
| #!substdef "!TCP_SIP!tcp:MY_IP_ADDRESS:5060!g" | |||||
| #!substdef "!UDP_ALG_SIP!udp:MY_IP_ADDRESS:7000!g" | |||||
| #!substdef "!TCP_ALG_SIP!tcp:MY_IP_ADDRESS:7000!g" | |||||
| listen=UDP_SIP | |||||
| listen=TCP_SIP | |||||
| listen=UDP_ALG_SIP | |||||
| listen=TCP_ALG_SIP | |||||
| ``` | |||||
| ## 7. Configure Logging | |||||
| ### Configure rsyslog | |||||
| ```bash | |||||
| mkdir -p /var/log/kamailio | |||||
| chown kamailio:kamailio /var/log/kamailio | |||||
| # Create rsyslog configuration | |||||
| cat > /etc/rsyslog.d/10-kamailio.conf << 'EOF' | |||||
| if $programname == 'kamailio' then /var/log/kamailio/kamailio.log | |||||
| & ~ | |||||
| EOF | |||||
| # Create logrotate configuration | |||||
| cat > /etc/logrotate.d/kamailio << 'EOF' | |||||
| /var/log/kamailio/kamailio.log { | |||||
| daily | |||||
| size 500M | |||||
| nodateext | |||||
| missingok | |||||
| notifempty | |||||
| rotate 31 | |||||
| maxage 5 | |||||
| create | |||||
| compress | |||||
| delaycompress | |||||
| sharedscripts | |||||
| postrotate | |||||
| /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true | |||||
| /bin/kill -HUP `cat /var/run/rsyslogd.pid 2> /dev/null` 2> /dev/null || true | |||||
| endscript | |||||
| } | |||||
| EOF | |||||
| # Restart rsyslog | |||||
| systemctl restart rsyslog | |||||
| ``` | |||||
| ## 8. Final Configuration and Start | |||||
| ### Start and Enable Services | |||||
| ```bash | |||||
| # Start PostgreSQL | |||||
| systemctl enable postgresql | |||||
| systemctl start postgresql | |||||
| # Start Kamailio | |||||
| systemctl enable kamailio | |||||
| systemctl start kamailio | |||||
| ``` | |||||
| ### Verify Configuration | |||||
| ```bash | |||||
| # Check Kamailio status | |||||
| systemctl status kamailio | |||||
| # Verify logs | |||||
| tail -f /var/log/kamailio/kamailio.log | |||||
| # Check SIP ports are open | |||||
| netstat -tulpn | grep kamailio | |||||
| ``` | ``` | ||||
| @ -0,0 +1,130 @@ | |||||
| route[AUTH] | |||||
| { | |||||
| if (!is_method("INVITE|MESSAGE|REFER")) { | |||||
| return; | |||||
| } | |||||
| #!ifdef DISPATCHER_ROLE | |||||
| if (!isflagset(FLAG_INTERNALLY_SOURCED)) { | |||||
| route(SETUP_AUTH_HEADERS); | |||||
| } | |||||
| #!endif | |||||
| } | |||||
| route[AUTH_HEADERS] | |||||
| { | |||||
| remove_hf_re("^X-"); | |||||
| if (!is_method("INVITE|MESSAGE|REFER")) { | |||||
| return; | |||||
| } | |||||
| xavp_params_implode("hf", "$var(outx)"); | |||||
| $var(out) = $(var(outx){re.subst,/^(.*);$$/\1/}); | |||||
| $var(c) = $(var(out){param.count}); | |||||
| xlog("L_DEBUG", "$ci|auth|headers $var(c) => $var(out) => $var(outx)\n"); | |||||
| while($var(c) > 0) { | |||||
| $var(idx) = $var(c) - 1; | |||||
| xlog("L_DEBUG", "$ci|auth|adding $(var(out){param.name,$var(idx)}): $(var(out){param.valueat,$var(idx)}{s.unescape.param})\n"); | |||||
| append_hf("$(var(out){param.name,$var(idx)}): $(var(out){param.valueat,$var(idx)}{s.unescape.param})\r\n"); | |||||
| $var(c) = $var(c) - 1; | |||||
| } | |||||
| } | |||||
| route[AUTH_HEADERS_JSON] | |||||
| { | |||||
| xavp_params_implode("hf", "$var(outx)"); | |||||
| $var(out) = $(var(outx){re.subst,/^(.*);$$/\1/}); | |||||
| $var(c) = $(var(out){param.count}); | |||||
| $var(headers_json) = ""; | |||||
| $var(sep) = ""; | |||||
| xlog("L_DEBUG", "$ci|auth|headers $var(c) => $var(out) => $var(outx)\n"); | |||||
| while($var(c) > 0) { | |||||
| $var(idx) = $var(c) - 1; | |||||
| xlog("L_DEBUG", "$ci|auth|adding $(var(out){param.name,$var(idx)}): $(var(out){param.valueat,$var(idx)}{s.unescape.param})\n"); | |||||
| append_hf("$(var(out){param.name,$var(idx)}): $(var(out){param.valueat,$var(idx)}{s.unescape.param})\r\n"); | |||||
| $var(headers_json) = $_s($var(headers_json)$var(sep)"$(var(out){param.name,$var(idx)})" : "$(var(out){param.valueat,$var(idx)}{s.unescape.param})"); | |||||
| $var(c) = $var(c) - 1; | |||||
| $var(sep) = " , "; | |||||
| } | |||||
| $var(headers_json) = $_s({ $var(headers_json) }); | |||||
| } | |||||
| route[SETUP_AUTH_HEADERS] | |||||
| { | |||||
| $xavp(hf=>X-AUTH-IP) = $si; | |||||
| $xavp(hf[0]=>X-AUTH-PORT) = $sp; | |||||
| #!ifdef REGISTRAR_ROLE | |||||
| $avp(is_registered) = "false"; | |||||
| $xavp(regcfg=>match_received) = $su; | |||||
| if (registered("location","$fu", 2, 1) != 1) return; | |||||
| $avp(is_registered) = "true"; | |||||
| #!ifdef WITH_AUTH_TOKEN | |||||
| route(AUTH_TOKEN); | |||||
| #!else | |||||
| route(AUTH_CCVS); | |||||
| #!endif | |||||
| #!endif | |||||
| } | |||||
| #!ifdef REGISTRAR_ROLE | |||||
| route[AUTH_TOKEN] | |||||
| { | |||||
| if($(xavp(ulattrs=>token){s.len}) > 0) { | |||||
| $xavp(hf[0]=>X-AUTH-Token) = $xavp(ulattrs=>token); | |||||
| } else { | |||||
| if($(xavp(ulattrs=>Authorizing-ID){s.len}) > 0 && $(xavp(ulattrs=>Account-ID){s.len})) { | |||||
| $xavp(hf[0]=>X-AUTH-Token) = $_s($(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-ID})@$(xavp(ulattrs=>custom_channel_vars){kz.json,Account-ID})); | |||||
| } | |||||
| } | |||||
| } | |||||
| route[AUTH_CCVS] | |||||
| { | |||||
| if($(xavp(ulattrs=>custom_channel_vars){kz.json,Account-ID}{s.len}) > 0 && $(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-Type}{s.len}) > 0) | |||||
| $xavp(hf[0]=>X-AUTH-Token) = $_s($(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-ID})@$(xavp(ulattrs=>custom_channel_vars){kz.json,Account-ID})); | |||||
| if($(xavp(ulattrs=>custom_channel_vars){kz.json,Account-ID}{s.len}) > 0) | |||||
| $xavp(hf[0]=>X-ecallmgr_Account-ID) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Account-ID}); | |||||
| if($(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-Type}{s.len}) > 0) | |||||
| $xavp(hf[0]=>X-ecallmgr_Authorizing-Type) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-Type}); | |||||
| if($(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-ID}{s.len}) > 0) | |||||
| $xavp(hf[0]=>X-ecallmgr_Authorizing-ID) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Authorizing-ID}); | |||||
| if($(xavp(ulattrs=>custom_channel_vars){kz.json,Username}{s.len}) > 0) | |||||
| $xavp(hf[0]=>X-ecallmgr_Username) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Username}); | |||||
| if($(xavp(ulattrs=>custom_channel_vars){kz.json,Realm}{s.len}) > 0) | |||||
| $xavp(hf[0]=>X-ecallmgr_Realm) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Realm}); | |||||
| if($(xavp(ulattrs=>custom_channel_vars){kz.json,Account-Realm}{s.len}) > 0) | |||||
| $xavp(hf[0]=>X-ecallmgr_Account-Realm) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Account-Realm}); | |||||
| if($(xavp(ulattrs=>custom_channel_vars){kz.json,Account-Name}{s.len}) > 0) | |||||
| $xavp(hf[0]=>X-ecallmgr_Account-Name) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Account-Name}{s.escape.param}); | |||||
| if($(xavp(ulattrs=>custom_channel_vars){kz.json,Presence-ID}{s.len}) > 0) | |||||
| $xavp(hf[0]=>X-ecallmgr_Presence-ID) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Presence-ID}); | |||||
| if($(xavp(ulattrs=>custom_channel_vars){kz.json,Owner-ID}{s.len}) > 0) | |||||
| $xavp(hf[0]=>X-ecallmgr_Owner-ID) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Owner-ID}); | |||||
| if($(xavp(ulattrs=>custom_channel_vars){kz.json,Hotdesk-Current-ID}{s.len}) > 0) | |||||
| $xavp(hf[0]=>X-ecallmgr_Hotdesk-Current-ID) = $(xavp(ulattrs=>custom_channel_vars){kz.json,Hotdesk-Current-ID}); | |||||
| } | |||||
| #!endif | |||||
| @ -0,0 +1,23 @@ | |||||
| ## to be enhanced | |||||
| route[AUTHORIZATION_CHECK] | |||||
| { | |||||
| if (!is_method("MESSAGE|NOTIFY|SUBSCRIBE|PUBLISH")) | |||||
| return; | |||||
| if(has_totag()) | |||||
| return; | |||||
| if (isflagset(FLAG_INTERNALLY_SOURCED)) | |||||
| return; | |||||
| if (isflagset(FLAG_TRUSTED_SOURCE)) | |||||
| return; | |||||
| $xavp(regcfg=>match_received) = $su; | |||||
| if(!(registered("location", "$fu", 2, 1) == 1 && $(xavp(ulattrs=>custom_channel_vars){s.len}) > 1)) { | |||||
| xlog("L_INFO", "$ci|log|not authorized $fu from $si:$sp\n"); | |||||
| send_reply("503", "Not Registered"); | |||||
| exit; | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,39 @@ | |||||
| ######## BLOCK BY IP[PORT] ######## | |||||
| #!trydef KZ_BLOCK_ENABLE 1 | |||||
| #!trydef KZ_BLOCK_LOG_LEVEL 1 | |||||
| #!trydef KZ_BLOCK_LOG_BUFFER 0 | |||||
| #!trydef KZ_BLOCK_DRY_RUN 0 | |||||
| #!ifdef KZ_BLOCK_COLD_CACHE | |||||
| #!substdef "!BLOCK_S_WARM_CACHE!!g" | |||||
| #!else | |||||
| #!substdef "!BLOCK_S_WARM_CACHE!dbtable=block_cache;dbmode=1;!g" | |||||
| #!endif | |||||
| modparam("htable", "htable", "block=>size=8;BLOCK_S_WARM_CACHE") | |||||
| modparam("statistics","variable", "block:blocked_requests") | |||||
| kazoo.block_enable = KZ_BLOCK_ENABLE descr "enable block processing" | |||||
| kazoo.block_log_level = KZ_BLOCK_LOG_LEVEL descr "block log level" | |||||
| kazoo.block_log_buffer = KZ_BLOCK_LOG_BUFFER descr "log the received buffer" | |||||
| kazoo.block_dry_run = KZ_BLOCK_DRY_RUN descr "log but keep processing" | |||||
| ## global param to enable route | |||||
| received_route_mode=1 | |||||
| event_route[core:msg-received] | |||||
| { | |||||
| if($sel(cfg_get.kazoo.block_enable) == 1) { | |||||
| if($sht(block=>$rcv(srcip)) || $sht(block=>$rcv(srcip)::$rcv(srcport))) { | |||||
| if($sel(cfg_get.kazoo.block_log_buffer) == 1) { | |||||
| xlog("$(sel(cfg_get.kazoo.block_log_level){s.int})", "|block|request from [$rcv(srcip):$rcv(srcport)] to [$rcv(rcvip):$rcv(rcvport)] was blocked => [$rcv(buf)]\n"); | |||||
| } else { | |||||
| xlog("$(sel(cfg_get.kazoo.block_log_level){s.int})", "|block|request from [$rcv(srcip):$rcv(srcport)] to [$rcv(rcvip):$rcv(rcvport)] was blocked\n"); | |||||
| } | |||||
| if($sel(cfg_get.kazoo.block_dry_run) == 0) { | |||||
| drop; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @ -0,0 +1,14 @@ | |||||
| #### db_kazoo module ### | |||||
| #!trydef KZ_DB_HOOK_TRACE 1 | |||||
| #!trydef KZ_DB_TRACE 0 | |||||
| #!trydef KZ_DB_TRACE_LOG_LEVEL 3 | |||||
| #!trydef KZ_DB_TRACE_FILTER 110 | |||||
| loadmodule "db_kazoo.so" | |||||
| modparam("db_kazoo", "trace_hook", KZ_DB_HOOK_TRACE) | |||||
| modparam("db_kazoo", "trace_enable", KZ_DB_TRACE) | |||||
| modparam("db_kazoo", "trace_log_level", KZ_DB_TRACE_LOG_LEVEL) | |||||
| modparam("db_kazoo", "trace_filter", KZ_DB_TRACE_FILTER) | |||||
| include_file "db_queries_kazoo.cfg" | |||||
| @ -0,0 +1,4 @@ | |||||
| #### db_mysql module ### | |||||
| loadmodule "db_mysql.so" | |||||
| include_file "db_queries_mysql.cfg" | |||||
| @ -0,0 +1,4 @@ | |||||
| #### db_postgres module ### | |||||
| loadmodule "db_postgres.so" | |||||
| include_file "db_queries_postgres.cfg" | |||||
| @ -1,15 +1,33 @@ | |||||
| ####### Database queries ######## | ####### Database queries ######## | ||||
| #!substdef "!KZQ_CHECK_MEDIA_SERVER_INSERT!insert into dispatcher (setid, destination) select \$var(SetId), \"\$var(MediaUrl)\" where not exists(select * from dispatcher where destination = \"\$var(MediaUrl)\")!g" | |||||
| #!substdef "!KZQ_COUNT_ALL_SUBSCRIBERS!select a.event, count(distinct watcher_username || \"@\" || watcher_domain) count_unique, count(*) count from event_list a, active_watchers b where b.event = a.event group by a.event!g" | |||||
| #!substdef "!KZQ_CHECK_MEDIA_SERVER_INSERT!insert into dispatcher (setid, destination, flags, attrs, description) select \$var(SetId), \"\$var(MediaUrl)\", \$var(flags), \"\$var(attrs)\", \"added by nodes role\" where not exists(select * from dispatcher where destination = \"\$var(MediaUrl)\")!g" | |||||
| #!substdef "!KZQ_COUNT_ALL_SUBSCRIBERS!select a.event, count(distinct watcher_uri) count_unique, count(*) count from event_list a left outer join active_watchers b on a.event = b.event group by a.event!g" | |||||
| #!substdef "!KZQ_COUNT_PRESENTITIES!select event, (select count(*) from presentity b where username = \"\$(var(payload){kz.json,From}{uri.user})\" and domain = \"\$(var(payload){kz.json,From}{uri.domain})\" and b.event = a.event) count from event_list a!g" | #!substdef "!KZQ_COUNT_PRESENTITIES!select event, (select count(*) from presentity b where username = \"\$(var(payload){kz.json,From}{uri.user})\" and domain = \"\$(var(payload){kz.json,From}{uri.domain})\" and b.event = a.event) count from event_list a!g" | ||||
| #!substdef "!KZQ_COUNT_SUBSCRIBERS!select event, (select count(*) from active_watchers b where presentity_uri = \"\$var(presentity)\" and b.event = a.event) count from event_list a!g" | |||||
| #!substdef "!KZQ_COUNT_SUBSCRIBERS!select event, (select count(*) from active_watchers b where presentity_uri = \"\$var(presentity)\" and b.event = a.event) count from event_list a union all select \"self\", count(distinct callid) from presentities where presentity_uri = \"\$var(presentity)\" and callid <> \"\$var(callid)\" and state in('early', 'confirmed', 'onthephone', 'busy', 'ringing')!g" | |||||
| #!substdef "!KZQ_EVENT_PRESENCE_RESET_DELETE!delete from presentity where domain=\"\$(kzE{kz.json,Realm})\" and username = \"\$(kzE{kz.json,Username})\"!g" | #!substdef "!KZQ_EVENT_PRESENCE_RESET_DELETE!delete from presentity where domain=\"\$(kzE{kz.json,Realm})\" and username = \"\$(kzE{kz.json,Username})\"!g" | ||||
| #!substdef "!KZQ_HANDLE_NEW_SUBSCRIBE_DELETE1!delete from active_watchers where callid = \"\$ci\"!g" | #!substdef "!KZQ_HANDLE_NEW_SUBSCRIBE_DELETE1!delete from active_watchers where callid = \"\$ci\"!g" | ||||
| #!substdef "!KZQ_HANDLE_NEW_SUBSCRIBE_DELETE2!delete from active_watchers where watcher_username=\"\$fU\" and presentity_uri=\"\$var(presentity_uri)\" and to_user=\"\$tU\" and watcher_domain=\"\$fd\" and event=\"\$hdr(Event)\"!g" | |||||
| #!substdef "!KZQ_RESET_ACCOUNT_DELETE!delete from presentity where domain=\"\$(kzE{kz.json,Realm})\"!g" | |||||
| #!substdef "!KZQ_RESET_ACCOUNT_UPDATE!update active_watchers set expires = \$TS where watcher_domain=\"\$(kzE{kz.json,Realm})\"!g" | |||||
| #!substdef "!KZQ_RESET_PUBLISHER_UPDATE!update active_watchers set expires = \$TS where id in (select b.id from presentity a inner join active_watchers b on a.username = b.to_user and a.domain = b.to_domain and a.event = b.event where a.sender = \"\$var(MediaUrl)\")!g" | |||||
| #!substdef "!KZQ_PRESENCE_SEARCH_DETAIL!select * from active_watchers_log where presentity_uri = \"\$var(presentity_uri)\"!g" | |||||
| #!substdef "!KZQ_PRESENCE_SEARCH_SUMMARY!select * from active_watchers where watcher_domain = \"\$var(Domain)\"!g" | |||||
| #!substdef "!KZQ_HANDLE_NEW_SUBSCRIBE_DELETE2!delete from active_watchers where presentity_uri=\"\$var(presentity_uri)\" and event=\"\$hdr(Event)\" and watcher_username=\"\$fU\" and to_user=\"\$tU\" and watcher_domain=\"\$fd\"!g" | |||||
| #!substdef "!KZQ_PRESENCE_SEARCH_SUMMARY!select * from active_watchers where to_domain = \"\$var(Domain)\"!g" | |||||
| #!substdef "!KZQ_PRESENCE_SEARCH_DETAIL!select a.*, b.time, b.result, b.sent_msg, b.received_msg from active_watchers a left outer join active_watchers_log b on a.presentity_uri = b.presentity_uri and a.event = b.event and a.callid = b.callid where a.presentity_uri = \"\$var(presentity_uri)\" !g" | |||||
| #!substdef "!KZQ_HAS_PRESENTITY!select count(*) as count from presentity where username = \"\$subs(to_user)\" and domain = \"\$subs(to_domain)\" and event = \"\$subs(event)\"!g" | #!substdef "!KZQ_HAS_PRESENTITY!select count(*) as count from presentity where username = \"\$subs(to_user)\" and domain = \"\$subs(to_domain)\" and event = \"\$subs(event)\"!g" | ||||
| #!substdef "!KZQ_REPLACE_WATCHERS_LOG!REPLACE INTO active_watchers_log (presentity_uri, watcher_username, watcher_domain, event, callid, to_user, to_domain, user_agent, time, result, sent_msg, received_msg) VALUES (\"\$subs(uri)\", \"\$subs(watcher_username)\", \"\$subs(watcher_domain)\", \"\$subs(event)\",\"\$subs(callid)\",\"\$subs(to_user)\",\"\$subs(to_domain)\", '\$(subs(user_agent){s.escape.common}{s.replace,\\\',''}{s.replace,\$\$,})', \$TS, \$notify_reply(\$rs), '\$(mb{s.escape.common}{s.replace,\\\',''}{s.replace,\$\$,})', '\$(notify_reply(\$mb){s.escape.common}{s.replace,\\\',''}{s.replace,\$\$,})')!g" | |||||
| # # #!substdef "!KZQ_RESET_PUBLISHER_UPDATE!update active_watchers set expires = \$TS where id in (select b.id from presentity a inner join active_watchers b on a.username = b.to_user and a.domain = b.to_domain and a.event = b.event where a.sender = \"\$var(MediaUrl)\")!g" | |||||
| #!substdef "!KZQ_RESET_PUBLISHER_UPDATE!INSERT INTO tmp_probe select distinct a.event, a.presentity_uri, 0 from presentities a inner join active_watchers b on a.presentity_uri = b.presentity_uri and a.event = b.event where sender = \"\$var(MediaUrl)\" and state in('early', 'confirmed', 'onthephone', 'busy', 'ringing')!g" | |||||
| #!substdef "!KZQ_PRESENCE_RESET!delete from presentity where sender = \"\$var(MediaUrl)\"!g" | #!substdef "!KZQ_PRESENCE_RESET!delete from presentity where sender = \"\$var(MediaUrl)\"!g" | ||||
| # # #!substdef "!KZQ_RESET_ACCOUNT_UPDATE!update active_watchers set expires = \$TS where watcher_domain=\"\$(kzE{kz.json,Realm})\"!g" | |||||
| #!substdef "!KZQ_RESET_ACCOUNT_UPDATE!INSERT INTO tmp_probe select distinct a.event, a.presentity_uri, 0 from presentities a inner join active_watchers b on a.presentity_uri = b.presentity_uri and a.event = b.event where domain=\"\$(kzE{kz.json,Realm})\" and state in('early', 'confirmed', 'onthephone', 'busy', 'ringing')!g" | |||||
| #!substdef "!KZQ_RESET_ACCOUNT_RESET!delete from presentity where domain=\"\$(kzE{kz.json,Realm})\"!g" | |||||
| #!substdef "!KZQ_RESET_PUBLISHER_ZONE_UPDATE!INSERT INTO tmp_probe select distinct a.event, a.presentity_uri, 0 from presentities a inner join wdispatcher c on a.sender = c.destination inner join active_watchers b on a.presentity_uri = b.presentity_uri and a.event = b.event where zone = \"\$var(Zone)\" and state in('early', 'confirmed', 'onthephone', 'busy', 'ringing')!g" | |||||
| #!substdef "!KZQ_PRESENCE_ZONE_RESET!delete from presentity where id in(select a.id from presentities a join wdispatcher c on a.sender = c.destination where zone = \"\$var(Zone)\")!g" | |||||
| #!substdef "!KZQ_DELETE_FROM_ACTIVE_WATCHERS_WHERE_EXPIRES!DELETE FROM active_watchers WHERE expires > 0 AND datetime(expires, 'unixepoch') < datetime('now', '-90 seconds')!g" | |||||
| #!substdef "!KZQ_DELETE_FROM_ACTIVE_WATCHERS_WHERE_PRESENTITY!DELETE FROM ACTIVE_WATCHERS WHERE PRESENTITY_URI=\"\$subs(uri)\" AND EVENT=\"\$subs(event)\" AND FROM_USER = \"\$subs(from_user)\" AND FROM_DOMAIN=\"\$subs(from_domain)\" AND CALLID <> \"\$subs(callid)\"!g" | |||||
| #!substdef "!KZQ_DELETE_FROM_PRESENTITY_WHERE_EXPIRES!DELETE FROM PRESENTITY WHERE expires > 0 AND datetime(expires, 'unixepoch') < datetime('now')!g" | |||||
| #!substdef "!KZQ_DELETE_FROM_PRESENTITY_WHERE_DIALOG_TERMINATED!DELETE FROM PRESENTITY WHERE ID IN(select id from presentities where event = 'dialog' and state = 'terminated' and received < datetime('now', '-5 minutes'))!g" | |||||
| @ -0,0 +1,46 @@ | |||||
| #!/bin/sh | |||||
| TEMP_DB_LOCATION=/tmp/db | |||||
| TEMP_DB=${TEMP_DB_LOCATION}/kazoo.db | |||||
| rm -rf ${TEMP_DB_LOCATION} | |||||
| . $(dirname $0)/kazoodb-sql.sh --source-only | |||||
| file=$(sql_db_prepare) | |||||
| sql_setup $file ${TEMP_DB_LOCATION} | |||||
| DB_VERSION=`KazooDB -db ${TEMP_DB} "select sum(table_version) from version;"` | |||||
| DB_CURRENT_DB=${DB_LOCATION:-/etc/kazoo/kamailio}/kazoo.db | |||||
| DB_CURRENT_VERSION=`KazooDB -db ${DB_CURRENT_DB} "select sum(table_version) from version;"` | |||||
| if [[ $DB_CURRENT_VERSION -ne $DB_VERSION ]]; then | |||||
| echo "db required version is ${DB_VERSION}, existing version is ${DB_CURRENT_VERSION}, applying diff" | |||||
| KazooDB-diff --schema ${DB_CURRENT_DB} ${TEMP_DB} | KazooDB -db ${DB_CURRENT_DB} | |||||
| KazooDB-diff --primarykey --table version ${DB_CURRENT_DB} ${TEMP_DB} | KazooDB -db ${DB_CURRENT_DB} | |||||
| KazooDB-diff --primarykey --table event_list ${DB_CURRENT_DB} ${TEMP_DB} | KazooDB -db ${DB_CURRENT_DB} | |||||
| fi | |||||
| for VIEW in `ls ${DB_SCRIPT_DIR}/vw_*.sql`; do | |||||
| filename=$(basename -- "$VIEW") | |||||
| filename="${filename%.*}" | |||||
| viewname=${filename#*_} | |||||
| v1=$(KazooDB -db ${DB_CURRENT_DB} "select sql from sqlite_master where type='view' and name='$viewname'" 2> /dev/null | tr -d ' ' | md5sum | cut -d ' ' -f1) | |||||
| v2=$(cat $VIEW | tr -d ' ' | md5sum | cut -d ' ' -f1) | |||||
| if [[ "$v1" != "$v2" ]]; then | |||||
| echo "rebuilding view $viewname" | |||||
| KazooDB -db ${DB_CURRENT_DB} "drop view if exists $viewname;" | |||||
| KazooDB -db ${DB_CURRENT_DB} < $VIEW | |||||
| fi | |||||
| done | |||||
| if [ -f ${DB_SCRIPT_DIR}/db_extra_check.sql ]; then | |||||
| . ${DB_SCRIPT_DIR}/db_extra_check.sql --source-only | |||||
| do_db_extra_check; | |||||
| fi | |||||
| for INIT in `ls ${DB_SCRIPT_DIR}/db_init_*.sql`; do | |||||
| KazooDB -db ${DB_CURRENT_DB} < $INIT | |||||
| done | |||||
| @ -1,104 +1,9 @@ | |||||
| #!/bin/sh -e | #!/bin/sh -e | ||||
| ##################################################################################### | |||||
| ## | |||||
| ## If you want prepare SQL file for PostgreSQL or MySQL server, then need to execute | |||||
| ## DB_ENGINE=postgres ./create-kazoodb-sql.sh | |||||
| ## | |||||
| ##################################################################################### | |||||
| KAMAILIO_SHARE_DIR=${KAMAILIO_SHARE_DIR:-/usr/share/kamailio} | |||||
| DB_ENGINE=${DB_ENGINE:-db_kazoo} | |||||
| RESULTED_SQL=${RESULTED_SQL:-/tmp/kamailio_initdb.sql} | |||||
| . $(dirname $0)/kazoodb-sql.sh --source-only | |||||
| . $(dirname $0)/$DB_ENGINE-specific --source-only | |||||
| sql_filelist() { | |||||
| cat << EOF | |||||
| acc-create.sql | |||||
| lcr-create.sql | |||||
| domain-create.sql | |||||
| group-create.sql | |||||
| permissions-create.sql | |||||
| registrar-create.sql | |||||
| usrloc-create.sql | |||||
| msilo-create.sql | |||||
| alias_db-create.sql | |||||
| uri_db-create.sql | |||||
| speeddial-create.sql | |||||
| avpops-create.sql | |||||
| auth_db-create.sql | |||||
| pdt-create.sql | |||||
| dialog-create.sql | |||||
| dispatcher-create.sql | |||||
| dialplan-create.sql | |||||
| topos-create.sql | |||||
| presence-create.sql | |||||
| rls-create.sql | |||||
| imc-create.sql | |||||
| cpl-create.sql | |||||
| siptrace-create.sql | |||||
| domainpolicy-create.sql | |||||
| carrierroute-create.sql | |||||
| userblacklist-create.sql | |||||
| htable-create.sql | |||||
| purple-create.sql | |||||
| uac-create.sql | |||||
| pipelimit-create.sql | |||||
| mtree-create.sql | |||||
| sca-create.sql | |||||
| mohqueue-create.sql | |||||
| rtpproxy-create.sql | |||||
| uid_auth_db-create.sql | |||||
| uid_avp_db-create.sql | |||||
| uid_domain-create.sql | |||||
| uid_gflags-create.sql | |||||
| uid_uri_db-create.sql | |||||
| EOF | |||||
| } | |||||
| sql_all_header() { | |||||
| cat << EOF | |||||
| CREATE TABLE version ( | |||||
| table_name VARCHAR(32) NOT NULL, | |||||
| table_version INTEGER DEFAULT 0 NOT NULL, | |||||
| CONSTRAINT version_table_name_idx UNIQUE (table_name) | |||||
| ); | |||||
| INSERT INTO version VALUES('version',1); | |||||
| EOF | |||||
| } | |||||
| sql_all_extra_tables() { | |||||
| cat << EOF | |||||
| CREATE TABLE event_list ( event varchar(25) PRIMARY KEY NOT NULL); | |||||
| INSERT INTO event_list VALUES('dialog'); | |||||
| INSERT INTO event_list VALUES('presence'); | |||||
| INSERT INTO event_list VALUES('message-summary'); | |||||
| INSERT INTO version VALUES('event_list',1); | |||||
| EOF | |||||
| } | |||||
| sql_all_footer() { | |||||
| cat << EOF | |||||
| COMMIT; | |||||
| EOF | |||||
| } | |||||
| echo "Creating kamailio database init file in '$RESULTED_SQL'" | |||||
| sql_db_pre_setup > $RESULTED_SQL | |||||
| sql_all_header >> $RESULTED_SQL | |||||
| sql_header >> $RESULTED_SQL | |||||
| for i in $(sql_filelist); do | |||||
| cat $KAMAILIO_SHARE_DIR/$DB_ENGINE/$i >> $RESULTED_SQL | |||||
| done | |||||
| sql_all_extra_tables >> $RESULTED_SQL | |||||
| sql_extra_tables >> $RESULTED_SQL | |||||
| sql_footer >> $RESULTED_SQL | |||||
| sql_all_footer >> $RESULTED_SQL | |||||
| sql_setup $RESULTED_SQL | |||||
| file=$(sql_db_prepare) | |||||
| echo "setting up kazoo db from init script $file" | |||||
| sql_setup $file | |||||
| exit 0 | exit 0 | ||||
| @ -0,0 +1,34 @@ | |||||
| do_db_extra_check() { | |||||
| # location | |||||
| if [[ $RESET_NON_UDP_ENABLED == "true" ]]; then | |||||
| KazooDB -db ${DB_CURRENT_DB} "delete from location where socket not like 'udp:%';" | |||||
| fi | |||||
| ##KazooDB -db ${DB_CURRENT_DB} "delete from location where expires > 0 and datetime(expires) < datetime('now', '-30 seconds');" | |||||
| KazooDB -db ${DB_CURRENT_DB} "delete from location_attrs where not exists(select id from location where ruid = location_attrs.ruid);" | |||||
| ## presence | |||||
| if [[ $RESET_NON_UDP_ENABLED == "true" ]]; then | |||||
| KazooDB -db ${DB_CURRENT_DB} "delete from active_watchers where socket_info not like 'udp:%';" | |||||
| fi | |||||
| KazooDB -db ${DB_CURRENT_DB} "delete from active_watchers where expires > 0 and datetime(expires, 'unixepoch') < datetime('now', '-10 seconds');" | |||||
| KazooDB -db ${DB_CURRENT_DB} "delete from presentity where expires > 0 AND datetime(expires, 'unixepoch') < datetime('now', '-10 seconds');" | |||||
| KazooDB -db ${DB_CURRENT_DB} "delete from presentity where id in(select id from presentities where state in('terminated','available'));" | |||||
| KazooDB -db ${DB_CURRENT_DB} "delete from active_watchers_log where id in(select id from active_watchers_log a where not exists(select callid from active_watchers b where b.callid = a.callid and b.watcher_username = a.watcher_username and b.watcher_domain = a.watcher_domain));" | |||||
| KazooDB -db ${DB_CURRENT_DB} "delete from presentity where id in(select id from presentities a where not exists(select * from active_watchers where presentity_uri = a.presentity_uri));" | |||||
| ## notify watchers of pending calls | |||||
| ## 'create temp table as' because it will be dropped as soon as we ended the session | |||||
| KazooDB -db ${DB_CURRENT_DB} "drop table if exists tmp_probe;" | |||||
| KazooDB -db ${DB_CURRENT_DB} "create table tmp_probe as select distinct a.event, a.presentity_uri, cast(2 as integer) action from presentities a inner join active_watchers b on a.presentity_uri = b.presentity_uri and a.event = b.event where state in('early', 'confirmed', 'onthephone', 'busy');" | |||||
| KazooDB -db ${DB_CURRENT_DB} "delete from presentity where id in(select id from presentities where state in('early', 'confirmed', 'onthephone', 'busy'));" | |||||
| ## keepalive | |||||
| if [[ $RESET_NON_UDP_ENABLED == "true" ]]; then | |||||
| KazooDB -db ${DB_CURRENT_DB} "delete from keepalive where sockinfo NOT LIKE 'udp%';" | |||||
| fi | |||||
| KazooDB -db ${DB_CURRENT_DB} "update keepalive set selected = 0, time_sent = datetime('now') where selected < 3;" | |||||
| } | |||||
| @ -0,0 +1,14 @@ | |||||
| CREATE TRIGGER if not exists active_watchers_watcher_uri_insert | |||||
| AFTER INSERT ON active_watchers | |||||
| FOR EACH ROW | |||||
| BEGIN | |||||
| UPDATE active_watchers SET watcher_uri = "sip:" || NEW.watcher_username || "@" || NEW.watcher_domain where id = NEW.id; | |||||
| END; | |||||
| CREATE TRIGGER if not exists active_watchers_watcher_uri_update | |||||
| AFTER UPDATE ON active_watchers | |||||
| FOR EACH ROW | |||||
| WHEN OLD.watcher_username <> NEW.watcher_username OR OLD.watcher_domain <> NEW.watcher_domain | |||||
| BEGIN | |||||
| UPDATE active_watchers SET watcher_uri = "sip:" || NEW.watcher_username || "@" || NEW.watcher_domain where id = NEW.id; | |||||
| END; | |||||
| @ -0,0 +1,56 @@ | |||||
| #!/bin/sh -e | |||||
| KAMAILIO_SHARE_DIR=${KAMAILIO_SHARE_DIR:-/usr/share/kamailio} | |||||
| DB_ENGINE=${DB_ENGINE:-db_kazoo} | |||||
| RESULTED_SQL=${RESULTED_SQL:-/tmp/kamailio_initdb.sql} | |||||
| . $(dirname $0)/$DB_ENGINE-specific --source-only | |||||
| sql_filelist() { | |||||
| echo `ls -A1 ${KAMAILIO_SHARE_DIR}/${DB_ENGINE}/*.sql | grep -v standard | tr '\n' '\0' | xargs -0 -n 1 basename | sort` | |||||
| } | |||||
| sql_all_header() { | |||||
| cat << EOF | |||||
| CREATE TABLE version ( | |||||
| table_name VARCHAR(32) NOT NULL, | |||||
| table_version INTEGER DEFAULT 0 NOT NULL, | |||||
| PRIMARY KEY(table_name) | |||||
| ); | |||||
| INSERT INTO version VALUES('version',1); | |||||
| EOF | |||||
| } | |||||
| sql_all_extra_tables() { | |||||
| cat << EOF | |||||
| CREATE TABLE event_list ( event varchar(25) PRIMARY KEY NOT NULL); | |||||
| INSERT INTO event_list VALUES('dialog'); | |||||
| INSERT INTO event_list VALUES('presence'); | |||||
| INSERT INTO event_list VALUES('message-summary'); | |||||
| INSERT INTO version VALUES('event_list',1); | |||||
| EOF | |||||
| } | |||||
| sql_all_footer() { | |||||
| cat << EOF | |||||
| COMMIT; | |||||
| EOF | |||||
| } | |||||
| sql_db_prepare() { | |||||
| sql_db_pre_setup > $RESULTED_SQL | |||||
| sql_all_header >> $RESULTED_SQL | |||||
| sql_header >> $RESULTED_SQL | |||||
| for i in $(sql_filelist); do | |||||
| cat $KAMAILIO_SHARE_DIR/$DB_ENGINE/$i >> $RESULTED_SQL | |||||
| done | |||||
| sql_all_extra_tables >> $RESULTED_SQL | |||||
| sql_extra_tables >> $RESULTED_SQL | |||||
| sql_footer >> $RESULTED_SQL | |||||
| sql_all_footer >> $RESULTED_SQL | |||||
| echo "$RESULTED_SQL" | |||||
| } | |||||
| @ -0,0 +1,20 @@ | |||||
| CREATE VIEW presentities as | |||||
| select id, cast(printf("sip:%s@%s",username,domain) as varchar(64)) presentity_uri , | |||||
| username, domain, event, cast(substr(etag, instr(etag,"@")+1) as varchar(64)) callid, | |||||
| datetime(received_time, 'unixepoch') as received, | |||||
| datetime(expires, 'unixepoch') as expire_date, | |||||
| expires, cast(sender as varchar(30)) sender, | |||||
| lower(cast( case when event = "dialog" | |||||
| then substr(body, instr(BODY,"<state>")+7, instr(body,"</state>") - instr(body,"<state>") - 7) | |||||
| when event = "presence" | |||||
| then case when instr(body,"<dm:note>") == 0 | |||||
| then replace(substr(body, instr(body,"<note>")+6, instr(body,"</note>") - instr(body,"<note>") - 6), " ", "") | |||||
| else replace(substr(body, instr(body,"<dm:note>")+9, instr(body,"</dm:note>") - instr(body,"<dm:note>") - 9), " ", "") | |||||
| end | |||||
| when event = "message-summary" | |||||
| then case when instr(body,"Messages-Waiting: yes") = 0 | |||||
| then "Waiting" | |||||
| else "Not-Waiting" | |||||
| end | |||||
| end as varchar(12))) state | |||||
| from presentity | |||||
| @ -0,0 +1,6 @@ | |||||
| CREATE VIEW w_keepalive_contact as | |||||
| select id, slot, selected, failed, case when instr(contact,";") > 0 | |||||
| then substr(contact, 1, instr(contact,";")-1) | |||||
| else contact | |||||
| end as contact | |||||
| from keepalive | |||||
| @ -0,0 +1,6 @@ | |||||
| CREATE VIEW w_location_contact as | |||||
| select id, ruid, case when instr(contact,";") > 0 | |||||
| then substr(contact, 1, instr(contact,";")-1) | |||||
| else contact | |||||
| end as contact | |||||
| from location | |||||
| @ -0,0 +1,6 @@ | |||||
| CREATE VIEW w_watchers_contact as | |||||
| select id, case when instr(contact,";") > 0 | |||||
| then substr(contact, 1, instr(contact,";")-1) | |||||
| else contact | |||||
| end as contact | |||||
| from active_watchers | |||||
| @ -0,0 +1,6 @@ | |||||
| CREATE VIEW wdispatcher as | |||||
| select *, | |||||
| cast(substr(attrs, instr(attrs, "zone=")+5, instr(attrs, ";profile")-instr(attrs, "zone=")-5) as varchar(20)) zone, | |||||
| cast(substr(attrs, instr(attrs, "duid=")+5, instr(attrs, ";node")-instr(attrs, "duid=")-5) as integer) idx, | |||||
| cast(substr(attrs, instr(attrs, "node=")+5) as varchar(50)) node | |||||
| from dispatcher | |||||
| @ -0,0 +1,88 @@ | |||||
| ## NOTE: DO NOT CHANGE THIS FILE, EDIT local.cfg ## | |||||
| ####### amqp defs ######## | |||||
| #!ifndef AMQP_DEFAULTS_INCLUDED | |||||
| #!define AMQP_DEFAULTS_INCLUDED | |||||
| #!trydef MY_AMQP_MAX_CHANNELS 25 | |||||
| #!trydef MY_AMQP_CONSUMER_PROCESSES 4 | |||||
| #!trydef MY_AMQP_CONSUMER_WORKERS 16 | |||||
| #!trydef MY_AMQP_HEARTBEATS 5 | |||||
| #!ifndef MY_AMQP_ZONE | |||||
| #!substdef "!MY_AMQP_ZONE!local!g" | |||||
| #!endif | |||||
| #!ifdef PRESENCE_ROLE | |||||
| #!trydef MY_AMQP_PUA_MODE 1 | |||||
| #!else | |||||
| #!trydef MY_AMQP_PUA_MODE 0 | |||||
| #!endif | |||||
| #!ifndef MY_AMQP_URL | |||||
| #!ifdef AMQP_URL1 | |||||
| #!substdef "!MY_AMQP_URL!$def(AMQP_URL1)!g" | |||||
| #!else | |||||
| #!substdef "!MY_AMQP_URL!amqp://guest:guest@127.0.0.1:5672!g" | |||||
| #!endif | |||||
| #!endif | |||||
| #!ifndef MY_AMQP_SECONDARY_URL | |||||
| #!ifdef AMQP_URL2 | |||||
| #!substdef "!MY_AMQP_SECONDARY_URL!$def(AMQP_URL2)!g" | |||||
| #!endif | |||||
| #!endif | |||||
| #!ifndef MY_AMQP_TERTIARY_URL | |||||
| #!ifdef AMQP_URL3 | |||||
| #!substdef "!MY_AMQP_TERTIARY_URL!$def(AMQP_URL3)!g" | |||||
| #!endif | |||||
| #!endif | |||||
| #!ifndef MY_AMQP_QUATERNARY_URL | |||||
| #!ifdef AMQP_URL4 | |||||
| #!substdef "!MY_AMQP_QUATERNARY_URL!$def(AMQP_URL4)!g" | |||||
| #!endif | |||||
| #!endif | |||||
| #!ifndef MY_AMQP_QUINARY_URL | |||||
| #!ifdef AMQP_URL5 | |||||
| #!substdef "!MY_AMQP_QUINARY_URL!$def(AMQP_URL5)!g" | |||||
| #!endif | |||||
| #!endif | |||||
| #!ifndef MY_AMQP_SENARY_URL | |||||
| #!ifdef AMQP_URL6 | |||||
| #!substdef "!MY_AMQP_SENARY_URL!$def(AMQP_URL6)!g" | |||||
| #!endif | |||||
| #!endif | |||||
| #!ifndef MY_AMQP_SEPTENARY_URL | |||||
| #!ifdef AMQP_URL7 | |||||
| #!substdef "!MY_AMQP_SEPTENARY_URL!$def(AMQP_URL7)!g" | |||||
| #!endif | |||||
| #!endif | |||||
| #!ifndef MY_AMQP_OCTONARY_URL | |||||
| #!ifdef AMQP_URL8 | |||||
| #!substdef "!MY_AMQP_OCTONARY_URL!$def(AMQP_URL8)!g" | |||||
| #!endif | |||||
| #!endif | |||||
| #!ifndef MY_AMQP_NONARY_URL | |||||
| #!ifdef AMQP_URL9 | |||||
| #!substdef "!MY_AMQP_NONARY_URL!$def(AMQP_URL9)!g" | |||||
| #!endif | |||||
| #!endif | |||||
| #!ifndef MY_AMQP_DENARY_URL | |||||
| #!ifdef AMQP_URL10 | |||||
| #!substdef "!MY_AMQP_DENARY_URL!$def(AMQP_URL10)!g" | |||||
| #!endif | |||||
| #!endif | |||||
| #!endif | |||||
| # vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab | |||||
| @ -0,0 +1,306 @@ | |||||
| ### DISPATCHER ROLE #### | |||||
| #!trydef KZ_DISPATCHER_PROBE_MODE 1 | |||||
| #!trydef DISPATCHER_ADD_SERVERS 1 | |||||
| #!trydef DISPATCHER_ADD_SECONDARY_IP 1 | |||||
| #!trydef DISPATCHER_SECONDARY_IP_GROUP 3 | |||||
| #!trydef DISPATCHER_ALG 0 | |||||
| #!trydef KZ_DISPATCHER_HASH_SIZE 8 | |||||
| #!trydef KZ_DISPATCHER_ADD_FLAGS 9 | |||||
| #!trydef KZ_DISPATCHER_PRIMARY_GROUP 1 | |||||
| #!trydef KZ_DISPATCHER_SECONDARY_GROUP 2 | |||||
| #!trydef KZ_DISPATCHER_CLASSIFY_GROUP 3 | |||||
| #!trydef KZ_DISPATCHER_ALTNET1_PRIMARY_GROUP 51 | |||||
| #!trydef KZ_DISPATCHER_ALTNET1_SECONDARY_GROUP 52 | |||||
| #!trydef KZ_DISPATCHER_ALTNET2_PRIMARY_GROUP 53 | |||||
| #!trydef KZ_DISPATCHER_ALTNET2_SECONDARY_GROUP 54 | |||||
| #!trydef KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP 10 | |||||
| #!trydef KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP 11 | |||||
| #!trydef KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP 20 | |||||
| #!trydef KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP 21 | |||||
| #!trydef KZ_DISPATCHER_MAX_RETRIES 2 | |||||
| #!trydef KZ_DISPATCHER_ROUTE_ASSOCIATED_MEDIA 1 | |||||
| #!trydef KZ_DISPATCHER_CLASSIFY_FLAGS 2 | |||||
| kazoo.dispatcher_auto_add = DISPATCHER_ADD_SERVERS descr "adds media servers reported by ecallmgr" | |||||
| kazoo.dispatcher_add_secondary_ip = DISPATCHER_ADD_SECONDARY_IP descr "adds internal ip from media servers reported by ecallmgr" | |||||
| kazoo.dispatcher_add_secondary_ip_group = DISPATCHER_SECONDARY_IP_GROUP descr "sets the group where to add internal ip from media servers reported by ecallmgr" | |||||
| kazoo.dispatcher_algorithm = DISPATCHER_ALG descr "dispatcher algorithm to use" | |||||
| kazoo.dispatcher_primary_group = KZ_DISPATCHER_PRIMARY_GROUP descr "dispatcher primary group" | |||||
| kazoo.dispatcher_secondary_group = KZ_DISPATCHER_SECONDARY_GROUP descr "dispatcher secondary group" | |||||
| kazoo.dispatcher_max_retries = KZ_DISPATCHER_MAX_RETRIES descr "max number of retries for media servers" | |||||
| kazoo.dispatcher_route_to_associated_media = KZ_DISPATCHER_ROUTE_ASSOCIATED_MEDIA descr "routes to associated media for atxfer" | |||||
| kazoo.dispatcher_classify_flags = KZ_DISPATCHER_CLASSIFY_FLAGS descr "dispatch classifier flags" | |||||
| ####### Dispatcher module ######## | |||||
| loadmodule "dispatcher.so" | |||||
| modparam("dispatcher", "db_url", "KAZOO_DB_URL") | |||||
| modparam("dispatcher", "flags", 2) | |||||
| modparam("dispatcher", "use_default", 0) | |||||
| modparam("dispatcher", "force_dst", 1) | |||||
| modparam("dispatcher", "dst_avp", "$avp(ds_dst)") | |||||
| modparam("dispatcher", "attrs_avp", "$avp(ds_attrs)") | |||||
| modparam("dispatcher", "grp_avp", "$avp(ds_grp)") | |||||
| modparam("dispatcher", "cnt_avp", "$avp(ds_cnt)") | |||||
| modparam("dispatcher", "hash_pvar", "$avp(ds_grp)") | |||||
| modparam("dispatcher", "ds_hash_size", KZ_DISPATCHER_HASH_SIZE) | |||||
| modparam("dispatcher", "setid_pvname", "$var(setid)") | |||||
| modparam("dispatcher", "attrs_pvname", "$var(attrs)") | |||||
| modparam("dispatcher", "ds_ping_method", "OPTIONS") | |||||
| modparam("dispatcher", "ds_ping_interval", 10) | |||||
| modparam("dispatcher", "ds_probing_threshold", 3) | |||||
| modparam("dispatcher", "ds_probing_mode", KZ_DISPATCHER_PROBE_MODE) | |||||
| modparam("dispatcher", "ds_ping_reply_codes", "501,403,404,400,200") | |||||
| modparam("dispatcher", "ds_ping_from", "sip:sipcheck@MY_HOSTNAME") | |||||
| #!import_file "dispatcher-network-params.cfg" | |||||
| ## Dispatcher Groups: | |||||
| ## 1 - Primary media servers | |||||
| ## 2 - Backup media servers | |||||
| ## 3 - Alternate media server IPs (used only for classification) | |||||
| ## 10 - Presence servers (if not locally handled) | |||||
| ## 20 - Registrar servers (if not locally handled) | |||||
| modparam("rtimer", "timer", "name=dispatcher_reload;interval=20;mode=1;") | |||||
| modparam("rtimer", "exec", "timer=dispatcher_reload;route=DISPATCHER_RELOAD") | |||||
| ####### Dispatcher Logic ######## | |||||
| route[DISPATCHER_CLASSIFY_SOURCE] | |||||
| { | |||||
| #!import_file "dispatcher-network-classify.cfg" | |||||
| if (is_myself("$ou")) { | |||||
| xlog("$var(log_request_level)", "$ci|log|original R-URI ($ou) is this proxy, treating as external sources\n"); | |||||
| } else { | |||||
| $var(classify_dispatcher_flag) = $(sel(cfg_get.kazoo.dispatcher_classify_flags){s.int}); | |||||
| if (ds_is_from_list(KZ_DISPATCHER_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_CLASSIFY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_ALTNET1_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_ALTNET1_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_ALTNET2_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_ALTNET2_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP, "$var(classify_dispatcher_flag)")) { | |||||
| xlog("$var(log_request_level)", "$ci|log|originated from internal sources\n"); | |||||
| setflag(FLAG_INTERNALLY_SOURCED); | |||||
| } else { | |||||
| xlog("$var(log_request_level)", "$ci|log|originated from external sources\n"); | |||||
| } | |||||
| } | |||||
| } | |||||
| # Take the routes from dispatcher - hash over callid | |||||
| # If prefered route defined, reorder the destionations | |||||
| route[DISPATCHER_FIND_ROUTES] | |||||
| { | |||||
| $var(ds_primary_group) = $sel(cfg_get.kazoo.dispatcher_primary_group); | |||||
| $var(ds_backup_group) = $sel(cfg_get.kazoo.dispatcher_secondary_group); | |||||
| #!ifndef PRESENCE_ROLE | |||||
| if (is_method("SUBSCRIBE")) { | |||||
| $var(ds_primary_group) = KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP; | |||||
| $var(ds_backup_group) = KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP; | |||||
| add_path(); | |||||
| } | |||||
| #!endif | |||||
| #!ifndef REGISTRAR_ROLE | |||||
| if (is_method("REGISTER")) { | |||||
| $var(ds_primary_group) = KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP; | |||||
| $var(ds_backup_group) = KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP; | |||||
| add_path(); | |||||
| } | |||||
| #!endif | |||||
| #!ifdef PRESENCE_ROLE | |||||
| route(PRESENCE_FAST_PICKUP_ATTEMPT); | |||||
| #!endif | |||||
| #!import_file "dispatcher-network-find.cfg" | |||||
| $var(ds_group) = $var(ds_primary_group); | |||||
| if (!ds_select_dst("$var(ds_primary_group)", "$sel(cfg_get.kazoo.dispatcher_algorithm)") || $(avp(ds_dst)[0]) == $null) { | |||||
| # we selected from primary group, try again in backup group | |||||
| if (!ds_select_dst("$var(ds_backup_group)", "$sel(cfg_get.kazoo.dispatcher_algorithm)") || $(avp(ds_dst)[0]) == $null) { | |||||
| xlog("L_WARN", "$ci|end|no servers available in primary or backup group\n"); | |||||
| sl_send_reply("480", "All servers busy"); | |||||
| exit; | |||||
| } else { | |||||
| $var(ds_group) = $var(ds_backup_group); | |||||
| } | |||||
| } | |||||
| $var(user_source) = $(ct{tobody.user}) + "@" + $si + ":" + $sp; | |||||
| if ($sht(associations=>$var(user_source)) != $null) { | |||||
| if($sel(cfg_get.kazoo.dispatcher_route_to_associated_media) == 1) { | |||||
| $var(prefered_route) = $sht(associations=>$var(user_source)); | |||||
| xlog("L_INFO", "$ci|route|found association for contact uri $var(user_source)\n"); | |||||
| route(DISPATCHER_PREFERRED_ROUTE); | |||||
| } | |||||
| $sht(associations=>$var(user_source)) = $null; | |||||
| } | |||||
| $avp(ds_retries) = 0; | |||||
| } | |||||
| route[DISPATCHER_PREFERRED_ROUTE] | |||||
| { | |||||
| ###### | |||||
| # check if the preferred route is active | |||||
| ###### | |||||
| if(!ds_is_from_list(-1, 6, "$var(prefered_route)")) { | |||||
| xlog("L_INFO", "$ci|log|associated media server $var(prefered_route) is inactive, moving to $avp(ds_dst)\n"); | |||||
| return -1; | |||||
| } | |||||
| xlog("L_INFO", "$ci|log|re-ordering the dispatcher list to maintain association with $var(prefered_route)\n"); | |||||
| ###### | |||||
| # filters current list from prefered route | |||||
| # * saves the current list to temp avp removing the preferred route if it exists | |||||
| # * resets current list | |||||
| # * copies the temp back to list | |||||
| # sets the prefered at top | |||||
| # sets $du (destination) to prefered | |||||
| ###### | |||||
| $var(i) = 0; | |||||
| while($(avp(ds_dst)[$var(i)]) != $null) { | |||||
| if($(avp(ds_dst)[$var(i)]) != $var(prefered_route)) { | |||||
| $avp(tmp_ds_dst) = $(avp(ds_dst)[$var(i)]); | |||||
| } | |||||
| $var(i) = $var(i) + 1; | |||||
| } | |||||
| $(avp(ds_dst)[*]) = $null; | |||||
| $var(i) = 0; | |||||
| while($(avp(tmp_ds_dst)[$var(i)]) != $null) { | |||||
| $avp(ds_dst) = $(avp(tmp_ds_dst)[$var(i)]); | |||||
| $var(i) = $var(i) + 1; | |||||
| } | |||||
| $avp(ds_dst) = $var(prefered_route); | |||||
| $du = $var(prefered_route); | |||||
| $(avp(tmp_ds_dst)[*]) = $null; | |||||
| return 1; | |||||
| } | |||||
| route[DISPATCHER_NEXT_ROUTE] | |||||
| { | |||||
| if($avp(ds_retries) >= $sel(cfg_get.kazoo.dispatcher_max_retries)) return; | |||||
| $avp(ds_retries) = $avp(ds_retries) + 1; | |||||
| $var(remaining) = $(sel(cfg_get.kazoo.dispatcher_max_retries){s.int}) - $avp(ds_retries); | |||||
| if(ds_next_dst()) { | |||||
| xlog("L_INFO", "$ci|log|remaining failed retry attempts: $var(remaining)\n"); | |||||
| xlog("L_INFO", "$ci|log|routing call to next media server $du\n"); | |||||
| setflag(FLAG_SKIP_NAT_CORRECTION); | |||||
| # reset the final reply timer | |||||
| $avp(final_reply_timer) = 3; | |||||
| # relay the request to the new media server | |||||
| route(RELAY); | |||||
| exit(); | |||||
| } | |||||
| } | |||||
| event_route[dispatcher:dst-down] | |||||
| { | |||||
| xlog("L_WARNING", "Destination down: $ru\n"); | |||||
| } | |||||
| event_route[dispatcher:dst-up] | |||||
| { | |||||
| xlog("L_NOTICE", "Destination up: $ru\n"); | |||||
| } | |||||
| route[DISPATCHER_CHECK_MEDIA_SERVER] | |||||
| { | |||||
| $var(check_media_server_ret) = 0; | |||||
| if($sel(cfg_get.kazoo.dispatcher_auto_add) == 1) { | |||||
| $var(SetId) = 1; | |||||
| if($var(Zone) != "MY_AMQP_ZONE") { | |||||
| $var(SetId) = 2; | |||||
| } | |||||
| $var(flags) = KZ_DISPATCHER_ADD_FLAGS; | |||||
| $var(attrs) = $_s(zone=$var(Zone);profile=$var(MediaProfile);duid=$(var(MediaUrl){s.corehash, MEDIA_SERVERS_HASH_SIZE});node=$var(MediaName)); | |||||
| #!import_file "dispatcher-custom-media-check.cfg" | |||||
| sql_query("exec", "KZQ_CHECK_MEDIA_SERVER_INSERT"); | |||||
| if($sqlrows(exec) > 0) { | |||||
| $shv(dispatcher_reload) = 1; | |||||
| $var(check_media_server_ret) = 1; | |||||
| } | |||||
| if($sel(cfg_get.kazoo.dispatcher_add_secondary_ip) == 1) { | |||||
| if($var(MediaIP) != "" && $var(MediaIP) != $(var(MediaUrl){uri.host})) { | |||||
| $var(MediaUrlBack) = $var(MediaUrl); | |||||
| $var(MediaUrl) = $_s($(var(MediaUrlBack){uri.scheme}):$var(MediaIP):$(var(MediaUrlBack){uri.port})); | |||||
| $var(attrs) = $_s(zone=$var(Zone);profile=$var(MediaProfile);duid=$(var(MediaUrl){s.corehash, MEDIA_SERVERS_HASH_SIZE});node=$var(MediaName)); | |||||
| $var(SetId) = $sel(cfg_get.kazoo.dispatcher_add_secondary_ip_group); | |||||
| sql_query("exec", "KZQ_CHECK_MEDIA_SERVER_INSERT"); | |||||
| if($sqlrows(exec) > 0) { | |||||
| $shv(dispatcher_reload) = 1; | |||||
| $var(check_media_server_ret) = 1; | |||||
| } | |||||
| $var(MediaUrl) = $var(MediaUrlBack); | |||||
| } | |||||
| } | |||||
| } | |||||
| return $var(check_media_server_ret); | |||||
| } | |||||
| route[DISPATCHER_RELOAD] | |||||
| { | |||||
| if($shv(dispatcher_reload) == 1) { | |||||
| xlog("L_NOTICE", "reloading dispatcher table\n"); | |||||
| ds_reload(); | |||||
| }; | |||||
| $shv(dispatcher_reload) = 0; | |||||
| } | |||||
| route[DISPATCHER_STATUS] | |||||
| { | |||||
| jsonrpc_exec('{"jsonrpc": "2.0", "method": "dispatcher.list", "id": 1}'); | |||||
| $var(Sets) = $(jsonrpl(body){kz.json, result.NRSETS}); | |||||
| $var(i) = 0; | |||||
| $var(ds_groups_json)=""; | |||||
| $var(Sep1) = ""; | |||||
| while($var(i) < $var(Sets)) { | |||||
| $var(Set) = $(jsonrpl(body){kz.json, result.RECORDS[$var(i)].SET}); | |||||
| $var(SetCount) = $(var(Set){kz.json.count,TARGETS}); | |||||
| $var(Sep2)=""; | |||||
| $var(ds_group_json)=""; | |||||
| $var(c) = 0; | |||||
| while($var(c) < $var(SetCount)) { | |||||
| $var(Dest) = $(var(Set){kz.json,TARGETS[$var(c)].DEST}); | |||||
| $var(record) = $_s("$(var(Dest){kz.json,URI})" : {"destination" : "$(var(Dest){kz.json,URI})", "flags" : "$(var(Dest){kz.json,FLAGS})", "priority" : $(var(Dest){kz.json,PRIORITY}), "attrs" : "$(var(Dest){kz.json,ATTRS.BODY})"}); | |||||
| $var(ds_group_json) = $var(ds_group_json) + $var(Sep2) + $var(record); | |||||
| $var(Sep2) = ","; | |||||
| $var(c) = $var(c) + 1; | |||||
| } | |||||
| $var(ds_groups_json) = $var(ds_groups_json) + $var(Sep1) + $_s("$(var(Set){kz.json,ID})" : { $var(ds_group_json) }); | |||||
| $var(Sep1)=", "; | |||||
| $var(i) = $var(i) + 1; | |||||
| } | |||||
| } | |||||
| # vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab | |||||
| @ -0,0 +1,309 @@ | |||||
| ### DISPATCHER ROLE #### | |||||
| #!trydef KZ_DISPATCHER_PROBE_MODE 1 | |||||
| #!trydef DISPATCHER_ADD_SERVERS 1 | |||||
| #!trydef DISPATCHER_ADD_SECONDARY_IP 1 | |||||
| #!trydef DISPATCHER_SECONDARY_IP_GROUP 3 | |||||
| #!trydef DISPATCHER_ALG 0 | |||||
| #!trydef KZ_DISPATCHER_HASH_SIZE 8 | |||||
| #!trydef KZ_DISPATCHER_ADD_FLAGS 9 | |||||
| #!trydef KZ_DISPATCHER_PRIMARY_GROUP 1 | |||||
| #!trydef KZ_DISPATCHER_SECONDARY_GROUP 2 | |||||
| #!trydef KZ_DISPATCHER_CLASSIFY_GROUP 3 | |||||
| #!trydef KZ_DISPATCHER_ALTNET1_PRIMARY_GROUP 51 | |||||
| #!trydef KZ_DISPATCHER_ALTNET1_SECONDARY_GROUP 52 | |||||
| #!trydef KZ_DISPATCHER_ALTNET2_PRIMARY_GROUP 53 | |||||
| #!trydef KZ_DISPATCHER_ALTNET2_SECONDARY_GROUP 54 | |||||
| #!trydef KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP 10 | |||||
| #!trydef KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP 11 | |||||
| #!trydef KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP 20 | |||||
| #!trydef KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP 21 | |||||
| #!trydef KZ_DISPATCHER_MAX_RETRIES 2 | |||||
| #!trydef KZ_DISPATCHER_ROUTE_ASSOCIATED_MEDIA 1 | |||||
| #!trydef KZ_DISPATCHER_CLASSIFY_FLAGS 2 | |||||
| #!trydef KZ_DISPATCHER_PRINT_ROUTES 1 | |||||
| kazoo.dispatcher_auto_add = DISPATCHER_ADD_SERVERS descr "adds media servers reported by ecallmgr" | |||||
| kazoo.dispatcher_add_secondary_ip = DISPATCHER_ADD_SECONDARY_IP descr "adds internal ip from media servers reported by ecallmgr" | |||||
| kazoo.dispatcher_add_secondary_ip_group = DISPATCHER_SECONDARY_IP_GROUP descr "sets the group where to add internal ip from media servers reported by ecallmgr" | |||||
| kazoo.dispatcher_algorithm = DISPATCHER_ALG descr "dispatcher algorithm to use" | |||||
| kazoo.dispatcher_primary_group = KZ_DISPATCHER_PRIMARY_GROUP descr "dispatcher primary group" | |||||
| kazoo.dispatcher_secondary_group = KZ_DISPATCHER_SECONDARY_GROUP descr "dispatcher secondary group" | |||||
| kazoo.dispatcher_max_retries = KZ_DISPATCHER_MAX_RETRIES descr "max number of retries for media servers" | |||||
| kazoo.dispatcher_route_to_associated_media = KZ_DISPATCHER_ROUTE_ASSOCIATED_MEDIA descr "routes to associated media for atxfer" | |||||
| kazoo.dispatcher_classify_flags = KZ_DISPATCHER_CLASSIFY_FLAGS descr "dispatch classifier flags" | |||||
| kazoo.dispatcher_print_routes = KZ_DISPATCHER_PRINT_ROUTES descr "should we log the selected routes" | |||||
| ####### Dispatcher module ######## | |||||
| loadmodule "dispatcher.so" | |||||
| modparam("dispatcher", "db_url", "KAZOO_DB_URL") | |||||
| modparam("dispatcher", "flags", 2) | |||||
| modparam("dispatcher", "use_default", 0) | |||||
| modparam("dispatcher", "force_dst", 1) | |||||
| modparam("dispatcher", "hash_pvar", "$avp(ds_grp)") | |||||
| modparam("dispatcher", "setid_pvname", "$var(setid)") | |||||
| modparam("dispatcher", "attrs_pvname", "$var(attrs)") | |||||
| modparam("dispatcher", "ds_ping_method", "OPTIONS") | |||||
| modparam("dispatcher", "ds_ping_interval", 10) | |||||
| modparam("dispatcher", "ds_probing_threshold", 3) | |||||
| modparam("dispatcher", "ds_probing_mode", KZ_DISPATCHER_PROBE_MODE) | |||||
| modparam("dispatcher", "ds_ping_reply_codes", "501,403,404,400,200") | |||||
| modparam("dispatcher", "ds_ping_from", "sip:sipcheck@MY_HOSTNAME") | |||||
| modparam("dispatcher", "xavp_dst", "ds_dst") | |||||
| modparam("dispatcher", "xavp_ctx", "ds_ctx") | |||||
| modparam("dispatcher", "ds_hash_size", KZ_DISPATCHER_HASH_SIZE) | |||||
| ## Dispatcher Groups: | |||||
| ## 1 - Primary media servers | |||||
| ## 2 - Backup media servers | |||||
| ## 3 - Alternate media server IPs (used only for classification) | |||||
| ## 10 - Presence servers (if not locally handled) | |||||
| ## 20 - Registrar servers (if not locally handled) | |||||
| modparam("rtimer", "timer", "name=dispatcher_reload;interval=20;mode=1;") | |||||
| modparam("rtimer", "exec", "timer=dispatcher_reload;route=DISPATCHER_RELOAD") | |||||
| ####### Dispatcher Logic ######## | |||||
| route[DISPATCHER_CLASSIFY_SOURCE] | |||||
| { | |||||
| route_if_exists("DISPATCHER_CUSTOM_NETWORK_CLASSIFY"); | |||||
| if (!isflagset(FLAG_NETWORK_CLASSIFIED)) { | |||||
| if (is_myself("$ou")) { | |||||
| xlog("$var(log_request_level)", "$ci|log|original R-URI ($ou) is this proxy, treating as external sources\n"); | |||||
| } else { | |||||
| $var(classify_dispatcher_flag) = $(sel(cfg_get.kazoo.dispatcher_classify_flags){s.int}); | |||||
| if (ds_is_from_list(KZ_DISPATCHER_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_CLASSIFY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_ALTNET1_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_ALTNET1_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_ALTNET2_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_ALTNET2_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP, "$var(classify_dispatcher_flag)")) { | |||||
| xlog("$var(log_request_level)", "$ci|log|originated from internal sources\n"); | |||||
| setflag(FLAG_INTERNALLY_SOURCED); | |||||
| } else { | |||||
| xlog("$var(log_request_level)", "$ci|log|originated from external sources\n"); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| # Take the routes from dispatcher - hash over callid | |||||
| # If prefered route defined, reorder the destionations | |||||
| route[DISPATCHER_FIND_ROUTES] | |||||
| { | |||||
| $var(ds_primary_group) = $(sel(cfg_get.kazoo.dispatcher_primary_group){s.int}); | |||||
| $var(ds_backup_group) = $(sel(cfg_get.kazoo.dispatcher_secondary_group){s.int}); | |||||
| #!ifndef PRESENCE_ROLE | |||||
| if (is_method("SUBSCRIBE")) { | |||||
| $var(ds_primary_group) = KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP; | |||||
| $var(ds_backup_group) = KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP; | |||||
| } | |||||
| #!endif | |||||
| #!ifndef REGISTRAR_ROLE | |||||
| if (is_method("REGISTER")) { | |||||
| $var(ds_primary_group) = KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP; | |||||
| $var(ds_backup_group) = KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP; | |||||
| } | |||||
| #!endif | |||||
| #!ifdef PRESENCE_ROLE | |||||
| route(PRESENCE_FAST_PICKUP_ATTEMPT); | |||||
| #!endif | |||||
| route_if_exists("DISPATCHER_CUSTOM_SET_GROUPS"); | |||||
| $var(ds_group) = $var(ds_primary_group); | |||||
| $var(ds_alg) = $sel(cfg_get.kazoo.dispatcher_algorithm); | |||||
| if(ds_list_exists("$var(ds_backup_group)")) { | |||||
| $var(ds_rule) = $_s($var(ds_primary_group)=$var(ds_alg);$var(ds_backup_group)=$var(ds_alg)); | |||||
| } else { | |||||
| $var(ds_rule) = $_s($var(ds_primary_group)=$var(ds_alg)); | |||||
| } | |||||
| ds_select_routes("$var(ds_rule)", "2"); | |||||
| if ($xavp(ds_ctx=>cnt) == 0) { | |||||
| xlog("L_WARN", "$ci|end|no servers available in primary or backup group\n"); | |||||
| sl_send_reply("480", "All servers busy"); | |||||
| exit; | |||||
| } | |||||
| route(PRINT_ROUTES); | |||||
| $var(user_source) = $(ct{tobody.user}) + "@" + $si + ":" + $sp; | |||||
| $var(redirect) = @from.uri.user + "@" + @from.uri.host + "->" | |||||
| + @ruri.user + "@" + @ruri.host; | |||||
| if ($sht(redirects=>$var(redirect)) != $null) { | |||||
| $var(prefered_route) = $sht(redirects=>$var(redirect)); | |||||
| xlog("L_INFO", "$ci|route|found redirect for $var(redirect) to $var(prefered_route)\n"); | |||||
| $avp(AVP_REDIRECT_KEY) = $var(redirect); | |||||
| route(DISPATCHER_PREFERRED_ROUTE); | |||||
| } else if ($sht(associations=>$var(user_source)) != $null) { | |||||
| if($sel(cfg_get.kazoo.dispatcher_route_to_associated_media) == 1) { | |||||
| $var(prefered_route) = $sht(associations=>$var(user_source)); | |||||
| xlog("L_INFO", "$ci|route|found association for contact uri $var(user_source)\n"); | |||||
| route(DISPATCHER_PREFERRED_ROUTE); | |||||
| } | |||||
| $sht(associations=>$var(user_source)) = $null; | |||||
| } | |||||
| $avp(ds_group) = $xavp(ds_dst=>grp); | |||||
| $avp(ds_retries) = 0; | |||||
| ds_set_dst(); | |||||
| } | |||||
| route[DISPATCHER_PREFERRED_ROUTE] | |||||
| { | |||||
| if(!ds_is_from_list(-1, 6, "$var(prefered_route)")) { | |||||
| xlog("L_INFO", "$ci|log|associated media server $var(prefered_route) is inactive, moving to $xavp(ds_dst=>uri)\n"); | |||||
| return -1; | |||||
| } | |||||
| xlog("L_INFO", "$ci|log|re-ordering the dispatcher list to maintain association with $var(prefered_route)\n"); | |||||
| $var(i) = $xavp(ds_ctx=>cnt) - 1; | |||||
| while($var(i) >= 0) { | |||||
| if($xavp(ds_dst[$var(i)]=>uri) == $var(prefered_route)) { | |||||
| $xavp(ds_dst[$var(i)]) = $null; | |||||
| } | |||||
| $var(i) = $var(i) - 1; | |||||
| } | |||||
| $xavp(ds_dst=>uri) = $var(prefered_route); | |||||
| $xavp(ds_dst[0]=>grp) = $var(setid); | |||||
| $xavp(ds_dst[0]=>attrs) = $var(attrs); | |||||
| return 1; | |||||
| } | |||||
| route[PRINT_ROUTES] | |||||
| { | |||||
| if($sel(cfg_get.kazoo.dispatcher_print_routes) == 0) return; | |||||
| $var(i) = 0; | |||||
| while($xavp(ds_dst[$var(i)]=>uri) != $null) { | |||||
| xlog("L_INFO", "$ci|route|group $xavp(ds_dst[$var(i)]=>grp) => $xavp(ds_dst[$var(i)]=>uri) => zone $(xavp(ds_dst[$var(i)]=>attrs){param.value,zone})\n"); | |||||
| $var(i) = $var(i) + 1; | |||||
| } | |||||
| } | |||||
| #!import_file "dispatcher-next-route.cfg" | |||||
| #!ifndef CUSTOM_DISPATCHER_NEXT_ROUTE | |||||
| # Try next destinations in failure route | |||||
| route[DISPATCHER_NEXT_ROUTE] | |||||
| { | |||||
| if($avp(ds_retries) >= $sel(cfg_get.kazoo.dispatcher_max_retries)) return; | |||||
| $avp(ds_retries) = $avp(ds_retries) + 1; | |||||
| if(ds_next_dst()) { | |||||
| xlog("L_INFO", "$ci|log|routing call to next media server $du\n"); | |||||
| setflag(FLAG_SKIP_NAT_CORRECTION); | |||||
| # relay the request to the new media server | |||||
| route(RELAY); | |||||
| exit; | |||||
| } | |||||
| } | |||||
| #!endif | |||||
| event_route[dispatcher:dst-down] | |||||
| { | |||||
| xlog("L_WARNING", "Destination down: $ru , $xavp(ds_dst=>uri), $xavp(ds_dst=>grp), $xavp(ds_dst=>attrs)\n"); | |||||
| } | |||||
| event_route[dispatcher:dst-up] | |||||
| { | |||||
| xlog("L_WARNING", "Destination up: $ru , $xavp(ds_dst=>uri), $xavp(ds_dst=>grp), $xavp(ds_dst=>attrs)\n"); | |||||
| } | |||||
| route[DISPATCHER_CHECK_MEDIA_SERVER] | |||||
| { | |||||
| $var(check_media_server_ret) = 0; | |||||
| if($sel(cfg_get.kazoo.dispatcher_auto_add) == 1) { | |||||
| $var(SetId) = 1; | |||||
| if($var(Zone) != "MY_AMQP_ZONE") { | |||||
| $var(SetId) = 2; | |||||
| } | |||||
| $var(flags) = KZ_DISPATCHER_ADD_FLAGS; | |||||
| $var(attrs) = $_s(zone=$var(Zone);profile=$var(MediaProfile);duid=$(var(MediaUrl){s.corehash, MEDIA_SERVERS_HASH_SIZE});node=$var(MediaName)); | |||||
| route_if_exists("DISPATCHER_CUSTOM_MEDIA_CHECK"); | |||||
| sql_query("exec", "KZQ_CHECK_MEDIA_SERVER_INSERT"); | |||||
| if($sqlrows(exec) > 0) { | |||||
| $shv(dispatcher_reload) = 1; | |||||
| $var(check_media_server_ret) = 1; | |||||
| } | |||||
| if($sel(cfg_get.kazoo.dispatcher_add_secondary_ip) == 1) { | |||||
| if($var(MediaIP) != "" && $var(MediaIP) != $(var(MediaUrl){uri.host})) { | |||||
| $var(MediaUrlBack) = $var(MediaUrl); | |||||
| $var(MediaUrl) = $_s($(var(MediaUrlBack){uri.scheme}):$var(MediaIP):$(var(MediaUrlBack){uri.port})); | |||||
| $var(attrs) = $_s(zone=$var(Zone);profile=$var(MediaProfile);duid=$(var(MediaUrl){s.corehash, MEDIA_SERVERS_HASH_SIZE});node=$var(MediaName)); | |||||
| $var(SetId) = $sel(cfg_get.kazoo.dispatcher_add_secondary_ip_group); | |||||
| route_if_exists("DISPATCHER_CUSTOM_MEDIA_CHECK"); | |||||
| sql_query("exec", "KZQ_CHECK_MEDIA_SERVER_INSERT"); | |||||
| if($sqlrows(exec) > 0) { | |||||
| $shv(dispatcher_reload) = 1; | |||||
| $var(check_media_server_ret) = 1; | |||||
| } | |||||
| $var(MediaUrl) = $var(MediaUrlBack); | |||||
| } | |||||
| } | |||||
| } | |||||
| return $var(check_media_server_ret); | |||||
| } | |||||
| route[DISPATCHER_RELOAD] | |||||
| { | |||||
| if($shv(dispatcher_reload) == 1) { | |||||
| xlog("L_WARNING", "reloading dispatcher table\n"); | |||||
| ds_reload(); | |||||
| }; | |||||
| $shv(dispatcher_reload) = 0; | |||||
| } | |||||
| route[DISPATCHER_STATUS] | |||||
| { | |||||
| jsonrpc_exec('{"jsonrpc": "2.0", "method": "dispatcher.list", "id": 1}'); | |||||
| $var(Sets) = $(jsonrpl(body){kz.json, result.NRSETS}); | |||||
| $var(i) = 0; | |||||
| $var(ds_groups_json)=""; | |||||
| $var(Sep1) = ""; | |||||
| while($var(i) < $var(Sets)) { | |||||
| $var(Set) = $(jsonrpl(body){kz.json, result.RECORDS[$var(i)].SET}); | |||||
| $var(SetCount) = $(var(Set){kz.json.count,TARGETS}); | |||||
| $var(Sep2)=""; | |||||
| $var(ds_group_json)=""; | |||||
| $var(c) = 0; | |||||
| while($var(c) < $var(SetCount)) { | |||||
| $var(Dest) = $(var(Set){kz.json,TARGETS[$var(c)].DEST}); | |||||
| $var(record) = $_s("$(var(Dest){kz.json,URI})" : {"destination" : "$(var(Dest){kz.json,URI})", "flags" : "$(var(Dest){kz.json,FLAGS})", "priority" : $(var(Dest){kz.json,PRIORITY}), "attrs" : "$(var(Dest){kz.json,ATTRS.BODY})"}); | |||||
| $var(ds_group_json) = $var(ds_group_json) + $var(Sep2) + $var(record); | |||||
| $var(Sep2) = ","; | |||||
| $var(c) = $var(c) + 1; | |||||
| } | |||||
| $var(ds_groups_json) = $var(ds_groups_json) + $var(Sep1) + $_s("$(var(Set){kz.json,ID})" : { $var(ds_group_json) }); | |||||
| $var(Sep1)=", "; | |||||
| $var(i) = $var(i) + 1; | |||||
| } | |||||
| } | |||||
| # vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab | |||||
| @ -0,0 +1,309 @@ | |||||
| ### DISPATCHER ROLE #### | |||||
| #!trydef KZ_DISPATCHER_PROBE_MODE 1 | |||||
| #!trydef DISPATCHER_ADD_SERVERS 1 | |||||
| #!trydef DISPATCHER_ADD_SECONDARY_IP 1 | |||||
| #!trydef DISPATCHER_SECONDARY_IP_GROUP 3 | |||||
| #!trydef DISPATCHER_ALG 0 | |||||
| #!trydef KZ_DISPATCHER_HASH_SIZE 8 | |||||
| #!trydef KZ_DISPATCHER_ADD_FLAGS 9 | |||||
| #!trydef KZ_DISPATCHER_PRIMARY_GROUP 1 | |||||
| #!trydef KZ_DISPATCHER_SECONDARY_GROUP 2 | |||||
| #!trydef KZ_DISPATCHER_CLASSIFY_GROUP 3 | |||||
| #!trydef KZ_DISPATCHER_ALTNET1_PRIMARY_GROUP 51 | |||||
| #!trydef KZ_DISPATCHER_ALTNET1_SECONDARY_GROUP 52 | |||||
| #!trydef KZ_DISPATCHER_ALTNET2_PRIMARY_GROUP 53 | |||||
| #!trydef KZ_DISPATCHER_ALTNET2_SECONDARY_GROUP 54 | |||||
| #!trydef KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP 10 | |||||
| #!trydef KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP 11 | |||||
| #!trydef KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP 20 | |||||
| #!trydef KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP 21 | |||||
| #!trydef KZ_DISPATCHER_MAX_RETRIES 2 | |||||
| #!trydef KZ_DISPATCHER_ROUTE_ASSOCIATED_MEDIA 1 | |||||
| #!trydef KZ_DISPATCHER_CLASSIFY_FLAGS 2 | |||||
| #!trydef KZ_DISPATCHER_PRINT_ROUTES 1 | |||||
| kazoo.dispatcher_auto_add = DISPATCHER_ADD_SERVERS descr "adds media servers reported by ecallmgr" | |||||
| kazoo.dispatcher_add_secondary_ip = DISPATCHER_ADD_SECONDARY_IP descr "adds internal ip from media servers reported by ecallmgr" | |||||
| kazoo.dispatcher_add_secondary_ip_group = DISPATCHER_SECONDARY_IP_GROUP descr "sets the group where to add internal ip from media servers reported by ecallmgr" | |||||
| kazoo.dispatcher_algorithm = DISPATCHER_ALG descr "dispatcher algorithm to use" | |||||
| kazoo.dispatcher_primary_group = KZ_DISPATCHER_PRIMARY_GROUP descr "dispatcher primary group" | |||||
| kazoo.dispatcher_secondary_group = KZ_DISPATCHER_SECONDARY_GROUP descr "dispatcher secondary group" | |||||
| kazoo.dispatcher_max_retries = KZ_DISPATCHER_MAX_RETRIES descr "max number of retries for media servers" | |||||
| kazoo.dispatcher_route_to_associated_media = KZ_DISPATCHER_ROUTE_ASSOCIATED_MEDIA descr "routes to associated media for atxfer" | |||||
| kazoo.dispatcher_classify_flags = KZ_DISPATCHER_CLASSIFY_FLAGS descr "dispatch classifier flags" | |||||
| kazoo.dispatcher_print_routes = KZ_DISPATCHER_PRINT_ROUTES descr "should we log the selected routes" | |||||
| ####### Dispatcher module ######## | |||||
| loadmodule "dispatcher.so" | |||||
| modparam("dispatcher", "db_url", "KAZOO_DB_URL") | |||||
| modparam("dispatcher", "flags", 2) | |||||
| modparam("dispatcher", "use_default", 0) | |||||
| modparam("dispatcher", "force_dst", 1) | |||||
| modparam("dispatcher", "hash_pvar", "$avp(ds_grp)") | |||||
| modparam("dispatcher", "setid_pvname", "$var(setid)") | |||||
| modparam("dispatcher", "attrs_pvname", "$var(attrs)") | |||||
| modparam("dispatcher", "ds_ping_method", "OPTIONS") | |||||
| modparam("dispatcher", "ds_ping_interval", 10) | |||||
| modparam("dispatcher", "ds_probing_threshold", 3) | |||||
| modparam("dispatcher", "ds_probing_mode", KZ_DISPATCHER_PROBE_MODE) | |||||
| modparam("dispatcher", "ds_ping_reply_codes", "501,403,404,400,200") | |||||
| modparam("dispatcher", "ds_ping_from", "sip:sipcheck@MY_HOSTNAME") | |||||
| modparam("dispatcher", "xavp_dst", "ds_dst") | |||||
| modparam("dispatcher", "xavp_ctx", "ds_ctx") | |||||
| modparam("dispatcher", "ds_hash_size", KZ_DISPATCHER_HASH_SIZE) | |||||
| ## Dispatcher Groups: | |||||
| ## 1 - Primary media servers | |||||
| ## 2 - Backup media servers | |||||
| ## 3 - Alternate media server IPs (used only for classification) | |||||
| ## 10 - Presence servers (if not locally handled) | |||||
| ## 20 - Registrar servers (if not locally handled) | |||||
| modparam("rtimer", "timer", "name=dispatcher_reload;interval=20;mode=1;") | |||||
| modparam("rtimer", "exec", "timer=dispatcher_reload;route=DISPATCHER_RELOAD") | |||||
| ####### Dispatcher Logic ######## | |||||
| route[DISPATCHER_CLASSIFY_SOURCE] | |||||
| { | |||||
| route_if_exists("DISPATCHER_CUSTOM_NETWORK_CLASSIFY"); | |||||
| if (!isflagset(FLAG_NETWORK_CLASSIFIED)) { | |||||
| if (is_myself("$ou")) { | |||||
| xlog("$var(log_request_level)", "$ci|log|original R-URI ($ou) is this proxy, treating as external sources\n"); | |||||
| } else { | |||||
| $var(classify_dispatcher_flag) = $(sel(cfg_get.kazoo.dispatcher_classify_flags){s.int}); | |||||
| if (ds_is_from_list(KZ_DISPATCHER_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_CLASSIFY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_ALTNET1_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_ALTNET1_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_ALTNET2_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_ALTNET2_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP, "$var(classify_dispatcher_flag)")) { | |||||
| xlog("$var(log_request_level)", "$ci|log|originated from internal sources\n"); | |||||
| setflag(FLAG_INTERNALLY_SOURCED); | |||||
| } else { | |||||
| xlog("$var(log_request_level)", "$ci|log|originated from external sources\n"); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| # Take the routes from dispatcher - hash over callid | |||||
| # If prefered route defined, reorder the destionations | |||||
| route[DISPATCHER_FIND_ROUTES] | |||||
| { | |||||
| $var(ds_primary_group) = $(sel(cfg_get.kazoo.dispatcher_primary_group){s.int}); | |||||
| $var(ds_backup_group) = $(sel(cfg_get.kazoo.dispatcher_secondary_group){s.int}); | |||||
| #!ifndef PRESENCE_ROLE | |||||
| if (is_method("SUBSCRIBE")) { | |||||
| $var(ds_primary_group) = KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP; | |||||
| $var(ds_backup_group) = KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP; | |||||
| } | |||||
| #!endif | |||||
| #!ifndef REGISTRAR_ROLE | |||||
| if (is_method("REGISTER")) { | |||||
| $var(ds_primary_group) = KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP; | |||||
| $var(ds_backup_group) = KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP; | |||||
| } | |||||
| #!endif | |||||
| #!ifdef PRESENCE_ROLE | |||||
| route(PRESENCE_FAST_PICKUP_ATTEMPT); | |||||
| #!endif | |||||
| route_if_exists("DISPATCHER_CUSTOM_SET_GROUPS"); | |||||
| $var(ds_group) = $var(ds_primary_group); | |||||
| $var(ds_alg) = $sel(cfg_get.kazoo.dispatcher_algorithm); | |||||
| if(ds_list_exists("$var(ds_backup_group)")) { | |||||
| $var(ds_rule) = $_s($var(ds_primary_group)=$var(ds_alg);$var(ds_backup_group)=$var(ds_alg)); | |||||
| } else { | |||||
| $var(ds_rule) = $_s($var(ds_primary_group)=$var(ds_alg)); | |||||
| } | |||||
| ds_select_routes("$var(ds_rule)", "2"); | |||||
| if ($xavp(ds_ctx=>cnt) == 0) { | |||||
| xlog("L_WARN", "$ci|end|no servers available in primary or backup group\n"); | |||||
| sl_send_reply("480", "All servers busy"); | |||||
| exit; | |||||
| } | |||||
| route(PRINT_ROUTES); | |||||
| $var(user_source) = $(ct{tobody.user}) + "@" + $si + ":" + $sp; | |||||
| $var(redirect) = @from.uri.user + "@" + @from.uri.host + "->" | |||||
| + @ruri.user + "@" + @ruri.host; | |||||
| if ($sht(redirects=>$var(redirect)) != $null) { | |||||
| $var(prefered_route) = $sht(redirects=>$var(redirect)); | |||||
| xlog("L_INFO", "$ci|route|found redirect for $var(redirect) to $var(prefered_route)\n"); | |||||
| $avp(AVP_REDIRECT_KEY) = $var(redirect); | |||||
| route(DISPATCHER_PREFERRED_ROUTE); | |||||
| } else if ($sht(associations=>$var(user_source)) != $null) { | |||||
| if($sel(cfg_get.kazoo.dispatcher_route_to_associated_media) == 1) { | |||||
| $var(prefered_route) = $sht(associations=>$var(user_source)); | |||||
| xlog("L_INFO", "$ci|route|found association for contact uri $var(user_source)\n"); | |||||
| route(DISPATCHER_PREFERRED_ROUTE); | |||||
| } | |||||
| $sht(associations=>$var(user_source)) = $null; | |||||
| } | |||||
| $avp(ds_group) = $xavp(ds_dst=>grp); | |||||
| $avp(ds_retries) = 0; | |||||
| ds_set_dst(); | |||||
| } | |||||
| route[DISPATCHER_PREFERRED_ROUTE] | |||||
| { | |||||
| if(!ds_is_from_list(-1, 6, "$var(prefered_route)")) { | |||||
| xlog("L_INFO", "$ci|log|associated media server $var(prefered_route) is inactive, moving to $xavp(ds_dst=>uri)\n"); | |||||
| return -1; | |||||
| } | |||||
| xlog("L_INFO", "$ci|log|re-ordering the dispatcher list to maintain association with $var(prefered_route)\n"); | |||||
| $var(i) = $xavp(ds_ctx=>cnt) - 1; | |||||
| while($var(i) >= 0) { | |||||
| if($xavp(ds_dst[$var(i)]=>uri) == $var(prefered_route)) { | |||||
| $xavp(ds_dst[$var(i)]) = $null; | |||||
| } | |||||
| $var(i) = $var(i) - 1; | |||||
| } | |||||
| $xavp(ds_dst=>uri) = $var(prefered_route); | |||||
| $xavp(ds_dst[0]=>grp) = $var(setid); | |||||
| $xavp(ds_dst[0]=>attrs) = $var(attrs); | |||||
| return 1; | |||||
| } | |||||
| route[PRINT_ROUTES] | |||||
| { | |||||
| if($sel(cfg_get.kazoo.dispatcher_print_routes) == 0) return; | |||||
| $var(i) = 0; | |||||
| while($xavp(ds_dst[$var(i)]=>uri) != $null) { | |||||
| xlog("L_INFO", "$ci|route|group $xavp(ds_dst[$var(i)]=>grp) => $xavp(ds_dst[$var(i)]=>uri) => zone $(xavp(ds_dst[$var(i)]=>attrs){param.value,zone})\n"); | |||||
| $var(i) = $var(i) + 1; | |||||
| } | |||||
| } | |||||
| #!import_file "dispatcher-next-route.cfg" | |||||
| #!ifndef CUSTOM_DISPATCHER_NEXT_ROUTE | |||||
| # Try next destinations in failure route | |||||
| route[DISPATCHER_NEXT_ROUTE] | |||||
| { | |||||
| if($avp(ds_retries) >= $sel(cfg_get.kazoo.dispatcher_max_retries)) return; | |||||
| $avp(ds_retries) = $avp(ds_retries) + 1; | |||||
| if(ds_next_dst()) { | |||||
| xlog("L_INFO", "$ci|log|routing call to next media server $du\n"); | |||||
| setflag(FLAG_SKIP_NAT_CORRECTION); | |||||
| # relay the request to the new media server | |||||
| route(RELAY); | |||||
| exit; | |||||
| } | |||||
| } | |||||
| #!endif | |||||
| event_route[dispatcher:dst-down] | |||||
| { | |||||
| xlog("L_WARNING", "Destination down: $ru , $xavp(ds_dst=>uri), $xavp(ds_dst=>grp), $xavp(ds_dst=>attrs)\n"); | |||||
| } | |||||
| event_route[dispatcher:dst-up] | |||||
| { | |||||
| xlog("L_WARNING", "Destination up: $ru , $xavp(ds_dst=>uri), $xavp(ds_dst=>grp), $xavp(ds_dst=>attrs)\n"); | |||||
| } | |||||
| route[DISPATCHER_CHECK_MEDIA_SERVER] | |||||
| { | |||||
| $var(check_media_server_ret) = 0; | |||||
| if($sel(cfg_get.kazoo.dispatcher_auto_add) == 1) { | |||||
| $var(SetId) = 1; | |||||
| if($var(Zone) != "MY_AMQP_ZONE") { | |||||
| $var(SetId) = 2; | |||||
| } | |||||
| $var(flags) = KZ_DISPATCHER_ADD_FLAGS; | |||||
| $var(attrs) = $_s(zone=$var(Zone);profile=$var(MediaProfile);duid=$(var(MediaUrl){s.corehash, MEDIA_SERVERS_HASH_SIZE});node=$var(MediaName)); | |||||
| route_if_exists("DISPATCHER_CUSTOM_MEDIA_CHECK"); | |||||
| sql_query("exec", "KZQ_CHECK_MEDIA_SERVER_INSERT"); | |||||
| if($sqlrows(exec) > 0) { | |||||
| $shv(dispatcher_reload) = 1; | |||||
| $var(check_media_server_ret) = 1; | |||||
| } | |||||
| if($sel(cfg_get.kazoo.dispatcher_add_secondary_ip) == 1) { | |||||
| if($var(MediaIP) != "" && $var(MediaIP) != $(var(MediaUrl){uri.host})) { | |||||
| $var(MediaUrlBack) = $var(MediaUrl); | |||||
| $var(MediaUrl) = $_s($(var(MediaUrlBack){uri.scheme}):$var(MediaIP):$(var(MediaUrlBack){uri.port})); | |||||
| $var(attrs) = $_s(zone=$var(Zone);profile=$var(MediaProfile);duid=$(var(MediaUrl){s.corehash, MEDIA_SERVERS_HASH_SIZE});node=$var(MediaName)); | |||||
| $var(SetId) = $sel(cfg_get.kazoo.dispatcher_add_secondary_ip_group); | |||||
| route_if_exists("DISPATCHER_CUSTOM_MEDIA_CHECK"); | |||||
| sql_query("exec", "KZQ_CHECK_MEDIA_SERVER_INSERT"); | |||||
| if($sqlrows(exec) > 0) { | |||||
| $shv(dispatcher_reload) = 1; | |||||
| $var(check_media_server_ret) = 1; | |||||
| } | |||||
| $var(MediaUrl) = $var(MediaUrlBack); | |||||
| } | |||||
| } | |||||
| } | |||||
| return $var(check_media_server_ret); | |||||
| } | |||||
| route[DISPATCHER_RELOAD] | |||||
| { | |||||
| if($shv(dispatcher_reload) == 1) { | |||||
| xlog("L_WARNING", "reloading dispatcher table\n"); | |||||
| ds_reload(); | |||||
| }; | |||||
| $shv(dispatcher_reload) = 0; | |||||
| } | |||||
| route[DISPATCHER_STATUS] | |||||
| { | |||||
| jsonrpc_exec('{"jsonrpc": "2.0", "method": "dispatcher.list", "id": 1}'); | |||||
| $var(Sets) = $(jsonrpl(body){kz.json, result.NRSETS}); | |||||
| $var(i) = 0; | |||||
| $var(ds_groups_json)=""; | |||||
| $var(Sep1) = ""; | |||||
| while($var(i) < $var(Sets)) { | |||||
| $var(Set) = $(jsonrpl(body){kz.json, result.RECORDS[$var(i)].SET}); | |||||
| $var(SetCount) = $(var(Set){kz.json.count,TARGETS}); | |||||
| $var(Sep2)=""; | |||||
| $var(ds_group_json)=""; | |||||
| $var(c) = 0; | |||||
| while($var(c) < $var(SetCount)) { | |||||
| $var(Dest) = $(var(Set){kz.json,TARGETS[$var(c)].DEST}); | |||||
| $var(record) = $_s("$(var(Dest){kz.json,URI})" : {"destination" : "$(var(Dest){kz.json,URI})", "flags" : "$(var(Dest){kz.json,FLAGS})", "priority" : $(var(Dest){kz.json,PRIORITY}), "attrs" : "$(var(Dest){kz.json,ATTRS.BODY})"}); | |||||
| $var(ds_group_json) = $var(ds_group_json) + $var(Sep2) + $var(record); | |||||
| $var(Sep2) = ","; | |||||
| $var(c) = $var(c) + 1; | |||||
| } | |||||
| $var(ds_groups_json) = $var(ds_groups_json) + $var(Sep1) + $_s("$(var(Set){kz.json,ID})" : { $var(ds_group_json) }); | |||||
| $var(Sep1)=", "; | |||||
| $var(i) = $var(i) + 1; | |||||
| } | |||||
| } | |||||
| # vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab | |||||
| @ -0,0 +1,309 @@ | |||||
| ### DISPATCHER ROLE #### | |||||
| #!trydef KZ_DISPATCHER_PROBE_MODE 1 | |||||
| #!trydef DISPATCHER_ADD_SERVERS 1 | |||||
| #!trydef DISPATCHER_ADD_SECONDARY_IP 1 | |||||
| #!trydef DISPATCHER_SECONDARY_IP_GROUP 3 | |||||
| #!trydef DISPATCHER_ALG 0 | |||||
| #!trydef KZ_DISPATCHER_HASH_SIZE 8 | |||||
| #!trydef KZ_DISPATCHER_ADD_FLAGS 9 | |||||
| #!trydef KZ_DISPATCHER_PRIMARY_GROUP 1 | |||||
| #!trydef KZ_DISPATCHER_SECONDARY_GROUP 2 | |||||
| #!trydef KZ_DISPATCHER_CLASSIFY_GROUP 3 | |||||
| #!trydef KZ_DISPATCHER_ALTNET1_PRIMARY_GROUP 51 | |||||
| #!trydef KZ_DISPATCHER_ALTNET1_SECONDARY_GROUP 52 | |||||
| #!trydef KZ_DISPATCHER_ALTNET2_PRIMARY_GROUP 53 | |||||
| #!trydef KZ_DISPATCHER_ALTNET2_SECONDARY_GROUP 54 | |||||
| #!trydef KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP 10 | |||||
| #!trydef KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP 11 | |||||
| #!trydef KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP 20 | |||||
| #!trydef KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP 21 | |||||
| #!trydef KZ_DISPATCHER_MAX_RETRIES 2 | |||||
| #!trydef KZ_DISPATCHER_ROUTE_ASSOCIATED_MEDIA 1 | |||||
| #!trydef KZ_DISPATCHER_CLASSIFY_FLAGS 2 | |||||
| #!trydef KZ_DISPATCHER_PRINT_ROUTES 1 | |||||
| kazoo.dispatcher_auto_add = DISPATCHER_ADD_SERVERS descr "adds media servers reported by ecallmgr" | |||||
| kazoo.dispatcher_add_secondary_ip = DISPATCHER_ADD_SECONDARY_IP descr "adds internal ip from media servers reported by ecallmgr" | |||||
| kazoo.dispatcher_add_secondary_ip_group = DISPATCHER_SECONDARY_IP_GROUP descr "sets the group where to add internal ip from media servers reported by ecallmgr" | |||||
| kazoo.dispatcher_algorithm = DISPATCHER_ALG descr "dispatcher algorithm to use" | |||||
| kazoo.dispatcher_primary_group = KZ_DISPATCHER_PRIMARY_GROUP descr "dispatcher primary group" | |||||
| kazoo.dispatcher_secondary_group = KZ_DISPATCHER_SECONDARY_GROUP descr "dispatcher secondary group" | |||||
| kazoo.dispatcher_max_retries = KZ_DISPATCHER_MAX_RETRIES descr "max number of retries for media servers" | |||||
| kazoo.dispatcher_route_to_associated_media = KZ_DISPATCHER_ROUTE_ASSOCIATED_MEDIA descr "routes to associated media for atxfer" | |||||
| kazoo.dispatcher_classify_flags = KZ_DISPATCHER_CLASSIFY_FLAGS descr "dispatch classifier flags" | |||||
| kazoo.dispatcher_print_routes = KZ_DISPATCHER_PRINT_ROUTES descr "should we log the selected routes" | |||||
| ####### Dispatcher module ######## | |||||
| loadmodule "dispatcher.so" | |||||
| modparam("dispatcher", "db_url", "KAZOO_DB_URL") | |||||
| modparam("dispatcher", "flags", 2) | |||||
| modparam("dispatcher", "use_default", 0) | |||||
| modparam("dispatcher", "force_dst", 1) | |||||
| modparam("dispatcher", "hash_pvar", "$avp(ds_grp)") | |||||
| modparam("dispatcher", "setid_pvname", "$var(setid)") | |||||
| modparam("dispatcher", "attrs_pvname", "$var(attrs)") | |||||
| modparam("dispatcher", "ds_ping_method", "OPTIONS") | |||||
| modparam("dispatcher", "ds_ping_interval", 10) | |||||
| modparam("dispatcher", "ds_probing_threshold", 3) | |||||
| modparam("dispatcher", "ds_probing_mode", KZ_DISPATCHER_PROBE_MODE) | |||||
| modparam("dispatcher", "ds_ping_reply_codes", "501,403,404,400,200") | |||||
| modparam("dispatcher", "ds_ping_from", "sip:sipcheck@MY_HOSTNAME") | |||||
| modparam("dispatcher", "xavp_dst", "ds_dst") | |||||
| modparam("dispatcher", "xavp_ctx", "ds_ctx") | |||||
| modparam("dispatcher", "ds_hash_size", KZ_DISPATCHER_HASH_SIZE) | |||||
| ## Dispatcher Groups: | |||||
| ## 1 - Primary media servers | |||||
| ## 2 - Backup media servers | |||||
| ## 3 - Alternate media server IPs (used only for classification) | |||||
| ## 10 - Presence servers (if not locally handled) | |||||
| ## 20 - Registrar servers (if not locally handled) | |||||
| modparam("rtimer", "timer", "name=dispatcher_reload;interval=20;mode=1;") | |||||
| modparam("rtimer", "exec", "timer=dispatcher_reload;route=DISPATCHER_RELOAD") | |||||
| ####### Dispatcher Logic ######## | |||||
| route[DISPATCHER_CLASSIFY_SOURCE] | |||||
| { | |||||
| route_if_exists("DISPATCHER_CUSTOM_NETWORK_CLASSIFY"); | |||||
| if (!isflagset(FLAG_NETWORK_CLASSIFIED)) { | |||||
| if (is_myself("$ou")) { | |||||
| xlog("$var(log_request_level)", "$ci|log|original R-URI ($ou) is this proxy, treating as external sources\n"); | |||||
| } else { | |||||
| $var(classify_dispatcher_flag) = $(sel(cfg_get.kazoo.dispatcher_classify_flags){s.int}); | |||||
| if (ds_is_from_list(KZ_DISPATCHER_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_CLASSIFY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_ALTNET1_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_ALTNET1_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_ALTNET2_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_ALTNET2_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP, "$var(classify_dispatcher_flag)") || | |||||
| ds_is_from_list(KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP, "$var(classify_dispatcher_flag)")) { | |||||
| xlog("$var(log_request_level)", "$ci|log|originated from internal sources\n"); | |||||
| setflag(FLAG_INTERNALLY_SOURCED); | |||||
| } else { | |||||
| xlog("$var(log_request_level)", "$ci|log|originated from external sources\n"); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| # Take the routes from dispatcher - hash over callid | |||||
| # If prefered route defined, reorder the destionations | |||||
| route[DISPATCHER_FIND_ROUTES] | |||||
| { | |||||
| $var(ds_primary_group) = $(sel(cfg_get.kazoo.dispatcher_primary_group){s.int}); | |||||
| $var(ds_backup_group) = $(sel(cfg_get.kazoo.dispatcher_secondary_group){s.int}); | |||||
| #!ifndef PRESENCE_ROLE | |||||
| if (is_method("SUBSCRIBE")) { | |||||
| $var(ds_primary_group) = KZ_DISPATCHER_PRESENCE_PRIMARY_GROUP; | |||||
| $var(ds_backup_group) = KZ_DISPATCHER_PRESENCE_SECONDARY_GROUP; | |||||
| } | |||||
| #!endif | |||||
| #!ifndef REGISTRAR_ROLE | |||||
| if (is_method("REGISTER")) { | |||||
| $var(ds_primary_group) = KZ_DISPATCHER_REGISTRAR_PRIMARY_GROUP; | |||||
| $var(ds_backup_group) = KZ_DISPATCHER_REGISTRAR_SECONDARY_GROUP; | |||||
| } | |||||
| #!endif | |||||
| #!ifdef PRESENCE_ROLE | |||||
| route(PRESENCE_FAST_PICKUP_ATTEMPT); | |||||
| #!endif | |||||
| route_if_exists("DISPATCHER_CUSTOM_SET_GROUPS"); | |||||
| $var(ds_group) = $var(ds_primary_group); | |||||
| $var(ds_alg) = $sel(cfg_get.kazoo.dispatcher_algorithm); | |||||
| if(ds_list_exists("$var(ds_backup_group)")) { | |||||
| $var(ds_rule) = $_s($var(ds_primary_group)=$var(ds_alg);$var(ds_backup_group)=$var(ds_alg)); | |||||
| } else { | |||||
| $var(ds_rule) = $_s($var(ds_primary_group)=$var(ds_alg)); | |||||
| } | |||||
| ds_select_routes("$var(ds_rule)", "2"); | |||||
| if ($xavp(ds_ctx=>cnt) == 0) { | |||||
| xlog("L_WARN", "$ci|end|no servers available in primary or backup group\n"); | |||||
| sl_send_reply("480", "All servers busy"); | |||||
| exit; | |||||
| } | |||||
| route(PRINT_ROUTES); | |||||
| $var(user_source) = $(ct{tobody.user}) + "@" + $si + ":" + $sp; | |||||
| $var(redirect) = @from.uri.user + "@" + @from.uri.host + "->" | |||||
| + @ruri.user + "@" + @ruri.host; | |||||
| if ($sht(redirects=>$var(redirect)) != $null) { | |||||
| $var(prefered_route) = $sht(redirects=>$var(redirect)); | |||||
| xlog("L_INFO", "$ci|route|found redirect for $var(redirect) to $var(prefered_route)\n"); | |||||
| $avp(AVP_REDIRECT_KEY) = $var(redirect); | |||||
| route(DISPATCHER_PREFERRED_ROUTE); | |||||
| } else if ($sht(associations=>$var(user_source)) != $null) { | |||||
| if($sel(cfg_get.kazoo.dispatcher_route_to_associated_media) == 1) { | |||||
| $var(prefered_route) = $sht(associations=>$var(user_source)); | |||||
| xlog("L_INFO", "$ci|route|found association for contact uri $var(user_source)\n"); | |||||
| route(DISPATCHER_PREFERRED_ROUTE); | |||||
| } | |||||
| $sht(associations=>$var(user_source)) = $null; | |||||
| } | |||||
| $avp(ds_group) = $xavp(ds_dst=>grp); | |||||
| $avp(ds_retries) = 0; | |||||
| ds_set_dst(); | |||||
| } | |||||
| route[DISPATCHER_PREFERRED_ROUTE] | |||||
| { | |||||
| if(!ds_is_from_list(-1, 6, "$var(prefered_route)")) { | |||||
| xlog("L_INFO", "$ci|log|associated media server $var(prefered_route) is inactive, moving to $xavp(ds_dst=>uri)\n"); | |||||
| return -1; | |||||
| } | |||||
| xlog("L_INFO", "$ci|log|re-ordering the dispatcher list to maintain association with $var(prefered_route)\n"); | |||||
| $var(i) = $xavp(ds_ctx=>cnt) - 1; | |||||
| while($var(i) >= 0) { | |||||
| if($xavp(ds_dst[$var(i)]=>uri) == $var(prefered_route)) { | |||||
| $xavp(ds_dst[$var(i)]) = $null; | |||||
| } | |||||
| $var(i) = $var(i) - 1; | |||||
| } | |||||
| $xavp(ds_dst=>uri) = $var(prefered_route); | |||||
| $xavp(ds_dst[0]=>grp) = $var(setid); | |||||
| $xavp(ds_dst[0]=>attrs) = $var(attrs); | |||||
| return 1; | |||||
| } | |||||
| route[PRINT_ROUTES] | |||||
| { | |||||
| if($sel(cfg_get.kazoo.dispatcher_print_routes) == 0) return; | |||||
| $var(i) = 0; | |||||
| while($xavp(ds_dst[$var(i)]=>uri) != $null) { | |||||
| xlog("L_INFO", "$ci|route|group $xavp(ds_dst[$var(i)]=>grp) => $xavp(ds_dst[$var(i)]=>uri) => zone $(xavp(ds_dst[$var(i)]=>attrs){param.value,zone})\n"); | |||||
| $var(i) = $var(i) + 1; | |||||
| } | |||||
| } | |||||
| #!import_file "dispatcher-next-route.cfg" | |||||
| #!ifndef CUSTOM_DISPATCHER_NEXT_ROUTE | |||||
| # Try next destinations in failure route | |||||
| route[DISPATCHER_NEXT_ROUTE] | |||||
| { | |||||
| if($avp(ds_retries) >= $sel(cfg_get.kazoo.dispatcher_max_retries)) return; | |||||
| $avp(ds_retries) = $avp(ds_retries) + 1; | |||||
| if(ds_next_dst()) { | |||||
| xlog("L_INFO", "$ci|log|routing call to next media server $du\n"); | |||||
| setflag(FLAG_SKIP_NAT_CORRECTION); | |||||
| # relay the request to the new media server | |||||
| route(RELAY); | |||||
| exit; | |||||
| } | |||||
| } | |||||
| #!endif | |||||
| event_route[dispatcher:dst-down] | |||||
| { | |||||
| xlog("L_WARNING", "Destination down: $ru , $xavp(ds_dst=>uri), $xavp(ds_dst=>grp), $xavp(ds_dst=>attrs)\n"); | |||||
| } | |||||
| event_route[dispatcher:dst-up] | |||||
| { | |||||
| xlog("L_WARNING", "Destination up: $ru , $xavp(ds_dst=>uri), $xavp(ds_dst=>grp), $xavp(ds_dst=>attrs)\n"); | |||||
| } | |||||
| route[DISPATCHER_CHECK_MEDIA_SERVER] | |||||
| { | |||||
| $var(check_media_server_ret) = 0; | |||||
| if($sel(cfg_get.kazoo.dispatcher_auto_add) == 1) { | |||||
| $var(SetId) = 1; | |||||
| if($var(Zone) != "MY_AMQP_ZONE") { | |||||
| $var(SetId) = 2; | |||||
| } | |||||
| $var(flags) = KZ_DISPATCHER_ADD_FLAGS; | |||||
| $var(attrs) = $_s(zone=$var(Zone);profile=$var(MediaProfile);duid=$(var(MediaUrl){s.corehash, MEDIA_SERVERS_HASH_SIZE});node=$var(MediaName)); | |||||
| route_if_exists("DISPATCHER_CUSTOM_MEDIA_CHECK"); | |||||
| sql_query("exec", "KZQ_CHECK_MEDIA_SERVER_INSERT"); | |||||
| if($sqlrows(exec) > 0) { | |||||
| $shv(dispatcher_reload) = 1; | |||||
| $var(check_media_server_ret) = 1; | |||||
| } | |||||
| if($sel(cfg_get.kazoo.dispatcher_add_secondary_ip) == 1) { | |||||
| if($var(MediaIP) != "" && $var(MediaIP) != $(var(MediaUrl){uri.host})) { | |||||
| $var(MediaUrlBack) = $var(MediaUrl); | |||||
| $var(MediaUrl) = $_s($(var(MediaUrlBack){uri.scheme}):$var(MediaIP):$(var(MediaUrlBack){uri.port})); | |||||
| $var(attrs) = $_s(zone=$var(Zone);profile=$var(MediaProfile);duid=$(var(MediaUrl){s.corehash, MEDIA_SERVERS_HASH_SIZE});node=$var(MediaName)); | |||||
| $var(SetId) = $sel(cfg_get.kazoo.dispatcher_add_secondary_ip_group); | |||||
| route_if_exists("DISPATCHER_CUSTOM_MEDIA_CHECK"); | |||||
| sql_query("exec", "KZQ_CHECK_MEDIA_SERVER_INSERT"); | |||||
| if($sqlrows(exec) > 0) { | |||||
| $shv(dispatcher_reload) = 1; | |||||
| $var(check_media_server_ret) = 1; | |||||
| } | |||||
| $var(MediaUrl) = $var(MediaUrlBack); | |||||
| } | |||||
| } | |||||
| } | |||||
| return $var(check_media_server_ret); | |||||
| } | |||||
| route[DISPATCHER_RELOAD] | |||||
| { | |||||
| if($shv(dispatcher_reload) == 1) { | |||||
| xlog("L_WARNING", "reloading dispatcher table\n"); | |||||
| ds_reload(); | |||||
| }; | |||||
| $shv(dispatcher_reload) = 0; | |||||
| } | |||||
| route[DISPATCHER_STATUS] | |||||
| { | |||||
| jsonrpc_exec('{"jsonrpc": "2.0", "method": "dispatcher.list", "id": 1}'); | |||||
| $var(Sets) = $(jsonrpl(body){kz.json, result.NRSETS}); | |||||
| $var(i) = 0; | |||||
| $var(ds_groups_json)=""; | |||||
| $var(Sep1) = ""; | |||||
| while($var(i) < $var(Sets)) { | |||||
| $var(Set) = $(jsonrpl(body){kz.json, result.RECORDS[$var(i)].SET}); | |||||
| $var(SetCount) = $(var(Set){kz.json.count,TARGETS}); | |||||
| $var(Sep2)=""; | |||||
| $var(ds_group_json)=""; | |||||
| $var(c) = 0; | |||||
| while($var(c) < $var(SetCount)) { | |||||
| $var(Dest) = $(var(Set){kz.json,TARGETS[$var(c)].DEST}); | |||||
| $var(record) = $_s("$(var(Dest){kz.json,URI})" : {"destination" : "$(var(Dest){kz.json,URI})", "flags" : "$(var(Dest){kz.json,FLAGS})", "priority" : $(var(Dest){kz.json,PRIORITY}), "attrs" : "$(var(Dest){kz.json,ATTRS.BODY})"}); | |||||
| $var(ds_group_json) = $var(ds_group_json) + $var(Sep2) + $var(record); | |||||
| $var(Sep2) = ","; | |||||
| $var(c) = $var(c) + 1; | |||||
| } | |||||
| $var(ds_groups_json) = $var(ds_groups_json) + $var(Sep1) + $_s("$(var(Set){kz.json,ID})" : { $var(ds_group_json) }); | |||||
| $var(Sep1)=", "; | |||||
| $var(i) = $var(i) + 1; | |||||
| } | |||||
| } | |||||
| # vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab | |||||
| @ -1,264 +0,0 @@ | |||||
| ######## Generic Hash Table container in shared memory ######## | |||||
| modparam("htable", "htable", "failover=>size=16;autoexpire=120") | |||||
| kazoo.dispatcher_auto_add = DISPATCHER_ADD_SERVERS descr "adds media servers reported by ecallmgr" | |||||
| ####### Dispatcher module ######## | |||||
| loadmodule "dispatcher.so" | |||||
| modparam("dispatcher", "db_url", "KAZOO_DB_URL") | |||||
| modparam("dispatcher", "flags", 2) | |||||
| modparam("dispatcher", "use_default", 0) | |||||
| modparam("dispatcher", "force_dst", 1) | |||||
| modparam("dispatcher", "dst_avp", "$avp(ds_dst)") | |||||
| modparam("dispatcher", "attrs_avp", "$avp(ds_attrs)") | |||||
| modparam("dispatcher", "grp_avp", "$avp(ds_grp)") | |||||
| modparam("dispatcher", "cnt_avp", "$avp(ds_cnt)") | |||||
| modparam("dispatcher", "hash_pvar", "$avp(ds_grp)") | |||||
| modparam("dispatcher", "setid_pvname", "$var(setid)") | |||||
| modparam("dispatcher", "ds_ping_method", "OPTIONS") | |||||
| modparam("dispatcher", "ds_ping_interval", 10) | |||||
| modparam("dispatcher", "ds_probing_threshold", 3) | |||||
| modparam("dispatcher", "ds_probing_mode", 1) | |||||
| modparam("dispatcher", "ds_ping_reply_codes", "501,403,404,400,200") | |||||
| modparam("dispatcher", "ds_ping_from", "sip:sipcheck@MY_HOSTNAME") | |||||
| #!import_file "dispatcher-network-params.cfg" | |||||
| ## Dispatcher Groups: | |||||
| ## 1 - Primary media servers | |||||
| ## 2 - Backup media servers | |||||
| ## 3 - Alternate media server IPs (used only for classification) | |||||
| ## 10 - Presence servers (if not locally handled) | |||||
| ## 20 - Registrar servers (if not locally handled) | |||||
| ####### Dispatcher Logic ######## | |||||
| route[DISPATCHER_CLASSIFY_SOURCE] | |||||
| { | |||||
| #!import_file "dispatcher-network-classify.cfg" | |||||
| if (is_myself("$ou")) { | |||||
| xlog("L_INFO", "$ci|log|original R-URI ($ou) is this proxy, treating as external sources\n"); | |||||
| } else if ( | |||||
| ds_is_from_list(1, 3) || | |||||
| ds_is_from_list(2, 3) || | |||||
| ds_is_from_list(3, 3) || | |||||
| ds_is_from_list(10, 3) || | |||||
| ds_is_from_list(20, 3) | |||||
| ) { | |||||
| xlog("L_INFO", "$ci|log|originated from internal sources\n"); | |||||
| setflag(FLAG_INTERNALLY_SOURCED); | |||||
| } else { | |||||
| xlog("L_INFO", "$ci|log|originated from external sources\n"); | |||||
| } | |||||
| } | |||||
| # Take the routes from dispatcher - hash over callid | |||||
| # If prefered route defined, reorder the destionations | |||||
| route[DISPATCHER_FIND_ROUTES] | |||||
| { | |||||
| if ($sht(failover=>$ci::current) != $null) { | |||||
| $du = $sht(failover=>$ci::current); | |||||
| return; | |||||
| } | |||||
| $var(ds_primary_group) = 1; | |||||
| $var(ds_backup_group) = 2; | |||||
| #!ifndef PRESENCE_ROLE | |||||
| if (is_method("SUBSCRIBE")) { | |||||
| $var(ds_primary_group) = 10; | |||||
| $var(ds_backup_group) = 11; | |||||
| } | |||||
| #!endif | |||||
| #!ifndef REGISTRAR_ROLE | |||||
| if (is_method("REGISTER")) { | |||||
| $var(ds_primary_group) = 20; | |||||
| $var(ds_backup_group) = 21; | |||||
| } | |||||
| #!endif | |||||
| #!ifdef FAST_PICKUP_ROLE | |||||
| route(FAST_PICKUP_ATTEMPT); | |||||
| #!endif | |||||
| #!import_file "dispatcher-network-find.cfg" | |||||
| $var(ds_group) = $var(ds_primary_group); | |||||
| if (!ds_select_dst("$var(ds_primary_group)", "0") || $(avp(ds_dst)[0]) == $null) { | |||||
| # we selected from primary group, try again in backup group | |||||
| if (!ds_select_dst("$var(ds_backup_group)", "0") || $(avp(ds_dst)[0]) == $null) { | |||||
| xlog("L_WARN", "$ci|end|no servers available in primary or backup group\n"); | |||||
| sl_send_reply("480", "All servers busy"); | |||||
| exit; | |||||
| } else { | |||||
| $var(ds_group) = $var(ds_backup_group); | |||||
| } | |||||
| } | |||||
| $var(user_source) = $(ct{tobody.user}) + "@" + $si + ":" + $sp; | |||||
| $var(redirect) = @from.uri.user + "@" + @from.uri.host + "->" | |||||
| + @ruri.user + "@" + @ruri.host; | |||||
| if ($sht(redirects=>$var(redirect)) != $null) { | |||||
| $var(prefered_route) = $sht(redirects=>$var(redirect)); | |||||
| xlog("L_INFO", "$ci|log|found redirect for $var(redirect)\n"); | |||||
| if (route(DISPATCHER_REORDER_ROUTES)) { | |||||
| $avp(AVP_REDIRECT_KEY) = $var(redirect); | |||||
| } | |||||
| } else if ($sht(associations=>$var(user_source)) != $null) { | |||||
| $var(prefered_route) = $sht(associations=>$var(user_source)); | |||||
| xlog("L_INFO", "$ci|log|found association for contact uri $var(user_source)\n"); | |||||
| if (!route(DISPATCHER_REORDER_ROUTES)) { | |||||
| $sht(associations=>$var(association)) = $null; | |||||
| } | |||||
| } | |||||
| } | |||||
| route[DISPATCHER_REORDER_ROUTES] | |||||
| { | |||||
| $var(i) = 0; | |||||
| $var(found) = 0; | |||||
| while($(avp(ds_dst)[$var(i)]) != $null) { | |||||
| if($(avp(ds_dst)[$var(i)]) != $var(prefered_route)) { | |||||
| $avp(tmp_ds_dst) = $(avp(ds_dst)[$var(i)]); | |||||
| } else { | |||||
| $var(found) = 1; | |||||
| } | |||||
| $var(i) = $var(i) + 1; | |||||
| } | |||||
| if (!$var(found) && $var(ds_group) == $var(ds_primary_group) && ds_select_dst("$var(ds_backup_group)", "0")) { | |||||
| $var(i) = 0; | |||||
| while($(avp(ds_dst)[$var(i)]) != $null) { | |||||
| if($(avp(ds_dst)[$var(i)]) == $var(prefered_route)) { | |||||
| xlog("L_INFO", "$ci|log|found associated media server in backup list\n"); | |||||
| $var(found) = 1; | |||||
| break; | |||||
| } | |||||
| $var(i) = $var(i) + 1; | |||||
| } | |||||
| } | |||||
| if ($var(found)) { | |||||
| xlog("L_INFO", "$ci|log|re-ordering the dispatcher list to maintain association with $var(prefered_route)\n"); | |||||
| $(avp(ds_dst)[*]) = $null; | |||||
| $var(i) = 0; | |||||
| while($(avp(tmp_ds_dst)[$var(i)]) != $null) { | |||||
| $avp(ds_dst) = $(avp(tmp_ds_dst)[$var(i)]); | |||||
| $var(i) = $var(i) + 1; | |||||
| } | |||||
| $avp(ds_dst) = $var(prefered_route); | |||||
| $du = $var(prefered_route); | |||||
| $(avp(tmp_ds_dst)[*]) = $null; | |||||
| } else { | |||||
| xlog("L_INFO", "$ci|log|associated media server $var(prefered_route) is inactive, moving to $rd\n"); | |||||
| return -1; | |||||
| } | |||||
| return 1; | |||||
| } | |||||
| route[DISPATCHER_NEXT_ROUTE] | |||||
| { | |||||
| $var(failover_count) = $sht(failover=>$ci::counts); | |||||
| if ($sht(failover=>$ci::counts) == $null) { | |||||
| $var(i) = 0; | |||||
| while($(avp(ds_dst)[$var(i)]) != $null) { | |||||
| $sht(failover=>$ci[$var(i)]) = $(avp(ds_dst)[$var(i)]); | |||||
| $var(i) = $var(i) + 1; | |||||
| if ($var(i) >= 3) { | |||||
| break; | |||||
| } | |||||
| } | |||||
| $sht(failover=>$ci::counts) = $var(i); | |||||
| $var(failover_count) = $var(i); | |||||
| } | |||||
| # try to find a new media server to send the call to | |||||
| if ($var(failover_count) > 1) { | |||||
| $var(failover_count) = $var(failover_count) - 1; | |||||
| $du = $sht(failover=>$ci[$var(failover_count)]); | |||||
| $sht(failover=>$ci::counts) = $var(failover_count); | |||||
| $sht(failover=>$ci::current) = $du; | |||||
| xlog("L_INFO", "$ci|log|remaining failed retry attempts: $var(failover_count)\n"); | |||||
| xlog("L_INFO", "$ci|log|routing call to next media server $du\n"); | |||||
| setflag(FLAG_SKIP_NAT_CORRECTION); | |||||
| # reset the final reply timer | |||||
| $avp(final_reply_timer) = 3; | |||||
| t_on_reply("INTERNAL_REPLY"); | |||||
| t_on_failure("INTERNAL_FAULT"); | |||||
| # relay the request to the new media server | |||||
| route(EXTERNAL_TO_INTERNAL_RELAY); | |||||
| exit(); | |||||
| } | |||||
| } | |||||
| event_route[dispatcher:dst-down] | |||||
| { | |||||
| xlog("L_ERR", "Destination down: $ru\n"); | |||||
| } | |||||
| event_route[dispatcher:dst-up] | |||||
| { | |||||
| xlog("L_WARNING", "Destination up: $ru\n"); | |||||
| } | |||||
| route[DISPATCHER_CHECK_MEDIA_SERVER] | |||||
| { | |||||
| if(@cfg_get.kazoo.dispatcher_auto_add == 1) { | |||||
| $var(SetId) = 1; | |||||
| if($var(Zone) != "MY_AMQP_ZONE") { | |||||
| $var(SetId) = 2; | |||||
| } | |||||
| sql_query("exec", "KZQ_CHECK_MEDIA_SERVER_INSERT"); | |||||
| if($sqlrows(exec) > 0) { | |||||
| xlog("L_WARNING", "reloading dispatcher table\n"); | |||||
| ds_reload(); | |||||
| } | |||||
| } | |||||
| } | |||||
| route[DISPATCHER_STATUS] | |||||
| { | |||||
| jsonrpc_exec('{"jsonrpc": "2.0", "method": "dispatcher.list", "id": 1}'); | |||||
| $var(Sets) = $(jsonrpl(body){kz.json, result.NRSETS}); | |||||
| $var(i) = 0; | |||||
| $var(ds_groups_json)=""; | |||||
| $var(Sep1) = ""; | |||||
| while($var(i) < $var(Sets)) { | |||||
| $var(Set) = $(jsonrpl(body){kz.json, result.RECORDS[$var(i)].SET}); | |||||
| $var(SetCount) = $(var(Set){kz.json.count,TARGETS}); | |||||
| $var(Sep2)=""; | |||||
| $var(ds_group_json)=""; | |||||
| $var(c) = 0; | |||||
| while($var(c) < $var(SetCount)) { | |||||
| $var(Dest) = $(var(Set){kz.json,TARGETS[$var(c)].DEST}); | |||||
| $var(record) = $_s("$(var(Dest){kz.json,URI})" : {"destination" : "$(var(Dest){kz.json,URI})", "flags" : "$(var(Dest){kz.json,FLAGS})", "priority" : $(var(Dest){kz.json,PRIORITY}), "attrs" : "$(var(Dest){kz.json,ATTRS.BODY})"}); | |||||
| $var(ds_group_json) = $var(ds_group_json) + $var(Sep2) + $var(record); | |||||
| $var(Sep2) = ","; | |||||
| $var(c) = $var(c) + 1; | |||||
| } | |||||
| $var(ds_groups_json) = $var(ds_groups_json) + $var(Sep1) + $_s("$(var(Set){kz.json,ID})" : { $var(ds_group_json) }); | |||||
| $var(Sep1)=", "; | |||||
| $var(i) = $var(i) + 1; | |||||
| } | |||||
| } | |||||
| # vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab | |||||
| @ -0,0 +1,81 @@ | |||||
| ####### Extra Traffic Filter Role Configuration ######## | |||||
| # Define default values for configuration options if not set in local.cfg | |||||
| #!ifndef ETFR_BAN_DURATION | |||||
| #!define ETFR_BAN_DURATION 1800 | |||||
| #!endif | |||||
| # Define Bad User-Agent Patterns | |||||
| #!ifndef ETFR_BAD_UA_PATTERNS | |||||
| #!define ETFR_BAD_UA_PATTERNS "friendly-scanner|sipcli|sipsak|VaxSIPUserAgent|iWar|CSipSimple|sipvicious|sip-scan|svmap|VaxIPUserAgent|sundayddr|sipv|smap|PSYCHO|iPing|DiSipell|WebSipp|masscan|zmap|SIPBot|friendly-request|siparmyknife" | |||||
| #!endif | |||||
| #!substdef "!ETFR_SUBST_BAD_UA_PATTERNS!$def(ETFR_BAD_UA_PATTERNS)!g" | |||||
| # Define SQL Injection Patterns | |||||
| #!ifndef ETFR_SQL_INJECTION_PATTERNS | |||||
| #!define ETFR_SQL_INJECTION_PATTERNS "([';]+|(--)+|(%27)+|(%23)+|(%24)+|[;]+|[']+)" | |||||
| #!endif | |||||
| # Initialize htable for banned IPs | |||||
| #!substdef "!ETFR_SUBST_BAN_DURATION!$def(ETFR_BAN_DURATION)!g" | |||||
| modparam("htable", "htable", "etfr_banned_ips=>size=8;autoexpire=ETFR_SUBST_BAN_DURATION") | |||||
| route[EXTRA_FILTER_REQUEST] { | |||||
| # Check if the source IP is banned | |||||
| if ($sht(etfr_banned_ips=>$si)) { | |||||
| xlog("L_WARN", "$ci|Fail2Ban| Dropping request from banned IP: $si\n"); | |||||
| exit; | |||||
| } | |||||
| # Proceed with INVITE filtering | |||||
| if (is_method("INVITE")) { | |||||
| # Extract the domain from the Request URI | |||||
| $var(domain) = $rd; | |||||
| # Check if the domain is an IP address | |||||
| if ($var(domain) =~ "^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$") { | |||||
| # Check if the source IP is in the carrier group | |||||
| if (!(allow_source_address(1) || allow_source_address(10))) { | |||||
| # Source IP is not a carrier, ban the IP | |||||
| xlog("L_ALERT", "$ci|Fail2Ban| Banned IP: $si Reason: INVITE with IP domain from untrusted source\n"); | |||||
| route(ETFR_BAN_IP); | |||||
| } else { | |||||
| xlog("L_WARN", "$ci|ETFR| Allowing Carrier IP: $si\n"); | |||||
| return; | |||||
| } | |||||
| } | |||||
| # Check if the Request URI contains user '1000' | |||||
| if ($rU == "1000") { | |||||
| xlog("L_ALERT", "$ci|Fail2Ban| Banned IP: $si Reason: Attempt to call user 1000\n"); | |||||
| route(ETFR_BAN_IP); | |||||
| } | |||||
| } | |||||
| # Check for known bad User-Agents | |||||
| if ($ua =~ "(ETFR_SUBST_BAD_UA_PATTERNS)") { | |||||
| xlog("L_ALERT", "$ci|Fail2Ban| Banned IP: $si Reason: Known bad User-Agent: $ua\n"); | |||||
| route(ETFR_BAN_IP); | |||||
| } | |||||
| # Check for SQL injection patterns in SIP message | |||||
| if ($rb =~ "(ETFR_SQL_INJECTION_PATTERNS)" || $ru =~ "(ETFR_SQL_INJECTION_PATTERNS)") { | |||||
| xlog("L_ALERT", "$ci|Fail2Ban| Banned IP: $si Reason: SQL injection attempt\n"); | |||||
| route(ETFR_BAN_IP); | |||||
| } | |||||
| return; | |||||
| } | |||||
| # Ban IP Route | |||||
| route[ETFR_BAN_IP] { | |||||
| # Add source IP to banned IPs table with auto-expire | |||||
| $sht(etfr_banned_ips=>$si) = $Ts; | |||||
| # Log the event for Fail2Ban | |||||
| xlog("L_ALERT", "$ci|end| Added IP $si to etfr_banned_ips htable\n"); | |||||
| # Drop the request | |||||
| exit; | |||||
| } | |||||
| @ -0,0 +1,343 @@ | |||||
| ######## KEEPALIVE PINGING ######## | |||||
| #!trydef KEEPALIVE_ENABLED 1 | |||||
| #!trydef KEEPALIVE_NAT_ONLY 0 | |||||
| #!trydef KEEPALIVE_UDP_ONLY 0 | |||||
| #!trydef KEEPALIVE_TIMERS 4 | |||||
| #!trydef KEEPALIVE_INTERVAL 60 | |||||
| #!trydef KEEPALIVE_TIMEOUT 5000 | |||||
| #!trydef KEEPALIVE_FAILED_THRESHOLD 2 | |||||
| #!trydef KEEPALIVE_EXPIRE_SUBSCRIPTIONS 1 | |||||
| #!trydef KEEPALIVE_EXPIRE_REGISTRATIONS 1 | |||||
| #!trydef KEEPALIVE_FAILED_ACTION 1 | |||||
| #!trydef KEEPALIVE_FAILED_LOG_LEVEL 0 | |||||
| #!trydef KEEPALIVE_EXPIRED_SUBSCRIPTION_ACTION 1 | |||||
| #!trydef KEEPALIVE_EXPIRED_REGISTRATION_ACTION 1 | |||||
| #!trydef KEEPALIVE_ON_SUBSCRIPTION_ACTION 1 | |||||
| #!trydef KEEPALIVE_ON_REGISTRATION_ACTION 1 | |||||
| #!substdef "!KEEPALIVE_S_FROM_URI!sip:keepalive@MY_HOSTNAME!g" | |||||
| #!substdef "!KEEPALIVE_S_TIMERS!$def(KEEPALIVE_TIMERS)!g" | |||||
| kazoo.keepalive_udp_only = KEEPALIVE_UDP_ONLY descr "should we send keepalive for udp only" | |||||
| kazoo.keepalive_nat_only = KEEPALIVE_NAT_ONLY descr "should we send keepalive for nat phones only" | |||||
| kazoo.keepalive_timeout = KEEPALIVE_TIMEOUT descr "timeout in ms for keepalive transaction" | |||||
| kazoo.keepalive_failed_threshold = KEEPALIVE_FAILED_THRESHOLD descr "how many times can a device fail to respond to OPTIONS" | |||||
| kazoo.keepalive_expire_subscriptions = KEEPALIVE_EXPIRE_SUBSCRIPTIONS descr "expires subscriptions that do not respond to OPTIONS" | |||||
| kazoo.keepalive_expire_registrations = KEEPALIVE_EXPIRE_REGISTRATIONS descr "expires registrations that do not respond to OPTIONS" | |||||
| kazoo.keepalive_failed_log_level = KEEPALIVE_FAILED_LOG_LEVEL descr "loglevel for keepalive failed reply" | |||||
| kazoo.keepalive_failed_action = KEEPALIVE_FAILED_ACTION descr "action for devices that exceed the threshold. 1 = disable, 2 = delete" | |||||
| kazoo.keepalive_interval = KEEPALIVE_INTERVAL descr "interval in seconds between attempts to send OPTIONS to device" | |||||
| kazoo.keepalive_expired_registration_action = KEEPALIVE_EXPIRED_REGISTRATION_ACTION descr "action when registrar expires a registration, 1 = delete , 2 = disable, 0 = none" | |||||
| kazoo.keepalive_expired_subscription_action = KEEPALIVE_EXPIRED_SUBSCRIPTION_ACTION descr "action when presence expires a subscription, 1 = delete , 2 = disable, 0 = none" | |||||
| kazoo.keepalive_on_registration_action = KEEPALIVE_ON_REGISTRATION_ACTION descr "action on registration, 1 = insert in keepalive , 0 = none" | |||||
| kazoo.keepalive_on_subscription_action = KEEPALIVE_ON_SUBSCRIPTION_ACTION descr "action on subscription, 1 = insert in keepalive , 0 = none" | |||||
| kazoo.keepalive_enable = KEEPALIVE_ENABLED descr "enable keepalive, 1 = on , 0 = off" | |||||
| modparam("rtimer", "timer", "name=keepalive_timer;interval=1;mode=KEEPALIVE_S_TIMERS;") | |||||
| modparam("rtimer", "exec", "timer=keepalive_timer;route=KEEPALIVE_TIMER") | |||||
| modparam("rtimer", "timer", "name=keepalive_db_timer;interval=1;mode=1;") | |||||
| modparam("rtimer", "exec", "timer=keepalive_db_timer;route=KEEPALIVE_DB_TIMER") | |||||
| ##modparam("rtimer", "timer", "name=keepalive_cleanup;interval=5;mode=1;") | |||||
| ##modparam("rtimer", "exec", "timer=keepalive_cleanup;route=KEEPALIVE_CLEANUP") | |||||
| modparam("mqueue","mqueue", "name=keepalive_db_queue") | |||||
| modparam("statistics","variable", "keepalive:success") | |||||
| modparam("statistics","variable", "keepalive:failure") | |||||
| modparam("statistics","variable", "keepalive:db:success") | |||||
| modparam("statistics","variable", "keepalive:db:failure") | |||||
| modparam("statistics","variable", "keepalive:client_options") | |||||
| modparam("statistics","variable", "keepalive:client_notify") | |||||
| modparam("statistics","variable", "keepalive:disabled") | |||||
| modparam("statistics","variable", "keepalive:removed") | |||||
| modparam("statistics","variable", "keepalive:expired_registrations") | |||||
| modparam("statistics","variable", "keepalive:expired_subscriptions") | |||||
| modparam("statistics","variable", "keepalive:from_registration") | |||||
| modparam("statistics","variable", "keepalive:from_subscription") | |||||
| modparam("statistics","variable", "keepalive:removed_from_registration") | |||||
| modparam("statistics","variable", "keepalive:removed_from_subscription") | |||||
| modparam("statistics","variable", "keepalive:disabled_from_expired_registration") | |||||
| modparam("statistics","variable", "keepalive:removed_from_expired_registration") | |||||
| modparam("statistics","variable", "keepalive:disabled_from_expired_subscription") | |||||
| modparam("statistics","variable", "keepalive:removed_from_expired_subscription") | |||||
| modparam("htable", "htable", "keepalive=>size=32;") | |||||
| route[KEEPALIVE_DB_TIMER] | |||||
| { | |||||
| $var(runloop) = 1; | |||||
| while(mq_fetch("keepalive_db_queue") == 1 && $var(runloop) < MAX_WHILE_LOOPS) { | |||||
| $var(ci) = $mqk(keepalive_db_queue); | |||||
| xlog("L_DEBUG", "Query : $var(ci) => $mqv(keepalive_db_queue)\n"); | |||||
| $var(sqlres) = sql_query("cb", "$mqv(keepalive_db_queue)"); | |||||
| xlog("L_DEBUG", "Query result : $var(sqlres)\n"); | |||||
| if($var(sqlres) < 0) { | |||||
| xlog("L_ERROR", "$var(ci)|log|error running query : $mqv(keepalive_db_queue)\n"); | |||||
| } else { | |||||
| $var(stat_update) = $_s(+$sqlrows(cb)); | |||||
| update_stat("$var(ci)", "$var(stat_update)"); | |||||
| $var(nrows) = $sqlrows(cb); | |||||
| xlog("L_DEBUG", "$var(ci)|log|end UPDATED $var(nrows) => $var(stat_update)\n"); | |||||
| if($var(nrows) == 0) { | |||||
| xlog("L_DEBUG", "$var(ci)|log|error no rows affected when running query\n"); | |||||
| } | |||||
| } | |||||
| $var(runloop) = $var(runloop) + 1; | |||||
| } | |||||
| } | |||||
| route[KEEPALIVE_CLEANUP] | |||||
| { | |||||
| if($sel(cfg_get.kazoo.keepalive_enable) == 0) return; | |||||
| $var(Query) = $_s(UPDATE keepalive SET SELECTED = 9 WHERE slot = $var(slot) AND selected = 0 and failed > $sel(cfg_get.kazoo.keepalive_failed_threshold)); | |||||
| # $var(Query) = $_s(UPDATE keepalive SET SELECTED = 9 where selected < 3 and failed > $sel(cfg_get.kazoo.keepalive_failed_threshold)); | |||||
| sql_query("cb", "$var(Query)"); | |||||
| if($sqlrows(cb) > 0) { | |||||
| if($sel(cfg_get.kazoo.keepalive_expire_registrations) == 1) { | |||||
| if($def(REGISTRAR_DB_MODE) == 3) { | |||||
| $var(Query) = $_s(update location set expires = last_modified where id in(select b.id from w_keepalive_contact a inner join w_location_contact b on a.contact = b.contact where selected = 9)); | |||||
| sql_query("cb", "$var(Query)"); | |||||
| $var(stat_update) = $_s(+$sqlrows(cb)); | |||||
| update_stat("keepalive:expired_registrations", "$var(stat_update)"); | |||||
| } else { | |||||
| $var(Query) = $_s(update location set expires = last_modified where id in(select b.id from w_keepalive_contact a inner join w_location_contact b on a.contact = b.contact where selected = 9)); | |||||
| sql_query("cb", "$var(Query)"); | |||||
| $var(stat_update) = $_s(+$sqlrows(cb)); | |||||
| update_stat("keepalive:expired_registrations", "$var(stat_update)"); | |||||
| } | |||||
| } | |||||
| if($sel(cfg_get.kazoo.keepalive_expire_subscriptions) == 1) { | |||||
| $var(Query) = $_s(DELETE FROM active_watchers where id in(select b.id from w_keepalive_contact a inner join w_watchers_contact b on a.contact = b.contact where selected = 9)); | |||||
| sql_query("cb", "$var(Query)"); | |||||
| $var(stat_update) = $_s(+$sqlrows(cb)); | |||||
| update_stat("keepalive:expired_subscriptions", "$var(stat_update)"); | |||||
| } | |||||
| if($sel(cfg_get.kazoo.keepalive_failed_action) == 2) { | |||||
| ## disable | |||||
| $var(Query) = $_s(UPDATE keepalive SET SELECTED = 10 where selected = 9); | |||||
| $var(stat) = "keepalive:disabled"; | |||||
| } else if($sel(cfg_get.kazoo.keepalive_failed_action) == 1) { | |||||
| ## delete - will be recreated on registration/subscription with same contact | |||||
| $var(Query) = $_s(DELETE FROM keepalive where selected = 9); | |||||
| $var(stat) = "keepalive:removed"; | |||||
| } | |||||
| sql_query("cb", "$var(Query)"); | |||||
| $var(stat_update) = $_s(+$sqlrows(cb)); | |||||
| update_stat("$var(stat)", "$var(stat_update)"); | |||||
| } | |||||
| } | |||||
| route[KEEPALIVE_TIMER] | |||||
| { | |||||
| if($sel(cfg_get.kazoo.keepalive_enable) == 0) return; | |||||
| $var(base_slot) = $rtimer_worker * $sel(cfg_get.kazoo.keepalive_interval); | |||||
| $var(slot) = $var(base_slot) + $var(tick); | |||||
| $var(Query) = $_s(UPDATE keepalive SET selected = 1 WHERE slot = $var(slot) AND selected = 0 AND time_sent < datetime('now', '-$sel(cfg_get.kazoo.keepalive_interval) seconds')); | |||||
| ## xlog("L_NOTICE", "SQLTIMER ($var(base_slot) + $var(tick))> $var(Query)\n"); | |||||
| $var(sqlres) = sql_query("cb", "$var(Query)"); | |||||
| if($var(sqlres) < 0) { | |||||
| xlog("L_ERROR", "$rtimer_worker|$var(tick)|log|error running query : $var(Query)\n"); | |||||
| } else { | |||||
| $var(nrows) = $sqlrows(cb); | |||||
| xlog("L_DEBUG", "$rtimer_worker|$var(tick)|log|selected $var(nrows) endpoints to ping\n"); | |||||
| } | |||||
| route(KEEPALIVE_CLEANUP); | |||||
| $var(Query) = $_s(SELECT id, contact, sockinfo from keepalive WHERE slot = $var(slot) AND selected = 1); | |||||
| xlog("L_DEBUG", "$rtimer_worker|$var(tick)|timer|SQL => $var(Query)\n"); | |||||
| $var(result) =sql_xquery("cb", "$var(Query)", "ra"); | |||||
| if($var(result) == 1) { | |||||
| while($xavp(ra) != $null) { | |||||
| $var(loop) = 0; | |||||
| while($xavp(ra) != $null && $var(loop) < MAX_WHILE_LOOPS) { | |||||
| route(KEEPALIVE_SEND_PING); | |||||
| pv_unset("$xavp(ra)"); | |||||
| $var(loop) = $var(loop) + 1; | |||||
| } | |||||
| } | |||||
| } | |||||
| $var(Query) = $_s(UPDATE keepalive SET selected = 2 WHERE slot = $var(slot) AND selected = 1); | |||||
| $var(sqlres) = sql_query("cb", "$var(Query)"); | |||||
| if($var(sqlres) < 0) { | |||||
| xlog("L_ERROR", "$rtimer_worker|$var(tick)|log|error running query : $var(Query)\n"); | |||||
| } | |||||
| $var(tick) = $var(tick) + 1; | |||||
| if($var(tick) > $sel(cfg_get.kazoo.keepalive_interval)) { | |||||
| $var(tick) = 0; | |||||
| } | |||||
| } | |||||
| route[KEEPALIVE_SEND_PING] | |||||
| { | |||||
| $var(CallId) = $uuid(g); | |||||
| xlog("L_DEBUG", "$var(CallId)|$rtimer_worker|timer|SENDING PING FROM $xavp(ra=>local_contact) TO => $xavp(ra=>contact)\n"); | |||||
| $uac_req(method)="OPTIONS"; | |||||
| $uac_req(hdrs) = "X-TM-Local: KEEPALIVE_PING\r\nX-TM-SockInfo: " + $xavp(ra=>sockinfo) + "\r\n"; | |||||
| $uac_req(turi) = $xavp(ra=>contact); | |||||
| $uac_req(ruri) = $xavp(ra=>contact); | |||||
| $uac_req(furi) = $_s(KEEPALIVE_S_FROM_URI;nat_id=$xavp(ra=>id)); | |||||
| $uac_req(ouri) = "sip:127.0.0.1:5090;transport=tcp"; | |||||
| $uac_req(callid) = $var(CallId); | |||||
| uac_req_send(); | |||||
| } | |||||
| onreply_route[KEEPALIVE_REPLY] | |||||
| { | |||||
| xlog("L_DEBUG", "$ci|keepalive|KEEPALIVE REPLY $(tu{nameaddr.uri})\n"); | |||||
| $var(Query) = $_s(UPDATE keepalive SET selected = 0, failed = 0, time_sent = datetime('now') WHERE id = $(fu{uri.param,nat_id}) AND SELECTED = 2); | |||||
| xlog("L_DEBUG", "$ci|keepalive|KEEPALIVE UPDATE SQL => '$var(Query)'\n"); | |||||
| mq_add("keepalive_db_queue", "keepalive:db:success", "$var(Query)"); | |||||
| update_stat("keepalive:success", "+1"); | |||||
| resetflag(FLAG_SIP_TRACE); | |||||
| } | |||||
| failure_route[KEEPALIVE_FAULT] | |||||
| { | |||||
| xlog("$(sel(cfg_get.kazoo.keepalive_failed_log_level){s.int})", "$ci|keepalive|received error $T_reply_code $T_reply_reason from $(tu{nameaddr.uri})\n"); | |||||
| $var(Query) = $_s(UPDATE keepalive SET selected = 0, failed = failed + 1, time_sent = datetime('now') WHERE id = $(fu{uri.param,nat_id}) AND SELECTED = 2); | |||||
| xlog("L_DEBUG", "$ci|keepalive|KEEPALIVE REMOVE SQL => '$var(Query)'\n"); | |||||
| mq_add("keepalive_db_queue", "keepalive:db:failure", "$var(Query)"); | |||||
| update_stat("keepalive:failure", "+1"); | |||||
| resetflag(FLAG_SIP_TRACE); | |||||
| } | |||||
| route[KEEPALIVE_PING] | |||||
| { | |||||
| $fs = $hdr(X-TM-SockInfo); | |||||
| remove_hf_re("^X-TM-SockInfo"); | |||||
| force_rport(); | |||||
| handle_ruri_alias(); | |||||
| record_route(); | |||||
| xlog("L_DEBUG", "$ci|local|sending $proto keepalive using $fs to $ru => $du => $tu\n"); | |||||
| t_on_reply("KEEPALIVE_REPLY"); | |||||
| t_on_failure("KEEPALIVE_FAULT"); | |||||
| t_set_fr(0, $sel(cfg_get.kazoo.keepalive_timeout)); | |||||
| t_relay(); | |||||
| } | |||||
| route[KEEPALIVE_ON_REGISTRATION] | |||||
| { | |||||
| if($sel(cfg_get.kazoo.keepalive_enable) == 0) return; | |||||
| if($sel(cfg_get.kazoo.keepalive_on_registration_action) == 0) { | |||||
| return; | |||||
| } | |||||
| if($proto == "ws" || $proto == "wss") { | |||||
| return; | |||||
| } | |||||
| if($sht(keepalive=>$si~$sp~$prid) != $null) { | |||||
| return; | |||||
| } | |||||
| if (isbflagset(FLB_NATB)) { | |||||
| if(!isbflagset(FLB_NATSIPPING)) { | |||||
| return; | |||||
| } | |||||
| } else { | |||||
| if($sel(cfg_get.kazoo.keepalive_nat_only) == 1) { | |||||
| return; | |||||
| } | |||||
| } | |||||
| $var(alias) = $(avp(AVP_RECV_PARAM){uri.host}) + "~" + $(avp(AVP_RECV_PARAM){uri.port}) + "~" + $prid; | |||||
| $var(contact) = $(ct{nameaddr.uri}) + ";alias=" + $var(alias); | |||||
| $var(local_contact) = "sip:" + $Ri + ":" + $Rp + ";transport=" + $proto; | |||||
| xlog("L_DEBUG", "$ci|keepalive|KEEPALIVE ON REG $var(save_result) $proto $RAut $var(contact) $var(alias) $(ct{nameaddr.uri}) $ct $avp(AVP_RECV_PARAM) $tu $xavp(ulrcd=>ruid) , $xavp(ulrcd=>contact) , $xavp(ulrcd=>expires)\n"); | |||||
| if($var(save_result) == 3) { | |||||
| $var(sql) = $_s(DELETE FROM keepalive WHERE contact = "$var(contact)"); | |||||
| $var(stat) = "keepalive:removed_from_registration"; | |||||
| } else { | |||||
| $var(max_slots) = $sel(cfg_get.kazoo.keepalive_interval) * KEEPALIVE_S_TIMERS; | |||||
| $var(slot) = $(var(contact){s.corehash, $var(max_slots)}); | |||||
| $var(sql) = $_s(INSERT OR IGNORE INTO keepalive (contact, received, sockinfo, slot) values("$var(contact)", "$var(alias)", "$(RAut{uri.tosocket})", $var(slot))); | |||||
| $var(stat) = "keepalive:from_registration"; | |||||
| } | |||||
| mq_add("keepalive_db_queue", "$var(stat)", "$var(sql)"); | |||||
| return; | |||||
| } | |||||
| route[KEEPALIVE_ON_SUBSCRIBE] | |||||
| { | |||||
| if($sel(cfg_get.kazoo.keepalive_enable) == 0) return; | |||||
| if($sel(cfg_get.kazoo.keepalive_on_subscription_action) == 0) { | |||||
| return; | |||||
| } | |||||
| if($sht(keepalive=>$si~$sp~$prid) != $null) { | |||||
| return; | |||||
| } | |||||
| $var(max_slots) = $sel(cfg_get.kazoo.keepalive_interval) * KEEPALIVE_S_TIMERS; | |||||
| $var(slot) = $(subs(contact){s.corehash, $var(max_slots)}); | |||||
| $var(alias) = $(subs(contact){uri.param,alias}); | |||||
| $var(sql) = $_s(INSERT OR IGNORE INTO keepalive (contact, received, sockinfo, slot) values("$subs(contact)", "$var(alias)", "$subs(sockinfo)", $var(slot))); | |||||
| mq_add("keepalive_db_queue", "keepalive:from_subscription", "$var(sql)"); | |||||
| } | |||||
| route[KEEPALIVE_ON_EXPIRED_REGISTRATION] | |||||
| { | |||||
| if($sel(cfg_get.kazoo.keepalive_enable) == 0) return; | |||||
| if($sel(cfg_get.kazoo.keepalive_expired_registration_action) == 2) { | |||||
| ## disable | |||||
| $var(Query) = $_s(UPDATE keepalive SET SELECTED = 10 where selected < 3 and contact like "$ulc(exp=>addr)%"); | |||||
| mq_add("keepalive_db_queue", "keepalive:disabled_from_expired_registration", "$var(Query)"); | |||||
| } else if($sel(cfg_get.kazoo.keepalive_expired_registration_action) == 1) { | |||||
| ## delete - will be recreated on registration with same contact | |||||
| $var(Query) = $_s(DELETE FROM keepalive where selected < 3 and contact like "$ulc(exp=>addr)%"); | |||||
| mq_add("keepalive_db_queue", "keepalive:removed_from_expired_registration", "$var(Query)"); | |||||
| } | |||||
| } | |||||
| route[KEEPALIVE_ON_OPTIONS] | |||||
| { | |||||
| if($sel(cfg_get.kazoo.keepalive_enable) == 0) return; | |||||
| if($shtinc(keepalive=>$si~$sp~$prid) == 1) { | |||||
| $var(Query) = $_s(UPDATE keepalive set selected = 3 where received = "$si~$sp~$prid" and selected <> 3 ); | |||||
| mq_add("keepalive_db_queue", "keepalive:client_options", "$var(Query)"); | |||||
| } | |||||
| } | |||||
| route[KEEPALIVE_ON_NOTIFY] | |||||
| { | |||||
| if($sel(cfg_get.kazoo.keepalive_enable) == 0) return; | |||||
| if($shtinc(keepalive=>$si~$sp~$prid) == 1) { | |||||
| $var(Query) = $_s(UPDATE keepalive set selected = 4 where received = "$si~$sp~$prid" and selected <> 4 ); | |||||
| mq_add("keepalive_db_queue", "keepalive:client_notify", "$var(Query)"); | |||||
| } | |||||
| } | |||||
| @ -1,60 +1,101 @@ | |||||
| modparam("htable", "htable", "msg=>size=32;autoexpire=60;") | |||||
| event_route[kazoo:consumer-event-message-route] | |||||
| route[HANDLE_MESSAGE] | |||||
| { | { | ||||
| $var(uri_username) = ""; | |||||
| kazoo_json($kzE, "Endpoints[0].To-Username", "$var(uri_username)"); | |||||
| $var(x) = $(kzE{kz.json,Endpoints[0].To-Username}); | |||||
| xlog("L_INFO", "received message route for $(kzE{kz.json,Endpoints[0].To-DID})\n"); | |||||
| if( $var(uri_username) != "" ) { | |||||
| $var(from_uri) = "sip:" + $(kzE{kz.json,Caller-ID-Number}) + "@" + $(kzE{kz.json,Endpoints[0].To-Realm}); | |||||
| $var(to_uri) = "sip:" + $(kzE{kz.json,Endpoints[0].To-Username}) + "@" + $(kzE{kz.json,Endpoints[0].To-Realm}); | |||||
| if (!is_method("MESSAGE")) return; | |||||
| if (isflagset(FLAG_INTERNALLY_SOURCED) || src_ip == myself) return; | |||||
| xlog("L_INFO", "$ci|log|MESSAGE from $fu to $tu\n"); | |||||
| route(AUTH); | |||||
| $xavp(regcfg=>match_received) = $su; | |||||
| if($avp(is_registered) != "true") { | |||||
| sl_send_reply("403", "Forbidden"); | |||||
| exit; | |||||
| } else { | } else { | ||||
| $var(from_uri) = "sip:" + $(kzE{kz.json,Caller-ID-Number}) + $(kzE{kz.json,Endpoints[0].To-Realm}); | |||||
| $var(to_uri) = $(kzE{kz.json,Endpoints[0].Route}); | |||||
| if($hdr(Content-Type) =~ "text/plain" || | |||||
| $hdr(Content-Type) =~ "text/html") { | |||||
| route(MESSAGE_INBOUND); | |||||
| } else { | |||||
| xlog("L_WARN", "$ci|end|dropping MESSAGE $hdr(Content-Type)\n"); | |||||
| sl_send_reply("200", "OK"); | |||||
| exit; | |||||
| } | |||||
| } | } | ||||
| $sht(msg=>$(kzE{kz.json,Call-ID})) = $kzE; | |||||
| } | |||||
| route[MESSAGE_INBOUND] | |||||
| { | |||||
| $var(key) = "kamailio@MY_HOSTNAME"; | |||||
| route(AUTH_HEADERS_JSON); | |||||
| $var(Payload) = $_s({"Event-Category" : "sms", "Event-Name" : "inbound", "Call-ID" : "$ci", "Message-ID" : "$ci", "Route-Type" : "onnet", "Route-ID" : "$(var(key){kz.encode})", "From" : "$fU", "To" : "$tU", "Body" : "$rb", "Custom-SIP-Headers" : $var(headers_json), "Msg-ID" : "$uuid(g)"}); | |||||
| $var(exchange) = "im"; | |||||
| $var(RoutingKey) = $_s(sms.inbound.onnet.$(ci{kz.encode})); | |||||
| xlog("L_INFO", "$ci|msg|sending inbound message $var(RoutingKey) => $var(Payload)\n"); | |||||
| kazoo_publish($var(exchange), $var(RoutingKey), $var(Payload)); | |||||
| sl_send_reply("200", "OK"); | |||||
| exit; | |||||
| } | |||||
| event_route[kazoo:consumer-event-sms-outbound] | |||||
| { | |||||
| xlog("L_INFO", "$(kzE{kz.json,Message-ID})|log|received message outbound for $(kzE{kz.json,Endpoints[0].To-DID})\n"); | |||||
| $var(from_uri) = $_s(sip:$(kzE{kz.json,From})@$(kzE{kz.json,Custom-Vars.Realm})); | |||||
| $var(to_uri) = $_s(sip:$(kzE{kz.json,Endpoints[0].To-Username})@$(kzE{kz.json,Endpoints[0].To-Realm})); | |||||
| $uac_req(method)="MESSAGE"; | $uac_req(method)="MESSAGE"; | ||||
| $uac_req(body)= $(kzE{kz.json,Body}); | |||||
| $uac_req(hdrs)="X-KAZOO-AOR: " + $var(to_uri)+ "\r\nContent-Type: text/plain\r\n"; | |||||
| $uac_req(body)= $kzE; | |||||
| $uac_req(hdrs)="X-TM-Local: MESSAGE_ROUTE\r\nX-KAZOO-AOR: " + $var(to_uri)+ "\r\nContent-Type: text/plain\r\n"; | |||||
| $uac_req(turi) = $var(to_uri); | $uac_req(turi) = $var(to_uri); | ||||
| $uac_req(ruri) = $var(to_uri); | $uac_req(ruri) = $var(to_uri); | ||||
| $uac_req(furi) = $var(from_uri); | $uac_req(furi) = $var(from_uri); | ||||
| $uac_req(ouri) = "sip:MY_IP_ADDRESS:5060"; | |||||
| $uac_req(callid) = $(kzE{kz.json,Call-ID}); | |||||
| xlog("L_INFO", "sending message from $var(from_uri) to $var(to_uri) \n"); | |||||
| $uac_req(ouri) = "sip:127.0.0.1:5090;transport=tcp"; | |||||
| $uac_req(callid) = $(kzE{kz.json,Message-ID}); | |||||
| xlog("L_INFO", "$(kzE{kz.json,Message-ID})|log|sending message from $var(from_uri) to $var(to_uri) \n"); | |||||
| uac_req_send(); | uac_req_send(); | ||||
| } | } | ||||
| route[MESSAGE_REPLY] | |||||
| route[MESSAGE_ROUTE] | |||||
| { | { | ||||
| if( $(sht(msg=>$ci)) == $null) { | |||||
| exit(); | |||||
| } | |||||
| remove_hf_re("^X-"); | |||||
| if($T_reply_code != 200 && $T_reply_code != 202) { | |||||
| $var(Result) = "Failure"; | |||||
| } else { | |||||
| $var(Result) = "Success"; | |||||
| route(ROUTE_TO_AOR); | |||||
| $var(JObj) = $rb; | |||||
| set_body("$(var(JObj){kz.json,Body})", "text/plain"); | |||||
| $avp(message_id) = $(var(JObj){kz.json,Message-ID}); | |||||
| $avp(msg_id) = $(var(JObj){kz.json,Msg-ID}); | |||||
| $avp(server_id) = $(var(JObj){kz.json,Server-ID}); | |||||
| t_on_reply("MESSAGE_REPLY"); | |||||
| t_on_failure("MESSAGE_FAULT"); | |||||
| t_relay(); | |||||
| } | |||||
| onreply_route[MESSAGE_REPLY] | |||||
| { | |||||
| if($T_reply_code < 300) { | |||||
| xlog("L_INFO", "$ci|log|sending success delivery message to $avp(server_id)\n"); | |||||
| $var(Payload) = $_s({"Event-Category" : "message", "Event-Name" : "delivery", "Call-ID" : "$ci", "Message-ID" : "$avp(message_id)" , "Delivery-Result-Code" : "sip:$T_reply_code", "Msg-ID" : "$avp(msg_id)" , "Status" : "delivered"}); | |||||
| $var(exchange) = "targeted"; | |||||
| $var(RK) = $avp(server_id); | |||||
| kazoo_publish($var(exchange), $var(RK), $var(Payload)); | |||||
| } | } | ||||
| } | |||||
| $var(Payload) = '{ "Event-Category" : "message", "Event-Name" : "delivery", "Call-ID" : "$(sht(msg=>$ci){kz.json,Call-ID})", "Message-ID" : "$(sht(msg=>$ci){kz.json,Message-ID})" , "Delivery-Result-Code" : "sip:$T_reply_code", "Msg-ID" : "$(sht(msg=>$ci){kz.json,Msg-ID})" , "Status" : "$var(Result)"}'; | |||||
| $var(RoutingKey) = $(sht(msg=>$ci){kz.json,Server-ID}); | |||||
| failure_route[MESSAGE_FAULT] | |||||
| { | |||||
| xlog("L_INFO", "$ci|log|sending failure delivery message to $avp(server_id)\n"); | |||||
| $var(Payload) = $_s({"Event-Category" : "message", "Event-Name" : "delivery", "Call-ID" : "$ci", "Message-ID" : "$avp(message_id)" , "Delivery-Result-Code" : "sip:$T_reply_code", "Msg-ID" : "$avp(msg_id)" , "Status" : "failure"}); | |||||
| $var(exchange) = "targeted"; | $var(exchange) = "targeted"; | ||||
| if($var(RoutingKey) == "") { | |||||
| $var(exchange) = "sms"; | |||||
| $var(RoutingKey) = "message.delivery." + $(sht(msg=>$ci){kz.json,Call-ID}{kz.encode}); | |||||
| } | |||||
| xlog("L_INFO", "sending delivery message for $ci\n"); | |||||
| kazoo_publish($var(exchange), $var(RoutingKey), $var(Payload)); | |||||
| $var(RK) = $avp(server_id); | |||||
| kazoo_publish($var(exchange), $var(RK), $var(Payload)); | |||||
| } | } | ||||
| route[MESSAGE_BINDINGS] | route[MESSAGE_BINDINGS] | ||||
| { | { | ||||
| $var(key) = "kamailio@MY_HOSTNAME"; | $var(key) = "kamailio@MY_HOSTNAME"; | ||||
| $var(payload) = "{ 'exchange' : 'sms' , 'type' : 'topic', 'queue' : 'MSG-QUEUE-MY_HOSTNAME', 'routing' : 'message.route." + $(var(key){kz.encode}) + ".*', 'no_ack' : 0 }"; | |||||
| $var(payload) = $_s({"name": "sms", "exchange": "im", "type": "topic", "queue": "MSG-QUEUE-MY_HOSTNAME", "routing": "sms.outbound.$(var(key){kz.encode}).*", "no_ack": false, "federate": true }); | |||||
| kazoo_subscribe("$var(payload)"); | kazoo_subscribe("$var(payload)"); | ||||
| } | } | ||||
| @ -1,45 +1,116 @@ | |||||
| ######## NAT Traversal module - signaling functions ######## | ######## NAT Traversal module - signaling functions ######## | ||||
| #!ifndef NATHELPER_LOADED | #!ifndef NATHELPER_LOADED | ||||
| loadmodule "nathelper.so" | loadmodule "nathelper.so" | ||||
| #!trydef NATHELPER_LOADED | |||||
| #!endif | #!endif | ||||
| modparam("nathelper", "received_avp", "$avp(AVP_RECV_PARAM)") | modparam("nathelper", "received_avp", "$avp(AVP_RECV_PARAM)") | ||||
| modparam("nathelper", "sipping_from", "sip:sipcheck@MY_HOSTNAME") | |||||
| modparam("nathelper", "sipping_from", "sip:registrar@MY_HOSTNAME") | |||||
| #!ifdef WEBSOCKETS_ROLE | |||||
| #!trydef KZ_NAT_DETECT 83 | |||||
| #!else | |||||
| #!trydef KZ_NAT_DETECT 19 | |||||
| #!endif | |||||
| #!trydef KZ_NAT_FIX_SDP_REQUEST 1 | |||||
| #!trydef KZ_NAT_FIX_SDP_REPLY 1 | |||||
| #!trydef KZ_NAT_SDP_TEST 8 | |||||
| #!trydef KZ_NAT_SDP_FIX 10 | |||||
| kazoo.nat_fix_sdp_request = KZ_NAT_FIX_SDP_REQUEST descr "performs request sdp replacement of private addresses" | |||||
| kazoo.nat_fix_sdp_reply = KZ_NAT_FIX_SDP_REPLY descr "performs reply sdp replacement of private addresses" | |||||
| ####### NAT Traversal Logic ######## | ####### NAT Traversal Logic ######## | ||||
| route[NAT_TEST_AND_CORRECT] | |||||
| route[NAT_SDP] | |||||
| { | |||||
| if( has_body("application/sdp")) { | |||||
| if( nat_uac_test(KZ_NAT_SDP_TEST)) { | |||||
| xlog("L_DEBUG", "$ci|log|applying sdp nat fix\n"); | |||||
| $var(ret) = fix_nated_sdp(KZ_NAT_SDP_FIX); | |||||
| xlog("L_DEBUG", "$ci|log|result of applying sdp nat fix is $var(ret)\n"); | |||||
| } else if( is_method("INVITE") && !isflagset(FLAG_INTERNALLY_SOURCED) && is_audio_on_hold()) { | |||||
| xlog("L_DEBUG", "$ci|log|applying sdp nat fix for held channel\n"); | |||||
| $var(ret) = fix_nated_sdp(KZ_NAT_SDP_FIX); | |||||
| xlog("L_DEBUG", "$ci|log|result of applying sdp nat fix for held channel is $var(ret)\n"); | |||||
| } | |||||
| } | |||||
| } | |||||
| route[NAT_DETECT] | |||||
| { | |||||
| if($sel(cfg_get.kazoo.nat_fix_sdp_request) == 1) { | |||||
| route(NAT_SDP); | |||||
| } | |||||
| if ($Rp == "5080") { | |||||
| setflag(FLAG_SKIP_NAT_CORRECTION); | |||||
| xlog("L_DEBUG", "$ci|log|skipping nat correction on PORT 5080\n"); | |||||
| } else { | |||||
| if (is_present_hf("Record-Route")) { | |||||
| $var(i) = 0; | |||||
| $var(rr_count) = $rr_count; | |||||
| while($var(i) < $var(rr_count)) { | |||||
| $var(rr_base) = $(hdr(Record-Route)[$var(i)]); | |||||
| $var(rr_idx) = 0; | |||||
| $var(rr) = $(var(rr_base){s.select,$var(rr_idx),,}); | |||||
| while($var(rr) != $null && $var(rr) != "") { | |||||
| $var(i) = $var(i) + 1; | |||||
| if (!is_myself("$(var(rr){nameaddr.uri})")) { | |||||
| setflag(FLAG_SKIP_NAT_CORRECTION); | |||||
| xlog("L_DEBUG", "$ci|log|skipping nat correction on record-route $(var(rr){nameaddr.uri})\n"); | |||||
| } | |||||
| $var(rr_idx) = $var(rr_idx) + 1; | |||||
| $var(rr) = $(var(rr_base){s.select,$var(rr_idx),,}); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| if (isflagset(FLAG_SKIP_NAT_CORRECTION)) { | |||||
| xlog("L_DEBUG", "$ci|log|skipping nat detection\n"); | |||||
| return; | |||||
| } | |||||
| force_rport(); | |||||
| if(nat_uac_test(KZ_NAT_DETECT)) { | |||||
| xlog("L_DEBUG", "$ci|log|detected nat request\n"); | |||||
| setflag(FLT_NATS); | |||||
| if (!is_method("REGISTER")) { | |||||
| if(is_first_hop()) set_contact_alias(); | |||||
| } | |||||
| } | |||||
| } | |||||
| route[NAT_MANAGE] | |||||
| { | { | ||||
| if (is_present_hf("Record-Route")) { | |||||
| $var(i) = 0; | |||||
| $var(rr_count) = $rr_count; | |||||
| while($var(i) < $var(rr_count)) { | |||||
| $var(rr_base) = $(hdr(Record-Route)[$var(i)]); | |||||
| $var(rr_idx) = 0; | |||||
| $var(rr) = $(var(rr_base){s.select,$var(rr_idx),,}); | |||||
| while($var(rr) != $null && $var(rr) != "") { | |||||
| $var(i) = $var(i) + 1; | |||||
| if (!is_myself("$(var(rr){nameaddr.uri})")) { | |||||
| setflag(FLAG_SKIP_NAT_CORRECTION); | |||||
| } | |||||
| $var(rr_idx) = $var(rr_idx) + 1; | |||||
| $var(rr) = $(var(rr_base){s.select,$var(rr_idx),,}); | |||||
| } | |||||
| } | |||||
| } else if ($Rp == "5080") { | |||||
| setflag(FLAG_SKIP_NAT_CORRECTION); | |||||
| } | |||||
| if (isflagset(FLAG_SKIP_NAT_CORRECTION)) { | |||||
| return(); | |||||
| } | |||||
| if (nat_uac_test("NAT_UAC_TEST_LEVEL")) { | |||||
| force_rport(); | |||||
| fix_nated_contact(); | |||||
| } | |||||
| if (has_body("application/sdp") && nat_uac_test("8")) { | |||||
| fix_nated_sdp("10"); | |||||
| } | |||||
| if( is_reply() && $sel(cfg_get.kazoo.nat_fix_sdp_reply) == 1) { | |||||
| route(NAT_SDP); | |||||
| } | |||||
| if ( is_request() && isflagset(FLAG_INTERNALLY_SOURCED)) { | |||||
| setbflag(FLB_NATB); | |||||
| } | |||||
| if ( is_request() && has_totag() ) { | |||||
| setbflag(FLB_NATB); | |||||
| } | |||||
| if (!(isflagset(FLT_NATS) || isbflagset(FLB_NATB))) { | |||||
| return; | |||||
| } | |||||
| if (is_reply()) { | |||||
| if(isflagset(FLT_NATS) || isbflagset(FLB_NATB)) { | |||||
| if(is_first_hop()) { | |||||
| set_contact_alias(); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | } | ||||
| # vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab | # vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab | ||||
| @ -0,0 +1,227 @@ | |||||
| #!trydef KZ_PRESENCE_REMOVE_WATCHER_ON_EXPIRED_REGISTRATION 0 | |||||
| #!trydef KZ_PRESENCE_MAX_NOTIFY_ERROR 3 | |||||
| #!trydef KZ_PRESENCE_NOTIFY_LOG_LEVEL 4 | |||||
| kazoo.presence_notify = 1 descr "enable/disable sending notify callback to omnipresence" | |||||
| kazoo.presence_notify_timeout = 5000 descr "timeout in ms waiting for notify reply" | |||||
| kazoo.presence_notify_log_body = 0 descr "logs the body sent in the notification" | |||||
| kazoo.presence_notify_log_resp_body = 0 descr "logs the body received from notification" | |||||
| kazoo.presence_notify_log_to_table = 1 descr "logs notify/reply to active_watchers_log table" | |||||
| kazoo.presence_notify_log_to_amqp = 0 descr "logs notify/reply to amqp" | |||||
| kazoo.presence_notify_record_route = 1 descr "add record route header to notify msg sent" | |||||
| kazoo.presence_notify_log_init_body = 0 descr "logs the body before its sent" | |||||
| kazoo.presence_notify_force_send_socket = 1 descr "forces the send socket to the contact" | |||||
| kazoo.presence_remove_watcher_on_expired_registration = KZ_PRESENCE_REMOVE_WATCHER_ON_EXPIRED_REGISTRATION descr "removes watcher on expired registration" | |||||
| kazoo.presence_max_notify_error = KZ_PRESENCE_MAX_NOTIFY_ERROR descr "number of consecutive fails allowed before removing the subscription" | |||||
| kazoo.presence_notify_log_level = KZ_PRESENCE_NOTIFY_LOG_LEVEL descr "loglevel for informational log messages" | |||||
| ######## Generic Hash Table container in shared memory ######## | |||||
| modparam("htable", "htable", "notify=>size=16;autoexpire=3600;updateexpire=1;initval=0") | |||||
| route[PRESENCE_LOCAL_REQ_NOTIFY] | |||||
| { | |||||
| if($rm != "NOTIFY") { | |||||
| return; | |||||
| } | |||||
| t_set_fr($sel(cfg_get.kazoo.presence_notify_timeout), $sel(cfg_get.kazoo.presence_notify_timeout)); | |||||
| xlog("L_DEBUG", "$ci|log|init preparing $subs(event) notify to $subs(watcher_username)@$subs(watcher_domain) on behalf of $subs(pres_uri) : $du\n"); | |||||
| if($sel(cfg_get.kazoo.presence_notify_log_init_body) == 1) { | |||||
| xlog("L_INFO", "$ci|log|init|body $(mb{s.escape.common}{s.replace,\','}{s.replace,$$,})\n"); | |||||
| } | |||||
| if($sel(cfg_get.kazoo.presence_notify_force_send_socket) == 1) { | |||||
| $fs = $_s($(pr{s.tolower}):$(hdr(Contact){nameaddr.uri}{uri.host}):$(hdr(Contact){nameaddr.uri}{uri.port})); | |||||
| xlog("L_DEBUG", "$ci|log|init|forcing socket to $fs, $(pr{s.tolower}):$(hdr(Contact){nameaddr.uri}{uri.host}):$(hdr(Contact){nameaddr.uri}{uri.port}) , $ct\n"); | |||||
| } | |||||
| if($sel(cfg_get.kazoo.presence_notify_record_route) == 1) { | |||||
| record_route(); | |||||
| } | |||||
| #!ifdef NAT_TRAVERSAL_ROLE | |||||
| if(!isdsturiset()) { | |||||
| handle_ruri_alias(); | |||||
| } | |||||
| #!endif | |||||
| } | |||||
| modparam("mqueue","mqueue", "name=presence_last_notity") | |||||
| modparam("rtimer", "timer", "name=notifytimer;interval=1;mode=1;") | |||||
| modparam("rtimer", "exec", "timer=notifytimer;route=PRESENCE_LOG_TIMER_ROUTE") | |||||
| modparam("rtimer", "timer", "name=pres_cleanup;interval=10;mode=1;") | |||||
| modparam("rtimer", "exec", "timer=pres_cleanup;route=PRESENCE_CLEANUP") | |||||
| modparam("rtimer", "timer", "name=pres_publisher_cleanup;interval=5;mode=1;") | |||||
| modparam("rtimer", "exec", "timer=pres_publisher_cleanup;route=PRESENCE_PUBLISHER_CLEANUP") | |||||
| event_route[presence:notify-reply] | |||||
| { | |||||
| if($sel(cfg_get.kazoo.presence_notify) != 1) | |||||
| return; | |||||
| $xavp(pres=>delete_subscription) = 0; | |||||
| ###Fix issues with nested variables in specific load orders | |||||
| $var(subs_uri) = $subs(uri); | |||||
| $var(subs_watcher_username) = $subs(watcher_username); | |||||
| $var(subs_watcher_domain) = $subs(watcher_domain); | |||||
| $var(subs_event) = $subs(event); | |||||
| $var(subs_callid) = $subs(callid); | |||||
| $var(subs_to_user) = $subs(to_user); | |||||
| $var(subs_to_domain) = $subs(to_domain); | |||||
| $var(subs_user_agent) = $(subs(user_agent){s.escape.common}{s.replace,\','}{s.replace,$$,}); | |||||
| $var(notify_reply_code) = $notify_reply($rs); | |||||
| $var(sent_msg) = $(mb{s.replace,\','}{s.replace,$$,}); | |||||
| $var(received_msg) = $(notify_reply($mb){s.replace,\','}{s.replace,$$,}); | |||||
| if($notify_reply($rs) == 200) { | |||||
| $sht(notify=>$ci) = $null; | |||||
| $sht(notify=>$ci::count) = 0; | |||||
| xlog("$(sel(cfg_get.kazoo.presence_notify_log_level){s.int})", "$ci|end|notified $subs(watcher_username)@$subs(watcher_domain) on behalf of $subs(pres_uri)\n"); | |||||
| } else if($subs(reason) == "timeout") { | |||||
| $xavp(pres=>delete_subscription) = 1; | |||||
| xlog("L_DEBUG", "$ci|end|deleting subscription $subs(pres_uri) for $subs(watcher_username)@$subs(watcher_domain) due to timeout\n"); | |||||
| } else if($notify_reply($rs) == 481 && $subs(reason) == "timeout") { | |||||
| xlog("L_DEBUG","$ci|end|sent subscription $hdr(Subscription-State)\n"); | |||||
| } else if($notify_reply($rs) == 408) { | |||||
| if($rP != "UDP") { | |||||
| $xavp(pres=>delete_subscription) = 1; | |||||
| xlog("L_ERROR", "$ci|warning|removing $rP watcher $subs(watcher_username)@$subs(watcher_domain) for $subs(pres_uri) with reply $notify_reply($rs)\n"); | |||||
| } else { | |||||
| $var(shtinc) = $shtinc(notify=>$ci::count); | |||||
| if($var(shtinc) > $sel(cfg_get.kazoo.presence_max_notify_error)) { | |||||
| $xavp(pres=>delete_subscription) = 1; | |||||
| xlog("L_WARNING", "$ci|error|removing $rP watcher $subs(watcher_username)@$subs(watcher_domain) for $subs(pres_uri) with reply $notify_reply($rs)\n"); | |||||
| } else { | |||||
| $var(level) = 6 - $var(shtinc); | |||||
| xlog("$var(level)", "$ci|error|received $notify_reply($rs) ($var(shtinc)/$sel(cfg_get.kazoo.presence_max_notify_error)) when notifying $subs(watcher_username)@$subs(watcher_domain) on behalf of $subs(pres_uri) with reply $notify_reply($rs)\n"); | |||||
| } | |||||
| } | |||||
| } else { | |||||
| $xavp(pres=>delete_subscription) = 1; | |||||
| xlog("L_WARNING", "$ci|end|deleting subscription $subs(pres_uri) as $subs(watcher_username)@$subs(watcher_domain) replied with $notify_reply($rs)\n"); | |||||
| } | |||||
| if($sel(cfg_get.kazoo.presence_notify_log_body) == 1) | |||||
| xlog("L_INFO", "$ci|log|sent|body $(mb{s.escape.common}{s.replace,\','}{s.replace,$$,})\n"); | |||||
| if($sel(cfg_get.kazoo.presence_notify_log_resp_body) == 1) | |||||
| xlog("L_INFO", "$ci|log|resp|body $(notify_reply($mb){s.escape.common}{s.replace,\','}{s.replace,$$,})\n"); | |||||
| if($sel(cfg_get.kazoo.presence_notify_log_to_amqp) == 1) { | |||||
| route(PRESENCE_NOTIFY_AMQP); | |||||
| } | |||||
| if($sel(cfg_get.kazoo.presence_notify_log_to_table) == 1) { | |||||
| if($xavp(pres=>delete_subscription) != 1 && $subs(reason) != "timeout") { | |||||
| $var(Query) = $_s(KZQ_REPLACE_WATCHERS_LOG); | |||||
| mq_add("presence_last_notity", "$subs(callid)", "$var(Query)"); | |||||
| } | |||||
| } | |||||
| } | |||||
| route[PRESENCE_LOG_TIMER_ROUTE] | |||||
| { | |||||
| $var(runloop) = 1; | |||||
| while(mq_fetch("presence_last_notity") == 1 && $var(runloop) < MAX_WHILE_LOOPS) { | |||||
| $var(ci) = $mqk(presence_last_notity); | |||||
| xlog("L_DEBUG", "Query : $mqv(presence_last_notity)\n"); | |||||
| $var(sqlres) = sql_query("cb", "$mqv(presence_last_notity)"); | |||||
| xlog("L_DEBUG", "Query result : $var(sqlres)\n"); | |||||
| if($var(sqlres) < 0) { | |||||
| xlog("L_ERROR", "$var(ci)|log|error running query : $mqv(presence_last_notity)\n"); | |||||
| } else { | |||||
| $var(nrows) = $sqlrows(cb); | |||||
| xlog("L_DEBUG", "$var(ci)|log|end UPDATED $var(nrows)\n"); | |||||
| if($var(nrows) == 0) { | |||||
| xlog("L_DEBUG", "$var(ci)|log|error no rows affected when running query\n"); | |||||
| } | |||||
| } | |||||
| $var(runloop) = $var(runloop) + 1; | |||||
| } | |||||
| } | |||||
| route[PRESENCE_NOTIFY_AMQP] | |||||
| { | |||||
| $var(amqp_payload_request) = $_s({"Event-Category" : "presence", "Event-Name" : "notify", "Event-Package" : "$subs(event)", "Timestamp" : $TS, "Call-ID" : "$subs(callid)", "From" : "$fu", "To" : "$subs(to_user)@$subs(to_domain)", "Sent" : "$(TS{s.ftime,%Y-%m-%d %H:%M:%S})", "Body" : "Hostname : MY_HOSTNAME\r\nTimestamp : $(TS{s.ftime,%Y-%m-%d %H:%M:%S})\r\n$(mb{s.escape.common}{s.replace,\','}{s.replace,$$,})\r\nResponse\r\n$(notify_reply($mb){s.escape.common}{s.replace,\','}{s.replace,$$,})","Remote-CSeq" : $subs(remote_cseq), "Local-CSeq" : $subs(local_cseq), "Sequence" : $cs, "Version" : $subs(version), "Reply" : $notify_reply($rs) }); | |||||
| $var(rk) = "notify." + $(subs(to_domain){kz.encode}) + "." + $(subs(to_user){kz.encode}); | |||||
| kazoo_publish("omnipresence", "$var(rk)", $var(amqp_payload_request)); | |||||
| xlog("L_INFO", "$ci|log|sent notify callback for event $subs(event) : $tu\n"); | |||||
| } | |||||
| route[PRESENCE_CLEANUP] | |||||
| { | |||||
| $var(Query) = $_s(KZQ_DELETE_FROM_ACTIVE_WATCHERS_WHERE_EXPIRES;); | |||||
| mq_add("presence_last_notity", "$uuid(g)", "$var(Query)"); | |||||
| $var(Query) = $_s(KZQ_DELETE_FROM_PRESENTITY_WHERE_EXPIRES;); | |||||
| mq_add("presence_last_notity", "$uuid(g)", "$var(Query)"); | |||||
| $var(Query) = $_s(KZQ_DELETE_FROM_PRESENTITY_WHERE_DIALOG_TERMINATED;); | |||||
| mq_add("presence_last_notity", "$uuid(g)", "$var(Query)"); | |||||
| $var(Query) = $_s(DELETE FROM ACTIVE_WATCHERS_LOG WHERE ID IN(select id from active_watchers_log a where not exists(select callid from active_watchers b where b.callid = a.callid and b.watcher_username = a.watcher_username and b.watcher_domain = a.watcher_domain));); | |||||
| mq_add("presence_last_notity", "$uuid(g)", "$var(Query)"); | |||||
| } | |||||
| route[PRESENCE_PUBLISHER_CLEANUP] | |||||
| { | |||||
| xlog("L_DEBUG", "processing presence publisher cleanup\n"); | |||||
| $var(sqlres) = sql_query("cb", "update tmp_probe set action = 1 where action = 0"); | |||||
| if($var(sqlres) < 0) { | |||||
| xlog("L_ERROR", "$var(ci)|log|error cleaning tmp_probe\n"); | |||||
| return; | |||||
| } else { | |||||
| $var(nrows) = $sqlrows(cb); | |||||
| if($var(nrows) > 0) { | |||||
| if (sql_xquery("cb", "select * from tmp_probe where action = 1", "cleanup_pres") == 1) | |||||
| { | |||||
| while($xavp(cleanup_pres) != $null) { | |||||
| xlog("L_DEBUG", "processing $xavp(cleanup_pres=>event) notifies for $xavp(cleanup_pres=>presentity_uri)\n"); | |||||
| pres_refresh_watchers("$xavp(cleanup_pres=>presentity_uri)", "$xavp(cleanup_pres=>event)", 1); | |||||
| pv_unset("$xavp(cleanup_pres)"); | |||||
| } | |||||
| } | |||||
| $var(sqlres) = sql_query("cb", "delete from tmp_probe where action = 1"); | |||||
| if($var(sqlres) < 0) { | |||||
| xlog("L_ERROR", "$var(ci)|log|error cleaning tmp_probe\n"); | |||||
| } else { | |||||
| $var(nrows) = $sqlrows(cb); | |||||
| if($var(nrows) > 0) { | |||||
| xlog("L_DEBUG", "presence publisher cleanup processed $var(nrows) rows\n"); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| route[PRESENCE_DEFERRED_INIT] | |||||
| { | |||||
| xlog("L_INFO", "processing presence deferred init\n"); | |||||
| $var(sqlres) = sql_query("cb", "update tmp_probe set action = 0 where action = 2"); | |||||
| if($var(sqlres) < 0) { | |||||
| xlog("L_ERROR", "$var(ci)|log|error cleaning tmp_probe\n"); | |||||
| return; | |||||
| } else { | |||||
| $var(nrows) = $sqlrows(cb); | |||||
| if($var(nrows) > 0) { | |||||
| xlog("L_NOTICE", "scheduled update for $var(nrows) watched presentities/event\n"); | |||||
| } | |||||
| } | |||||
| } | |||||
| route[PRESENCE_EXPIRED_REGISTRATION] | |||||
| { | |||||
| if($sel(cfg_get.kazoo.presence_remove_watcher_on_expired_registration) == 1) { | |||||
| $var(watcher) = $_s(sip:$ulc(exp=>aor)); | |||||
| $var(watcher_username) = $(var(watcher){uri.user}); | |||||
| $var(watcher_domain) = $(var(watcher){uri.host}); | |||||
| $var(Query) = $_s(DELETE FROM active_watchers WHERE watcher_username = "$var(watcher_username)" and watcher_domain = "$var(watcher_domain)";); | |||||
| mq_add("presence_last_notity", "$uuid(g)", "$var(Query)"); | |||||
| } | |||||
| } | |||||
| @ -1,117 +0,0 @@ | |||||
| kazoo.presence_notify = 1 descr "enable/disable sending notify callback to omnipresence" | |||||
| kazoo.presence_notify_timeout = 3000 descr "timeout in ms waiting for notify reply" | |||||
| kazoo.presence_notify_log_body = 0 descr "logs the body sent in the notification" | |||||
| kazoo.presence_notify_log_resp_body = 0 descr "logs the body received from notification" | |||||
| kazoo.presence_notify_log_to_table = 1 descr "logs notify/reply to active_watchers_log table" | |||||
| kazoo.presence_notify_log_to_amqp = 0 descr "logs notify/reply to amqp" | |||||
| kazoo.presence_notify_record_route = 1 descr "add record route header to notify msg sent" | |||||
| kazoo.presence_notify_log_init_body = 0 descr "logs the body before its sent" | |||||
| kazoo.presence_notify_force_send_socket = 0 descr "forces the send socket to the contact" | |||||
| ######## Generic Hash Table container in shared memory ######## | |||||
| modparam("htable", "htable", "notify=>size=16;autoexpire=3600;updateexpire=1;initval=0") | |||||
| #!trydef PRESENCE_NOTIFY_INIT | |||||
| #!trydef MAX_NOTIFY_ERROR 5 | |||||
| route[PRESENCE_LOCAL_NOTIFY] | |||||
| { | |||||
| if($rm != "NOTIFY") { | |||||
| return; | |||||
| } | |||||
| t_set_fr(@cfg_get.kazoo.presence_notify_timeout, @cfg_get.kazoo.presence_notify_timeout); | |||||
| xlog("L_INFO", "$ci|log|init preparing $subs(event) notify to $subs(watcher_username)@$subs(watcher_domain) on behalf of $subs(pres_uri) : $du\n"); | |||||
| if(@cfg_get.kazoo.presence_notify_log_init_body == 1) { | |||||
| xlog("L_INFO", "$ci|log|init|body $(mb{s.escape.common}{s.replace,\','}{s.replace,$$,})\n"); | |||||
| } | |||||
| if(@cfg_get.kazoo.presence_notify_force_send_socket == 1) { | |||||
| $fs = $_s($(pr{s.tolower}):$(hdr(Contact){nameaddr.uri}{uri.host}):$(hdr(Contact){nameaddr.uri}{uri.port})); | |||||
| xlog("L_INFO", "$ci|log|init|forcing socket to $fs, $(pr{s.tolower}):$(hdr(Contact){nameaddr.uri}{uri.host}):$(hdr(Contact){nameaddr.uri}{uri.port}) , $ct\n"); | |||||
| } | |||||
| if(@cfg_get.kazoo.presence_notify_record_route == 1) { | |||||
| record_route(); | |||||
| } | |||||
| } | |||||
| modparam("mqueue","mqueue", "name=presence_last_notity") | |||||
| ####### RTIMER module ########## | |||||
| #!ifndef RTIMER_LOADED | |||||
| loadmodule "rtimer.so" | |||||
| #!trydef RTIMER_LOADED | |||||
| #!endif | |||||
| modparam("rtimer", "timer", "name=notifytimer;interval=500000u;mode=2;") | |||||
| modparam("rtimer", "exec", "timer=notifytimer;route=PRESENCE_LOG_TIMER_ROUTE") | |||||
| event_route[presence:notify-reply] | |||||
| { | |||||
| if(@cfg_get.kazoo.presence_notify != 1) | |||||
| return; | |||||
| $xavp(pres=>delete_subscription) = 0; | |||||
| if($subs(reason) == "timeout") { | |||||
| $xavp(pres=>delete_subscription) = 1; | |||||
| xlog("L_INFO", "$ci|end|deleting subscribtion $subs(pres_uri) for $subs(watcher_username)@$subs(watcher_domain) due to timeout\n"); | |||||
| } else if($notify_reply($rs) == 200) { | |||||
| $sht(notify=>$ci) = $null; | |||||
| $sht(notify=>$ci::count) = 0; | |||||
| xlog("L_INFO", "$ci|end|notified $subs(watcher_username)@$subs(watcher_domain) on behalf of $subs(pres_uri)\n"); | |||||
| } else { | |||||
| xlog("L_ERROR", "$ci|error|received $notify_reply($rs) when notifying $subs(watcher_username)@$subs(watcher_domain) on behalf of $subs(pres_uri)\n"); | |||||
| if($rP != "UDP") { | |||||
| $xavp(pres=>delete_subscription) = 1; | |||||
| xlog("L_ERROR", "$ci|error|removing $rP watcher $subs(watcher_username)@$subs(watcher_domain) for $subs(pres_uri)\n"); | |||||
| } else { | |||||
| $var(shtinc) = $shtinc(notify=>$ci::count); | |||||
| if($var(shtinc) > MAX_NOTIFY_ERROR) { | |||||
| $xavp(pres=>delete_subscription) = 1; | |||||
| xlog("L_ERROR", "$ci|error|removing $rP watcher $subs(watcher_username)@$subs(watcher_domain) for $subs(pres_uri)\n"); | |||||
| } | |||||
| } | |||||
| } | |||||
| if(@cfg_get.kazoo.presence_notify_log_body == 1) | |||||
| xlog("L_INFO", "$ci|log|sent|body $(mb{s.escape.common}{s.replace,\','}{s.replace,$$,})\n"); | |||||
| if(@cfg_get.kazoo.presence_notify_log_resp_body == 1) | |||||
| xlog("L_INFO", "$ci|log|resp|body $(notify_reply($mb){s.escape.common}{s.replace,\','}{s.replace,$$,})\n"); | |||||
| if(@cfg_get.kazoo.presence_notify_log_to_amqp == 1) { | |||||
| route(PRESENCE_NOTIFY_AMQP); | |||||
| } | |||||
| if(@cfg_get.kazoo.presence_notify_log_to_table == 1) { | |||||
| $var(Query) = $_s(REPLACE INTO active_watchers_log (presentity_uri, watcher_username, watcher_domain, event, callid, to_user, to_domain, user_agent, time, result, sent_msg, received_msg) VALUES ("$subs(uri)", "$subs(watcher_username)", "$subs(watcher_domain)", "$subs(event)","$subs(callid)","$subs(to_user)","$subs(to_domain)", '$(subs(user_agent){s.escape.common}{s.replace,\',''}{s.replace,$$,})', $TS, $notify_reply($rs), '$(mb{s.escape.common}{s.replace,\',''}{s.replace,$$,})', '$(notify_reply($mb){s.escape.common}{s.replace,\',''}{s.replace,$$,})')); | |||||
| mq_add("presence_last_notity", "$subs(callid)", "$var(Query)"); | |||||
| } | |||||
| } | |||||
| route[PRESENCE_LOG_TIMER_ROUTE] | |||||
| { | |||||
| $var(runloop) = 1; | |||||
| while(mq_fetch("presence_last_notity") == 1 && $var(runloop) < MAX_WHILE_LOOPS) { | |||||
| $var(ci) = $mqk(presence_last_notity); | |||||
| xlog("L_DEBUG", "Query : $mqv(presence_last_notity)\n"); | |||||
| $var(sqlres) = sql_query("cb", "$mqv(presence_last_notity)"); | |||||
| xlog("L_DEBUG", "Query result : $var(sqlres)\n"); | |||||
| if($var(sqlres) < 0) { | |||||
| xlog("L_ERROR", "$var(ci)|log|error updating active_watchers_log\n"); | |||||
| } else { | |||||
| $var(nrows) = $sqlrows(cb); | |||||
| xlog("L_DEBUG", "$var(ci)|log|end UPDATED $var(nrows)\n"); | |||||
| if($var(nrows) == 0) { | |||||
| xlog("L_ERROR", "$var(ci)|log|error no rows affected when updating active_watchers_log\n"); | |||||
| } | |||||
| } | |||||
| $var(runloop) = $var(runloop) + 1; | |||||
| } | |||||
| } | |||||
| route[PRESENCE_NOTIFY_AMQP] | |||||
| { | |||||
| $var(amqp_payload_request) = $_s({"Event-Category" : "presence", "Event-Name" : "notify", "Event-Package" : "$subs(event)", "Timestamp" : $TS, "Call-ID" : "$subs(callid)", "From" : "$fu", "To" : "$subs(to_user)@$subs(to_domain)", "Sent" : "$(TS{s.ftime,%Y-%m-%d %H:%M:%S})", "Body" : "Hostname : MY_HOSTNAME\r\nTimestamp : $(TS{s.ftime,%Y-%m-%d %H:%M:%S})\r\n$(mb{s.escape.common}{s.replace,\','}{s.replace,$$,})\r\nResponse\r\n$(notify_reply($mb){s.escape.common}{s.replace,\','}{s.replace,$$,})","Remote-CSeq" : $subs(remote_cseq), "Local-CSeq" : $subs(local_cseq), "Sequence" : $cs, "Version" : $subs(version), "Reply" : $notify_reply($rs) }); | |||||
| $var(rk) = "notify." + $(subs(to_domain){kz.encode}) + "." + $(subs(to_user){kz.encode}); | |||||
| kazoo_publish("omnipresence", "$var(rk)", $var(amqp_payload_request)); | |||||
| xlog("L_INFO", "$ci|log|sent notify callback for event $subs(event) : $tu\n"); | |||||
| } | |||||
| @ -0,0 +1,67 @@ | |||||
| #!trydef SANITY_CHECK_USE_PORT 1 | |||||
| #!trydef SANITY_DROPS_REQUEST 1 | |||||
| #!trydef SANITY_DEFAULT_CHECK 17895 | |||||
| #!trydef SANITY_URI_CHECKS 7 | |||||
| #!trydef SANITY_TRACE_REQUEST 1 | |||||
| #!substdef "!SANITY_SUBST_CACHE_PERIOD!$def(SANITY_CACHE_PERIOD)!g" | |||||
| ######## SIP message formatting sanity checks [requires sl] ######## | |||||
| loadmodule "sanity.so" | |||||
| modparam("sanity", "default_checks", SANITY_DEFAULT_CHECK) | |||||
| modparam("sanity", "uri_checks", SANITY_URI_CHECKS) | |||||
| modparam("sanity", "autodrop", 0) | |||||
| modparam("sanity", "noreply", 1) | |||||
| modparam("debugger", "mod_level", "sanity=-3") | |||||
| kazoo.sanity_check_use_port = SANITY_CHECK_USE_PORT descr "should we keep track of ip and port for sanity failures" | |||||
| kazoo.sanity_drops_request = SANITY_DROPS_REQUEST descr "should we drop the request or send error on sanity failure" | |||||
| kazoo.sanity_trace_request = SANITY_TRACE_REQUEST descr "should we trace the request if sip trace role is enabled" | |||||
| route[SANITY_CHECK] | |||||
| { | |||||
| ## CVE-2018-14767 | |||||
| if($(hdr(To)[1]) != $null) { | |||||
| xlog("second To header not null - dropping message"); | |||||
| drop; | |||||
| } | |||||
| $var(sanity_key) = ""; | |||||
| if($sel(cfg_get.kazoo.sanity_check_use_port) == 1) { | |||||
| $var(sanity_key) = $_s("$si::$sp"); | |||||
| } else { | |||||
| $var(sanity_key) = $_s("$si"); | |||||
| } | |||||
| if (!sanity_check()) { | |||||
| #!ifdef SIP_TRACE_ROLE | |||||
| sip_trace(); | |||||
| #!endif | |||||
| if($sel(cfg_get.kazoo.sanity_drops_request) == 1) { | |||||
| xlog("L_WARN", "$ci|end|dropping insane message from $si:$sp\n"); | |||||
| drop; | |||||
| } else { | |||||
| xlog("L_WARN", "$ci|end|insane message from $si:$sp\n"); | |||||
| send_reply("400", "Bad Request"); | |||||
| exit; | |||||
| } | |||||
| } | |||||
| if (!mf_process_maxfwd_header("10")) { | |||||
| xlog("L_WARN", "$ci|end|too much hops, not enough barley from $si:$sp\n"); | |||||
| send_reply("483", "Too Many Hops"); | |||||
| exit; | |||||
| } | |||||
| if ($ua == "friendly-scanner" || | |||||
| $ua == "sundayddr" || | |||||
| $ua == "pplsip" || | |||||
| $ua =~ "NiceGuy" || | |||||
| $ua =~ "PortSIP" || | |||||
| $ua =~ "sipcli" ) { | |||||
| xlog("L_WARN", "$ci|end|dropping message with user-agent $ua from $si:$sp\n"); | |||||
| drop; | |||||
| } | |||||
| } | |||||