Version 2.1.0 — (last revised 2024/09/16 13:05:56 UTC)
Asterisk/VoIP documentation for hobbyists, switchers, collectors, and phreaks
© 2025 PhreakNet
PhreakNet Docs Change Log RSS Feed
Early on, it was determined that there existed a great need to document all of its common dialplan code, dependencies, and instructions in order to make it easier for both its operators and any newbies joining the network to find their way. This reference is a continually-growing repository of common code and resources shared across nodes that experienced node operators and newcomers alike will find helpful. This documentation consists of "sub-docs" which individually provide detailed and useful information about different components of the network and the nodes that comprise it.
This documentation is largely generic Asterisk documentation. While some aspects may be specific to specific networks, much — if not most — of the concepts are agnostic and applicable to any Asterisk system. This documentation is designed and written to be accessible to newcomers, to help newbies get up and running and familiar with their Asterisk systems. However, it is also a helpful resource for more seasoned veterans as well.
This is the most comprehensive documentation about using Asterisk for typical and atypical purposes, and this is an actively maintained and living resource. This documentation wasn't written overnight — quite the contrary, it's grown piece by piece since 2018. Community contributions are always appreciated, and if there's something you think should be documented here that isn't, let us know and we can add it.
This documentation is written by hobbyists, for hobbyists. If you notice a typo or something that's not quite right here, we'd love to fix it! If you find something missing here that you think should be present, we'd love to add it! Contributions are always welcome and are greatly appreciated. To make a contribution, please drop the editor a line at docs @ phreaknet.org (trim the spaces out please, before copying into your mail program). Alternately, post to the mailing list if you think the change warrants community discussion.
In general, you should create a new ticket on InterLinked Issues so we can keep track of any pending issues. Below are some steps for common contributions.
Please open a ticket on InterLinked Issues, the in-house issue tracker. The category should be "PhreakNet Docs".
You can either describe the update that is needed and include changes in the issue or provide a diff. In the latter case, you must create the diff on InterLinked Paste and link the paste to the issue. Make sure to set the expiration to at least a couple weeks or longer (the default is 24 hours).
phreaknet genpatch. You will need to run this for each file that needs to be updated. This is an interactive utility, so follow the instructions provided for the process. Make sure you update the version number and date in the relevant file. DO NOT include a verbose description of the fix anywhere in the config file (e.g. 2021-07-15 JS: fixed blah-blah-blah). Instead, include this in the issue tracker and it will be included in the change log. This avoids cluttering the boilerplate configs themselves with unnecessary comments. Updating an individual context or subroutine with a last updated date is okay.
First, you should test your code (a lot) and make sure no regressions or unexpected behavior are encountered. Consider adding test cases using either the test suite or unit tests. Test suite cases are more flexible but unit tests are easier and more self-contained for single modules, especially functions that are expected to produce a certain output. Make sure to build Asterisk with development mode if using PhreakScript. You must compile with developer mode since the compilation requirements for development mode are stricter and will catch errors and warnings that a normal install will not.
Second, you should try to submit your changes upstream to Asterisk or DAHDI. No, seriously, we're not joking. If we think your change is likely to be accepted by Sangoma, we will reject it, unless you have tried and Sangoma has rejected it. As many changes should be submitted upstream to Sangoma as feasibly possible.
For the time being, DAHDI contributions may be done directly since the DAHDI project is not actively being maintained.
app_foobar: Add bar to the foobar. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. PHREAKSCRIPT-123 #close Resolves: #45
This documentation is dedicated to the late Brian Clancy, who sadly passed away of terminal illnesses on 2020/02/13. Without Brian, not only would this documentation not exist, this network would not exist. Brian was a good friend to all and a kind and patient mentor from the beginning. Brian lives on as the voice of the network, reachable on network operator numbers, Coin Zone calls, TIME (231-2301), and as a conversation partner (549-3344). But his most important impact has been his influence on the countless individuals whom he has left behind. He will be forever remembered for his persistence, work ethic, and strong-spirited determination. Thank you, Brian, for all you have done!
To operate your own node, you will need a server running Asterisk, a powerful but free VoIP/TDM/analog PBX/CO switch software solution. You don't need a powerful system to run Asterisk — many node operators use servers with 1GB of RAM or less — even 512MB will be sufficient. uLaw (pronounced mu-law or, frequently but erroneously, u-law), is the preferred codec in the United States for VoIP, as it is 64kbps, or PSTN quality. Consequently, you will also need an Internet connection (but you knew that already, didn't you?). Although you can operate a node even with a very low-speed Internet connection, it is undesirable to have a connection speed of under 512kbps. A T1 (1.544Mbps) will be sufficient, and any package of broadband Internet will be more than enough bandwidth for several VoIP calls.
Some Asterisk servers are hosted servers, meaning they are not physically located at the premises of their owners. Hosted servers can be a great option for those just getting started or those without decent Internet connections or the space and resources to operate an on-premises Asterisk server. If you go this route, do understand its limitations. First, we can't stress enough how important it is to choose a reputable host. We once used a HiFormance host on a plan that was (wait for it!) $10/year. Of course, you know what they say: if it sounds too good to be true, it probably is. In mid-December 2018, without warning, HiFormance servers stopped working without warning — owners were unable to SSH into the servers and the services on them went down. With some effort, it was discovered that HiFormance was closing its doors. Ironically, a post on the website informed its customers that HiFormance would be closing its doors and that data should be backed up, yet, HiFormance never emailed its customers and most people discovered this only after their servers stopped working. Two years later, in November 2020, our VPSCheap server stopped working for a few days due to "complications" that arose during a cluster migration. A week later, the server came back up, but it was a brand new server — all the data was gone. Bad VPS hosts are unfortunately quite common, and it may be worth paying a couple bucks more for a more stable and reliable solution.
From our experiences with multiple VPS providers, we've seen some of the things that work and don't work well. We recommend using Digital Ocean's $4 per month Droplet, which is very affordable and reliable. You can sign up using our referral link if you aren't already a member, and we'll both get some free credit (after you verify your account, you'll get $100 to spend on "Droplets", which are VPSes). Thanks for helping to keep our costs low, so we can work on more cool projects for you!
Note: If you do use Digital Ocean, you should add a reliable DNS resolver, as by default, they provide their own. An issue observed with these is they intermittently fail to resolve ddns.us (and possibly other) hostnames. This can be fixed by editing /etc/systemd/resolved.conf.d/DigitalOcean.conf and adding another resolver, like 1.1.1.1, to the end of the resolver list. This will provide an alternate that doesn't have this issue. Then run systemctl restart systemd-resolved, and you should be able to resolve these hostnames and call these numbers.
Operating your Asterisk server locally is also an option. Almost any old computer from this millennium will suffice, but your options are really quite flexible. Asterisk can run seamlessly on a Raspberry Pi, which is a compact, low-energy solution that works well for many node operators. While you may run into roadblocks with connecting channel banks and other equipment to a Pi, for those with just ATAs (analog telephone adapters), a Pi should be more than sufficient. Many Asterisk nodes are operated using Raspberry Pis.
If you want the premium analog experience, an ATA is not sufficient, you'll want something that can interoperate with the DAHDI channel driver in Asterisk (DAHDI consists of the drivers for telephony cards, and Asterisk uses these to control them). There are a few off-brand cards, but the majority of cards fall into two categories: Digium or Sangoma cards. Digium cards are those originally manufactured by Digium, and Sangoma cards are those originally manufactured by Sangoma, prior to Sangoma's acquisition of Digium. UNDER NO CIRCUMSTANCES WHATSOEVER SHOULD YOU PURCHASE OR OBTAIN A SANGOMA CARD. These are known to be very buggy and defective, due to underlying timing bugs in the wanpipe software which Sangoma cards require (but Digium cards do not). For example, dial pulsing will not work at all on T1 CAS channels using a Sangoma card. Digium cards do not have any of these issues and should work without any problems.
Both of these cards can be found readily on the used market. However, even if you have to pay a bit more for one, a Digium card is a much better investment. If you have PCI slots in your machine (as opposed to PCIe), you can find some very cheap Digium cards on the used market as well.
Asterisk is a free open-source VoIP telephony toolkit that has "taken the telecom industry by storm". It is widely used in the telephony community, by professionals and hobbyists alike, and is a requirement for operating a node, no matter what hardware is being used.
To start with, you'll need a flavor of Linux (also free and open-source) in order to run Asterisk. We recommend Debian, which works well on a variety of platforms. Any Linux commands featured in this documentation will assume an instance of Debian, but if you use a different flavor of Linux, you can consult your operating system's documentation for the proper commands and syntax. In many cases, minor variations in syntax and keywords will be the key distinguishment.
As for Asterisk itself, we recommend using the latest LTS release, Asterisk 18. Unlike other software packages, Asterisk has a large number of versions circulating, a great number of which are currently in use. Systems running Asterisk 1.0 and 1.2, for instance, are plentiful on C*NET. For our purposes, we've not needed any legacy functionality found in these versions that the newer versions lack; however, if you choose to install the Project MF patches on your system, an older version may be required. However, due to the latest PhreakNet patches, most of this functionality is now available in modern Asterisk.
A quick note before we start here. This documentation goes into a fair amount of detail on some things, but it's simply impossible to cover everything comprehensively. There are two good ways to explore further and learn about the various things you can do with Asterisk and how to use them:
A frequently asked question is how one builds Asterisk expertise. It really is a skill that takes experience to come — that is a lot of doing it. One can spend years trying to master Asterisk and not come close to doing or even learning everything possible, so don't be overwhelmed by not understanding how everything fits together. You will always be finding better ways to do certain things, and often there is more than one way to skin a cat. So, instead, choose to focus on specific objectives and outcomes and then look at the documentation for the relevant resources (e.g. application, function, module, config file, etc.). This kind of curious and progressive learning will go a long way.
If you're trying to do something, chances are somebody else has or might want to as well. Asking questions on the list facilitates the proliferation of knowledge and sharing of techniques, examples, etc. and is encouraged. Don't be shy!
Most of this documentation assumes you are using Debian (if you're using a different Linux distro, you might need to use yum instead of apt for instance, and some of the package names may also be different). It also assumes you're using a headless/non-GUI installation. If you have a GUI, you'll probably want to get rid of it. You'll also want to make sure SSH is enabled so you can remotely manage your system. If you're using a VPS, this part is kind of done for you, but here is the general process, starting with using passwd root to set a strong password for the 'root' account. Some VPS hosts allow you to reset this if needed, but you shouldn't forget this. 'root' is equivalent to the built-in 'Administrator' account on Windows.
Helpful link: How to Install and Set Up Headless Linux
You may also wish to use SSH keys instead of a password login. Most SFTP clients, like FileZilla, also support this. If you're using Windows, you should use KiTTY instead of PuTTY. KiTTY is basically "PuTTY on steroids", and allows you to, among things that PuTTY cannot do, store passwords for saved sessions so that you don't need to enter them manually each time. You don't have to use KiTTY, but you should use an SSH client that has this feature. This gives you no excuse not to use a long and secure password (and length is paramount, not complexity!).
Now, run nano /etc/ssh/sshd_config.
Hit CTRL+W to search for PermitRootLogin. It probably won't be found, but we just want to make sure. If it is found, change no to yes. If it isn't found, go to the end of the file and add PermitRootLogin yes on a new line. Then use CTRL+X, y, ENTER to save changes and exit.
Finally, many commands that need to be run throughout the Docs need to be performed as root. If something isn't working, make sure that you either a) logged in as root, b) su to root or c) use sudo to run with root privileges. For general system monitoring and accessing the Asterisk CLI, the root account is not needed, depending on how you configure Asterisk.
If you are using FreeBSD, you will need to run the following in the root account to allow su'ing into the root account from a non-root account: pw usermod USERNAME -G wheel.
There are several different ways to use Asterisk. Packages like FreePBX exist that offer a GUI (graphical user interface) for configuration, which runs on Asterisk behind the scenes. You can, of course, use "just Asterisk", which is commonly referred to as "vanilla Asterisk", and this is by far the best option and is highly recommended. While GUI-based options like FreePBX may make it easier to get started initially, they are not worth it in the long-run, as you will find yourself restricted in terms of what you can configure, as much of the customizability and flexibility of Asterisk disappears when you use a GUI like FreePBX. The rest of this documentation will assume you are using vanilla Asterisk as it is the only way to truly realize the full power of Asterisk. However, other systems are used not infrequently in the greater hobbyist community so there may be others who have done something you are trying to do.
The automated install uses the PhreakScript utility to automatically install Asterisk (and optionally, DAHDI) on your server, completely automated. It is recommended for new installations. Method B (below) also explains step by step each part of the install process. The PhreakScript utility simply does all this for you, if you want to get up and running quickly.
Please report feedback, bugs, and comments on the PhreakNet mailing list!
PhreakScript must be run as root. However, Asterisk can be installed as a different user using the -u or --user flag.
Here's how to get and use PhreakScript, assuming you have cd'd into the directory where you want to install it (e.g. /etc/asterisk/scripts or /usr/local/bin. Simply run the following command sequences:
cd /usr/local/src; wget https://docs.phreaknet.org/script/phreaknet.sh; chmod +x phreaknet.sh; ./phreaknet.sh make
Here, we provide a few options to PhreakScript, telling it to also install DAHDI, patch back in some of the older drives that were removed, and set Asterisk up to run as the user "asterisk" (which will automatically be created for us if needed). For a full list of options, run phreaknet help before starting.
phreaknet update; phreaknet install --dahdi --drivers --user=asterisk;
Grab the revertive pulsing sounds, the Pat Fleet audio library, as well as the boilerplate PhreakNet audio files (e.g. dial tone, busy tone, etc.):
phreaknet pulsar; phreaknet sounds --boilerplate
phreaknet config --api-key=YOURAPIKEY --clli=YOURCLLI --disa=YOUR7DIGITDISANUMBER
You should run the command below after you've added a switch in the user portal.
phreaknet keygen --rotate
PhreakScript will automatically install all dependencies and install Asterisk. To install boilerplate code, run phreaknet config. For full usage, run phreaknet help.
Once installation has completed, don't forget to replace all the sample 5551XXX numbers with your office code.
While there are many ways to install Asterisk on your system, the best and most reliable way to install Asterisk is by compiling from source. On one occasion, we installed Asterisk from its binaries in the default Debian repository with the result that all of our existing dialplan code didn't work, and other strange issues were encountered as well: differing directory structures, improper reloading of modules, etc. Never, NEVER, ever install Asterisk from a package. "Always from source" is really the only way to go, and will save you a lot of hassle and frustration down the line. Installing from source is easy, and we lay out the process step by step in this section.
If you are not comfortable going through the procedures to install from source, or even if you are, we recommend you use Method A: Install automatically using PhreakScript. Not only will PhreakScript do everything for you, but it also adds in many bug fixes that you'll need which are not present upstream, as well as many additional new features and improvements over a base vanilla Asterisk install.
For this reason, following the instructions to install manually below is considered deprecated and provided for informational purposes only.
This section should be completed using the root user, even if you do not plan to run Asterisk as root. If you are not running as root, use sudo.
First, before doing anything, make sure the timezone on your server is set properly. By default, it will probably be UTC (Universal Coordinated Time, a.k.a. Greenwich Mean Time). If you live in North America, this may be of little use to you. You will want the time to be set to your local time so that in the console and in the logs, the times accurately reflect your experience. Even if you don't care, you should still change the time to your local timezone (and if you have a hosted server, you should change it to your timezone, not that of the locality in which the server is hosted). Your server's time is used for various things, including the "mock billing system", which depends on accurate timekeeping by each node (more on this in the "Billing" section).
For those on Debian 10/11, our OS of choice for running Asterisk, here is how to change the time.
At the shell prompt, type timedatectl list-timezones
Make note of the name that corresponds to your region. Now, change the timezone by typing a command like this one:
timedatectl set-timezone US/Central
The above would set your timezone to Central Time. Similarly, America/Chicago would also work.
Ensure NTP is enabled and running:
timedatectl set-ntp on timedatectl set-ntp true timedatectl status
Now, verify the time is correct by executing timedatectl alone. Asterisk, MySQL, and any other services that use the system time will need to be restarted to pick it up. You may wish to simply restart the server.
Make sure your system is up to date (apt-get update and then apt-get upgrade).
If you get a cryptic error about CD-ROMs when you try using the package manager, open /etc/apt/sources.list and comment out the cdrom line. This is intended to allow you to install packages from disc, but you likely want to pull them from the Internet instead.
After this, there are a few packages you will want or need that are easy to install!
The following packages are not Asterisk-related and are not mandatory, but are a valuable asset to anyone operating a Linux-based server. Generally, you can install a package from the default Debian repository by typing sudo apt-get install name where name is what you are trying to install. Here are a few must-haves for any server exposed to the Internet:
apt-get install ntp -y
apt-get install iptables -y
apt-get install tcpdump -y (to use just run tcpdump port 5060, or whatever your SIP port is)
apt-get install -y sudo
Once you have iptables installed, run the following command from the shell command-line:
iptables -A INPUT -p udp -m udp --dport 5060 -m string --string "User-Agent: friendly-scanner" --algo bm --icase --to 65535 -j REJECT
It has been reported that 79% of honeypot traffic gets blocked by this one rule!
Note that iptables rules do not persist across reboot; you could use one of the various methods of persisting your iptables rules, or just run the above as a @reboot cron job. If you are not running SIP on the default ports and don't have it open in your firewall, you can also skip the above step.
Here are some other Linux tools may want on your Asterisk server. They are not required for basic Asterisk functionality but you may find some of them helpful for certain things. Here's how you would install them from the Debian command line:
apt-get install -y wget
apt-get install -y curl
apt-get install -y sox
sudo apt-get install -y libcurl4-openssl-dev
apt-get install -y mpg123
apt-get install -y dnsutils
apt-get install -y php
apt-get install -y festival
apt-get install -y bc
apt-get install -y apache2
a2enmod ssl
a2enmod rewrite
a2enmod proxy_http
a2enmod proxy_connect
systemctl restart apache2
If you need a free SSL certificate, you can use Let's Encrypt to get one. The below instructions show how you can use certbot to get a free certificate. This requires installing snap. If you would prefer not to, you can also use acme.sh.
apt install snapd snap install core snap install hello-world hello-world snap install --classic certbot ln -s /snap/bin/certbot /usr/bin/certbot certbot certonly --apache certbot renew --dry-run
Newer versions of Asterisk may have some issues, but here is one list of pre-reqs for Asterisk 18, courtesy S. Y.:
# Install dependencies apt -y install linux-headers-`uname -r` \ build-essential \ binutils-dev \ git \ bison \ flex \ default-libmysqlclient-dev \ freetds-dev \ libbluetooth-dev \ libcodec2-dev \ libcurl4-openssl-dev \ libedit-dev \ libfftw3-dev \ libghc-postgresql-simple-dev \ libgmime-3.0-dev \ libical-dev \ libjansson-dev \ libneon27-dev \ libosptk-dev \ libnewt-dev \ libradcli-dev \ librust-backtrace-dev \ libsndfile1-dev \ libspandsp-dev \ libspeexdsp-dev \ libsqlite0-dev \ libsqlite3-dev \ libssl-dev \ libunbound-dev \ libvorbis-dev \ libxml2-dev \ unixodbc-dev \ uuid-dev \ xmlstarlet \ libiksemel-dev \ libtolua-dev \ libsrtp2-dev \ libldap2-dev \ libsnmp-dev \ libpopt-dev
DAHDI is maintained by the same company that maintains Asterisk and is what bridges Asterisk to analog telephony (e.g. channel banks, etc.). Unlike Asterisk, which runs at the user level, DAHDI runs at the kernel level. DAHDI was once called Zaptel, and though there have been some changes, it's basically the same thing, just evolved a bit. Asterisk relies on DAHDI for the lower-level functions needed to work with analog equipment.
If possible, you should probably install DAHDI before Asterisk.
You will need to install DAHDI if you:
You do not need to install DAHDI if:
It probably doesn't hurt to install DAHDI even if you don't need it, but if you're sure you won't need it, you can safely skip this step. Asterisk itself doesn't depend on DAHDI, except for DAHDI-specific channel technologies and the MeetMe application.
Generally, in order to be useful, you need a real server physically located near you to be able to take advantage of DAHDI for its TDM features (besides MeetMe, which is deprecated as of 19 anyways and will be removed in the near future). However, you can still compile DAHDI on any server, which can be useful for development and basic testing.
dahdi-linux is what contains the actual drivers needed.
apt-get dist-upgrade apt-get install linux-headers-`uname -r` cd /usr/src wget http://downloads.asterisk.org/pub/telephony/dahdi-linux/dahdi-linux-current.tar.gz wget http://downloads.asterisk.org/pub/telephony/dahdi-tools/dahdi-tools-current.tar.gz tar -zxvf dahdi-linux-current.tar.gz tar -zxvf dahdi-tools-current.tar.gz cd /usr/src/dahdi-linux-3.4.0 # if running make results in an error about pci-aspm.h not existing: nano include/dahdi/kernel.h #undef CONFIG_PCImake
WARNING: DO NOT INSTALL ASTERISK WITHOUT INSTALLING ALL THE PRE-REQS! Otherwise, you will probably find later that you are missing something that requires you to recompile and reinstall Asterisk after installing that pre-req. Do it right the first time! If you are not comfortable or sure of how to do this, you should use PhreakScript instead as it automatically handles all dependencies.
We now recommend the latest LTS version of vanilla Asterisk, which is currently Asterisk 20.
Here are instructions for Debian 12 and the latest version of Asterisk 20 (21.4.3 as of this writing, but almost certainly something else by the time you read this, so adjust appropriately), boiled down to just the commands:
rm -rf /usr/lib/asterisk/modules # optional - if upgrading Asterisk, wipe out all the modules in advance of the upgrade, to remove old modules that aren't in the new versions cd /usr/src wget https://downloads.asterisk.org/pub/telephony/asterisk/asterisk-18-current.tar.gz tar -zxvf asterisk-20-current.tar.gz cd asterisk-21.4.3 ./contrib/scripts/install_prereq install
Change country code from 61 to 1 (or your country code, if you're not in the NANPA) if/when prompted.
./contrib/scripts/get_mp3_source.sh ./configure --with-jansson-bundled cp contrib/scripts/voicemailpwcheck.py /usr/local/bin chmod +x /usr/local/bin/voicemailpwcheck.py
If you need to support older ATAs, run the following two lines — otherwise, TLS will not work with older ATAs (such as the Grandstream HT7xx series), and encryption won't be possible. TLS 1.0 isn't great, but it's better than nothing. If you only have recent/modern ATAs, or you're not using ATAs/SIP clients, you can probably skip this step:
sed -i 's/TLSv1.2/TLSv1.0/g' /etc/ssl/openssl.cnf sed -i 's/DEFAULT@SECLEVEL=2/DEFAULT@SECLEVEL=1/g' /etc/ssl/openssl.cnf
If you do make the changes above, it would not be a bad idea to reboot at this point.
Now, to begin the actual Asterisk compilation process:
make menuselect
Check the following unchecked boxes by using the arrow keys to navigate and pressing ENTER:
Save & Exit.
make # compile Asterisk. This is the longest step, if you are installing for the first time. make samples # do not run this on upgrades or it will wipe out your config! make install # actually install modules make config # install init script make install-logrotate # auto compress and rotate log files
For a fresh install, make will take a while. It could take anywhere from 30 minutes, if you are using a decent VPS, to 3 hours, if you are using a Raspberry Pi.
If you see errors from make samples about not being able to create phoneprov files, you can ignore that.
If you freshly installed Asterisk, open modules.conf for editing (e.g. nano /etc/asterisk/modules.conf) and look for this:
noload => chan_sip.so
If this line is present and you want to continue using the older SIP channel driver as opposed to the newer PJSIP channel driver, replace chan_sip.so with chan_pjsip.so. However, you should use PJSIP instead of SIP if you are starting out, and eventually SIP will be removed for those currently using it should make plans to migrate. But, if you're not ready to make the switch yet, you'll need to do this so SIP will continue working for you.
Although Asterisk runs as root by default, that isn't generally recommended or necessary. Granular use of the sudoers.d directory will allow you to do operations that require root privileges from within the dialplan.
apt-get install sudo adduser -c "Asterisk" asterisk passwd asterisk
Assuming you used Certbot to set up Let's Encrypt certificates, you'll also want to ensure Asterisk has read access to them:
# Asterisk needs read access to certs for TLS: # Allow group to open relevant folders chmod -R 740 /etc/letsencrypt/live/ chmod -R 740 /etc/letsencrypt/archive/ # Make the relevant letsencrypt folders owned by said group. chgrp -R asterisk /etc/letsencrypt/live chgrp -R asterisk /etc/letsencrypt/archive chown -R asterisk /etc/asterisk/ /usr/lib/asterisk /var/spool/asterisk/ /var/lib/asterisk/ /var/run/asterisk/ /var/log/asterisk /usr/sbin/asterisk
Edit /usr/sbin/safe_asterisk to specify the user as which to run around line 78, like this:
# # Don't fork when running "safely" # ASTARGS="-U asterisk"
Now, edit /etc/default/asterisk and uncomment these:
AST_USER="asterisk" AST_GROUP="asterisk"
Now, if you do need to perform root operations with Asterisk (such as manipulating iptables), create /etc/sudoers.d/iptables and add this to it:
asterisk ALL=(ALL:ALL) NOPASSWD:/usr/sbin/iptables
Now, you could, say, block an IP address from within the dialplan, without needing to provide a password. Simply prefix sudo to the relevant command. At the same time, you can sleep a little surer at night, knowing that Asterisk has limited access to your system.
WARNING: You should not do this if you are trying to install Asterisk. This is provided for informational purposes only, if you need to install an older version of Asterisk for debugging or testing purposes. Otherwise, there is absolutely no reason you should do this!
If you are trying to install an older (obsolete) version of Asterisk (particular older than 13), you probably won't be able to on recent versions of Debian. Here is an example of an install script for Asterisk 12 and Debian 8.11 that installs a minimal running Asterisk system (not really useful for much):
#!/bin/sh # WARNING: Do not use this to install modern versions of Asterisk. Use PhreakScript instead. # This is provided only for reference only for installing obsolete versions of Asterisk on obsolete versions of Debian. # Super Simple Asterisk Installer # (C) PhreakNet 2022 https://phreaknet.org # Install Asterisk 12 on Debian 8.11 RELEASE=asterisk-12.0.0 # nano /etc/apt/sources.list # deb https://archive.debian.org/debian/ jessie contrib main non-free apt-get update wget https://downloads.asterisk.org/pub/telephony/asterisk/old-releases/$RELEASE.tar.gz tar -zxvf $RELEASE.tar.gz cd $RELEASE apt-get install aptitude -y --force-yes apt-get install build-essentials -y --force-yes apt-get install libncurses-dev -y --force-yes apt-get install uuid-dev -y --force-yes ./contrib/scripts/install_prereq install ./configure make menuselect.makeopts # Disable everything menuselect/menuselect --disable-category MENUSELECT_ADDONS --disable-category MENUSELECT_APPS --disable-category MENUSELECT_CDR --disable-category MENUSELECT_CEL --disable-category MENUSELECT_CHANNELS --disable-category MENUSELECT_CODECS --disable-category MENUSELECT_FORMATS --disable-category MENUSELECT_FUNCS --disable-category MENUSELECT_PBX --disable-category MENUSELECT_RES --disable-category MENUSELECT_TESTS --disable-category MENUSELECT_CFLAGS --disable-category MENUSELECT_OPTS_app_voicemail --disable-category MENUSELECT_UTILS --disable-category MENUSELECT_AGIS --disable-category MENUSELECT_EMBED --disable-category MENUSELECT_CORE_SOUNDS --disable-category MENUSELECT_MOH --disable-category MENUSELECT_EXTRA_SOUNDS menuselect.makeopts # Enable the bare essentials menuselect/menuselect --enable LOADABLE_MODULES menuselect.makeopts menuselect/menuselect --enable app_chanspy --enable app_confbridge --enable app_dial --enable app_dumpchan --enable app_originate --enable app_mixmonitor --enable app_playback --enable app_playtones --enable app_read --enable app_senddtmf --enable app_stack --enable app_verbose --enable app_adsiprog --enable app_getcpeid menuselect.makeopts menuselect/menuselect --enable chan_bridge_media --enable chan_iax2 --enable chan_sip menuselect.makeopts menuselect/menuselect --enable chan_a_mu --enable codec_ulaw menuselect.makeopts menuselect/menuselect --enable format_wav --enable format_pcm menuselect.makeopts menuselect/menuselect --enable func_callerid --enable func_curl --enable func_global --enable func_groupcount --enable func_module --enable func_volume menuselect.makeopts menuselect/menuselect --enable pbx_config --enable pbx_spool menuselect.makeopts menuselect/menuselect --enable res_adsi --enable res_convert --enable res_crypto --enable res_curl menuselect.makeopts menuselect/menuselect --enable EXTRA-SOUNDS-EN-ULAW menuselect.makeopts make -j2 make install if [ ! -d /etc/asterisk ]; then make samples fi
If you're not already a PhreakNet community member, you'll need to follow the Getting Started guide to get set up.
Self-service reservation of office codes can be done through the PhreakNet portal. If you need assistance or have questions, you can post to the list or call the Business Office at 811.
Below, we'll break down the components of the registration process:
If you don't have a static IP address, you can use a DDNS (dynamic DNS) service to automatically have an A record updated whenever your IP address changes. PhreakNet doesn't offer any DDNS services, but our friends over at C*NET do. You'll get your own .ckts subdomain that you can then use for your C*NET, PhreakNet, and other routings.
Other important attributes that are defined for an IAX2 user:
In most cases, calls are peer to peer with all routing info contained in the dial string. A username, host, and password may be specified here.
If you have an existing dialplan, it should be fairly easy to get set up, though some caveats should be noted.
If you are getting started with PhreakNet and are already an NPSTN member, the following should be noted:
The sections "Initial Configuration" and "Common Contexts" contain individual contexts in a well-documented manner for those thirsty for the details. However, for your convenience, if you'd like to get up and running with little attention to the details, you can simply use our boilerplate code. Below, you'll find an essential copy of each of the vital Asterisk configuration files you'll need to get started. You will need to adjust some things, such as properly setting certain variables and defining numbers, and so forth, but the code is otherwise as plug and play as possible. Helpful comments are included to help beginners get started, learning, and up and running quickly — no need to fear Asterisk!
If you are getting started for the first time, backup the files below on your system. Then, replace them with the ones below and go through each file, customizing to the extent required as directed.
If you already have an Asterisk system, you'll want to review the contents of these files and merge their contents into your system, since everything you need to get started is included there.
verbose and timestamps. verbose should be at least 3, and timestamps should be yes.extensions.conf — put this in /etc/asterisk/dialplanapp_verify module. See verification for more details.extensions.conf — put this in /etc/asterisk/dialplanextensions.conf — put this in /etc/asterisk/dialplanA command like this can be used to download a file and replace an existing one:
wget https://raw.githubusercontent.com/InterLinked1/phreaknet-boilerplate/master/dialplan/verification.conf -O verification.conf -O /etc/asterisk/dialplan/verification.conf --no-cache
First, be sure to grab the Pat Fleet sound library for Asterisk, to replace the default Allison Smith prompts to the extent possible. Trust us — this is a major upgrade.
You will probably want at least a few audio files to get started — the basic call progress tones and intercepts. We encourage all node owners to add variety to the network by giving their nodes their own unique soundscapes. However, if you want to get up and running immediately, we've assembled a set of the basic audio files you will need. Download these files and place them in /var/lib/asterisk/sounds/en/custom/signal/, unless otherwise stated:
/var/lib/asterisk/moh/ringback/These files are provided for convenience, but if everyone uses them, the network's going to sound pretty stagnant, so please consider finding your own unique audio sources. There are a few available at Telephone World, This Is A Recording (for intercepts). You can also scour Evan Doorbell recordings for something more your style if you're looking for something particular. For example, if you decide your switch is going to be a simulated "Number 5 Crossbar" switch, then you should look for #5XB sounds you can use (you can use Audacity to prepare the audio and export it as a WAV file to then convert with SoX).
Note that the above is not your one-stop shop for getting started! Be sure you have completed everything outlined in the "Pre-Requisites" section above.
The boilerplate code above is only a starting point. Many of the contexts individually laid out in this documentation, like the simulated signaling subroutines (e.g. MFer, SFer, dial pulser) are not included in the boilerplate configuration files above. Only the basics that every node really needs to fully participate in the network are included in the boilerplate code. Beyond the contents of the files above, you may wish to further add to your system using other contexts outlined in this documentation.
A word about authentication and encryption:
By default, VoIP, even using IAX2, is not encrypted. Encryption is easy, and it's now included in the boilerplate iax.conf. No other changes are necessary and there are not compatability issues. Some will argue that MD5 is not very robust, but it's better than nothing.
A few notes about IAX2 encryption that are not obvious from looking at the official Asterisk IAX2 or encryption documentation:
Accepting UNAUTHENTICATED call... when a call comes in. It must say Accepting AUTHENTICATED call...
RSA is more secure than MD5. However, due to technical limitations and backward-compatability attempts, RSA is only supplementary to non-encrypted or MD5-encrypted "primary" IAX2 users. When supported by both nodes involved in a call, a standardized RSA process will allow for a more securely encrypted call.
RSA encryption has been a stagnant addition to Asterisk for a long time. The key thing to note is that RSA encryption never existed originally in IAX2. RSA authentication predates encryption in IAX2. Encryption was later added, but for plain text and MD5 only (our testing never got to the plain text encryption to work, but that's deprecated now and there's no good reason to ever use plain text). But yes, you read that right. The weak authentication methods got encryption, and the strong one didn't. How much sense does that make? Not?
As early as 2012, people have complained about RSA encryption not working. Digium actually fixed the issue, more or less, in 2014, but the patch was never incorporated into Asterisk. Finally in 2021, after we decided to revisit RSA encryption in Asterisk, we decided to add it to Asterisk ourselves.
There are a few things to know about RSA encryption that you won't find in the IAX2 documentation, so we're providing them here, straight from the horse's mouth.
First off, res_crypto, the cryptography module Asterisk uses, only supports 1024-bit RSA keys. 2048-bit and 4096-bit keys are not supported. The reason for this is that the only code using res_crypto is the IAX2 channel driver and DUNDI, in Asterisk. Though IAX2 remains popular in some communities today, it never really took in the mainstream VoIP world and is basically dead to its developers, and DUNDI never really took off at all, so it's deader than dead. As you can imagine, there's no incentive for Digium/Sangoma to improve res_crypto by adding support for 2048-bit or 4096-bit keys. If it does get added, it will be by the community (read: this is an open invitation to roll up your sleeves if you'd like to make that happen!)
Secondly, Asterisk needs to know the passphrase to your private key, but it requires this be typed in interactively. Fortunately, 1024-bit keys don't require a passphrase, so it's probably best to not have one at all. The instructions below will show you how to generate a private key that doesn't have a passphrase, which eliminates the need for administrator intervention in loading the keys.
Next, some basic syntax. The Dial() application lets you specify a secret, like this:
Dial(IAX2/iaxuser:iaxpassword@iaxhost.example.com/5551212)
What you may not have known is that Dial() also lets you specify a private key (or outfile), to use, for the purpose of RSA-authenticated calls:
Dial(IAX2/iaxuser:[privatekeyname]@iaxhost.example.com/5551212)
Here, [privatekeyname] is the name of a private key in /var/lib/asterisk/keys/, without the folder path and without the .key file extension. Just the filename.
Also, notice we said this is how you can make an RSA-authenticated call. Not an RSA-encrypted call. Since the beginning, RSA authentication has not allowed encryption, so this was perfectly sufficient. However, RSA patched to support encryption requires a secret. Well, here is the problem with Dial(). You can't pass both a secret (which was intended for plain text and MD5, only, initially) and a key file name (which was and still is for RSA authentication only). So, you can use RSA authentication without encryption by specifying all the gory details in the Dial() command, but not if you want to use RSA authentication with encryption. Instead, you will need a separate iax.conf peer endpoint for your destination, add all the details there, and then reference that peer in the Dial command, e.g.:
iax.conf:
[myrsaendpoint] type=peer host=iaxhost.example.com username=iaxuser auth=rsa forceencryption=yes outkey=privatekeyname secret=iaxpassword
(The above is an example — DO NOT put that in your config).
A quick clarification here. A peer is for an outgoing call. A user is for an incoming call. A friend is for both. (This is for IAX2 only.)
RSA encryption is supported for any nodes that use MD5 encryption for their primary network IAX2 user.
If you are not running Asterisk as root, it goes without saying that keys will need to be readable to the user as which it is running.
Finally, do not use openssl to generate the keys. That is, do not do this:
cd /var/lib/asterisk/keys/ openssl genrsa -des3 -out phreaknetrsa.key -passout pass:SOMESECRETPASSWORDHERE 2048 openssl rsa -in phreaknetrsa.key -pubout -passin pass:SOMESECRETPASSWORDHERE -out phreaknetrsa.pub
For one, that's a 2048-bit key so it won't work anyways. And mercy help you if you add a secret. Instead, use the astgenkey tool provided with Asterisk to generate your keys. It's super easy to run:
cd /var/lib/asterisk/keys/ astgenkey -q -n phreaknetrsa cat phreaknetrsa.pub # upload your public key at https://portal.phreaknet.org/rsa touch /etc/asterisk/iax-phreaknet-rsa-in.conf touch /etc/asterisk/iax-phreaknet-rsa-out.conf
If you are running Asterisk as not root, make the user as which Asterisk runs own the private key and the new files:
chown asterisk phreaknetrsa.key chown asterisk /etc/asterisk/iax.conf chown asterisk /etc/asterisk/iax-phreaknet*
Now, open the Asterisk CLI and run the following commands:
module reload res_crypto keys init keys show
You should see your public and private RSA keys loaded. This is a crucial step.
Initialize iax-phreaknet-rsa-in.conf with the following contents:
inkeys=phreaknetrsa ; colon-separated list of public keys to accept
As you can see, iax-phreaknet-rsa-out.conf is an automatically managed file containing users for outgoing calls, which will be updated automatically as needed. This subroutine does make any API requests at all, since it already has all the information needed.
You need to create iax-phreaknet-rsa-out.conf, but no need to add anything to it to initialize it. This means you can occasionally clear it out from time to time by running echo "" > /etc/asterisk/iax-phreaknet-rsa-out.conf from time to time, if you want to get rid of old peers that have piled up every now and then. The dialplan will create new peers as necessary when needed.
If at first you don't succeed, enable IAX2 debugging with iax2 set debug on.
Most failures occur before the call can get to the dialplan, so this is essential for narrowing down the cause of the issue.
The Business Office is happy to assist with Asterisk issues if needed. However, a detailed trace is needed in order to assist with dialplan issues. For dialplan troubleshooting, please use PhreakScript to perform a CLI trace as follows:
phreaknet update phreaknet trace
If you use PhreakScript's trace feature, you do not need to open the CLI yourself and copy and paste the CLI output. This is handled automatically.
Follow the instructions displayed by the wizard. At the end, a URL to a paste of the CLI trace will be displayed. Then, submit a ticket to the Business Office (choose PhreakNet for Asterisk dialplan related issues, NOT Asterisk!). By default, pastes are only live for 24 hours before they are deleted. You can extend the duration online at paste.interlinked.us. You can also configure redactions here.
At this point, we will assume you have a working Asterisk server and have reached out to get a thousand block allocated to you. In the meantime, you can work on getting your exchange setup so that everything will be working by the time your exchange appears in the route table (which usually occurs in less than 1 business day).
A note about Asterisk directories is necessary at this point. For those of you using the regular (compiled from source) version of Asterisk on Debian Linux, directories of particular importance are noted below:
/etc/asterisk/ — where the Asterisk configuration files reside
/var/lib/asterisk/agi-bin/ — where Asterisk AGI programs go
/var/lib/asterisk/moh/ — where music-on-hold audio files reside
/var/lib/asterisk/sounds/en/custom/ — where your custom audio files go (most any audio besides MOH)
/var/log/asterisk/ — where the Asterisk logs are located
/var/spool/asterisk/ — where recordings and voicemails are created
These paths are the default ones, assuming you haven't changed them in the Asterisk configuration.
Additionally, the AstDB database (e.g. the underlying database used by DB, DBDelTree, DB_KEYS, DB_DELETE, etc.) is stored in /var/lib/asterisk/astdb.sqlite3. Be sure to back this up periodically if you are using it!
As you spend more time working Asterisk, you'll become more and more familiar with these directories.
To get started, we need to adjust some settings and configure some settings. The following configuration (.conf) files are all located in /etc/asterisk/. You will need to modify them. There are a few ways you can do this. You can opt for the "local modification" approach or the "direct modification" approach.
Regardless of which method you are using, but particularly if you opt for the local modification approach, you will need an SFTP client, like FileZilla. If you use FileZilla, you will need to change the "Default Transfer Type" to binary. You can do this by going to Edit → Settings → Transfers → FTP: File Types → Default transfer type. Select "Binary" and uncheck the two "Treat files as ASCII file(s)" at the bottom as well.
You will need to use an FTP client like FileZilla (but using the SFTP protocol) to transfer over your audio files as well as your .conf files each time you make a revision if you opt for the local modification editing approach. You can use your client's site manager to save your connection settings so you don't need to re-enter the connection information each time.
The section below provides detailed commentary and explanation on setting up your Asterisk switch. If you don't care about the details and want to get up and running as soon as possible, see the "Boilerplate Code" section of this documentation. It provides files you can simply copy and paste, rather than providing you with the configuration piecemeal as below.
There are a couple settings you will want to tweak in this file that will impact your debugging. Make sure you have the following options set and uncommented:
[options] verbose = 3 timestamp = yes
By default, the Asterisk console does not give you terribly detailed information as to what's going on when your system is in use. You can manually set the verbosity to, say, 3, for instance, by typing core set verbose 3 at the Asterisk command line interface (or CLI). However, rather than have to manually type this every time you want to debug, it's easier to automatically set the console's verbosity. Verbosities range from 1 through 10 — 1 and 2 are pretty bare in detail, and 10 is not terribly more informative than 3 is (at least that's been our experience), so we'd say setting the default verbosity at 3 is a good starting place. You can tweak this later as you adjust to how much detail each verbosity level provides.
Setting timestamp to yes will provide timestamps in the console, also helpful for debugging. All calls are automatically logged with timestamps, but enabling this will allow you to see your dialplan's execution line by line with important contextual information regarding timing.
Unless you know what you're doing, make sure that you have autoload enabled:
[modules] autoload=yes
There are a number of VoIP protocols in use today, SIP/PJSIP and IAX2 being two of the more popular ones. There are many others, as well, that should be disabled if you are not using them. Otherwise, they increase the attack surface of your Asterisk system. You can disable other infrequently used or unused modules by adding the following to your [modules] context:
noload => chan_skinny.so ; Don't load skinny (tcp port 2000) noload => chan_mgcp.so ; Don't load MGCP (udp port 2727) noload => chan_unistim.so ; Don't load unistim (udp port 5000) noload => chan_ooh323.so ; Don't load ooh323 (tcp port 1720) noload => chan_323 noload => pbx_dundi.so ; Don't load dundi (udp port 4520)
The last statement disables DUNDI. If you don't know what that is, you're probably not using it and it's safe to do a "noload" on it. If you are using it by chance, then obviously, don't add that line!
If you so wish, you can look through your modules.conf and/or do some research and disable other modules you are not using. Be absolutely certain not to disable anything you might possibly need! It may help to consult a list of Asterisk modules. At the Asterisk CLI, you can also type module show to see all currently loaded modules, allowing you to see if there's anything loaidng you don't need.
Consult the boilerplate sip.conf for starter code.
Note that SIP is deprecated and will eventually be removed from Asterisk. PJSIP is the replacement for SIP.
A thing or two about bindport. Changing this to a value that is not 5060 will change the port that SIP is running on on your server. Changing the SIP port will make it more difficult for attackers and spammers to probe your Asterisk switch unbeknownst to you. Of course, tools like iptables and fail2ban should be relied on to prevent repeated brute authentication attempts (as well as changing the SSH port away from port 22), but changing the SIP port to a random number can further discourage spammers. The idea is to not use port 5060 for external SIP connections by changing your port to something non-standard. For example, you could set bindport=39145. Pick a port between 16383 and 65535 and never tell anyone what port you are using! Do not forward that UDP port in your router and ensure that UDP port 5600 is not forwarded in your router either. Indeed you should not need RTP UDP ports (usually 10000-20000) forwarded either.
The vast majority of VoIP providers use SIP (as opposed to IAX2, though voip.ms does support IAX2), so you'll likely need to use SIP or PJSIP for these.
DTMF can be finicky. Some have the best luck with SIP Info and specifying it explictly in sip.conf. Others have the best luck with RFC2833 and not explicitly specifying it in sip.conf (and only specifying it in the ATA's configuration options. You'll need to choose an option and try dialing through a DISA or using an echo test to make sure DTMF digits are being received at the distant end.
If you'd like to know more about what these do, consult the Asterisk documentation.
Consult the boilerplate pjsip.conf for starter code.
PJSIP is the new SIP channel driver in Asterisk. It was released as part of Asterisk 12. SIP was deprecated in 16 and will be removed by 21 (as of 18, or possibly even 16, it is already no longer built by default). PJSIP is the future of SIP in Asterisk, and migrating to PJSIP now before your Asterisk falls off the SIP cliff is highly recommended!
Architecturally, PJSIP is very different from SIP, and Sangoma is very proud of that. chan_sip is fairly monolithic, whereas PJSIP is more modular, standards based, and utilizes the open-source pjproject under the hood. Sangoma has described SIP as "a channel driver that happens to implement the SIP stack" and PJSIP as "a SIP stack that just happens to have a channel driver".
Another difference is that chan_sip will always just "kind of work", even if it's not in the way you intended. PJSIP, on the other hand, is fairly strict with regards to configuration, so if you make a typo or syntax error, the relevant component simply will not reload, alerting you that there is a fatal error you must resolve. Joshua Colp, from Sangoma, sums this up as "we believe that if you told PJSIP to do something, and it can't understand what you meant, then it should fail, because you told it to do something for a reason" (paraphrasing).
chan_sip is no longer receiving any attention from Sangoma as it is, as all of Sangoma's efforts, SIP-wise, are going into PJSIP. This means if you are encountering bugs or issues in SIP, they may very well be resolved by moving to PJSIP. As an example, some ATAs using TLS were having delayed re-registration with Asterisk if Asterisk restarted with SIP. This proved to be very annoying during testing. With PJSIP, this issue disappeared entirely.
Those are the advantages of moving to PJSIP — what about the downsides?
The disadvantage is that PJSIP has a higher learning curve than SIP. There are more moving parts, and for a newbie getting started, chan_sip is arguably much simpler and more straightforward than PJSIP. Below, we'll break down some of the major components involved. There is a lot, so the official Asterisk wiki will be a more in-depth resource.
Below are some code snippets from the boilerplate pjsip.conf. Let's go through each section in detail.
Similar to chan_sip, chan_pjsip supports UDP, TCP, and TLS. UDP and TCP may be bound on the same port, whereas each TLS port is bound on separate ports. We say "each", because nothing stops you from running multiple TLS ports, each running a different version of TLS. This allows you to support TLS 1.0, if needed, for older ATAs, while running your more modern ATAs on TLS 1.2, giving you the best of both worlds — compatability and security.
[transport-udp] type = transport protocol = udp bind = 0.0.0.0:16555 tos = cs3 [transport-tcp] type = transport protocol = tcp bind = 0.0.0.0:16555 tos = cs3 ; If you don't have TLS certificates and aren't using TLS, don't uncomment these. PJSIP will error out and not load. ;[transport-tls] ;type = transport ;protocol = tls ;bind = 0.0.0.0:16556 ;tos = cs3 ;cert_file = /etc/letsencrypt/live/example.com/fullchain.pem ;priv_key_file = /etc/letsencrypt/live/example.com/privkey.pem ;verify_server = no ;method = tlsv1
Above are the transport sections for UDP, TCP, and TLS 1.0. The actual names of these sections is not set, but something like transport-udp is probably fairly standard.
Similar to with SIP, TLS transports will need to include your certificate information. The method is tlsv1 for TLS 1.0 and tlsv1_2 for TLS 1.2.
In the transports above, we bind UDP, TCP, and TLS to ports 16555 and 16556. Running SIP on non-standard ports (that is, not 5060 or 5061) is a general best practice. It's security by obscurity, but the fact is that a lot of spam traffic will leave you alone if you aren't running on these ports, reducing the load on your system. Running iptables and fail2ban to deal with the rest is still an obvious must (see the relevant sections in the Docs for setup instructions).
Remember, if you run on non-standard ports, you'll need to explicitly include the port on any clients wherever the server might be mentioned, e.g. example.com:16555.
So, the big question — which protocol should I use?
The answer is TLS, if you can swing it. Not all SIP devices or softphones will support TLS, might support it only as a "premium" feature (e.g. Zoiper), or might only support up to TLS 1.0. The general rule of thumb is use the best protocol that you can. For some devices, that might be TLS 1.2. For others, it might be TLS 1.0. For some, it might mean just plain old UDP or TCP (UDP is more common than TCP, of the two).
Note that transports are not explicitly associated with specific users. Your SIP users will implicitly choose which transport to use by explicitly providing the port and protocol.
[lines-endpoint](!) type = endpoint disallow = all allow = g722 allow = ulaw rtp_symmetric = yes force_rport = yes rewrite_contact = yes direct_media = no inband_progress = yes tos_audio = ef device_state_busy_at = 1 trust_id_outbound = no trust_id_inbound = no notify_early_inuse_ringing = yes context = from-internal ; context in the dialplan in which this user originates a call allow_subscribe = yes subscribe_context = phreaknet-hints
Similar to SIP, PJSIP supports templates, which allow you to greatly simplify configuration by putting common configuration in a separate section, and then specifying that template section in your actual sections. This reduces clutter and increases manageability.
The template above is designed for "line endpoints", that is ATAs, softphones, and other "clients" (as opposed to for trunks, registrations, etc. where Asterisk is either an equal or a client).
We permit the ulaw and g722 codecs in this template to allow for high-quality audio. If you're not in the US, you should allow alaw as well.
We use device_state_busy_at to ensure that an endpoint is considered "busy" if it has any calls currently in progress, since it's a line, and that's how lines work.
allow_subscribe and subscribe-context are used for presence (e.g. busy lamp fields).
[lines-aor](!) type = aor max_contacts = 1 qualify_frequency = 30
Here's where PJSIP can start to get a bit funky, if you're used to SIP. An AOR stands for "address of record". The important thing really is that max_contacts should be 1. In theory, it doesn't need to be, and PJSIP actually allows a specific endpoint to have multiple contacts, which means you could register two softphones to the same SIP user. In practice, that's kinds of pointless, because Asterisk has no way of differentiating these, and all your SIP endpoints should have a separate user, as a best practice. Increasing max_contacts is not the right way to make your calls follow you everywhere — there are much better ways to do that, in dialplan.
[lines-auth](!) type = auth
This doesn't really need to be a template, but since you can specify the template on the same line as the auth section name for your individual users, you'll save one line per user.
; every user needs to have an AOR (address of record) section, auth section, and endpoint section. To minimize clutter, we use templates for each. [DeskPhone1](lines-aor) [DeskPhone1](lines-auth) username = DeskPhone1 password = samplepasswordhere [DeskPhone1](lines-endpoint) callerid = "John Smith" <5552368> ; change the CNAM and caller ID of your line here ;media_encryption = sdes ; for SRTP (voice path), if your endpoint supports it. Make sure to connect to the TLS port so the signaling is encrypted, too. auth = DeskPhone1 ;outbound_auth = DeskPhone1 aors = DeskPhone1 ;mailboxes = 2368@vmcontext ; for voicemail MWI
Here's where we finally define an actual "user". Notice that each user is comprised of three things we've already discussed — AOR sections, auth sections, and endpoint sections. This can be a big change if you're used to SIP or IAX2, where each user is generally comprised of just a single section. You can't do that in PJSIP, because it's a much more modular channel driver.
The auth section is where you define the credentials for the user. How does this user authenticate to you?
The endpoint is where the "meat" of the user is. The endpoint references the corresponding auth and aor contexts. We've included outbound_auth here but commented it out. outbound_auth is used to specify the auth section containing credentials for peers where Asterisk is the user/client, rather than the server. For an ATA or subscriber line, Asterisk is not the client, so no outbound_auth is needed. Likewise, if Asterisk is only the user, then you would not have an auth section specified, because the remote end doesn't need to authenticate against you — you need to authenticate against it.
media_encryption = sdes is the equivalent of encryption = yes in SIP. PJSIP just supports multiple different kinds — sdes refers to standard SRTP. TLS + SRTP = a secure line (TLS encrypts the signalling, SRTP encrypts the voice path — but SRTP is somewhat pointless without TLS, since the keys are sent in the clear).
If you're using voicemail, you can specify mailboxes here, which will be used for MWI. You can also reference them from the dialplan to avoid duplicating code, using one of the PJSIP functions. Note that it's mailboxes, not mailbox as it was in sip.conf. A lot of the keywords are slightly different.
Another thing to keep in mind is that PJSIP uses RFC4833 for DTMF, not RFC2833 as SIP does. One issue with migrating SIP to PJSIP is that DTMF on some lines may stop working suddenly (e.g. you "can't break dialtone"). This will happen if some ATAs are configured to use SIP INFO and Asterisk is trying to use RFC2833 instead. You should
Unlike SIP, PJSIP does not allow anonymous access by default, which is really a good thing, since there's generally no reason to. You don't need to set allowguest = no as in sip.conf because that is the default behavior.
Finally, making outbound calls to SIP URIs with PJSIP is more involved than with SIP. Dialing a SIP endpoint took care of some things for you which allowed you specify a fairly normal looking dial string, e.g. Dial(SIP/telephreak@voip.telephreak.org).
In PJSIP, there is no such thing as a "naked" dial like that. Every call must be associated explicitly with an endpoint. What this means is you'll actually need to create an endpoint (or multiple) for outgoing calls, even when you're explicitly providing all routing info in the dial string. Here's what that might look like: Dial(PJSIP/outgoing/sip:telephreak@voip.telephreak.org).
Here, outgoing refers to an endpoint section in pjsip.conf. Notice that it looks similar to what we've defined for users, but it's a little bit different.
[outgoing-aor](!) type = aor maximum_expiration = 60 minimum_expiration = 60 default_expiration = 180 [outgoing-identify](!) type = identify endpoint = outgoing match = 127.0.0.1 [outgoing-endpoint](!) type = endpoint rtp_symmetric = yes force_rport = yes rewrite_contact = yes direct_media = no tos_audio = ef disallow = all allow = g722 allow = ulaw language = en aors = outgoing [outgoing](outgoing-aor) [outgoing](outgoing-identify) [outgoing](outgoing-endpoint) transport = transport-udp
The "default" outgoing endpoint we've set up here uses UDP. If you wanted to make an encrypted TLS call, you might define another outgoing endpoint, e.g. outgoing-tls12 for outgoing TLS 1.2 calls. Note that these are only used for calls where you explicitly say to use these. If you're making a call to something to which you're registered, you're not going to be using this. This is more for "anonymous outbound calls", essentially.
PJSIP has a lot of stuff you can configure and set up, with the caveat that there is a lot you need to configure and set up, as compared to chan_sip, which you can get going fairly easily and lazily, and will do some things behind the scenes for you to infer what it should do. It's a double-edged sword.
If you're already using SIP and you want to migrate to PJSIP, there is a conversion script on the Asterisk wiki that you can run on your sip.conf that will spit out a pjsip.conf. The good news is that this easily converts your config without you needing to worry about what matches up with what, between the two configs. The problem is that it's not 100% accurate, and if your sip.conf is non-trivial, it will likely spit out an incorrect config that has a ton of issues that you'll need to manually rectify (this is what happened to us). Just keep this in mind and be prepared to spend a few hours debugging why your registrations are not working, etc. We've contributed a few bug fixes and additions to this script, to improve it for those using it, but one major issue of which we're aware is the scenario where you have multiple registrations to a single provider. This script will butcher that up majorly, in a seriously epic fail, so you should plan to manually visit those. Once your migration is complete, make sure all your registrations come online and that your users and peers can reach you.
chan_dahdi.conf is the Asterisk config file for the DAHDI channel driver. However, the kernel-level /etc/dahdi/system.conf also needs to be configured.
DAHDI allows you to use real (e.g. TDM) telephone equipment with Asterisk. Most commonly, instead of an ATA, you can use a channel bank, for instance. There is much more overhead to getting set up, but line densities tend to be higher and you'll get more capabilities. Consider this the "premium" telephony experience. It's akin to what POTS TDM switches at the real phone companies are using.
DAHDI is one of the least intuitive and most confusing aspects of Asterisk to work with. A few tips for those getting started:
chan_dahdi.conf FXS lines use fxo signalling and FXO lines use fxs signalling. It seems backwards, but that's how it is.
chan_dahdi.conf, there are two ways to configure channels. The older and more popular method is the "fallthrough" method, which can be very confusing to those used to working with other Asterisk config files. In the [channels] config section, any channel settings configured persist until they are overridden, and you simply define your channels there, like this:
[channels] cadence=2000,-4000 cadence=300,200,1000,200,300,-4000 cadence=800,400,800,-4000 cadence=400,200,300,200,800,-4000 cadence=400,200,800,200,800,-3600 cadence=200,400,200,400,200,-4000 cadence=800,200,400,200,800,-3600 cadence=1650,-350 cadence=800,200,300,200,400,-4000 cadence=400,200,400,-2000 signalling = fxo_ks ; yeah, this makes no sense, but it's right... callwaiting = no callwaitingcallerid = no threewaycalling = no transfer = no canpark = no cancallforward = no callreturn = no mailbox = 123@context immediate = yes transfertobusy = no ; whether can transfer to a busy station. context = from-internal adsi = yes useincomingcalleridondahditransfer = no ; Line 1 callerid = John Smith <211> threewaycalling = no channel => 1 ; Line 2 callerid = Jane Smith <212> channel => 2 ; Line 3 callerid = Paul Smith <213> threewaycalling = yes channel => 3The problem with this is that when you set threewaycalling to no for line 1, it will apply to any channels you configure until it is explicitly overridden again. This means that you can change a setting in one place, thinking you are changing it for one line, and end up screwing up the configuration of many other lines at the same time in unintended ways.
Consequently, an alternate way of configuring channels that is similar to how other channel driver config files work is by defining each channel in its own section, and using templates to set "inheritable" settings, like so:
[channels] cadence=2000,-4000 cadence=300,200,1000,200,300,-4000 cadence=800,400,800,-4000 cadence=400,200,300,200,800,-4000 cadence=400,200,800,200,800,-3600 cadence=200,400,200,400,200,-4000 cadence=800,200,400,200,800,-3600 cadence=1650,-350 cadence=800,200,300,200,400,-4000 cadence=400,200,400,-2000 [fxs](!) signalling = fxo_ks ; yeah, this makes no sense, but it's right... callwaiting = no callwaitingcallerid = no threewaycalling = no transfer = no canpark = no cancallforward = no callreturn = no mailbox = 123@context immediate = yes transfertobusy = no ; whether can transfer to a busy station. context = from-internal adsi = yes useincomingcalleridondahditransfer = no [line-1](fxs) dahdichan = 1 callerid = John Smith <211> [line-2](fxs) dahdichan = 2 callerid = Jane Smith <212> description = Line 2
This is generally considered to be the better way of configuring chan_dahdi, especially if you are starting from scratch with a new system, and if you are configuring lines (as opposed to something like a PRI).
Getting started out with DAHDI can be tricky. Here, we'll assume that you are configuring FXS lines (thus, using FXO signalling). The example above uses kewlstart.
At this point, we'll assume that DAHDI Linux and DAHDI Tools have already been installed (such as by using PhreakScript).
dahdi_genconf will generate a default config file, which is intended for PRI and not for FXS ports, e.g. with the following:
# termtype: te bchan=1-23 dchan=24
Never run dahdi_genconf more than once. If you run it again, you'll wipe out your config.
You'll need to manually change /etc/dahdi/system.conf to look something like this:
# Span 1: WCT13x/0 "Wildcard TE131/TE133 Card 0" (MASTER) ESF/B8ZS RED ClockSource span=1,1,0,esf,b8zs fxols=1 fxols=2 fxols=3 fxols=4 fxols=5 fxols=6 fxols=7 fxols=8 fxols=9 fxols=10 fxols=11 fxols=12 fxols=13 fxols=14 fxols=15 fxols=16 fxols=17 fxols=18 fxols=19 fxols=20 fxols=21 fxols=22 fxols=23 fxols=24 echocanceller=mg2,1-23 # Global data loadzone = us defaultzone = us
The example above uses loop start, but you could also use the cooler (or "kewler") kewlstart, which is similar but has more capabilities (simply use fxoks for that). In fact, in most cases, you'll want to use ks, not ls. KS provides loop disconnect on hangup, and this is typical of most "real" POTS switches.
Note that for disconnect supervision to work properly on FXO ports, you also need to set this in the channel bank. For example, using an Adit 600, you might need to do something likeset 2:1-8 signal lscpd (here, 2 refers to card #2) — lscpd will make loop disconnect supervision work properly so that if an incoming call to an FXO port hangs up, it actually clears towards DAHDI. With simply ls, this will not work correctly for FXO ports (but should suffice for FXS ports).
But that's rather repetitive, isn't it? So you could also do:
# Span 1: WCT13x/0 "Wildcard TE131/TE133 Card 0" (MASTER) ESF/B8ZS RED ClockSource span=1,1,0,esf,b8zs fxoks = 1-24 echocanceller=mg2,1-23 # Global data loadzone = us defaultzone = us
(Here, we do use kewlstart).
Take a look at /etc/dahdi/system.conf.sample for more details on usage.
Then, run dahdi_cfg -vvvvv. Each v indicates more verbosity (similar to as with the asterisk or rasterisk arguments.
You may then see something like this (the below is for a single span, with fxols for all):
DAHDI Tools Version - 3.1.0 DAHDI Version: 3.1.0 Echo Canceller(s): HWEC Configuration ====================== SPAN 1: ESF/B8ZS Build-out: 0 db (CSU)/0-133 feet (DSX-1) Channel map: Channel 01: FXO Loopstart (Default) (Echo Canceler: mg2) (Slaves: 01) Channel 02: FXO Loopstart (Default) (Echo Canceler: mg2) (Slaves: 02) Channel 03: FXO Loopstart (Default) (Echo Canceler: mg2) (Slaves: 03) Channel 04: FXO Loopstart (Default) (Echo Canceler: mg2) (Slaves: 04) Channel 05: FXO Loopstart (Default) (Echo Canceler: mg2) (Slaves: 05) Channel 06: FXO Loopstart (Default) (Echo Canceler: mg2) (Slaves: 06) Channel 07: FXO Loopstart (Default) (Echo Canceler: mg2) (Slaves: 07) Channel 08: FXO Loopstart (Default) (Echo Canceler: mg2) (Slaves: 08) Channel 09: FXO Loopstart (Default) (Echo Canceler: mg2) (Slaves: 09) Channel 10: FXO Loopstart (Default) (Echo Canceler: mg2) (Slaves: 10) Channel 11: FXO Loopstart (Default) (Echo Canceler: mg2) (Slaves: 11) Channel 12: FXO Loopstart (Default) (Echo Canceler: mg2) (Slaves: 12) Channel 13: FXO Loopstart (Default) (Echo Canceler: mg2) (Slaves: 13) Channel 14: FXO Loopstart (Default) (Echo Canceler: mg2) (Slaves: 14) Channel 15: FXO Loopstart (Default) (Echo Canceler: mg2) (Slaves: 15) Channel 16: FXO Loopstart (Default) (Echo Canceler: mg2) (Slaves: 16) Channel 17: FXO Loopstart (Default) (Echo Canceler: mg2) (Slaves: 17) Channel 18: FXO Loopstart (Default) (Echo Canceler: mg2) (Slaves: 18) Channel 19: FXO Loopstart (Default) (Echo Canceler: mg2) (Slaves: 19) Channel 20: FXO Loopstart (Default) (Echo Canceler: mg2) (Slaves: 20) Channel 21: FXO Loopstart (Default) (Echo Canceler: mg2) (Slaves: 21) Channel 22: FXO Loopstart (Default) (Echo Canceler: mg2) (Slaves: 22) Channel 23: FXO Loopstart (Default) (Echo Canceler: mg2) (Slaves: 23) Channel 24: FXO Loopstart (Default) (Echo Canceler: none) (Slaves: 24) 24 channels to configure. Setting echocan for channel 1 to mg2 Setting echocan for channel 2 to mg2 Setting echocan for channel 3 to mg2 Setting echocan for channel 4 to mg2 Setting echocan for channel 5 to mg2 Setting echocan for channel 6 to mg2 Setting echocan for channel 7 to mg2 Setting echocan for channel 8 to mg2 Setting echocan for channel 9 to mg2 Setting echocan for channel 10 to mg2 Setting echocan for channel 11 to mg2 Setting echocan for channel 12 to mg2 Setting echocan for channel 13 to mg2 Setting echocan for channel 14 to mg2 Setting echocan for channel 15 to mg2 Setting echocan for channel 16 to mg2 Setting echocan for channel 17 to mg2 Setting echocan for channel 18 to mg2 Setting echocan for channel 19 to mg2 Setting echocan for channel 20 to mg2 Setting echocan for channel 21 to mg2 Setting echocan for channel 22 to mg2 Setting echocan for channel 23 to mg2 Setting echocan for channel 24 to none
DAHDI needs to be restarted whenever its config is changed, such as if you've changed the type of signalling used by a span, so run service dahdi restart. (Some guides may also tell you to simply reboot).
Then, finally, comes configuring things in "user land" at the Asterisk level, namely chan_dahdi.conf. Once that's been done, you'll want to issue dahdi restart at the Asterisk CLI.
Pay careful attention to any warnings that may arise when you do this, e.g. don't ignore this:
[Mar 25 20:17:06] WARNING[585]: chan_dahdi.c:7376 handle_alarms: Detected alarm on channel 1: Red Alarm [Mar 25 20:17:06] WARNING[585]: chan_dahdi.c:7376 handle_alarms: Detected alarm on channel 2: Red Alarm [Mar 25 20:17:06] WARNING[585]: chan_dahdi.c:7376 handle_alarms: Detected alarm on channel 3: Red Alarm [Mar 25 20:17:06] WARNING[585]: chan_dahdi.c:7376 handle_alarms: Detected alarm on channel 4: Red Alarm [Mar 25 20:17:06] WARNING[585]: chan_dahdi.c:7376 handle_alarms: Detected alarm on channel 5: Red Alarm [Mar 25 20:17:06] WARNING[585]: chan_dahdi.c:7376 handle_alarms: Detected alarm on channel 6: Red Alarm [Mar 25 20:17:06] WARNING[585]: chan_dahdi.c:7376 handle_alarms: Detected alarm on channel 7: Red Alarm [Mar 25 20:17:06] WARNING[585]: chan_dahdi.c:12535 mkintf: Attempt to configure channel 7 with signaling FXO Loopstart ignored because it is already configured to be FXO Loopstart. [Mar 25 20:17:06] WARNING[585]: chan_dahdi.c:7376 handle_alarms: Detected alarm on channel 7: Red Alarm
You can use dahdi show status in the Asterisk CLI to get the status of your telephony cards.
In the case above, red alarm means a T1 signaling issue, likely caused by a loose connection or no connection at all (in the proper place).
If you have multiple spans (cards/ports), you will likely want to manually configure their ordering, so the ordering doesn't change on you randomly, depending on driver load order, or if cards are removed/added.
To do this, first add options dahdi auto_assign_spans=0 to /etc/modprobe.d/dahdi.conf.
Then, add your configuration to /etc/dahdi/assigned-spans.conf and then use dahdi_span_assignments to make your configuration effective. Here is an example of what that might end up looking like:
# Autogenerated by /usr/sbin/dahdi_span_assignments on Sun Sep 15 08:05:47 PM EDT 2024 # Map devices + local spans to span + base channel number # Device: [] @Board_ID_Switch_4 /sys/devices/pci0000:00/0000:00:01.0/0000:04:00.0/0000:05:08.0/pci:0000:05:08.0 /sys/devices/pci0000:00/0000:00:01.0/0000:04:00.0/0000:05:08.0/pci:0000:05:08.0 1:4:73 /sys/devices/pci0000:00/0000:00:01.0/0000:04:00.0/0000:05:08.0/pci:0000:05:08.0 2:5:97 /sys/devices/pci0000:00/0000:00:01.0/0000:04:00.0/0000:05:08.0/pci:0000:05:08.0 3:3:49 /sys/devices/pci0000:00/0000:00:01.0/0000:04:00.0/0000:05:08.0/pci:0000:05:08.0 4:6:121 # Device: [] @PCI_Bus_08_Slot_09 /sys/devices/pci0000:00/0000:00:06.0/0000:07:00.0/0000:08:08.0/pci:0000:08:08.0 /sys/devices/pci0000:00/0000:00:06.0/0000:07:00.0/0000:08:08.0/pci:0000:08:08.0 1:2:25 # Device: [] @PCI_Express_Bus_14_Slot_09 /sys/devices/pci0000:00/0000:00:1c.6/0000:0d:00.0/0000:0e:08.0/pci:0000:0e:08.0 /sys/devices/pci0000:00/0000:00:1c.6/0000:0d:00.0/0000:0e:08.0/pci:0000:0e:08.0 1:1:1
wanpipe is required for Sangoma cards only. If you have only Digium cards, you do not need wanpipe (though having it installed doesn't hurt anything, if you already have it). PhreakScript automatically installs wanpipe for you if you use the --wanpipe option.
Note that the community consensus is that Digium cards are superior to Sangoma cards. Dial pulsing is often reported to be more erratic with Sangoma cards (even the T1 cards), and Sangoma cards also require wanpipe, which although still maintained, is better avoided if possible.
To configure a Sangoma card, run wancfg, which is an interactive utility that does work similar to dahdi_genconf. There is also another tool called wancfg_dahdi that wraps some of these steps.
Before you begin, double check to see what card you have. lspci and dahdi_hardware have been known to report inaccurate card models for Sangoma cards.
wancfg
/etc/wanpipe/wanpipe1.conf, which was autocreated by wancfg. Most of the options probably won't make sense to you, but you should take a look and ensure that there isn't anything obviously off here (e.g. your card is configured for ADSL instead of TDM, etc.)
Now, you should be able to test your card to see if it comes up properly. Run wanrouter restart. You may see a warning about ifconfig not being found on your system, due to the wanrouter script still using this now-deprecated (and unavailable, on newer systems) command.
If you haven't already, go ahead and back up /etc/dahdi/system.conf, before proceeding, in case dahdi_genconf overwrites something that was previously there (although if something is suddenly missing, the driver for that card is probably not loaded and you need to modprobe it).
Now, you can go ahead and rerun dahdi_genconf. After you run dahdi_genconf, double check /etc/dahdi/system.conf and make sure any other spans you may have had configured are still there. Don't forget that T1 spans are always configured as PRI by default, so if you are setting up analog channels (e.g. on a channel bank, using T1 CAS signalling), then you will need to edit the config by hand to reflect that.
Once you've done that, rerun dahdi_cfg, since DAHDI's configuration has been updated.
After that, you can (finally!) map the channels appropriately in /etc/asterisk/chan_dahdi.conf. Whew!
Further Resources:
The DAHDI dial syntax is a bit peculiar. See this old mailing list post for some gory details.
The most important modifier to the regular dial syntax is specifying the ring cadence. This is done together with specifying the channel number, e.g. Dial(DAHDI/4r2) would dial line 4 (in your first span) and use ring cadence 2. Here are some comments from the code that describe all the options:
* Dial(DAHDI/pseudo[/extension]) * Dial(DAHDI/[c|r |d][/extension]) * Dial(DAHDI/(g|G|r|R) [c|r |d][/extension]) * * g - channel group allocation search forward * G - channel group allocation search backward * r - channel group allocation round robin search forward * R - channel group allocation round robin search backward * * c - Wait for DTMF digit to confirm answer * r - Set distintive ring cadance number * d - Force bearer capability for ISDN/SS7 call to digital.
To troubleshoot audio on DAHDI lines, you can use dahdi_monitor.
DAHDI debug messages are logged to /var/log/messages, but they are not particularly verbose by default, so if you are developing in the DAHDI kernel, you may want to add some module_printk statements of your own.
Consult the boilerplate musiconhold.conf for starter code.
Music on hold is how custom ringback tones are used in Asterisk.
[ringback] mode=files directory=moh/ringback/rbs1
The [ringback] class is referenced in the Dial Statement in [phreaknet-ring]. If you change the name, make sure to do so in both places.
As written, this context expects your ringback audio file to be located in /var/lib/asterisk/moh/ringback/ and be named rbs1.ulaw. Adjust the paths if needed, but you should keep music on hold files in the moh directory. We recommend creating a separate directory inside of moh for your ringback audio and then placing it inside of that.
If you need a ringback audio file, there are a few available at Telephone World. You can also scour Evan Doorbell recordings for something more your style if you're looking for something particular. For example, if you decide your switch is going to be a simulated "Number 5 Crossbar" switch, then you should look for a #5XB ringback you can use (you can use Audacity to prepare the audio and export it as a WAV file to then convert with SoX). Likewise, you should find #5XB busy and reorder signals you can use.
Now, delete the [default] context and add the following:
[default] mode=files directory=moh/silence random = no [asteriskdefault] mode=files directory=moh random=yes
Create the folder silence inside the moh folder and then copy /var/lib/asterisk/sounds/en/silence/10.ulaw into it.
What did this accomplish? In keeping with the realism factor, by default, Asterisk's default music on hold will play if you flash during a call. In most cases, this is undesirable. Not only is it generally frowned-upon in production systems, but music-on-hold on an otherwise simulated electromechanical switch will stand out like a sore thumb. Now, when you flash, the party you just put on hold will not hear anything.
Remember, to reload music on hold you will need to enter moh reload from the Asterisk CLI.
Consult the boilerplate iax.conf for starter code.
If you're not sure whether you have IAX trunking enabled, you can do the following:
asterisk -rmodule show like iaxmodules.conf (see the modules.conf section if you're unsure about this).Once you've determined that the IAX2 module is working, you'll need to modify iax.conf, which is located in /etc/asterisk/.
The verification subroutines is part of the boilerplate code (verification.conf).
The verification subroutines are still supported and are being maintained. They are not deprecated. An alternative, however, is to use the Verify dialplan application. This is available if you installed Asterisk using PhreakScript (PhreakNet Asterisk).
app_verify uses the verify.conf config file. The boilerplate config file covers usage with PhreakNet, C*NET, and NPSTN, as well as incoming PSTN calls. Functionality should be identical, more or less, to using the verification subroutines. The major difference from a UX point of view is the module provides some additional statistics and probably performs better, since it's written in C instead of in dialplan. Since it's just a single dialplan call, the CLI doesn't get cluttered up with verification dialplan execution, if that annoys you.
In other words, use either app_verify (the Verify() and OutVerify() applications) or verification.conf, but don't use both. Ultimately, pick whichever method is easier or better for you. They are both fully supported.
PRE-REQUISITE: You MUST have DIG installed on your server (part of the dnsutils). Please see the Pre-Requisites section for more details.
The verification subroutines rely on the following global variables being properly defined: maindisa, allowdisathru, and allowpstnthru.
Here is a list of the 2-digit "caller verification status codes". The network name on the left refers to the original source of the caller. The first upstream node (the node into which an external caller originally dials) determines the code below to use and passes it along to downstream nodes.
00 — Reserved, for local temporary use (e.g. if sending a call over a trunk that doesn't pass channel variables, temporarily turn null CVS into 00 and add that to the extension, then convert back on the other end)10 — NPSTN, valid and legitimate11 — NPSTN, valid but illegitimate19 — NPSTN, untrusted/illegitimate (validity spoofed by upstream node)20 — C*NET, valid and legitimate21 — C*NET, valid but illegitimate30 — US PSTN, valid31 — US PSTN, invalid32 — US PSTN, anonymous40 — UK PSTN, valid41 — UK PSTN, invalid42 — UK PSTN, anonymous50 — AU PSTN, valid51 — AU PSTN, invalid52 — AU PSTN, anonymous60 — Other PSTN, valid61 — Other PSTN, invalid62 — Other PSTN, anonymous70 — PhreakNet, valid and legitimate71 — PhreakNet, valid but illegitimate72 — PhreakNet, invalid and illegitimate75 — PhreakNet, ANI fail, Operator Number Identification77 — PhreakNet, fatal verification failure78 — Blacklisted number (drop call)79 — PhreakNet, untrusted/illegitimate (validity spoofed by upstream node)90 — Other, valid91 — Other, invalid92 — Other, anonymousGenerally, X0 indicates the call is valid. Note that we can only confirm the caller if the CVS (caller verification status) code is 10 or 20. 30 or 40 indicate PSTN calls that, while they appear to be valid, cannot be 100% confirmed to be so. 9X codes are reserved for other use, such as assigning CVS codes to other private networks. This way, such calls do not have an empty CVS code and do not appear to be originating locally when performing CVS branch checks.
The verification subroutines also process STIR/SHAKEN headers as part of the verification process for incoming PSTN calls from VoIP providers. This information is available in adjunct to the CVS code, and may be used by the direct or downstream node operators for further call filtering as desired.
If the last digit the CVS code is not 0, the caller ID is almost definitely spoofed, unless the last digit is 2, which indicates an anonymous PSTN caller whose identity, while not necessarily spoofed, cannot possibly be verified.
Note that validity and legitimacy here are two different concepts. Validity refers to a number being of proper format. PSTN calls can be determined to have a valid number, based on the rules specified for PSTN numbering, but verifying that number is a legitimate is different altogether. Legitimacy can only be easily determined for calls for private peer-to-peer VoIP networks (NOT the PSTN).
CVS codes are frequently used to provide different classes of service. For instance, if you have sensitive contexts to which you wish to allow only trusted callers, you can branch based on the CVS code. You can also use CVS codes to act accordingly in your dial plan based on the origin of the caller. All you would need to do in this case is check the first digit of the CVS code to determine from where the caller originally dialed in (or the second to check the call's legitimacy). The second digit says more about the caller's verification status. Since the first digit is network status and the second is verification status, you could, for example, use GotoIf($["${clidverif:-2:1}"="7"]?phreaknet) and GotoIf($["${clidverif:-2:1}"="2"]?cnet) within your dialplan.
WARNING: If you use CVS codes to configure "forks" in your dialplan, you must always define an exception for calls where the clidverif variable is not defined, which will be the case for any local calls. Since all incoming calls to your node will be assigned a CVS code, if a call does not have a CVS code, it is a local call and you should handle it accordingly, like so: GotoIf($[${ISNULL(${clidverif})}]?local). If you don't add this "null variable exception", any calls originating from your switch will not route properly at any such forks in your dialplan.
At this point, you may wonder why using IAX variables to pass around these 2-digit codes is necessary. If you care to examine the code carefully, the reason becomes obvious, but the quick answer is that it is only possible to accurately verify calls from the last upstream node. If a caller dials through a DISA and then dials to another node, this third node cannot possibly verify the original caller. This is because while its Caller ID is the original Caller ID, the IP address from which the caller will appear to be coming belongs to the second node. Hence, if a simple IP verification technique is used, the caller will be flagged as fradulent. Hence, it is necessary for each upstream node to "pass along" the results of its verification tests to subsequent downstream nodes. In this way, downstream nodes can be as sure of the validity of the caller as if he had dialed that node directly. Furthermore, the validity of the upstream node itself is also verified to be sure we can trust its judgment (i.e. to make sure a rogue impostor server pretending to be an in-network node is not fradulently attempting to pass along inaccurate verification information). Hence, the ${maindisa} variable is used to allow a downstream node to do a reverse lookup and confirm the node is who it says it is. With these subroutines, in conjunction with the CNAM subroutines below, it is impossible for a non-network node to fradulently present itself to any node, no matter how far up or downstream in a call a node may happen to be.
At last, extensions.conf, the heart of the Asterisk dialplan! Here is where all (or at least most) of the action happens.
Consult the boilerplate dialplan files for starter code (extensions.conf, verification.conf, phreaknet.conf, and phreaknet-aux.conf).
While it is highly recommended to grab the latest boilerplate code and adapt them to your dialplan, they are not strictly required. You will, however, need the following, at minimum, for a "minimally viable dialplan":
from-phreaknet) and the outgoing contexts (e.g. to-phreaknet and dialphreaknet), from the top and bottom of phreaknet.conf, respectively. You can fill in the gaps in the middle as desired.
A word about variables: don't make them all uppercase. All-uppercase variable names are reserved for use by Asterisk. Use lowercase, camelCase, or CapitalizeEachWord, but don't make them ALLUPPERCASE.
Before continuing, you may wish to reload or restart Asterisk. To restart Asterisk entirely, type core restart now at the Asterisk CLI. To just reload a particular module, you can generally type the module name followed by the reload, such as sip reload. To reload music-on-hold, for example, you would type moh reload. To reload voicemail, you would type voicemail reload. To reload the dialplan (which is something you'll end up doing quite frequently, you'll type dialplan reload. To reload all modules without restarting Asterisk, you can simply type reload.
Occasionally, you may need to reboot your server as well. To do this, from the Asterisk CLI, type exit to quit the Asterisk CLI and exit to the Linux command line. Then type reboot. That's it!
Playback() has a root of /var/lib/asterisk/sounds/en/ so you only need to specify directories downstream from that point. Of course, adjust the Playback() path to that of your audio files. You will need to use SoX to convert WAV recordings of your switch tones to μLaw files; refer to the SoX section in Appendix A for more information.
Notice that the file extension (.ulaw) is not specified. Asterisk will search for the best audio file for the call and automatically select that one. If there is only one file with that name (excluding the file extension), then you can be assured it will be the ulaw file.
Hopefully all the audio files you need are on your Asterisk switch by now. Once you've modified your files (and copied them over to the server if you modified them locally), be sure to enter dialplan reload at the Asterisk CLI prompt. Take care that you don't see a WARNING message when you hit Enter; if you do, debug the error before continuing.
If you end up modifying a lot of different config files for different modules, reload will reload everything in Asterisk. Generally, it's better to just reload the specific thing you need (like dialplan) since reloading everything will take a little while (by this, we mean up to 10 seconds, rather than instantly).
Finally, some (few) things may require a restart: core restart now. Once Asterisk exits, enter asterisk -r to enter back into the Asterisk CLI.
The ATA's default digit map (also frequently, but erroneously, called a dial plan) will not be sufficient. You will need to tweak the digit map/dial plan to the specifications of your system, but for a basic configuration, the following should be sufficient:
Linksys:
(0|[2-9]11|11[2-9]|660S0|95[89]|10[2-9]xx|100xx|101xxxx|[2-9][2-9]xxxxx|1[2-9][2-9]xxxxx)
Grandstream:
{ 0|[2-9]11|11[2-9]|660|95[89]|10[2-9]xx|100xx|101xxxx|[2-9][2-9]xxxxx|1[2-9][2-9]xxxxx}
The above dial plan can be explained as follows:
You may also wish to get dial tone from Asterisk (recommended). That can be accomplished through the use of hotline dialing. For instance, you may wish to automatically connect to extension 20, which will go to a dial tone in Asterisk:
(<:20>S0)
If you want to a lock a particular phone into hotline dialing a certain extension, the first example is one way to go. For regular usage, the second method might be more suitable. In fact, using the second method, you can control the hotline behavior within Asterisk, which is more robust and manageable.
The above example is for Linksys-style digit maps. Grandstream uses can configure the off-hook auto dial number (with a timeout of 0) on the appropriate page. If you'd rather hear city dial tone when you pick up your phone as opposed to the precise dial tone generated by your ATA, you can have your ATA auto-dial your city dial tone DISA. Most DISAs are NNX-1111, meaning the station number 1111 in each active exchange is usually a DISA. In this documentation, we will pretend we are setting up the 555 (KLondike5) exchange. It would follow that your DISA number would be 555-1111 (or KL5-1111). You could, instead of mirroring your Asterisk dial plan on your ATA and having to coordinate the two, have your ATA auto-dial your DISA. The bonus of this is you don't need to worry about updating your ATA dial plan if you make a change to your Asterisk routing. You also get to hear city dial tone (woo hoo!).
If you do this, you should configure a short code on your system corresponding to a non-billing number, like 20, for instance, go to the dial tone in Asterisk. This way, billing is not invoked for the call. Now, whenever you lift your handset, your ATA will connect to your Asterisk system in a split second and you'll be hit with city dial tone immediately!
You may find it useful to automatically have voicemail notifications or voicemail messages themselves emailed to you. Asterisk integrates with the system mailer, so if you do not have one configured, you will need to install and configure one. This guide will cover the installation and configuration of Postfix on Debian Linux.
apt-get update apt-get upgrade apt-get install mailutils apt-get install postfix
sed -i 's/inet_interfaces = all/inet_interfaces = loopback-only/g' /etc/postfix/main.cf
sed -i 's/mydestination = $myhostname, /mydestination = $myhostname./g' /etc/postfix/main.cf
sed -i 's/myhostname = YOURSERVERNAME/myhostname = sub.example.com/g' /etc/postfix/main.cf ← you may want to manually make this edit using the nano text editor.
systemctl restart postfix
To enable TLS, something like this should be in your /etc/postfix/main.cf:
# TLS parameters
smtpd_tls_cert_file=/etc/letsencrypt/live/example.com/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/example.com/privkey.pem
smtpd_tls_security_level=encrypt
smtp_use_tls=yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
At this point, there are two main options from which to choose. You could use SMTP to send emails using another account (i.e. a Gmail, Hotmail, Yahoo, etc. account), which may be ideal if you already have an account hosted elsewhere you want to use to send messages. Or, you could have messages be sent directly, in which case you will want to ensure that there is an SPF record for the domain in question pointing to your server. Otherwise, sent emails will likely go straight to spam. We recommend using a subdomain specifically for your Asterisk server if you go this route. Each domain or subdomain may have one SPF record. Set up Let's Encrypt on the server if you haven't already done this for hosting a web server, so that email transmission is encrypted.
Trying to work with mail and sendmail in Linux is usually harder than performing brain surgery, so if you get stressed out easily, Linux email configuration and testing is NOT for you. This is because Linux mail programs are not designed for sending mail to the Internet, but sending mail between users on the same system. You will need to do a fair bit of work to fix this or all of your mail will get classified as spam.
To send a test email, run something like this: echo "Test" | mail -s "Test Email" -a "From: from@asterisk.example.com" to@example.com. Or, you can use this method.
At this point, your messages may be going to spam. Wouldn't it be nice if you knew why? Fortunately, such services exist. Try a few and see what you can improve. Another good one is unspam.email.
One improvement beyond TLS and SPF will be to set up DKIM with Postfix.
Check the error log if things aren't working right: tail -50 /var/log/mail.log.
Finally, in Asterisk's voicemail.conf, make sure that it is configured to send voicemail notifications (and attachments as well, if you prefer) by email and that you have the send from address set properly.
If you need assistance, there are several ways to get support.
The first (and recommended) way is to post to the PhreakNet Mailing List. Somebody else may have experienced your issue and may be able to provide tips or a solution.
A second option, more suited for specific issues, is to contact the Business Office for assistance. A representative will ask you for a CLI trace. If you do this, make sure you have timestamps = yes and verbose = 3 set in Asterisk.
The Business Office is happy to assist with Asterisk issues if needed. However, a detailed trace is needed in order to assist with dialplan issues. For dialplan troubleshooting, please use PhreakScript to perform a CLI trace as follows:
phreaknet update phreaknet trace
If you use PhreakScript's trace feature, you do not need to open the CLI yourself and copy and paste the CLI output. This is handled automatically.
Follow the instructions displayed by the wizard. At the end, a URL to a paste of the CLI trace will be displayed. Then, submit a ticket to the Business Office (choose PhreakNet for Asterisk dialplan related issues, NOT Asterisk!). By default, pastes are only live for 24 hours before they are deleted. You can extend the duration online at paste.interlinked.us. You can also configure redactions here.
If your issue is TLS related in any way (and even if it's not), packet captures are likely useful. You'll want to do these from the server, e.g.:
tshark -f "not port 22 and host 1.1.1.1" -i any -w test1.pcap
Assuming you have tshark installed (apt-get install tshark), this will take a packet capture of anything not on port 22 from or to 1.1.1.1 (change this to your home IP address, or wherever you're trying to troubleshoot). This will narrow down the pcap hopefully to only the minimum needed to troubleshoot, as otherwise you will be logging thousands of packets per second. Once done, hit CTRL+C and then copy the pcap file over to your PC where you can use Wireshark to open it up graphically and inspect it.
If you have a machine with two Ethernet ports, you can also take a packet capture via port mirror. In this case, you'll want to specify the MAC address of the device on your network for which to capture all packets sent or receive. It may be something like tshark -i enp3s0 -f "ether host aabbccddeeff" -w test1.pcap
If Asterisk is crashing for whatever reason, you need to get a backtrace (use phreaknet backtrace to help with this).
It's also possible that Asterisk isn't crashing but the system is running out of memory and simply killing the process. If Asterisk is terminated mysteriously, run dmesg and see if that's the case. If it is, you will likely want to add some swap to your system (which PhreakScript can also help with).
Note: New to Asterisk? No problem — we're here to help! Simply call the business office at 811 and we'll help you get set up.
DAHDI can be more difficult to debug issues with compared to Asterisk issues, since there is a complex interaction of hardware, drivers, the kernel, and Asterisk.
Sometimes you'll encounter an issue where the system just doesn't seem to "see" your DAHDI card.
For instance, dahdi_cfg -vvvvvvvv will return an error about a missing span, and your card won't show up if you try using dahdi_tool.
Usually doing modprobe on the kernel module for the card will bring it up, e.g. modprobe wcte13xp.
You may need to do this each reboot (or automate it properly).
dahdi_cfg -vvvvvv and get line 0: Unable to open master device '/dev/dahdi/ctl'
phreaknet dahdi and try running this again.dahdi_cfg but get errors like DAHDI_SPANCONFIG failed on span 3: No such device or address (6)modprobe dahdi, you need to modprobe each of the drivers you are using, e.g. modprobe wcte13xp, modprobe wctdm, etc. If a modprobe fails, you might be using a driver that was removed at one point and isn't built by default. In this case, run phreaknet dahdi --drivers to get these drivers.Make sure your DAHDI cards are on their own, dedicated IRQ.
I once had a system where if you made a three-way call, and God forbid over an IAX2 trunk and out of the system, call quality would go straight to hell. It literally sounded like there was 80-90% packet loss. It was the complete opposite of what DAHDI should be: pristine, perfect audio — on the contrary, lots of this:
[Oct 23 20:08:52] DEBUG[24501][C-00000028]: chan_dahdi.c:9047 my_dahdi_write: Write returned -1 (Unknown error 500) on channel 1 [Oct 23 20:08:52] DEBUG[24501][C-00000028]: res_timing_timerfd.c:167 timerfd_timer_ack: Expected to acknowledge 1 ticks but got 2 instead [Oct 23 20:08:52] DEBUG[24499][C-00000028]: res_timing_timerfd.c:167 timerfd_timer_ack: Expected to acknowledge 1 ticks but got 2 instead [Oct 23 20:08:52] DEBUG[24501][C-00000028]: chan_dahdi.c:9047 my_dahdi_write: Write returned -1 (Unknown error 500) on channel 1 [Oct 23 20:08:52] DEBUG[24499][C-00000028]: chan_dahdi.c:9047 my_dahdi_write: Write returned -1 (Unknown error 500) on channel 2 [Oct 23 20:08:52] DEBUG[24501][C-00000028]: res_timing_timerfd.c:167 timerfd_timer_ack: Expected to acknowledge 1 ticks but got 2 instead [Oct 23 20:08:52] DEBUG[24499][C-00000028]: res_timing_timerfd.c:167 timerfd_timer_ack: Expected to acknowledge 1 ticks but got 3 instead [Oct 23 20:08:52] DEBUG[24501][C-00000028]: chan_dahdi.c:9047 my_dahdi_write: Write returned -1 (Unknown error 500) on channel 1 [Oct 23 20:08:52] DEBUG[24499][C-00000028]: chan_dahdi.c:9047 my_dahdi_write: Write returned -1 (Unknown error 500) on channel 2 [Oct 23 20:08:52] DEBUG[24501][C-00000028]: res_timing_timerfd.c:167 timerfd_timer_ack: Expected to acknowledge 1 ticks but got 2 instead [Oct 23 20:08:52] DEBUG[24501][C-00000028]: chan_dahdi.c:9047 my_dahdi_write: Write returned -1 (Unknown error 500) on channel 1 [Oct 23 20:08:52] DEBUG[24499][C-00000028]: res_timing_timerfd.c:167 timerfd_timer_ack: Expected to acknowledge 1 ticks but got 2 instead [Oct 23 20:08:52] DEBUG[24499][C-00000028]: chan_dahdi.c:9047 my_dahdi_write: Write returned -1 (Unknown error 500) on channel 2 [Oct 23 20:08:52] DEBUG[24501][C-00000028]: res_timing_timerfd.c:167 timerfd_timer_ack: Expected to acknowledge 1 ticks but got 2 instead [Oct 23 20:08:52] DEBUG[24501][C-00000028]: chan_dahdi.c:9047 my_dahdi_write: Write returned -1 (Unknown error 500) on channel 1 [Oct 23 20:08:52] DEBUG[24499][C-00000028]: res_timing_timerfd.c:167 timerfd_timer_ack: Expected to acknowledge 1 ticks but got 2 instead [Oct 23 20:08:52] DEBUG[24499][C-00000028]: chan_dahdi.c:9047 my_dahdi_write: Write returned -1 (Unknown error 500) on channel 2 [Oct 23 20:08:52] DEBUG[24501][C-00000028]: res_timing_timerfd.c:167 timerfd_timer_ack: Expected to acknowledge 1 ticks but got 2 instead [Oct 23 20:08:52] DEBUG[24501][C-00000028]: chan_dahdi.c:9047 my_dahdi_write: Write returned -1 (Unknown error 500) on channel 1 [Oct 23 20:08:52] DEBUG[24499][C-00000028]: res_timing_timerfd.c:167 timerfd_timer_ack: Expected to acknowledge 1 ticks but got 2 instead [Oct 23 20:08:52] DEBUG[24499][C-00000028]: chan_dahdi.c:9047 my_dahdi_write: Write returned -1 (Unknown error 500) on channel 2 [Oct 23 20:08:52] DEBUG[24501][C-00000028]: res_timing_timerfd.c:167 timerfd_timer_ack: Expected to acknowledge 1 ticks but got 2 instead [Oct 23 20:08:52] DEBUG[24501][C-00000028]: chan_dahdi.c:9047 my_dahdi_write: Write returned -1 (Unknown error 500) on channel 1 [Oct 23 20:08:52] DEBUG[24499][C-00000028]: res_timing_timerfd.c:167 timerfd_timer_ack: Expected to acknowledge 1 ticks but got 2 instead [Oct 23 20:08:52] DEBUG[24499][C-00000028]: chan_dahdi.c:9047 my_dahdi_write: Write returned -1 (Unknown error 500) on channel 2 [Oct 23 20:08:52] DEBUG[24501][C-00000028]: res_timing_timerfd.c:167 timerfd_timer_ack: Expected to acknowledge 1 ticks but got 2 instead [Oct 23 20:08:53] DEBUG[24501][C-00000028]: chan_dahdi.c:9047 my_dahdi_write: Write returned -1 (Unknown error 500) on channel 1 [Oct 23 20:08:53] DEBUG[24499][C-00000028]: chan_dahdi.c:9047 my_dahdi_write: Write returned -1 (Unknown error 500) on channel 2 [Oct 23 20:08:53] DEBUG[24501][C-00000028]: res_timing_timerfd.c:167 timerfd_timer_ack: Expected to acknowledge 1 ticks but got 2 instead [Oct 23 20:08:53] DEBUG[24499][C-00000028]: res_timing_timerfd.c:167 timerfd_timer_ack: Expected to acknowledge 1 ticks but got 2 instead [Oct 23 20:08:53] DEBUG[24501][C-00000028]: chan_dahdi.c:9047 my_dahdi_write: Write returned -1 (Unknown error 500) on channel 1 [Oct 23 20:08:53] DEBUG[24499][C-00000028]: chan_dahdi.c:9047 my_dahdi_write: Write returned -1 (Unknown error 500) on channel 2 [Oct 23 20:08:53] DEBUG[24501][C-00000028]: res_timing_timerfd.c:167 timerfd_timer_ack: Expected to acknowledge 1 ticks but got 2 instead [Oct 23 20:08:53] DEBUG[24499][C-00000028]: res_timing_timerfd.c:167 timerfd_timer_ack: Expected to acknowledge 1 ticks but got 2 instead [Oct 23 20:08:53] DEBUG[24501][C-00000028]: chan_dahdi.c:9047 my_dahdi_write: Write returned -1 (Unknown error 500) on channel 1 [Oct 23 20:08:53] DEBUG[24499][C-00000028]: chan_dahdi.c:9047 my_dahdi_write: Write returned -1 (Unknown error 500) on channel 2 [Oct 23 20:08:53] DEBUG[24501][C-00000028]: res_timing_timerfd.c:167 timerfd_timer_ack: Expected to acknowledge 1 ticks but got 2 instead [Oct 23 20:08:53] DEBUG[24501][C-00000028]: chan_dahdi.c:9047 my_dahdi_write: Write returned -1 (Unknown error 500) on channel 1 [Oct 23 20:08:53] DEBUG[24499][C-00000028]: res_timing_timerfd.c:167 timerfd_timer_ack: Expected to acknowledge 1 ticks but got 2 instead [Oct 23 20:08:53] DEBUG[24499][C-00000028]: chan_dahdi.c:9047 my_dahdi_write: Write returned -1 (Unknown error 500) on channel 2 [Oct 23 20:08:53] DEBUG[24501][C-00000028]: res_timing_timerfd.c:167 timerfd_timer_ack: Expected to acknowledge 1 ticks but got 2 instead [Oct 23 20:08:53] DEBUG[24501][C-00000028]: chan_dahdi.c:9047 my_dahdi_write: Write returned -1 (Unknown error 500) on channel 1 [Oct 23 20:08:53] DEBUG[24499][C-00000028]: res_timing_timerfd.c:167 timerfd_timer_ack: Expected to acknowledge 1 ticks but got 2 instead
The usual tips and tricks for DAHDI troubleshooting didn't bring anything up: no IRQ misses, dahdi_test passed with flying colors, and so forth.
Here's what the IRQs looked like on that machine (lspci -b -vv for even more info):
# lspci -vb | grep -B 3 -A 5 "IRQ 11"
00:1a.0 USB controller: Intel Corporation 82801I (ICH9 Family) USB UHCI Controller #4 (rev 02) (prog-if 00 [UHCI])
Subsystem: Super Micro Computer Inc 82801I (ICH9 Family) USB UHCI Controller
Flags: bus master, medium devsel, latency 0, IRQ 11
I/O ports at cc00
Capabilities: [50] PCI Advanced Features
Kernel driver in use: uhci_hcd
Kernel modules: uhci_hcd
--
Kernel driver in use: pcieport
00:1c.5 PCI bridge: Intel Corporation 82801I (ICH9 Family) PCI Express Port 6 (rev 02) (prog-if 00 [Normal decode])
Flags: bus master, fast devsel, latency 0, IRQ 11
Bus: primary=00, secondary=03, subordinate=03, sec-latency=0
I/O behind bridge: 0000e000-0000efff
Memory behind bridge: fea00000-feafffff
Prefetchable memory behind bridge: 0000000400400000-00000004005fffff
Capabilities: [40] Express Root Port (Slot+), MSI 00
--
01:00.0 Network controller: Digium, Inc. Wildcard TE133 single-span T1/E1/J1 card (PCI Express) (rev 02)
Physical Slot: 0
Flags: bus master, fast devsel, latency 0, IRQ 11
Memory at fe8e0000 (32-bit, non-prefetchable)
Capabilities: [40] Power Management version 3
Capabilities: [48] MSI: Enable+ Count=1/1 Maskable- 64bit+
Capabilities: [58] Express Endpoint, MSI 00
Kernel driver in use: wcte13xp
--
02:00.0 Ethernet controller: Intel Corporation 82574L Gigabit Network Connection
Subsystem: Super Micro Computer Inc 82574L Gigabit Network Connection
Physical Slot: 0-1
Flags: bus master, fast devsel, latency 0, IRQ 11
Memory at fe9e0000 (32-bit, non-prefetchable)
I/O ports at dc00
Memory at fe9dc000 (32-bit, non-prefetchable)
Capabilities: [c8] Power Management version 2
Capabilities: [d0] MSI: Enable- Count=1/1 Maskable- 64bit+
Yeah, you definitely don't want your T1 card sharing an IRQ with your Ethernet card.
Inward operators function much as they do/did on the PSTN. While the network operator will be able to help with most dialing difficulties, a network operator may occasionally have need to request the assistance of a particular exchange's inward operator, in order to diagnose line difficulties or complete calls.
All node owners may appoint and allocate any destination as the inward operator for some particular numberspace that they own.
The exchange owner with the largest ownership share of an office code (NNX code) will be granted rights to the incumbent/primary routing of that code. Additional inward operators will be reachable by also including a routing code to bypass the main NNX and connect to a different exchange's inward operator.
Inward operators are not intended to be reachable by ordinary dialing procedures / regular subscribers. This means that local inwards on each exchange will be able to reach other inwards, through non-public dialing mechanisms, but hosted users, for example, would not be able to reach inwards.
There are semi-public and non-public routings used on the network. Semi-public routings are those that, in theory, anyone on the network with an Asterisk tandem could reach. Non-public routings are those restricted to access only by the local inward on that switch and a network operator. Other inwards would not be able to access these.
The routings are set up in a way to mirror how routing used to work.
Below are some examples of each:
**In most cases, the "+" above means that the sequence could be sent all at once or broken into multiple stages of keying (e.g. KP + NXX + ST. KP + 121 + ST *OR* simply KP + NXX 121 + ST).
As the examples above illustrate, the mechanism by which routing works is essentially quite recursive.
The "primary" NNX belongs to the first NNX-X office code is assigned, regardless of which thousand block it is. These NNX routings will work automatically — there is no need to set anything additional up. NXX-0XX routings (routing codes / terminating toll center codes) do require additional manual setup:
***Technically it does, but not in a way that is used for routing NNX-XXXX. The immediate route used to get there (NNX or NXX0XX) is present in the dialed IAX variable (on the PSTN, 0XX would go to a different switch, but if you had another inward hosted, you'd get both kinds and might want to differentiate here). This variable is not made use of by default, but if, say, you wanted to put up a different "Milliwatt tone" on one "switch" versus another (on the same server), or know which NXX was called when an inward station is rung, this would allow you to do that. Anyways, think of ${IAXVAR(dialed)} not as digits being sent to you but which "trunk group" a call came in on, allowing you to tell what exchange this is for, if that matters to you.
Also note that due to the way things are set up, supposing NNX is Tandem A, there is a difference between NNX-0XX routing to Tandem B as opposed to a hosted operator on Tandem A. Say NNX-0XX is supposed to go to inward "C". If NXX-0XX goes to Tandem B, things work as one would expect. NNX-0XX+121 will reach Tandem B's inward operator, as will NNX-0XX-121. If NNX-0XX goes to Tandem A, it will not be initially discernible from a routing directly to NNX on Tandem A (or any of its other NNX codes, for the matter, if any). Thus, NNX-0XX+121 will actually ring Tandem A's main inward operator, since NNX-0XX and NNX actually route to the same server. (Technically, the node operator could make some changes to get around this). However, NXX+0XX-121 would likely work as intended (as would NXX-0XX+0XX-121 for that matter, and possibly NXX+0XX+121, depending on how trunks are configured). A note is made about this in phreaknet-inward-semipublic in the boilerplate code. The point is, there is a small technical difference in how routings work when "two-stage" keying is used as opposed to sending them all at once, and if weird things happen with the latter, two-stage keying will probably give the intended route.
For all practical purposes on a network of this size, 121, 131, 141, 151, and 161 at most exchanges will likely all go to the same thing. However, some exchange operators may choose to break things out further, and this enables them to do so.
The basic idea is that, starting from the beginning, NNXs and 0XXs will route around the network. A 1XX code is required to do anything "useful", such as ringing an inward station, for example.
The examples above assume that NNX-XXXX is actually a subscriber line on that switch. If it isn't, the operation will fail. Thus, 555 + 127 + 231-2368 would succeed only if the routing codes 555 and 231 went to the same exact place, in which case it doesn't matter which one is used for the first three digits.
***As you can see, there is a bit of an art here to routing and using these codes, as it truly is dialing "instructions" that may differ depending on what point A is, what point B is, and how you want to get from point A to point B. There are many ways to do things and slight nuances to routing around. Complex routings are probably not very useful, but can be helpful if needed for testing. You could try to tandem stack through operator trunks like in the 60s, but it would probably be more exciting to key NXX + 121 + ST, have an inward connect you to another inward, and then keep repeating them, building a stack through real operator equipment (e.g. cordboards, etc.). Simply keying a long route is unlikely to get you much besides tons of packet loss.
Routing around the network to a non-public destination is not possible, because "routing around" arrives in incoming trunk groups with semipublic permissions only. For instance, 555 + 231 + 121 would reach the 231 inward, but 555 + 231 + 127 + 231-1234 would *not* successfully busy line verify 231-1234 (directly doing 231 + 127 + 231-1234 would, but only if done by a network operator). The 231 local inward would just access an inward trunk on his/her switch and do 127 + 231-1234 directly, since s/he wouldn't need to route to his own switch first.
The sample extension *12 is used in the boilerplate code as a potential code for accessing inward trunks (a Touch-Tone phone is required). This is freely changeable per each exchange operator's discretion and has no impact on anything else, since it is only used for his local access to his own inward trunk context.
The "billing" functionality is purely for fun. The idea is to show you all the calls you make and what they would have cost back in the 1970s, purely for fun and educational purposes. The bill is for fun, and you are not actually charged anything. Nodes participate in this system voluntarily and with little overhead on their part. The code necessary to generate the necessary "toll tickets" is part of the basic boilerplate code. Once a user has made a call from his or her telephone, he or she can login to the member portal to view a mock bill containing calls made within the past 30 days.
If you have made any calls from any of the numbers listed here via a node participating in the billing system, your calls are automatically ticketed. A charge is issued for all completed calls based on the time and day when the call was made, the caller and the callee and the distance between them, and how the call was completed. This means calls during the day will cost more than calls in the evening or on weekends, calls completed to nodes further away will cost more than those to nearby nodes, and calls completed with the assistance of an operator will cost more than those completed without.
All of the rates on the network are based on those issued with the Bell System's 1977 issue of its "Phone Thing", which was distributed to many customers in the late 1970s. If you have one of the originals, it will accurately tell you the cost of all of your calls! Haven't one? Fear not! Print out the document linked above and assemble your own helpful dialing aid. You should be able to accurately predict the rate you will be charged based on the information in the "Phone Thing".
For the most part, the "Phone Thing" will accurately provide rate information. Designed for interstate phone calls on the PSTN, it applies whenever "long distance" calls occur — that is, calls between a node and any other. A few exceptions exist to this otherwise completely accurately simulated billing model exist: local calls are all charged a $0.05 fee and use 1 message unit in the process (to not charge message units, simply do not ticket the call for such calls). In some locales, such as New York City, local calls were not free and used message units; therefore, this is not explicitly unrealistic. Furthermore, all "international calls" to nodes outside of the U.S., as well as calls that involve any international call, are billed at a rate higher than that assessed when placing a continental call of the maximum distance possible. Specifically, international calls are $1 for the first minute and $0.50 for each subsequent minute, if dialed directly during "peak" (full rate) hours. As the "Phone Thing" dictates, a 35% of 60% discount applies during select hours. Calls to special numbers that contain fewer than 7 digits (e.g. 0, 11N, N11, and 958/959, as well as 660+) are not ticketed and are thus completely free. Such calls will not appear on your bill.
The time used when issuing charges is determined by the time zone of the caller. Make sure it's correct in the user portal when you log in. Additionally, make sure that all numbers from which you originate calls are in the White Pages. If you don't want to make listings public, you don't have to, but adding them here is important for many different components of network functionality.
If you have multiple numbers used to make calls, a bill is generated for each number.
As stated before, this entire operation is purely for fun. The rates reflect the value of the dollar during that era; therefore, accounting for inflation, their actual impact would be much greater. However, consider the charges on your billing statement to be an accurate reflection of the cost of your telephone calls — in the late 1970s!
ZEnith numbers are the predecessor to toll-free numbers. Calls to ZEnith numbers are basically "automatic collect" calls. These calls must be placed through the operator. You cannot dial them yourself. If you'd like a ZEnith number, simply fill out the ZEnith translation reservation form in the user portal.
PhreakNet has a set of standards to which all members are highly encouraged to adhere. Doing so ensures the network operates reliably and smoothly for everyone with an enjoyable experience for all.
New functionality and standards are driven by new and changing network goals and requirements. Such standards are ultimately determined by administration, with input solicited from the community with Requests For Comments during planning periods. Community input is always welcome and encouraged. Administration will direct standards per network requirements on behalf of and in response to the community.
Although this list is inevitably incomplete, here are a few important recommended standards:
Dial().PhreakNet provides a series of APIs for member usage. All APIs use the GET method. Overall usage is counted but PhreakNet API calls are not metered.
The routing and verification APIs are two sides of the same API. On an inbound call, it functions as a verification API. On an outbound call, it functions as a routing lookup API (with some additional out-verification options). Blacklist integration is also built into the API
The HTTP API endpoint is https://api.phreaknet.org/v1/.
Arguments:
m (MF), s (SF), t for StepNet routing and o for (~inward) operator routing:
a — ACTS trunk (coin phones only)
c — Coin Zone trunk (coin phones only)
m — MF signaling
t — StepNet routing. Route the call using StepNet instead of directly peer-to-peer, if possible. (Side note: The boilerplate code is configured to fallback to StepNet if a regular subscriber-dialed call fails the first time, for any reason. The reason for this is that sometimes, for strange bizarre reasons we haven't figured out, Node A cannot call Node C directly but most other nodes can reach Node C and Node A can reach most other nodes. Thus, Node A → Node B → Node C works even though Node A → Node C directly fails due to "congestion". Thus, tandeming through another node (e.g. a la StepNet) usually fixes this issue and can increase call completion rates.)
o — Operator routing. Changes the mode by enabling operator routing. This flag should never be used on anything publicly accessible by "subscribers"/users, local or from the outside. It is only intended to allow each exchange's local inward operator to access operator routings, in a separate isolated context.
s — SF signaling
number for inbound verification.
The following arguments are applicable only to usage for verification purposes:
For outbound routings, the API returns the dial string routing for the call, optionally prefixed by a verification token if instructed, in which case ~ is used as a delimeter. The API is used even for configuring RSA calls, in order to obtain the IAX2 secret for the call.
For inbound verification, the API returns a 2-digit CVS (Caller Verification Status) code based on the arguments provided. If the CVS code 78 is returned, the call is blacklist per the desired threshold and the call should be immediately dropped. Otherwise, normal call progress may continue.
This API is not designed to be used manually within the dialplan. The provided wrappers part of the verification subroutines should be used to interface with this API (that is, used as a public API to this semipublic API). Otherwise, unexpected behavior may occur.
The RSA API allows you to download the RSA public key of another PhreakNet node.
The HTTP API endpoint is https://api.phreaknet.org/v1/rsa.
Arguments:
The API returns the public key if one is available or a 404 response if not.
The Directory Availability API allows you to programatically add directory listings to the General Directory (not available for White Pages).
The HTTP API endpoint is https://api.phreaknet.org/v1/directoryadd.
Arguments:
The API returns 1 if your rule is successfully updated and 0 if not.
The Directory Availability API allows you to programatically update your directory availability rule.
The HTTP API endpoint is https://api.phreaknet.org/v1/directoryrule.
Arguments:
The API returns 1 if your rule is successfully updated and 0 if not.
The blacklist API is a standalone API that can be used for screening calls. Blacklist functionality is part of the main routing API, so generally there isn't a need to use this API on its own, but if you wish to, you may (e.g. this would allow you to use it for other calls not arriving through PhreakNet).
The HTTP API endpoint is https://api.phreaknet.org/v1/blacklist.
Arguments:
The API returns a float score (e.g. 1.5) between 0 and 3, allowing you to make a determination based on the score and your needs. Scores correspond to:
The billing API is used to insert billing tickets into the toll ticketing system. This is used to generate mock bills that you can view anytime in the member portal. There are no actual charges that are due — this is purely a fun and educational way to see what your calls would have cost in 1977. The charges are accurate based on the distance between members in the U.S. International calls are billed at a higher rate than the most expensive domestic call, but at an arbitrary value.
This API is called programatically in the dialplan automatically, never manually.
The HTTP API endpoint is https://api.phreaknet.org/v1/billing.
Arguments:
Other non-public parameters exist to handle coin calls. Third number billing uses the public parameters.
The API returns 0 if the ticket was processed and non-0 otherwise. Note that this does not necessarily constitute user error — free calls (like Operator) will not be ticketed. Likewise, if the answered duration is 0, the call will not be ticketed. This closely mirrors the way that electromechanical switches handled billing of toll calls. Calls that never supervised were never ticketed.
The CNAM API allows for free CNAM dips for PhreakNet numbers. It can be used in lieu of the ${CALLERID(name)} that might be set on an incoming call, particularly if you want to see who is actually calling you (as opposed to, say, "Living Room Phone"). This is only for PhreakNet CNAM dips (not PSTN CNAM, etc.).
The HTTP API endpoint is https://api.phreaknet.org/v1/cnam.
Arguments:
The API returns an uppercase maximum 15-character CNAM string, to be universally compatible with CPE. The CNAM API uses the White Pages, Directory, and route table in that order of preference to generate CNAM data.
The time zone API allows retrieving the time zone associated with a PhreakNet number. The algorithm used is similar to that used for the CNAM API. This allows you to set up your own time-based service number on the network and provide callers with the correct information based on their individual time zones. This is the same API used by network time services.
The HTTP API endpoint is https://api.phreaknet.org/v1/tz.
Arguments:
The API returns a tz-format time zone or an empty result if no time zone could be determined, allowing you to handle the default case.
The ZIP code API allows you to retrieve information about any ZIP code.
The HTTP API endpoint is https://api.phreaknet.org/v1/zip.
Arguments:
city, state, county, areacode or timezone.
The API returns the requested property for the provided ZIP code.
The NPA API allows you to retrieve the geographic NPA of U.S. PhreakNet numbers.
The HTTP API endpoint is https://api.phreaknet.org/v1/npa.
Arguments:
The API returns the NPA for U.S. numbers.
The Distance code API allows you to retrieve the distance, in miles, between two U.S. PhreakNet numbers.
The HTTP API endpoint is https://api.phreaknet.org/v1/distance.
Arguments:
The API returns a float containing the precise distance between the two ZIP codes associated with the provided numbers. An empty response is returned for calls involving unallocated or international numbers.
The Local API returns information about exchanges that are local to a PhreakNet caller.
The HTTP API endpoint is https://api.phreaknet.org/v1/local.
Arguments:
The API returns a JSON response containing local NNX-X exchanges and their city, state, and country.
The Local API returns whether a call between two PhreakNet numbers is considered "local" or not for the purposes of billing.
The HTTP API endpoint is https://api.phreaknet.org/v1/islocal.
Arguments:
The API returns 1 if the call is local or free (no-charge) and 0 if it would be considered a toll call.
The PSTN local call tells you if a call between two NPA-NXXs is local or not.
The HTTP API endpoint is https://api.phreaknet.org/v1/npanxx.
Arguments:
The API returns N if a call is not local and Y if it is or otherwise.
The existence API tells you if a subscriber-dialed number exists or not.
The HTTP API endpoint is https://api.phreaknet.org/v1/exists.
Arguments:
The API returns 1 if a number exists and 0 otherwise.
The Rates API provides detailed rate information for a call between points A and B on the network and may be used to obtain current rate information for any type of call.
The HTTP API endpoint is https://api.phreaknet.org/v1/rates.
Arguments:
The API returns a JSON response with the following data:
The Telegram API allows you to retrieve a ticker stream of a telegram you have sent or received.
The HTTP API endpoint is https://api.phreaknet.org/v1/telegram.
Arguments:
The API returns an ASCII ticker string for the telegram, suitable for feeding into a telegraph for transmission.
The Cisco Phone Directory API allows you to import PhreakNet White Pages entries into a Cisco IP phone or compatible device's contacts.
The HTTP API endpoint is https://api.phreaknet.org/v1/cisco.
Arguments:
The API returns a XML file containing the directory.
If there's an API that you'd like to see that doesn't exist yet, post to the list to discuss. Maybe others were looking for the same thing.
PhreakNet uses a number of standardized dialplan and IAX variables. Their names and purposes are described below:
| Scope | Dialplan variable | IAX variable | Name | Purpose | Set Conditions | Valid Values | |
|---|---|---|---|---|---|---|---|
| Global | interlinkedkey | — | InterLinked API Key | Contains tandem owner's InterLinked API key | N/A | 32-char API key | |
| Global | clli | — | CLLIUnique switch CLLI for identification | ||||
| Global | mainphreaknetdisa | nodevia | Main DISA | Contain's a 7-digit # routing to that node | N/A | 7-digit PhreakNet number on node | |
| Channel | clidverif | clidverif | Caller Verification Status code | Contains caller's originating network and verification status | Verification Subroutines | 2-digit CVS code (see Verification). | |
| Channel | mlppdigit | mlpp | Call Priority | Contains call precedence | MLPP/AUTOVON routines | A, B, C, D, 0 | |
| Channel | ssverstat | ssverstat | STIR/SHAKEN | Contains validation/attestation disposition | A, B, C, D, E, F |
By their very nature, global variables are static.
Variables will be added as they are needed for network features. All channel variables listed above should be rewritten if calls are regenerated in order to maintain proper channel state (if you are not doing complicated things in your dialplan using ConfBridge(), you probably don't need to worry about this).
All nodes should aim for 100% correct supervisory status at all times for network compliance purposes. This includes supervising on billable/chargeable calls and not supervising when it is not appropriate (e.g. test numbers, intercept recordings, operator services, etc.).
The most common way to avoid providing false supervision when it is not desired is by using the noanswer flag for Playback() when needed, as follows: same => n,Playback(myaudio,noanswer) — however, note that, to avoid audio passthrough issues, you should use a Progress() statement on calls where there is not immediate answer supervision to allow audio to pass through, e.g:
exten => s,1,Progress() ; allow audio pass through before supervision same => n,Playback(myaudio,noanswer) ; play without supervising same => n,Answer() ; NOW answer the call same => n,Playback(myaudio2) same => n,Hangup()
In other words, you should always explicitly begin with a Progress() or an Answer(). We do not recommend relying on implicit supervisory functions of Asterisk applications like Playback().
If your dialplan is already littered with simple Playback commands, you can use the following RegEx in Notepad++'s find and replace feature to locate Playback() statements that don't have the noanswer switch: ^(?!.*noanswer).*Playback.*$
Our friend Read() also provides answer supervision by default. The n option can be used to disable this, e.g. Read(number,custom/file,7,n).
Also note that the revertive pulsing script provides false supervision (which is NEVER desired). You must manually patch this script as described in the Revertive Pulsing section. If you do not patch this script, you should not use it. Inpulsing and outpulsing should never supervise.
Finally, advanced dialplan code may involve the ConfBridge() application where it is desired not to supervise. You should use the answer_channel=no user option to prevent ConfBridge() from automatically answering.
PhreakNet has a number of "NP Intercept" codes. These codes are integrated into the route table and are not provided by end offices or Class 4 tandems. (Thus, these codes should not be used by member nodes, but members may be interested in what these codes mean and what codes exist.)
These codes are manually dialable in the 231-90XX range.
| Code | Function | Usage | |
|---|---|---|---|
| 41 | Nonworking Operator Route | Invalid operator routing | |
| 53 | Authentication Failure | CRTC/Route table authentication failed, call redirected to intercept | |
| 54 | Unsupported Protocol | Non-IAX2 protocol in use. | |
| 55 | Feature Group D Code Change | You know, "If you dialed a 5 digit code, it has changed " - that one. | |
| 57 | Centralized Intercept | Non-assigned number is dialed (number not in service) | |
| 58 | Permanent Signal | No number is dialed | |
| 59 | Invalid Number | Invalid lookup request | |
| 66 | Call Quarantined | Malicious call quarantine | |
| 77 | Inclement Weather | Destination tandem is unavailable due to weather-related conditions | |
| 88 | Facility Trouble | Destination tandem is unavailable due to non-local facility trouble | |
| 89 | Non-Provisioned Number | Assigned but unprovisioned number dialed | |
| 90 | Invalid Code | Invalid NP Code |
Member nodes may take advantage of network centralized intercept services if they do not wish to provide their own. To do so, perform a lookup for a non-assigned network number and note the format (57 + the dialed #). In the dialplan, adjust your pattern matching such that the dialed number is suffixed to the 57 extension prefix. If no number can be provided, 57 alone is sufficient.
ANI II (pronounced "A-N-I two or Annie two") digits provide information about the type of originating line, call routing, and class of service. They are used on the PSTN for a variety of purposes. They provide additional information to downstream nodes about the nature of the call being received.
For the sake of consistency, the ANI II codes used on the network mirror their PSTN counterparts where relevant or possible. However, the exact usage of many codes is slightly different.
| Code | Purpose |
|---|---|
| 00 | Normal subscriber line (implied) |
| 01 | Multiparty line |
| 02 | ANI failure |
| 27 | Network controlled payphone |
| 34 | Operator-assisted |
| 60 | TRS call (unrestricted) |
| 61 | IMTS (Improved Mobile Telephone Service) |
| 67 | TRS call (restricted) |
| 70 | Non-network controlled payphone (e.g. COCOT, Charge-A-Call) |
ANI2 if conveyed using ${CALLERID(ani2)}, which transmits natively over IAX2 trunks. No special variables are required.
A few words about the PhreakNet numbering plan:
For the most part, PhreakNet adheres to the traditional NANPA guidelines as they were originally set. This means that although NXX office codes exist today in the PSTN in the U.S., only NNX office codes are allowed on PhreakNet.
PhreakNet does not use country codes. Any node anywhere in the world on the network can be dialed with just 7 digits. This was an intentional decision made in order to make all nodes seem "local" and not "far away". Dialing more than 7 digits can discourage others from dialing a destination. This was a decision reached to better the network's experience for everyone.
Another dialing option is to dial 1+ for long-distance call. Dialing 1 + 7 digits will route your call over 2600 Hz-controlled trunks to the destination. The call goes to the same destination as if you had dialed it using 7 digits, but using a 2600-Hz controlled trunk, so now you can use your blue box on the call if you like.
In addition to that, PhreakNet has Feature Group B (950-WXXX) and Feature Group D dial-around codes (101XXXX). At this time, a public listing of these carrier access codes is not available.
Note that 10[02-9]XX represents former Feature Group D codes. These codes are part of the PhreakNet dial plan and will be routed to the appropriate intercept.
Any regular (NNX) calls dialable as 7 digits may also be dialed as 0+7D or 1+7D. 0+7D will complete the call through TSPS. 1+7D will complete the call over a 2600 Hz trunk which can be blue boxed.
976 exchange numbers are premium-rate numbers charged at a premium rate.
Furthermore, there are special numbers on PhreakNet, such as the following operator and directory services:
Other directory services include:
Finally, network-wide test numbers include:
To avoid confusion, we will use "Directory Assistance" to refer to 411 and 555-1212, which go first to a human operator and then to an automatic one if none is available and "Information" to refer exclusively to 113, which is our automated directory service.
Other special NXX/NXX codes include 101 (Feature Group D), 950 (Feature Group B), 976 (premium rate), 973 (mobile telephone service), and 555 (fictitious numbers).
Calls to 555-1212 route over a specially emulated "#5XB automatic call distributor" trunk. It works the way that Bill Acker described in 2014. You'll need a silver box, such as that found at PhreakNet in order to drop into maintenance mode on this trunk.
The following is a list of standardized station numbers (the last 4 digits of NNX-XXXX). If you use any of the following, you are highly encouraged to adhere to the following numbering conventions, assuming the "1" and "9" thousand blocks are allocated to you (if not, you may wish to consider allocating X9xx extensions as such instead). Being in compliance ensures that all users can expect a consistent experience across most exchanges. If your node is not in compliance, it is especially important any numbers similar to the following are published in the directory. If your node is in compliance, it is up to you whether you feel it necessary to publish these extensions in the network directory.
"0041" → Loop Around Side A"0042" → Loop Around Side B"1111" → Switch DISA"9900" → Milliwatt"9901" → Switch Verification"9906" → Milliwatt Synchronization"9922" → DTMF Test"9931" → Echo Test"9932" → Silent Termination"9941" → Switch Telephone"9945" → Milliwatt"9950" → Business Office"9960" → Milliwatt"9970" → Busy"9971" → Reorder"9972" → Supervision Test"9979" → Tone Sweep (Loop Checker/Loop Check Generator)"9990" → Ringout"9996" → Loop Around Side A"9997" → Loop Around Side BThe 99XX numbers here are called "Official" numbers. For example, 9901 is "Official 01". The "Official" numbers you see above are factually accurate and reflect Evan Doorbell's experiences in the greater New York area. The only non-"Official" number above is 1111, for ease of access. NNX-9941 is also a modern, rather than historical, convention. While NNX-9990 was used historically as the number to reach the switch telephone, since 9941 is already reserved for that purpose, 9990 is generally reserved for ringout tests (i.e. ring, no answer). While NNX-9901 used to commonly go to an actual verification operator, today the number usually provides basic switch information; nevertheless, the name "switch verification" has stuck.
Since echo tests and DTMF tests were not common in the old network, we have settled on sensible numbers here which have no historical basis.
In Asterisk, there are a lot of ways to do the same thing. Some ways are simpler than others, and newer functions allow for much simplification of dialplan code. These optimizations will result in some ever-slight performance increases, and most importantly will make your dialplan easier to read.
Here are some basic rules that can get you started. These rules can be plugged right into Notepad++ "Find in All Files" with "Regular expression" as the mode. Line 1 is the Find, Line 2 is the Replace. Or, to simply find matches using grep, you can use grep -P 'expression' *.conf (make sure to use single quotes, not double quotes, and either grep -P or grep -E, but not grep -e, should work.
The easiest to run all of these tests is to use PhreakScript. Simply type phreaknet validate and PhreakScript will test your dialplan for common problems. We recommend that you manually fix any problems that the tool may find, but the below regular expression would allow you to automate this step.
"${var}"="" into ISNULL check
"\${(.*?)}"=""
${ISNULL\(${$1}\)}
"${var}"!="" into EXISTS check
"\${(.*?)}"!=""
${EXISTS\(${$1}\)}
\$\[\${ISNULL\(([^&]*?)\)}\]
\${ISNULL\($1\)}
\$\[\${EXISTS\(([^&]*?)\)}\]
\${EXISTS\($1\)}
${SHELL(curl "url")} with ${CURL(url)}. This won't replace SHELL calls that curl a URL but also pipe to other commands.
\${SHELL\(curl "(.*?)"\)}
\${CURL\($1\)}
ExecIf($[${condition}]?Return(true):Return(false)) with Return(${IF($[${condition}]?true:false)}).
ExecIf\(\$\[(.*?)\]\?Return\((.*?)\):Return\((.*?)\)\)
Return\(\${IF\(\$\[$1\]?$2:$3\)\}\)
ExecIf($[${cond}]?Return(something)) with ReturnIf(${cond}?something).
ExecIf\(\$\[(.*?)\]\?Return\((.*?)\)\) ReturnIf\(\$\[$1\]?$2\)
ExecIf(${cond}?Return(something)) with ReturnIf(${cond}?something).
ExecIf\(\$\{(.*?)\}\?Return\((.*?)\)\)
ReturnIf\(\$\{$1\}?$2\)
ExecIf(${cond}?Return) with ReturnIf(${cond}?).
ExecIf\(\$\{(.*?)\}\?Return\)
ReturnIf\(\$\{$1\}?\)
ExecIf($[cond]?Return) with ReturnIf(${cond}?).
ExecIf\(\$\[(.*?)\]\?Return\) ReturnIf\(\$\[$1\]?\)
Return(${IF(${cond}?1:0)}) with Return(${cond}). Run AFTER the above find/replace.
Return\(\${IF\((.*?)\?1:0\)\}\)
Return\($1\)
ExecIf\(\$\[(.*?)\]\?([A-Za-z]+)\((.*?)\):\2\((.*?)\)\)
$2\(\$\{IF\($\[$1\]?$3:$4\)\}\)
The following rule will identify invalid branching syntax caused by not surrounding functions in an expression (if this matches anything, you probably have syntax errors):
If\(\$\{(.*?)&(.*?)\}\?
Here is another common syntax error, caused by forgetting the priority 1 before the application:
exten => ([*#\[\]a-zA-z0-9]*?),[^1]
This will find applications that are not closed, if they are followed by a comment:
=> (.*?),([1n]),(.*?)\(([^\)]*) ; => ($1),($2),($3)\(($4)\) ;
If you are still using the (now deprecated) pre-release LOOKUP function, you can replace it with EVAL_EXTEN:
The first find/replace will replace the special lookup priorities with regular extensions that EVAL_EXTEN uses. The second pair will replace the LOOKUP function calls with EVAL_EXTEN.
exten => (.*?),lookup,(.*)
exten => ($1),1,Return\(($2)\)
\$\{LOOKUP\((.*?)@(.*?)\)\}
\$\{EVAL_EXTEN\(($2),($1),1\)\}
SUBROUTINES ONLY: Replace global channel variables with local channel variables, where appropriate!
\,Set\(([A-Za-z]+)= \,Set\(LOCAL\(($1)\)=
NOTE: The first regex does not work with comments. The second regex above does not work for nested LOOKUPs. You should use this to help in migration, but do not blindly run a Find+Replace All Files without knowing what your codebase is like. These are more intended to allow you to quickly manually replace these.
Additionally, the regex above does not find LOOKUPs that are used with functions such as CUT.
Other structural optimizations, many made possible by (merged) PhreakNet patches to Asterisk:
If you have the full suite of unofficial PhreakNet patches, not yet merged into Asterisk, below are further optimizations/simplifications:
One general rule of thumb is if you have lots of System() calls in your dialplan, and in particular, lots of System(asterisk -rx 'command') calls, you are likely doing something wrong or at least inefficiently when there is a better way to do whatever you are trying to do.
Familiarize yourself with the list of applications and functions in Asterisk, especially as new stuff is added. The documentation will explain usage, but being aware of what functions exist to do what will generally help lead you down the right path.
Sometimes, a custom module/application/function in Asterisk makes sense. You can write one yourself, or contact us and see if we can write it for you.
The following are useful supplements to your Asterisk system:
To replace Asterisk's default Allison Smith voice prompts with "vintage" Pat Fleet prompts, run the following:
cd /var/lib/asterisk/sounds/en
rm -f *
rm -rf dictate
rm -rf digits
rm -rf followme
rm -rf letters
rm -rf phonetic
rm -rf silence
cd /
wget https://github.com/hharte/PatFleet-asterisk/archive/master.zip
unzip PatFleet-asterisk-master.zip -d /var/lib/asterisk/sounds/en
rm -f PatFleet-asterisk-master.zip
Note that not all Allison Smith prompts are currently replicated as Pat Fleet prompts. To only overwrite the ones that weren't redone by Pat, don't run the delete commands.
If the code above doesn't work for any reason, just know that the files and folders in /var/lib/asterisk/sounds/en should be replaced with those in the ZIP file, with the exception of the custom subdirectory which contains your custom recordings!
n or a d to /var/lib/asterisk/sounds/en/custom/digits/. You may need to create this directory./var/lib/asterisk/sounds/en/custom/ais/. You may need to create this directory.extensions.conf:
[ais7] ; PhreakNet 20190212 NA
exten => start,1,Set(LOCAL(num)=${ARG1})
same => n,Playback(custom/digits/${num:-7:1}n,noanswer)
same => n,Playback(custom/digits/${num:-6:1}n,noanswer)
same => n,Playback(custom/digits/${num:-5:1}d,noanswer)
same => n,Playback(custom/digits/blank,noanswer)
same => n,Playback(custom/digits/${num:-4:1}n,noanswer)
same => n,GotoIf($[${num:-3:3}=000]?thousand)
same => n,Playback(custom/digits/${num:-3:1}n,noanswer)
same => n,Playback(custom/digits/${num:-2:1}n,noanswer)
same => n,Playback(custom/digits/${num:-1:1}d,noanswer)
same => n,Return()
same => n(thousand),Playback(custom/ais/thousand,noanswer)
same => n,Return()
[aisnis] ; PhreakNet 20190212 NA
exten => start,1,Playback(custom/ais/clunk,noanswer)
same => n,Playback(custom/ais/numreach,noanswer)
same => n,Gosub(ais7,start,1(${ARG1}))
same => n,Playback(custom/ais/notinservice,noanswer)
same => n,Playback(custom/ais/pleasecheck,noanswer)
same => n,Playback(custom/ais/dialagain,noanswer)
same => n,Playback(custom/digits/blank,noanswer)
same => n,Return
[aischanged] ; PhreakNet 20190212 NA ; This requires an argument with the new number
exten => start,1,Set(LOCAL(num)=${ARG1})
same => n,Set(LOCAL(newnum)=${ARG2})
same => n,Verbose(AIS Number Changed -- "${num}")
same => n,Playback(custom/ais/clunk,noanswer)
same => n,Playback(custom/ais/numreach,noanswer)
same => n,Gosub(ais7,start,1(${num}))
same => n,Playback(custom/ais/hasbeenchanged,noanswer)
same => n,Playback(custom/ais/newnumberis,noanswer)
same => n,Gosub(ais7,start,1(${newnum}))
same => n,Playback(custom/ais/pleasemakenote,noanswer)
same => n,Playback(custom/digits/blank,noanswer)
same => n,Return
[aisnpachanged] ; PhreakNet 20190212 NA ; This requires an argument with the new number
exten => start,1,Set(LOCAL(oldnum)=${ARG1})
same => n,Set(LOCAL(newnum)=${ARG2})
same => n,Verbose(AIS Number Changed To Different NPA -- "${oldnum}")
same => n,Playback(custom/ais/clunk,noanswer)
same => n,Playback(custom/ais/numreach,noanswer)
same => n,GoToIf($[${oldnum}=nonum]?changed)
same => n,Gosub(ais7,start,1(${oldnum}))
same => n(changed),Playback(custom/ais/hasbeenchanged,noanswer)
same => n,Playback(custom/ais/newnumberis,noanswer)
same => n,GoToIf($[${LEN(${newnum})}=7]?seven)
same => n,Playback(custom/ais/area,noanswer)
same => n,Playback(custom/digits/${newnum:-10:1}n,noanswer)
same => n,Playback(custom/digits/${newnum:-9:1}n,noanswer)
same => n,Playback(custom/digits/${newnum:-8:1}d,noanswer)
same => n,Playback(custom/digits/blank,noanswer)
same => n(seven),Gosub(ais7,start,1(${newnum}))
same => n,Playback(custom/ais/pleasemakenote,noanswer)
same => n,Playback(custom/digits/blank,noanswer)
same => n,Playback(custom/ais/numreach,noanswer)
same => n,Playback(custom/ais/hasbeenchanged,noanswer)
same => n,Playback(custom/ais/newnumberis,noanswer)
same => n,GoToIf($[${LEN(${newnum})}=7]?seven2)
same => n,Playback(custom/ais/area,noanswer)
same => n,Playback(custom/digits/${newnum:-10:1}n,noanswer)
same => n,Playback(custom/digits/${newnum:-9:1}n,noanswer)
same => n,Playback(custom/digits/${newnum:-8:1}d,noanswer)
same => n,Playback(custom/digits/blank,noanswer)
same => n(seven2),Gosub(ais7,start,1(${newnum}))
same => n,Playback(custom/ais/pleasemakenote,noanswer)
same => n,Playback(custom/ais/dialagain,noanswer)
same => n,Playback(custom/digits/blank,noanswer)
same => n,Return
[aisworking] ; PhreakNet 20190212 NA
exten => start,1,Playback(custom/ais/clunk,noanswer)
same => n,Playback(custom/ais/numreach,noanswer)
same => n,Gosub(ais7,start,1(${ARG1}))
same => n,Playback(custom/ais/isworkingnum,noanswer)
same => n,Playback(custom/ais/willdialagainplease,noanswer)
same => n,Playback(custom/digits/blank,noanswer)
same => n,Return
[KLondike5] all your 555 extensions here include => invalidincomingNow, tweak your code so it is as follows:
[KLondike5]
all your 555 extensions here
include => KLondike5-unmatched
[KLondike5-unmatched]
exten => _XXXX,1,Gosub(aisnis,start,1(${OC1}${EXTEN:-4}))
same => n,Hangup()
Now, any time anyone calls a 555-XXXX number that doesn't exist, he will hear AIS instead of CBCAD!
An important technical footnote is necessary here: if you have multiple office codes, you will need a separate AIS "catch" context for each of them. The reason for this is that by the time a call hits [KLondike5], only the last 4 digits have been sent to that context, meaning the [KLondike5] context has no idea what office code was dialed. However, AIS expects the proper office code! Notice that ${OC1} is specified to add the office code back in before sending the call to AIS.
Consequently, if you had both the KLondike5 and KLondike6 exchanges, your code might look like this:
[KLondike5]
all your 555 extensions here
include => KLondike5-unmatched
[KLondike5-unmatched]
exten => _XXXX,1,Gosub(aisnis,start,1(${OC1}${EXTEN:-4}))
same => n,Hangup()
[KLondike6]
all your 556 extensions here
include => KLondike6-unmatched
[KLondike6-unmatched]
exten => _XXXX,1,Gosub(aisnis,start,1(${OC2}${EXTEN:-4}))
same => n,Hangup()
A prerequisite for creating an ANAC (automatic number announcement circuit) is having the Jane Barbe AIS audio files downloaded. If you already have AIS on your system, you're all set. If you don't, you don't need AIS to have an ANAC. Simply navigate to the C*NET Sounds Download page and download all the files in that directory beginning with a numeral (you will see two for each number, one ending with an "n", and the other ending with a "d"). You don't need the other audio files in this directory unless you'd also like to set AIS up on your node.
Download all these files and use SoX to convert them to ulaw files (see Appendix A for more on this). Then, place the ulaw files inside /var/lib/asterisk/sounds/en/custom/digits/ on your system. You may need to create the digits directory if you don't have AIS on your node (and hence never created that directory).
Then, copy and paste the following code into your dialplan (i.e. extensions.conf):
[anac] ; PhreakNet 20190212 NA
exten => start,1,Set(LOCAL(num)=${FILTER(0-9,${CALLERID(num)})})
same => n,GotoIf($[${LEN(${num})}=7]?d7)
same => n,GotoIf($[${LEN(${num})}=6]?d6)
same => n,GotoIf($[${LEN(${num})}=5]?d5)
same => n,GotoIf($[${LEN(${num})}=4]?d4)
same => n,GotoIf($[${LEN(${num})}=3]?d3)
same => n,GotoIf($[${LEN(${num})}=2]?d2)
same => n,GotoIf($[${LEN(${num})}=1]?d1)
same => n,GotoIf($[${LEN(${num})}=0]?d0)
same => n(d7),Playback(custom/digits/${num:-7:1}n,noanswer)
same => n(d6),Playback(custom/digits/${num:-6:1}n,noanswer)
same => n(d5),Playback(custom/digits/${num:-5:1}d,noanswer)
same => n,Playback(custom/digits/blank,noanswer)
same => n(d4),Playback(custom/digits/${num:-4:1}n,noanswer)
same => n(d3),Playback(custom/digits/${num:-3:1}n,noanswer)
same => n(d2),Playback(custom/digits/${num:-2:1}n,noanswer)
same => n(d1),Playback(custom/digits/${num:-1:1}d,noanswer)
same => n(d0),Playback(beep,noanswer)
same => n(done),Return
Now, to make your ANAC work, you'll need to put it on an extension. "958" is a network-wide ANAC, so you may want to put your ANAC on an extension ending in 958, like so:
exten => 9958,1,Gosub(anac,start,1) same => n,Hangup()
The reason we haven't included an Answer() statement here is because this is a test line, and test lines in the old network hardly ever supervised. Your ANAC should not supervise.
Doing time announcements is something relatively complex that Asterisk makes relatively simple. The code featured here is the same code that runs POPCORN network-wide. You can set-up a speaking clock or "time number" on your node that is hardcoded to use your timezone, if you wish. The following code makes this relatively easy to do:
[time] ; PhreakNet 20190212 NA ; ARG1 is number of times to announce the time, ARG2 is the timezone to use
exten => s,1,Set(NumLoops=0)
same => n(start),Set(FutureTime=$[${EPOCH} + 8])
same => n,Set(FutureTimeMod=$[${FutureTime} % 10])
same => n,Set(FutureTime=$[${FutureTime} - ${FutureTimeMod} + 10])
same => n,Gosub(sub-hr12format,s,1(${ARG2}))
same => n,WaitUntil(${FutureTime})
same => n(playbeep),Playback(beep)
same => n,GotoIf($[${LEN(${ARG4})}=6]?skipwait)
same => n,Wait(5)
same => n(skipwait),Set(NumLoops=$[${NumLoops} + 1])
same => n,GotoIf($[${NumLoops} < ${ARG1}]?start)
same => n,GotoIf($[${LEN(${ARG3})}=4]?skipgoodbye)
same => n,Playback(goodbye)
same => n(skipgoodbye),Return()
[sub-hr12format]
exten => s,1,Answer
exten => s,n,Playback(at-tone-time-exactly)
exten => s,n,SayUnixTime(${FutureTime},${ARG1},IM 'vm-and' S 'seconds' p)
exten => s,n,Return()
exten => s,n,Playback(at-tone-time-exactly)
exten => s,n,SayUnixTime(${FutureTime},${ARG1},IM 'vm-and' S 'seconds' p)
exten => s,n,Return()
ARG1 is the number of times to announce the time. POPCORN is set to announce the time 100 times, so it goes on for quite a while. You'll probably want to set yours to a number between 5 and 10.
ARG2 is the timezone to use. The timezones are the "tz" format used in Unix. You can use this list of timezones and corresponding TZ database names to help you.
ARG3 and ARG4 are optional, and you will probably not need to use them. If ARG3 is set to skip, or any 4 characters for that matter, the speaking clock will not say "goodbye" before exiting. You may need to use ARG3 if you use this speaking clock as part of a broader context, rather than just a single, dedicated extension.
If ARG4 is set to nowait, or any 6 characters for that matter, then the speaking clock will not wait 5 seconds after the beep before entering another cycle. This is usually useful when you are calling [time] with ARG1 set to 1 (i.e. you only want the time announced once), and you wish to immediately exit the subroutine after the beep and continue with the dialplan code in the extension that called it. Note that if ARG1 is NOT 1 and you use ARG4 to disable the wait, it will not only disable the wait the last cycle, but every cycle, which is potentially undesirable. ARG4 is only meant to be set if ARG1 is equal to 1, but if you want to make the subroutine a bit more foolproof, you might modify it slightly so that it only calls GotoIf($[${LEN(${ARG4})}=6]?skipwait) if it is in its last cycle (in which case NumLoops will be 1 less than ARG1).
Now, to create a speaking clock for say, Chicago, or any city located in the Central Time Zone, that announces the time 7 times, all you need to do is add the following to your dialplan:
exten => 2006,1,Answer() same => n,Gosub(time,s,1(7,America/Chicago)) same => n,Hangup()The speaking clock above is the traditional "at the tone, the time will be exactly X:YY and ZZ seconds, A.M. beep.
If you'd like something a bit more customizable, check out the Asterisk TIM project on GitHub. At this time, the voice provided is Pat Simmons, but you can obtain and use your own custom audio prompts.
For instructions on how to get airport-code-based weather reports in Asterisk, see this NerdVittles tutorial.
Currently, we don't have any of these types of services. The temperature readings provided at BE1-1200 and related numbers are powered by paid APIs.
In Asterisk, there are actually several ways you could implement a milliwatt (or 1004 Hz test) tone. Asterisk itself has a Milliwatt function:
[mw] exten => start,1,Wait(0.5) same => n,Milliwatt(m) same => n,Return
We wait 0.5 seconds before starting as milliwatt numbers usually offer a split second of silence before blasting your eardrums. The m option was added to Asterisk by PhreakNet to add the correct standard timing (1 second pause every 10 seconds).
By now, you probably know that to call this, you would need to call Gosub(mw,start,1(600)) from an extension in your dialplan. (You can tell this is a subroutine because it has the Return statement in it.)
However, a great many people choose to create their milliwatt test numbers themselves. Since a milliwatt test tone consists of pure frequencies, this is relatively easy. To make things interesting, we have here chosen to combine 1004 Hz and 1000 Hz for our milliwatt (the latter was the original frequency, according to Steph Kerman "A mW is inherently a pure tone, originally nominally 1000Hz but eventually these tones were offset by 4Hz to 404, 1004 and 2804 for compatibility with digital transmission"):
[mwtone]
exten => start,1,Wait(0.5)
same => n,PlayTones(1004/1000)
same => n,Wait(${ARG1})
same => n,Return
In this case, calling Gosub(mwtone,start,1(600)) would play a 1004 Hz tone for 600 seconds (or 10 minutes). Note that isn't quite the same as a Milliwatt tone test. You can tweak the timings to make it work like one, though.
Now, if you want to really kick it up a notch, you can increase the volume of the channel so the milliwatt tone comes out more loudly than it would otherwise:
[mwtone]
exten => start,1,SET(VOLUME(TX)=8)
same => n,Wait(0.5)
same => n,PlayTones(1004/1000)
same => n,Wait(${ARG1})
same => n,SET(VOLUME(TX)=1)
same => n,Return
A volume specification of about 8 matches PSTN milliwatt test numbers fairly closely. Of course, you can play around with this until you find a volume setting that works for you. Simply replace 8 with ${ARG2}, and then pass in a second argument containing the new volume. This way, you can easily create multiple extensions with different volume milliwatt tones.
Ringback is a fairly simple task that is quite involved in terms of dialplan code. Here is a simple way to do it:
[ringback]
exten => s,1,Progress
same => n,PlayTones(600*120)
same => n,Wait(60)
exten => h,1,Originate(Local/${CALLERID(num)}@to-phreaknet,app,Wait,1209600,,,ac(5559959)n(Ringback))
The PlayTones(600*120) is what will happen when this number is called. In this case, you will here 600 Hz modulated with 120 Hz, or old city dial tone (though it sounds a bit modern, given that it's generated by a computer rather than an electromechanical tone plant). This line is optional, but does provide an indication to the caller that something has happened; if you don't want the caller to hear anything, you could replace this with Wait(60).
The ringback itself doesn't actually happen until the caller hangs up (which is why the h extension is used here as well). When the caller hangs up, Asterisk creates a call file, dumps it in the spool directory, and it gets processed.
You will need to replace 5559959 here with the extension at which you create your ringback number. If you choose to have it be extension 9959 on your exchange, you don't need to change anything; otherwise, adjust the last 4 digits to the proper extension number. You should make sure that the number you use here matches the number used to call your ringback line. That way, if somebody calls your ringback line, the incoming Caller ID on the automatically generated call matches the number he dialed in the first place.
Note that [ringback] is not a subroutine. You will need to call it as exten => 9959,1,Goto(ringback,s,1).
First, as outlined in the "Pre-Requisites" section, you will need to have PHP installed in order to use the revertive pulsing script. Once PHP is installed, exit the Asterisk CLI to the main command line and run the following commands:
wget https://octothorpe.info/downloads/pulsar-agi.tar.gz
mv pulsar-agi.tar.gz /var/lib/asterisk
cd /var/lib/asterisk
tar xvfz pulsar-agi.tar.gz
chmod 777 /var/lib/asterisk/agi-bin/pulsar.agi
A file named pulsar.agi should now be located in /var/lib/asterisk/agi-bin/.
Audio files go in /var/lib/asterisk/sounds/pulsar/.
It's worth mentioning that by default this script DOES supervise, which is incorrect! If you modify the AGI file, you can add the noanswer flag to the Playback command so that revertive pulsing does NOT return premature answer supervision (e.g. turn Playback(file) into Playback(file,noanswer).
Do not use revertive pulsing if your revertive pulsing supervises (i.e. don't use revertive pulsing if you are not going to modify the AGI). Otherwise, it will supervise, which is against the supervision standards.
Now, add the following subroutine to your dialplan:
[revertive] ; PhreakNet 20190212 NA ; Revertive pulsing (requires PHP installation)
exten => start,1,Verbose(Revertive Pulse Generator: ${ARG1})
same => n,AGI(pulsar.agi,${ARG1},${ARG2},${ARG3}) ; ARG2 can be set to 1 to indicate a "B-side" that adds 5 pulses to the second RP digit.
same => n,Return() ; ARG1 should be a 4-digit extension and ARG3 must be one of the following: panel,1xb,5xb
ARG1 is the 4-digit extension to revertive pulse.
ARG2 can be set to 1 to indicate a "B-side" that adds 5 pulses to the second RP digit. Otherwise, set it to 0.
ARG3 should be the type of revertive pulsing to simulate. Your options are panel, 1xb, or 5xb. If you are simulating one of these switches by chance, then use that one. Each type of revertive pulsing sounds very distinctive, so make sure to get this one right!
As you can see, you might call the revertive pulser like this: Gosub(revertive,start,1(${EXTEN:-4},0,5xb)). This will simulate #5XB revertive pulsing.
Unlike MF digits, which you could use for both inpulsing and outpulsing, revertive pulsing is a signaling method you should only use for incoming calls. Let's revisit our incoming contexts:
[internal-users]
include => local
include => long-distance
include => invalidincoming
[external-users]
include => local
include => invalidincoming
[local]
exten => _${OC1}XXXX,1,Goto(KLondike5,${EXTEN:-4:4},1)
You might modify [local] so it is as follows:
[local]
exten => _${OC1}XXXX,1,Gosub(revertive,start,1(${EXTEN:-4},0,5xb))
same => n,Goto(KLondike5,${EXTEN:-4:4},1)
Now, all callers dialing into whichever office code ${OC1} happens to be will hear Number 5 crossbar revertive inpulsing before the call connects!
The only catch here is, if you look at the [internal-users] context, you will see that you will also hear revertive pulsing on a call that is "local" to you, i.e. within the same exchange. At worst, this is undesired, at best, it is not really technically correct.
The solution is having a different context for incoming "long-distance" calls, like so:
[internal-users]
include => local-intraoffice
include => long-distance
include => invalidincoming
[external-users]
include => local-interoffice
include => invalidincoming
[local-intraoffice]
exten => _${OC1}XXXX,1,Goto(KLondike5,${EXTEN:-4:4},1)
[local-interoffice]
exten => _${OC1}XXXX,1,Gosub(revertive,start,1(${EXTEN:-4},0,5xb))
same => n,Goto(KLondike5,${EXTEN:-4:4},1)
Now, callers from other exchanges will hear revertive pulsing on all calls to KLondike5, but you will not. It is recommended that you adopt this approach.
If you'd like, in order to economize on code, you might adjust the last two contexts to the following:
[local-intraoffice]
exten => _${OC1}XXXX,1,Goto(KLondike5,${EXTEN:-4:4},1)
[local-interoffice]
exten => _${OC1}XXXX,1,Gosub(revertive,start,1(${EXTEN:-4},0,5xb))
same => n,Goto(local-intraoffice,${EXTEN:-4:4},1)
What's the point of this, you might ask? We just made external callers hop through another step!
The advantage of structuring your code this way is you can simply define the inpulsing for each exchange in [local-interoffice], then send it to the other context. If you wanted a sound played on all incoming calls, you could include it in the first context only; in other words, you can cut down on future duplicated code.
The downside of using this approach is, as before, all internal and external callers are now sent to the same destination context. If you had a [KLondike5-internal] context, you might want to keep them separate, in order to allow different classes of callers access to different classes of extensions:
[internal-users]
include => local-intraoffice
include => long-distance
include => invalidincoming
[external-users]
include => local-interoffice
include => invalidincoming
[local-intraoffice]
exten => _${OC1}XXXX,1,Goto(KLondike5-internal,${EXTEN:-4:4},1)
[local-interoffice]
exten => _${OC1}XXXX,1,Gosub(revertive,start,1(${EXTEN:-4},0,5xb))
same => n,Goto(KLondike5,${EXTEN:-4:4},1)
[KLondike5-internal]
exten => 6666,1,Goto(verysecretcontext,s,1)
include => KLondike5
[KLondike5]
; all public extensions here
include => invalidincoming ; if you have AIS, you should include KLondike5-unmatched instead
Now, if you call KL5-6666, you will end up going to [verysecretcontext], but callers from other exchanges will end up hearing an intercept message (or AIS) instead. Technically, this might not make sense, as the extension exists; it's just not accessible to external callers, and from Asterisk's perspective when routing an incoming call from another exchanges, the extension does not exist since it's in a different context to which it does not have access.
Part of Asterisk is structuring your dialplan code properly, and this is a skill that takes time to develop. Fortunately, you have an almost infinite amount of flexibility in terms of how you route your calls, so pick the approach that works best for you, knowing that you have the flexibility to tweak it should you ever need to.
Perhaps one of the most common and popular additions to any node is the MFer. Creating an MFer that would properly work with any number of digits proved to be a challenge, but in the end, it was surmounted. First, you may want to consider adding the MF tone specifications to the [us] context (if you are in the U.S.) in indications.conf, even though we will not be using them expressly:
mf1 = !700+900/55,!0/50 mf2 = !700+1100/55,!0/50 mf3 = !900+1100/55,!0/50 mf4 = !700+1300/55,!0/50 mf5 = !900+1300/55,!0/50 mf6 = !1100+1300/55,!0/50 mf7 = !700+1500/55,!0/50 mf8 = !900+1500/55,!0/50 mf9 = !1100+1500/55,!0/50 mf0 = !1300+1500/55,!0/50 kp = !1100+1700/100,!0/50 kp2 = !1300+1700/100,!0/50 st = !1500+1700/35,!0/50 st2 = !900+1700/35,!0/50
Depending on the specifications you use, the duration of each MF should be 50ms or 55ms, as it is in the case above. KP is 100ms and ST is 35ms, per Bell System specifications.
Here, we have used 50ms for each number. So it is! If you'd prefer to use 55ms tones, change the first 50 you see for MF1 through M0 to 55 (but not the second one!)
Now, add the following subroutines to your dialplan:
[signallookup] ; PhreakNet 20210208 NA
exten => MF,1,Return("|","!0/${ARG3}","!700+900/${ARG1}|!0/${ARG2}","!700+1100/${ARG1}|!0/${ARG2}","!900+1100/${ARG1}|!0/${ARG2}","!700+1300/${ARG1}|!0/${ARG2}","!900+1300/${ARG1}|!0/${ARG2}","!1100+1300/${ARG1}|!0/${ARG2}","!700+1500/${ARG1}|!0/${ARG2}","!900+1500/${ARG1}|!0/${ARG2}","!1100+1500/${ARG1}|!0/${ARG2}","!1300+1500/${ARG1}|!0/${ARG2}","!1100+1700/${ARG5}|!0/${ARG2}","!1500+1700/${ARG4}|!0/${ARG2}","!900+1700/${ARG4}|!0/${ARG2}","!1300+1700/${ARG4}|!0/${ARG2}","!700+1700/${ARG4}|!0/${ARG2}")
exten => SF,1,Return("|",200,100,"!0/200","!${ARG1}/${ARG2}|!0/${ARG3}","!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}","!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}","!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}","!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}","!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}","!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}","!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}","!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}","!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}") ; ARG1 = frequency (2600), ARG2 = on (60ms), ARG3 = off (40ms) / SFX = interdigit silence
[mfer] ; PhreakNet 20181212 NA/BJC, revised 20210208
exten => start,1,Set(number=${FILTER(0-9,${ARG1})}) ; ARG1 = digits to MF
same => n,Gosub(signallookup,MF,1(50,50,500,35,100)) ; ARG1 = on, ARG2=off, ARG3=silence, ARG4=ST duration, ARG5=KP duration
same => n,Set(ARRAY(digitsep,mfx,mf1,mf2,mf3,mf4,mf5,mf6,mf7,mf8,mf9,mf0,mfkp,mfst,mfstp,mfst2p,mfst3p)=${GOSUB_RETVAL}) ; R1, CCIT5: STP ~ code 12, ST2P ~ KP2, ST3P ~ code 11
same => n,Set(c=0)
same => n,Set(numdigits=${LEN(${ARG1})})
same => n,Set(tonestring=${mfx}${digitsep}${mfkp}${digitsep})
same => n,While($[${c}<${numdigits}])
same => n,Set(mfnext=${mf${number:${c}:1}})
same => n,Set(tonestring=${tonestring}${mfnext}${digitsep})
same => n,Set(c=${INC(c)})
same => n,EndWhile
same => n,Set(mfnext=${mfst})
same => n,Set(tonestring=${tonestring}${mfnext}${digitsep})
same => n,Set(tonestring=${tonestring}${mfx})
same => n,Set(toneduration=$[100*${LEN(${ARG1})}+1785])
same => n,PlayTones(${FILTER(0-9\x21/|+,${tonestring})})
same => n,Wait($[${toneduration}/1000])
same => n,StopPlayTones()
same => n,Return()
Below is an expanded MFer than do sequencing MF using different ST tone variations. It is not currently production ready, as longer sequences suffer from more and more of the end being cut off, so an additional timing buffer would need to be refined:
[mfer2] ; PhreakNet 20181212 NA/BJC, revised 20210208
exten => start,1,NoOp()
same => n,Set(lon=50) ; 50
same => n,Set(loff=50) ; 50
same => n,Set(lsil=500) ; 500
same => n,Set(lst=50) ; 35/50
same => n,Set(lkp=100) ; 100
same => n,Gosub(signallookup,MF,1(${lon},${loff},${lsil},${lst},${lkp})) ; ARG1 = on, ARG2=off, ARG3=silence, ARG4=ST duration, ARG5=KP duration
same => n,Set(ARRAY(digitsep,mfx,mf1,mf2,mf3,mf4,mf5,mf6,mf7,mf8,mf9,mf0,mfkp,mfst,mfstp,mfst2p,mfst3p)=${GOSUB_RETVAL}) ; R1, CCIT5: STP ~ code 12, ST2P ~ KP2, ST3P ~ code 11
same => n,Set(number=${FILTER(0-9,${ARG1})}) ; ARG1 = digits to MF
same => n,Set(mfstart=${FILTER(0-9,${ARG2})}) ; ARG2 = optional ST delimiter
same => n,Set(number2=${FILTER(0-9,${ARG3})}) ; ARG3 = optional 2nd group of digits to MF
same => n,Set(cv=0)
same => n,Set(numdigits=${LEN(${number})})
same => n,Set(tonestring=${mfx}${digitsep}${mfkp}${digitsep})
same => n,While($[${cv}<${numdigits}])
same => n,Set(mfnext=${mf${number:${cv}:1}})
same => n,Set(tonestring=${tonestring}${mfnext}${digitsep})
same => n,Set(cv=${INC(cv)})
same => n,EndWhile()
same => n,Set(mfnext=${mfst})
same => n,ExecIf($["${mfstart}"="mfstp"]?Set(mfnext=${mfstp})) ; R1 STP, CCIT5: Code 12
same => n,ExecIf($["${mfstart}"="mfst2p"]?Set(mfnext=${mfst2p})) ; R1 ST2P, CCIT5: KP2
same => n,ExecIf($["${mfstart}"="mfst3p"]?Set(mfnext=${mfst3p})) ; R1 ST3P, CCIT5: Code 11
same => n,Set(tonestring=${tonestring}${mfnext})
;same => n,Set(tonestring=${digitsep}${tonestring}${mfx})
same => n,Set(toneduration=$[$[${lon}+${loff}]*$[${LEN(${number})}+${LEN(${number2})}]+${lsil}+${lkp}+${loff}+${lst}+${loff}])
same => n,GotoIf($[${LEN(${number2})}=0]?play)
same => n,Set(cv=0)
same => n,Set(numdigits=${LEN(${number2})})
same => n,Set(tonestring=${tonestring}${digitsep}${mfkp}${digitsep})
same => n,While($[${cv}<${numdigits}])
same => n,Set(mfnext=${mf${number2:${cv}:1}})
same => n,Set(tonestring=${tonestring}${mfnext}${digitsep})
same => n,Set(cv=${INC(cv)})
same => n,EndWhile()
same => n,Set(tonestring=${tonestring}${mfst})
same => n,Set(toneduration=$[${toneduration}+${lkp}+${loff}+${lst}+${loff}]) ; add on aditional KP/ST
same => n(play),Set(td=0)
same => n,Set(UNSHIFT(tones,|)=${tonestring})
same => n,While($["${SET(t=${SHIFT(tones,|)})}" != ""])
same => n,Set(t=${FILTER(0-9,${CUT(t,/,2)})})
same => n,Set(td=$[${td}+${t}])
same => n,EndWhile()
same => n,Set(toneduration=${td}) ; increased buffer needed for longer strings
same => n,PlayTones(${FILTER(0-9\x21/|+,${tonestring})})
same => n,Wait($[${toneduration}/1000])
same => n,StopPlayTones()
same => n,Return()
A note about the [mfer] subroutine is perhaps warranted here. The original approach to a dynamic MFer was using a subroutine to loop through each digit and generate an MF tone using the tone definitions in indications.conf. However, this approach, originally tested by Don Froula, does not work for one reason or another. Hence, the idea came about of not using indications.conf but instead dynamically building up a tone string and passing that into PlayTones() all at once. Don Froula, intrigued by the idea, admitted this could work, and Naveen and Brian immediately set upon implementing it. With Brian's help, the complex subroutine you see above now allows a number of any length to be MFed. The KP and ST tones are automatically prepended and appended to the tone string automatically; there is no need to specify this.
To call the MFer, all you need to do is pass in the digits to MF (not including KP and ST) as ARG1, like so: Gosub(mfer,start,1(5551212)).
The above will result in KP + 5 + 5 + 5 + 1 + 2 + 1 + 2 + ST being MFed.
You can now use this MFer on incoming and/or outgoing calls from your node. Perhaps you want to have MF inpulsing on calls interoffice calls to your second exchange:
[local-interoffice]
exten => _${OC1}XXXX,1,Gosub(revertive,start,1(${EXTEN:-4},0,5xb))
same => n,Goto(KLondike5,${EXTEN:-4:4},1)
exten => _${OC2}XXXX,1,Gosub(mfer,start,1(${EXTEN}))
same => n,Goto(KLondike6,${EXTEN:-4:4},1)
Or perhaps, you only have one exchange code but be really ambitious:
exten => _${OC1}XXXX,1,Gosub(mfer,start,1(${EXTEN}))
same => n,Gosub(revertive,start,1(${EXTEN:-4},0,5xb))
same => n,Goto(KLondike5,${EXTEN:-4:4},1)
NOTE: All the above is obsolete and has been superseded by the native SendMF() application in Asterisk.
Now, external callers would hear MFing, followed by #5XB revertive pulsing.
You have the flexibility to choose from various inpulsing and outpulsing options for your node, but remember to stay "period-correct". You might hear MFing followed by revertive pulsing, for instance, but you would not be likely to hear revertive pulsing followed by MFing! Pay attention to the order of your inpulsing and outpulsing and make sure it stays realistic.
Note: Do not add any outpulsing directly in the dialphreaknet subroutine! Instead, create a separate outpulsing context that you call from within phreaknet-route.
If you do not already have the [signallookup] subroutine (the same one used for the MFer), you will need that:
[signallookup] ; PhreakNet 20210208 NA ; Bell System specs say 1st 50 should be 55? / MFX - silence / ST - Don has 35 here set to 50
exten => MF,1,Return("|","!0/${ARG3}","!700+900/${ARG1}|!0/${ARG2}","!700+1100/${ARG1}|!0/${ARG2}","!900+1100/${ARG1}|!0/${ARG2}","!700+1300/${ARG1}|!0/${ARG2}","!900+1300/${ARG1}|!0/${ARG2}","!1100+1300/${ARG1}|!0/${ARG2}","!700+1500/${ARG1}|!0/${ARG2}","!900+1500/${ARG1}|!0/${ARG2}","!1100+1500/${ARG1}|!0/${ARG2}","!1300+1500/${ARG1}|!0/${ARG2}","!1100+1700/100|!0/${ARG2}","!1500+1700/${ARG4}|!0/${ARG2}","!1300+1700/100|!0/${ARG2}","!900+1700/${ARG4}|!0/${ARG2}","!700+1700/${ARG4}|!0/${ARG2}")
exten => SF,1,Return("|",200,100,"!0/200","!${ARG1}/${ARG2}|!0/${ARG3}","!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}","!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}","!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}","!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}","!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}","!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}","!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}","!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}","!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}|!${ARG1}/${ARG2}|!0/${ARG3}") ; ARG1 = frequency (2600), ARG2 = on (60ms), ARG3 = off (40ms) / SFX = interdigit silence
Regardless, you will need the [sfer] subroutine:
[sfer] ; PhreakNet 20190218 NA, revised 20210208 ; ARG1 = digits to SF
exten => start,1,Set(number=${FILTER(0-9,${ARG1})}) ; ARG1 = digits to do something with
same => n,Gosub(signallookup,SF,1(2600,60,40))
same => n,Set(ARRAY(digitsep,sfinter,sfpulse,sfx,sf1,sf2,sf3,sf4,sf5,sf6,sf7,sf8,sf9,sf0)=${GOSUB_RETVAL})
same => n,Set(c=0)
same => n,Set(p=0)
same => n,Set(numdigits=${LEN(${ARG1})})
same => n,Set(tonestring=)
same => n,While($[${c}<${numdigits}])
same => n,Set(nextp=${number:${c}:1})
same => n,ExecIf($["${nextp}"="0"]?Set(nextp=10))
same => n,Set(p=$[${p}+${nextp}])
same => n,Set(sfnext=${sf${number:${c}:1}})
same => n,Set(tonestring=${tonestring}${sfnext}${digitsep})
same => n,Set(tonestring=${tonestring}${sfx}${digitsep})
same => n,Set(c=${INC(c)})
same => n,EndWhile
same => n,Set(toneduration=$[${sfpulse}*${p}+${sfinter}*${numdigits}])
same => n,PlayTones(${FILTER(0-9\x21/|+,${tonestring})})
same => n,Wait($[${toneduration}/1000])
same => n,StopPlayTones()
same => n,Return()
Below is the dialplan coded needed for the dial pulser:
[dialpulser] ; PhreakNet 20190212 NA
exten => start,1,Set(number=${ARG1}) ; ARG1 = digits to dial pulse
same => n,Set(c=0)
same => n,Set(numdigits=${LEN(${ARG1})})
same => n,While($[${c}<${numdigits}])
same => n,Playback(custom/dialpulses/dp${number:${c}:1},noanswer)
same => n,Set(c=${INC(c)})
same => n,EndWhile
same => n,Return
ARG1 is simply what number to dial pulse. The number can be of any length (beside 0, obviously).
You will need audio recordings of each number being dial pulsed. You can easily extract dial pulses from various Evan Doorbell recordings. Prefix each digit with dp when you save the audio file, convert to ulaw, and then move to /var/lib/asterisk/sounds/en/custom/dialpulses/.
If you'd prefer to use our dial pulsing audio files, you may download them here.
Creating a conference bridge in Asterisk is relatively easy. Here, we will provide a template for creating a kind of so-called "party line" conference bridge, much like those on which Evan Doorbell spent hours talking and listening in the 1970s.
You will need to add the following to confbridge.conf:
[bridge] type=bridge sound_join=/var/lib/asterisk/sounds/en/custom/conf/confjoin ; The sound played to everyone when someone enters the conference. sound_leave=/var/lib/asterisk/sounds/en/custom/conf/confdis ; The sound played to everyone when someone leaves the conference. [caller] type=user dsp_drop_silence=no announce_only_user=no [volmenu] type=menu 4=decrease_listening_volume 5=reset_listening_volume 6=increase_listening_volume 7=decrease_talking_volume 8=reset_talking_volume 9=increase_talking_volume 0=toggle_mute [advmenu] type=menu 1=participant_count 4=decrease_listening_volume 5=reset_listening_volume 6=increase_listening_volume 7=decrease_talking_volume 8=reset_talking_volume 9=increase_talking_volume 0=toggle_mute
You will need the "confjoin" and "confdis" audio files. You can use whatever audio files you like here; we recommend extracting actual "party line" conference joining and disconnect noises from an Evan Doorbell recording.
To have an extension go to a conference bridge, specify the following in your dialplan: ConfBridge(1,bridge,caller).
In this case, we have given the bridge an ID of 1. This number should be unique for each conference. You may choose to set this equal to the extension on which this conference is located.
You can have multiple extensions go to the same bridge but with different "experiences". For example, you could create a separate extension that joins the same bridge but also features a menu: ConfBridge(1,bridge,caller,volmenu). As you've probably figured out by now, ARG1 for ConfBridge is which bridge to use, ARG2 is which bridge profile to user, ARG3 is which user profile to use, and ARG4, which is optional, is which menu to use, if any. If you're trying to recreate a 1970s "party line", though, omit the menu.
It is important to note that conferences are not created or defined in confbridge.conf! Creating a second conference is as simple as making another extension with a ConfBridge call that uses something different for ARG1. For instance, ConfBridge(2111,bridge,caller) and ConfBridge(052,bridge,caller) would be two different conferences entirely, though they both use the same bridge and user profiles, so the experiences (i.e. sounds and functionality) will be the same.
By default, the ConfBridge() application will supervise with no alternative, unlike the Playback() application which accepts a noanswer argument. Because ConfBridge is often the only way to get much functionality in Asterisk to work as desired, this is a significant limitation; however, modifying the source code can remove this behavior for better operation.
Patch Instructions:
apps directory.app_confbridge.c for editingast_answer(chan); with //ast_answer(chan);.
sed -i 's/ast_answer(chan)/\/\/ast_answer(chan)/g' apps/app_confbridge.c
make and then make install to recompile Asterisk.service asterisk stop and then service asterisk start to restart Asterisk.ConfBridge() will no longer automatically supervise a call. Once you've patched your Asterisk system, you must manually perform supervisory functions, as follows:
exten => s,1,Answer() same => n,ConfBridge(mybridge) same => n,Hangup()
exten => s,1,Progress() same => n,ConfBridge(mybridge) same => n,Hangup()
exten => s,1,ConfBridge(mybridge) same => n,Hangup()
As of June 2021, Asterisk's app_confbridge now has the answer_channel user option. Set answer_channel = no, with Asterisk 18.5+/Asterisk 16.19+. No patching is required.
You must either use Progress() or Answer(). Failing to do so may result in no audio being passed at all.
Take care to revisit all uses of ConfBridge in your dialplan code to ensure you're using Progress or Answer before any calls to ConfBridge.
Answering machines and voicemail are, in many ways, the antithesis of each other. Functionally, an answering machine has no place in Asterisk. However, it may be neat to simulate a physical telephone answering device (or answering machine) in Asterisk, to make it sound like somebody has reached an answering machine. This can be done with fairly trivial dialplan code.
Behind the scenes, the VoiceMail application can still be used. For the most part, the caller would never notice the difference. However, by default, Asterisk plays its own beep tone to the caller. Simply add the t option, specifying a custom beep tone to use, or leaving this argument empty to suppress the beep entirely.
This allows you to use your own outgoing answering machines without a modern Asterisk tone coming on at the end, and you can even use beep tones that are noticably analog and old sounding.
Note that if a user presses the # key while recording, Asterisk will say "thank you" and exit the VoiceMail application (playing auth-thankyou). This patch does not address that behavior. If users are allowed to review messages in voicemail.conf, an additional menu plays afterwards anyways, so it's not merely a question of suppressing an auth-thankyou somewhere, and it's probably best to just leave this behavior be.
As of April 2021, Asterisk itself has very minimal support for hook flashing. All Asterisk has historically done is propogate these events across channels from one to the other, if they are compatible. It has not had any ability to do anything with these events or expose them in any way (i.e. AMI).
There are two primary reasons for this:
features.confFor building advanced functionality, it is essential to be able to handle hook flashes in Asterisk rather than let them be handled locally. In fact, ATAs have better support for this than they do handling these events locally. Grandstream ATAs, for example, will not connect to the switch at all if you flash to spawn a three-way call, even if you have off-hook auto-dial configured. Generally speaking, you are limited to the idiosyncrasies of different ATAs and many events are simply impossible to handle in the desired way. Sending flash events to Asterisk and performing bridge operations switch-side is vastly superior, though it requires a significant investment in configuring such a system (not for the light-hearted!) You will need to handle flash events as desired and implement all relevant functionality yourself, including writing your own Call Waiting from scratch. However, if you are designing an actual Class 5 switch, this is probably what you are trying to do anyways.
Regardless of the purpose, being able to handle flash events increases flexibility. The good news is that as of April 2021, patches to make hook flash events a first class citizen in Asterisk are now available! To add hook flash events to Asterisk, it's as easy as running the following:
cd /tmp wget https://code.phreaknet.org/asterisk/sip.patch wget https://code.phreaknet.org/asterisk/file.patch wget https://issues.asterisk.org/jira/secure/attachment/60149/ASTERISK-29373.diff wget https://code.phreaknet.org/asterisk/stasis_sample.patch wget https://code.phreaknet.org/asterisk/stasis_channels.h.patch wget https://code.phreaknet.org/asterisk/stasis_channels.c.patch wget https://code.phreaknet.org/asterisk/manager_channels.patch wget https://code.phreaknet.org/asterisk/stasis.patch wget https://code.phreaknet.org/asterisk/channel.patch cd /usr/src/asterisk-18.3.0/ patch -u -b channels/chan_sip.c -i /tmp/sip.patch # add application/hook-flash support for SIP INFO flash events patch -u -b main/file.c -i /tmp/file.patch # ignore flash events and don't throw an error patch -u -b res/res_rtp_asterisk.c -i /tmp/ASTERISK-29373.diff # don't create duplicate flash events for RTP flashes patch -u -b configs/samples/stasis.conf.sample /tmp/stasis_sample.patch # AMI flash event patch -u -b include/asterisk/stasis_channels.h /tmp/stasis_channels.h.patch # AMI flash event patch -u -b main/stasis_channels.c /tmp/stasis_channels.c.patch # AMI flash event patch -u -b main/manager_channels.c /tmp/manager_channels.patch # AMI flash event patch -u -b main/stasis.c /tmp/stasis.patch # AMI flash event patch -u -b main/channel.c /tmp/channel.patch # stop throwing warning for flash event and handle flash events by triggering AMI event make make install asterisk -rx "core restart now"
As of Asterisk 18.4 and 18.5, all of these patches are part of "official" Asterisk from Sangoma.
This will expose hook flashes as AMI events. You will need to handle them using an out of band AMI process, such as PAMI for PHP. You can then spawn dialplan execution to perform flash logic and do other operations as desired based on the state of the call(s).
As of April 2021, the patches to add AMI support have been submitted to Digium but are not yet part of the master Asterisk source code. Until the feature is available natively, you simply need to patch your copy and recompile. It should not take more than a minute or two to do.
Credits & Contributions: J. Colp, Digium for correcting improper RTP stream handling of flash events; N.A. for two issues which add application/hook-flash support to SIP, suppress errors in file.c, and adding full AMI (Asterisk Manager Interface) support for flash events.
It is relatively simple to set up shared (and even talkable) busy signals or simulated drum announcement machines with Asterisk. The below will cover a simple example of a drum announcement. There are multiple ways to do this and this is just an example.
You will likely want the non-supervising ConfBridge patch for this kind of stuff.
Typically, the idea with these is:
The example below cuts callers into an announcement for one announcement cycle and then sends them to another destination.
The example below supervises when callers are cut into the bridge. For intercepts, this may not be desirable. Instead of the initial Dial(), you could use MusicOnHold() directly and then StopMusicOnHold() instead of Answer() in the [drum]. With the patch to ConfBridge, callers will then be cut into a bridge, and the call still will not have supervised. All depends on how you want to set things up.
The example below is similar to the code that powers Centralized Intercept on PhreakNet. POPCORN (767-2676) on PhreakNet also uses similar "drum technology". Callers are cut in at the same time and stay on for 4 full cycles of the time from when they entered. Then, they're dropped to a "post-time conference" for about 10 seconds, then disconnected. This is an example of a more elaborate system.
exten => _X!,1,Dial(Local/${EXTEN}@drum,,m(ringback)g) ; drum announcement
same => n,Goto(somewhere-else,s,1)
[drum]
exten => _X!,1,Set(GROUP(drumintercept)=1)
same => n,Set(CDR_PROP(disable)=1)
same => n,Set(CONFBRIDGE(user,wait_marked)=yes)
same => n,Set(CONFBRIDGE(user,end_marked)=yes)
same => n,Set(CONFBRIDGE(user,dtmf_passthrough)=no)
same => n,Set(CONFBRIDGE(user,startmuted)=yes)
same => n,Set(CONFBRIDGE(user,dsp_drop_silence)=yes)
same => n,GotoIf($[${GROUP_COUNT(1@drumintercept)}=1]?startannouncement:waitloop)
same => n(startannouncement),Originate(Local/1@drum-announcement,exten,announcement-access,1,,a)
same => n,Wait(0.1)
same => n(waitloop),GotoIf($["${CONFBRIDGE_INFO(parties,drumintercept1)}"="0"]?startannouncement) ; if nobody is in the conference, start it up
same => n,WaitForCondition(#,#[#{GROUP_COUNT(1@interceptcutin)}>0])
same => n(bridge),Answer()
same => n,ConfBridge(drumintercept1,silentbridge,incogtalkeroptimized)
same => n,Set(GROUP(drumintercept)=)
same => n,Hangup()
[announcement-access]
exten => 1,1,Set(CONFBRIDGE(user,marked)=yes)
same => n,Set(CDR_PROP(disable)=1)
same => n,ConfBridge(drumintercept1,silentbridge,incogtalkeroptimized)
same => n,Hangup()
[announcement-monitor]
exten => 1,1,Answer()
same => n,Set(CDR_PROP(disable)=1)
same => n,ConfBridge(drumintercept1,silentbridge,incoglistener)
same => n,Hangup()
[drum-announcement]
exten => 1,1,Answer()
same => n,Set(CDR_PROP(disable)=1)
same => n,Wait(${RAND(2,3)})
same => n,Set(GROUP(interceptcutin)=1)
same => n,Wait(0.85)
same => n,Set(GROUP(interceptcutin)=)
same => n,Set(VOLUME(TX)=2)
same => n,Playback(custom/intercept-announcement,noanswer)
same => n,Wait(3)
same => n,System(asterisk -rx "confbridge kick drumintercept1 all") ; you could kicked all the unmarked users here, instead of all the users
same => n,Hangup() ; hang up, and kick out everyone presently in the bridge
Here is an example of a more featured intercept with configurable options, which does not supervise (provided that the answer_channel = no user option is present, either added at runtime or in the user template used):
same => n,Gosub(intercept-drum,s,1(sample,ringback,1,0,0)) ; announcement
same => n,Hangup()
[intercept-drum-announcements]
exten => sample,lookup,custom/myintercept
; a dial is not used, which means this works without supervising! Actually ringing the special op. will mean that we need FRAME_DROP.
[intercept-drum] ; ARG1 = intercept, ARG2 = ringback MOH class, ARG3 = # of iterations (0 = forever)
; ARG4 = 0 = wait for next iteration to cut in, 1 = cut in immediately, ARG5 = talkable intercept: 0 = no, 1 = yes
exten => s,1,Progress()
same => n,StartMusicOnHold(${ARG2})
same => n,Set(CONFBRIDGE(user,template)=incogtalkeroptimized)
same => n,Set(CONFBRIDGE(user,wait_marked)=yes)
same => n,Set(CONFBRIDGE(user,end_marked)=yes)
same => n,Set(CONFBRIDGE(user,dtmf_passthrough)=no)
same => n,ExecIf($["${ARG5}"!="1"]?Set(CONFBRIDGE(user,startmuted)=yes))
same => n,Set(CONFBRIDGE(user,dsp_drop_silence)=yes)
; if this seems backwards, it is. But we want variables set on the control channel, not the bridge channel.
same => n,ExecIf($[${GROUP_COUNT(${ARG1}@interceptdrumon)}=0]?Originate(Local/${ARG1}@intercept-drum-announce,exten,intercept-drum-announcement,${ARG1},1,,av(anycut=${ARG4})))
same => n,Set(GROUP(interceptdrumlisten)=${ARG1})
same => n,Wait(0.05) ; wait for the machine to "start up"...
same => n,Set(c=0)
same => n,WaitForCondition(#,#[#{GROUP_COUNT(${ARG1}@interceptcutin)}>0],,0.2)
same => n,StopMusicOnHold() ; ConfBridge marked user wait is useless. It still adds you to the bridge in a janky way.
same => n,While($["${ARG3}"="0"|${INC(c)}<=${ARG3}])
same => n,ConfBridge(interceptdrum${ARG1},silentbridge)
same => n,EndWhile()
same => n,Set(GROUP(interceptdrumlisten)=)
same => n,Return()
[intercept-drum-announcement]
exten => _[0-9A-Za-z].,1,Set(CDR_PROP(disable)=1)
same => n,ExecIf($[${GROUP_COUNT(${EXTEN}@interceptdrumon)}>0]?Hangup)
same => n,Set(GROUP(interceptdrumon)=${EXTEN})
same => n,Answer()
same => n,Wait(${RAND(1,3)}) ; takes a moment to "start up"
same => n(cutin),Set(GROUP(interceptcutin)=${EXTEN})
same => n,Wait(0.5) ; cut in waiting callers. In theory, we could put everyone in a "waiting" ConfBridge, but that's probably even more CPU.
same => n,ExecIf($["${anycut}"!="1"]?Set(GROUP(interceptcutin)=)) ; now, nobody else can join until the next loop, unless that's permitted.
same => n,Playback(${LOOKUP(${EXTEN}@intercept-drum-announcements)})
same => n,Wait(0.4)
same => n,ConfKick(interceptdrum${EXTEN},participants) ; kick all current listeners to the intercept if it's 1x only.
same => n,Wait(0.4)
same => n,GotoIf($[${GROUP_COUNT(${EXTEN}@interceptdrumlisten)}>0]?cutin) ; callers are waiting for this intercept, cut them in
same => n,Hangup()
[intercept-drum-announce]
exten => _[0-9A-Za-z].,1,Set(CDR_PROP(disable)=1)
same => n,Set(CONFBRIDGE(user,template)=incogtalkeroptimized)
same => n,Set(CONFBRIDGE(user,marked)=yes)
same => n,Answer()
same => n,ConfBridge(interceptdrum${EXTEN},silentbridge)
same => n,Hangup()
[intercept-drum-monitor]
exten => _[0-9A-Za-z].,1,Set(CDR_PROP(disable)=1)
same => n,Answer()
same => n,ConfBridge(interceptdrum${EXTEN},silentbridge,incoglistener)
same => n,Hangup()
One would think that ChanSpy() could be used for this kind of thing, but ChanSpy is, for these purposes, almost completely useless, due to a long persistent limitation with audiohooks in Asterisk.
You will need to use ConfBridge. The non-supervising ConfBridge patches are a must-have pre-req. Once you have that, the mechanism is as follows:
There is more involved, of course. Each call effectively has a unique conference bridge. Hangup handling using the h extension is an art that must be carefully mastered. Because the calling party is no longer directly connected to the called party, you will need to manually check for different cases and kick the other party if one has left. And if you forget to do this in all the required places, then you may find that you have "ghost" bridges with nobody in them piling up as calls take place. When a call is completed, the conference bridge should get destroyed.
Because there are some people interested in this concept, a subset of the crosstalk/carrier code used on the main tandem is provided below for reference.
;;; Carrier Code:
[carriersetup]
exten => in,1,Set(CDR_PROP(disable)=1)
same => n,Gosub(carrierlookup,${ARG1},1)
same => n,ExecIf($[${GOSUB_RETVAL}=0]?Return)
same => n,Set(LOCAL(channel)=${FILTER(0-9,${UNIQUEID})})
same => n,Set(__callednumber=${ARG1}) ; do we really need this?
same => n,ExecIf($[${GROUP_COUNT(1@carriercalls)}=0]?DBdeltree(carrierchannels))
same => n,Set(GROUP(carriercalls)=1)
same => n,Set(GROUP(carriercrosstalk)=1)
same => n,Set(DB(carrierchannels/${channel})=${CHANNEL})
same => n,ExecIf($[${GROUP_COUNT(0@carriercrosstalk)}=0]?Originate(Local/s@carriercrosstalk,app,Wait,9999999,,,av(CDR_PROP(disable)=1^CALLERID(num)=${CALLERID(num)}^CALLERID(name)=${CALLERID(name)})))
same => n,Set(randl=BCDE) ; Subtle L-Carrier track options (we'll randomly pick one)
same => n,Set(LOCAL(carriergroup)=${randl:$[${RAND(1,${LEN(${randl})})}-1]:1})
same => n,Set(SHARED(carriergroup)=${carriergroup})
same => n,Originate(Local/${carriergroup}@carriernoise,exten,carrierinject,${channel},1,,av(CALLERID(num)=${CALLERID(num)}^CALLERID(name)=${CALLERID(name)})) ; Main L-Carrier
same => n,Originate(Local/monitor@carriercrosstalk,exten,carrierinject,${channel},1,,av(CALLERID(num)=${CALLERID(num)}^CALLERID(name)=${CALLERID(name)})) ; Crosstalk
same => n,Return(${channel})
exten => out,1,Set(CDR_PROP(disable)=1)
same => n,Gosub(carrierlookup,${ARG1},1)
same => n,ExecIf($[${GOSUB_RETVAL}=0]?Return)
same => n,Set(LOCAL(channel)=${FILTER(0-9,${UNIQUEID})})
same => n,Set(__callednumber=${ARG1}) ; do we really need this?
same => n,ExecIf($[${GROUP_COUNT(1@carriercalls)}=0]?DBdeltree(carrierchannels))
same => n,Set(GROUP(carriercalls)=1)
same => n,Set(GROUP(carriercrosstalk)=1)
same => n,Set(DB(carrierchannels/${channel})=${CHANNEL})
same => n,ExecIf($[${GROUP_COUNT(0@carriercrosstalk)}=0]?Originate(Local/s@carriercrosstalk,app,Wait,9999999,,,av(CDR_PROP(disable)=1^CALLERID(num)=${CALLERID(num)}^CALLERID(name)=${CALLERID(name)})))
same => n,Set(randl=BCDE) ; Subtle L-Carrier track options (we'll randomly pick one)
same => n,Set(LOCAL(carriergroup)=${randl:$[${RAND(1,${LEN(${randl})})}-1]:1})
same => n,Set(SHARED(carriergroup)=${carriergroup})
same => n,Originate(Local/${channel}@carrierinject,exten,carriernoise,${carriergroup},1,,av(CALLERID(num)=${CALLERID(num)}^CALLERID(name)=${CALLERID(name)})) ; Main L-Carrier
same => n,Originate(Local/monitor@carriercrosstalk,exten,carrierinject,${channel},1,,av(CALLERID(num)=${CALLERID(num)}^CALLERID(name)=${CALLERID(name)})) ; Crosstalk
same => n,Return(${channel})
[regeneratecall] ; ARG1 = local channel ID, ARG2 = local channel context, ARG3 = context, ARG4 = in/out, ARG5 = called #
exten => s,1,Originate(Local/${ARG1}@${ARG2},exten,${ARG3},${ARG5},1,,av(CALLERID(num)=${CALLERID(num)}^CALLERID(name)=${CALLERID(name)}^CALLERID(pres)=${CALLERID(pres)}^calldirection=${ARG4}^__channel=${ARG1}^__autovonchan=${autovonchan}^__clidverif=${clidverif}^__mlppdigit=${mlppdigit}^__forcesecurechannel=${forcesecurechannel}^__dtlocation=${dtlocation}))
same => n,Return(${ARG1})
[carrierbridge]
exten => _X!,1,Set(channel=${EXTEN}) ; if caller hangs up, end call
same => n,Set(CDR_PROP(disable)=1)
same => n,Progress()
same => n,Set(carriergroup=${SHARED(carriergroup,${DB(carrierchannels/${channel})})})
same => n,ExecIf($["${carriergroup}"!="B"]?Set(VOLUME(TX)=-${RAND(7,9)}))
same => n,ExecIf($["${carriergroup}"!="B"]?Playback(custom/switch/connect/carrierconnect1,noanswer))
same => n,ExecIf($["${carriergroup}"!="B"]?Set(VOLUME(TX)=1))
same => n,ConfBridge(channel${channel},silentbridge,incogtalker) ; this MUST NOT ANSWER the call
same => n,ExecIf($["${SHARED(carrieranswered,${DB(carrierchannels/${channel})})}"="1"]?Answer():Hangup) ; prevent answering the call if it wasn't... actually answered!
same => n,Set(SHARED(carrieranswered,${DB(carrierchannels/${channel})})=2) ; this is the ${channel} channel so we don't need to explicitly specify it with SHARED
same => n,ConfBridge(channel${channel},silentbridge,incogtalker)
same => n,Hangup() ; used was kicked (other party hung up)
exten => h,1,ExecIf($[${CONFBRIDGE_INFO(parties,channel${channel})}>0]?ConfKick(channel${channel},all))
[carrieronward]
exten => _X!,1,Set(CDR_PROP(disable)=1)
same => n,Answer() ; bridge audio to caller immediately
same => n,Wait(${RAND(1,2)})
same => n,Set(carriergroup=${SHARED(carriergroup,${DB(carrierchannels/${channel})})})
same => n,Wait(0.5)
same => n,ExecIf($["${calldirection}"="out"]?Wait(${RAND(1,${RAND(2,5)})})) ; give time for the L-carrier "B-loop" sound to play
same => n,ExecIf($["${calldirection}"="in"]?Dial(Local/${EXTEN}@intraoffice-connect,,G(split))) ; channel variables will carry
same => n,ExecIf($["${calldirection}"="out"]?Dial(Local/${EXTEN}@to-phreaknet,,G(split))) ; channel variables will carry
same => n,ConfKick(channel${channel},all) ; if called party hangs up without answering, end call
same => n(caller),Goto(carrieronward-hangup,s,1) ; so h extension doesn't execute
same => n(split),Goto(caller) ; disconnect caller to get rid of an unnecessary channel
same => n(callee),Set(SHARED(carrieranswered,${DB(carrierchannels/${channel})})=1)
same => n,ConfKick(channel${channel},${DB(carrierchannels/${channel})}) ; kick the caller from the bridge, which will Answer() the call and then drop him back in
same => n,Set(CDR_PROP(disable)=1)
same => n,Goto(carrierbridgecallee,${channel},1)
exten => h,1,ExecIf($[${CONFBRIDGE_INFO(parties,channel${channel})}>0]?ConfKick(channel${channel},all)) ; if calling party hangs up, end call
[carrieronward-hangup]
exten => s,1,Hangup()
[carrierbridgecallee]
exten => _X!,1,Set(channel=${EXTEN})
same => n,Set(CDR_PROP(disable)=1)
same => n,Originate(Local/answer@carriernoise,exten,carrierinject,${channel},1,,a)
same => n(wait),WaitForCondition(#,#["#{SHARED(carrieranswered,#{DB(carrierchannels/#{channel})})}"="2"],1) ; prevents race conditions, where if the ConfKick before carrieronward,caller has NOT YET taken effect, we don't kill the call (that call must finish before this executes)
same => n(bridge),ExecIf($[${CONFBRIDGE_INFO(parties,channel${channel})}>0]?ConfBridge(channel${channel},silentbridge,incogtalker))
same => n,Hangup()
exten => h,1,ExecIf($[${CONFBRIDGE_INFO(parties,channel${channel})}>0]?ConfKick(channel${channel},all)) ; if called party hangs up, end call
[carrierbridgeaccess]
exten => _X!,1,Set(CDR_PROP(disable)=1)
same => n,Answer()
same => n,ConfBridge(channel${EXTEN},silentbridge,incogtalker)
same => n,Hangup()
The standard way to create an echo test in Asterisk would be as follows:
exten => 9931,1,Goto(echo,s,1) [echo] exten => s,1,Answer() ; Echo test with instructions same => n,Playback(demo-echotest) same => n,Echo() same => n,Playback(demo-echodone) same => n,Playback(vm-goodbye) same => n,Hangup()
We have created a separate context just for the echo test here, as this is generally good practice. Instead of duplicating code should you wish to add another echo test on a different extension, you can simply copy the GoTo statement and send it to the same context.
Note that the use of the s extension is completely arbitrary and could be anything. In macros, you are required to use the s extension, but subroutines often use the start extension instead (but could use anything, including s, as you may see elsewhere in this documentation).
However, this may not be what you want on your node. If you call extension 9931, by dialing, say, 555-9931, you won't immediately be dumped into the echo test. Most Asterisk systems with echo tests use the code above, which plays an introductory message about the echo test first and a concluding message afterward (if you press # as opposed to simply hanging up). If you simply want your extension to go to an echo test (perhaps more realistic if you are trying to stick with the "vintage" theme, you can replace the above [echo] context with the following:
[echo] exten => s,1,Progress() ; Echo test with no instructions same => n,Echo() same => n,Hangup()
Now, you'll immediately enter the echo test when you call extension 9931, and you won't hear anything if you press "#" before it terminates the call. Here, we use Progress instead of Answer, since an echo test is a test number, so it should not provide answer supervision.
Creating a silent termination line is incredibly simple:
[silentterm] exten => start,1,Wait(86400) same => n,Return
What this subroutine actually does, when called, is wait for 86,400 seconds (or 24 hours), before returning. This way, a caller can't call your silent termination line and stay there forever.
To create a silent termination extension, simply add the following subroutine call to an extension:
exten => 9932,1,Gosub(silentterm,start,1) same => n,Hangup
Note that this silent termination line will not "supe" (it won't provide answer supervision). You can add an Answer statement first to change that:
exten => 9932,1,Answer same => n,Gosub(silentterm,start,1) same => n,Hangup
Asterisk allows you to use the mpg123 utility to play MP3 streams from the Internet. Although it is not so popular anymore, in the mid to late-20th century, it was quite common to be able to listen to live music feeds and radio stations using certain access numbers, allowing people to listen to their favorite stations and news from wherever they were (provided they were willing to foot the long-distance charges). In Asterisk, there are two approaches you can take to play an MP3 stream.
The first approach is to define the stream in musiconhold.conf. For our example here, we will create a stream for the KZSU radio station which, as of this writing, features, among other things, a 1950s 701B SxS electromechanical switch in its office. We will also create a stream for KPFA, the flagship station of the Pacifica Radio Network:
[KZSU] mode=custom application = /usr/bin/mpg123 -q -s --mono -r 8000 -f 8192 -b 0 http://171.66.118.110:8080/kzsu-1-128.mp3 [KPFA] mode=custom application = /usr/bin/mpg123 -q -s --mono -r 8000 -f 8192 -b 0 http://streams.kpfa.org:8000/kpfa
Now, you will need to add the appropriate dialplan code to access the Music on Hold streams you defined:
exten => 5078,1,Answer() same => n,Set(TIMEOUT(absolute)=3600) same => n,MusicOnHold(KZSU) same => n,Hangup() exten => 5732,1,Answer() same => n,Set(TIMEOUT(absolute)=3600) same => n,MusicOnHold(KPFA) same => n,Hangup()
The timeouts you see simply prevent the extension from being tied up forever (even though multiple people can access the stream). After 3600 seconds, or 1 hour, the call will automatically be disconnected. This can help ensure callers don't dial into a stream and let it run for perpetuity.
Now by dialing extension 5078 (or KZSU if dialing by letters) or dialing extension 5732 (or KPFA), you can listen to those respective radio stations.
*Technically, Z is not on the telephone dial, so we have substituted 0 for Z, since the two were equated for ZEnith dialing in many areas.
The downside of this approach is that it doesn't scale well. Every MP3 stream you define in musiconhold.conf is running all the time, 24/7/365. While we don't think this makes much sense (and perhaps constitutes a bug, unintentional or otherwise) in Asterisk, that's how it is. We learned this the hard way when we defined around 100 MP3 streams in musiconhold.conf. As soon we entered moh reload at the Asterisk CLI, the server immediately ground almost to a halt. Needless to say, things were not pleasant. We recommend using this approach only if you have a few streams; if you are looking to have more than 5 or 10 streams, a better approach is to not use musiconhold.conf at all but instead to create the stream on demand directly in the dialplan, like so:
exten => 5078,1,Answer() same => n,Set(TIMEOUT(absolute)=3600) same => n,MP3Player(http://171.66.118.110:8080/kzsu-1-128.mp3) same => n,Hangup() exten => 5732,1,Answer() same => n,Set(TIMEOUT(absolute)=3600) same => n,MP3Player(http://streams.kpfa.org:8000/kpfa) same => n,Hangup()
As you can see, musiconhold.conf is not used at all. The advantage of this is that streams are not running when they are not in use. Resources will only be used to play the stream when there is an active call connected to these extensions.
So, which approach should you use? The downside of the latter approach is that a separate stream instance is created for each caller, even if they are all accessing the same stream. Thus, the approach you implement will depend largely on how and by whom your streams will be used. If you expect a lot of callers will be calling a small number of streams, go with the first method. If you want to create a large number of streams and don't expect much traffic to any single stream in particular, you should consider the second method, since you will not dedicating unnecessary resources to playing the streams when they are not in use.
Finally, worth mentioning is that since the latter approach creates the stream on-demand, rather than accessing an "already-on" stream, there is an additional delay when the stream is called of about 1 second. The delay is not really noticable unless you are listening for it, but you may want to keep this in mind if you need a stream to available the split instant you call it. If this is the case for you, then you will want to define the stream in musiconhold.conf so that it is always playing and immediately accessible. That being said, the discrepancy is only about 1 second, so it is not really worth doing this unless you have a good reason. The former approach is recommended if you only have a few streams and expect high traffic to them, but we personally prefer the latter approach as it allows you to have an unlimited number of streams that, provided they are generally low-traffic, will keep resource utilization to a minimum (i.e. none) when idle.
In other words, if streaming is a big part of what you do, but you don't have too many, define your streams in musiconhold.conf. Otherwise, don't; simply create the streams on demand.
Loop arounds are test lines that, while not as common in the PSTN today as they used to be, are still around if you know where to look (or rather, what to call). Of course, you can create your own loop arounds as well!
For those unfamiliar, a loop around is a pair of numbers, generally two consecutive numbers, which could be anything, used by telephone technicians. In the heyday of phreaking, they were prone to abuse by phreaks who would use them to anonymously talk to other people without having to give out their real phone number. If one person called one number and another called the corresponding number of the pair, they would be bridged together — free of charge.
In a loop around pair, while waiting for somebody to call the other line, one of the numbers functions as a milliwatt test while the other functions as a silent termination test. As soon as the other number is called, however, the two lines are immediately bridged. Either the low or high number, in theory, can be the tone or silent side, and it doesn't matter which line is called first or by whom.
Thanks to John Covert for the following code to create loop arounds or "loops" in Asterisk.
[looptest] ; ARG1 is the unique loopid; ARG2 is "tone" for the tone side and nothing for the silent side
exten => s,1,Wait(1)
same => n,Answer()
same => n,Set(loopid=${ARG1})
same => n,Set(looptone=${ARG2})
same => n,Set(GROUP(side)=looparound_${loopid}${ARG2}) ; only one caller per side of the loop
same => n,NoOp(${SET(gc=${GROUP_COUNT(looparound_${loopid}${ARG2}@side)})})
same => n,GotoIf($[${gc}>1]?busy)
same => n,Set(GROUP(looparound)=looparound_${loopid}) ; This group is for who's first. Both sides are in it.
same => n,Goto(loop,s,1)
same => n(busy),Set(GROUP()=)
same => n,Goto(stepbusy,s,1) ; only one user on any side at a time
[loop]
exten => s,1,NoOp(${SET(gc=${GROUP_COUNT(looparound_${loopid}@looparound)})})
same => n,GotoIf($[${gc}=2]?bridge) ; First Caller waits, second caller bridges
same => n,Set(loopdbdel=1) ; only this side deals with creating and deleting the database
same => n,Set(DB(loop/${loopid})=${CHANNEL})
same => n,ExecIf($["${looptone}" = "tone"]?Playtones(1004/10000,0/2000))
same => n,Wait(360000) ; 100 hours max wait time for the other guy to show up.
same => n,Goto(1)
same => n(bridge),Set(loopchan=${DB(loop/${loopid})})
same => n,GotoIf($["${loopchan}" = ""]?1) ; Other side hung up just as we arrived, so we're now the first side
same => n,Bridge(${loopchan})
same => n,Goto(1)
exten => h,1,ExecIf($["${loopdbdel}" != ""]?DBdel(loop/${loopid}))
A loop pair then might be created as follows:
exten => 0041,1,Gosub(looptest,s,1(${EXTEN:-4:3},tone))
same => n,Hangup()
exten => 0042,1,Gosub(looptest,s,1(${EXTEN:-4:3}))
same => n,Hangup()
exten => 9996,1,Gosub(looptest,s,1(${EXTEN:-4:3},tone))
same => n,Hangup()
exten => 9997,1,Gosub(looptest,s,1(${EXTEN:-4:3}))
same => n,Hangup()
If you have multiple exchanges, you might opt to adopt the following approach instead:
[KLondike5]
exten => _004[1-2],1,Goto(looparound,${OC1}${EXTEN},1)
exten => _999[6-7],1,Goto(looparound,${OC1}${EXTEN},1)
[KLondike6]
exten => _004[1-2],1,Goto(looparound,${OC2}${EXTEN},1)
exten => _999[6-7],1,Goto(looparound,${OC2}${EXTEN},1)
[looparound]
exten => _NNX0041,1,Gosub(looptest,s,1(${EXTEN:-7:6},tone))
same => n,Hangup()
exten => _NNX0042,1,Gosub(looptest,s,1(${EXTEN:-7:6}))
same => n,Hangup()
exten => _NNX9996,1,Gosub(looptest,s,1(${EXTEN:-7:6},tone))
same => n,Hangup()
exten => _NNX9997,1,Gosub(looptest,s,1(${EXTEN:-7:6}))
same => n,Hangup()
Adopt whichever approach makes sense for you. The important thing to note is that if you strip the very last digit of all of your loop numbers, none of them should be identical unless they are part of the same loop pair. What this means is that if you have 0041 and 0042 setup as a loop pair, you can't have 0048 and 0049 also setup as a loop pair, because "004" is used to identify the loop pair and you've now created two supposedly different "pairs" that are, not, in fact, going to work properly. As long as you don't create more than one loop around pair in the same 10s group, you'll be fine.
The following would allow you to "tap" any of your lines. Optionally, if you would also like to allow the network operator access to a node's local verification trunks for troubleshooting and test purposes (which is recommended in keeping with the theme of the network)..
There are several levels of "channel spying" in Asterisk. You can simple listen to the channel, you can whisper to one of the parties (the calling party/owner of the channel), and you can barge into the conversation and be heard by both parties (interrupt). You should use the "listen" option for busy-line verification; the "barge" option should be used for busy-line interrupt. To allow the PhreakNet operator to do busy-line verification and interrupt on lines on your node, please leave a message at the number above.
Here is the dialplan code needed to use ChanSpy, assuming the variable chan is at this point the name of the SIP device or channel on which to spy.
Listen only (Verification):
same => n,ChanSpy(SIP/${chan},q)
Whisper:
same => n,ChanSpy(SIP/${chan},qw)
Barge (Interrupt):
same => n,ChanSpy(SIP/${chan},qB)
The 'q' option will not play a beep/announce the channel's name before tapping into the line (in all cases, this is audible by you only, not the spied-on channel). In conjunction with q and other options, you can use v(N) to change the volume where N is between -4 and 4. You can read further about ChanSpy on the VoIP Info site.
You can easily setup virtual T1 trunks in Asterisk. Here's how to set up the virtual NICs in Debian 9:
sudo apt-get update
sudo apt-get install build-essentialmodprobe tun to load the tun Linux kernel module. If you are using a hosted VM, you may need to enable "tun" with the virtual machine tun enable switch (it may say "TUN/TAP ON").
wget https://code.phreaknet.org/asterisk/virtual-nic/addr1.c
wget https://code.phreaknet.org/asterisk/virtual-nic/addr2.c
wget https://code.phreaknet.org/asterisk/virtual-nic/taptap-modified.c
gcc taptap-modified.c -o taptap
gcc addr1.c -o addr1
gcc addr2.c -o addr2You now have 3 executable binaries: taptap, addr1, and addr2:
taptap creates two virtual NICs named "tun0" and tun1" with random MAC addresses, and sets up the virtual crossover cable buffers. You can see these along with the hardware NICs with ifconfig -a
addr1 sets the tun0 random MAC address to 11:11:11:11:11:11
addr2 sets the tun1 random MAC address to 22:22:22:22:22:22
sbin so they are in an executable path and change the permissions:
mv /root/addr1 /sbin/
mv /root/addr2 /sbin/
mv /root/taptap /sbin/
sudo chmod 755 /sbin/addr1
sudo chmod 755 /sbin/addr2
sudo chmod 755 /sbin/taptap
taptap should be run at an elevated user priority of "-20" for best performance. Use the "nice" command to invoke in the background:
nice -n -20 taptap&ifconfig -aifconfig tun0 up and ifconfig tun1 up. Then they are ready for use by ProjectMF. Invoking these needs to be done at VM startup in a script, before Asterisk and Dahdi are started. Of course, all this can be done in a startup script before Zaptel and Asterisk are started.Contrary to what you may have read elsewhere on the web, you can setup virtual modems in Asterisk! Here, we will set up a virtual modem and use that to create a BBS.
sudo apt-get install telnetd -y
sudo apt-get install telnet -y
sudo apt-get install xinetd -y
sudo apt-get install tcpd -y
service xinetd restart
sudo apt-get install lynx -y — text/line mode text browser
sudo apt-get install less -y — navigation of large outputs
sudo apt-get install libxml2-utils -y — HTML parser
sudo apt-get install bc -y — Basic Calculator
sudo apt-get install sshpass -y — SSH Auto-Password Passer
sudo apt-get install lynx -y — SSH Auto-Password Passer
If telnet does not work, or later stops working, follow the steps in these two StackOverflow answers:
Here are the critical steps from the two answers linked above:
telnet stream tcp nowait telnetd /usr/sbin/tcpd /usr/sbin/in.telnetd to /etc/inetd.conf.
/etc/xinetd.conf:
Simple configuration file for xinetd
#
# Some defaults, and include /etc/xinetd.d/
defaults
{
# Please note that you need a log_type line to be able to use log_on_success
# and log_on_failure. The default is the following :
# log_type = SYSLOG daemon info
instances = 60
log_type = SYSLOG authpriv
log_on_success = HOST PID
log_on_failure = HOST
cps = 25 30
}
sudo /etc/init.d/xinetd restart
sudo apt-get install tcpd
nano /etc/issue.net
Debian GNU/Linux 9 and replace it with text like:
Welcome to the BBS! Login with username "com" and password "com"Press CTRL+X to save, then Y to confirm, then press ENTER.
sudo adduser -p $(openssl passwd -l com) com (the first "com" is the password, the second is the password)
To change the password last type sudo passwd com and it will ask for the new password.
To get the user ID of the user, type id -u com.
To make this a passwordless account, first modify /etc/ssh/sshd_config and change #PermitEmptyPasswords no to PermitEmptyPasswords yes
Then, pw usermod com -w none
touch /home/com/main.sh
usermod -s /home/com/main.sh com
chmod a+x /home/com/main.sh
Alternate Instructions: adduser com; sudo chsh -s /home/com/main.sh com
touch /home/com/.hushlogin
rm -rf /etc/motd
touch /etc/motd
Allow certain system access to the controlled shell environment:
chmod 777 -R /var/spool/asterisk
chmod 777 -R /home/com/log
wget https://raw.githubusercontent.com/proquar/asterisk-Softmodem/app_softmodem/app_softmodem.cwget https://code.phreaknet.org/asterisk/app_softmodem.c
mv app_softmodem.c /usr/src/asterisk-13.24.0/apps/
cd /user/src/asterisk-13.24.0/apps/
make apps
make install
service asterisk restart
reboot
exten => btx,1,Answer() same => n,Softmodem(host, port, options) same => n,Hangup() Without any arguments the application acts as a V.23 modem and connects to a Telnet server (port 23) on localhost. Options are: r(...): rx cutoff (dBi, float, default: -35) t(...): tx power (dBi, float, default: -28) v(...): modem version (default: V23): V21 - 300/300 baud V23 - 1200/75 baud Bell103 - 300/300 baud V22 - 1200/1200 baud V22bis - 2400/2400 baud l or m: least or most significant bit first (default: m) d(...): amount of data bits (5-8, default: 8) s(...): amount of stop bits (1-2, default: 1) u: Send Ulm Relay Protocol header to Telnet server n: Send NULL-Byte to modem after carrier detection (Btx specific) The modem seems to work fine with VOIP as long as you use a codec like G.711 (alaw/ulaw). Please deactivate any echo cancellation you might use.In your dialplan, to use a "Bell 103" 300 baud modem, you might use the following:
exten => 4221,1,Answer() same => n,Softmodem(127.0.0.1,23,v(Bell103)ld(8)s(1)un) same => n,Hangup()
asterisk -r and then dialplan reloadAsterisk actually has very good fax support built in (not including the fax stuff that Digium sells), so if you aren't using it, you're missing out.
Receiving faxes in Asterisk is easier than sending them, purely for logistical reasons. It's easy to have an incoming fax emailed to you. It's a bit more involved to receive documents in a compatible format and get them onto the system in a way that they can be sent.
Here are good starting resources for receiving and sending faxes:
To make incoming faxes behave like voicemails, you can call a System command in the hangup handler to have incoming faxes emailed to you as TIF files.
The link above discussing outgoing faxes discusses an approach for doing this. However, it may be more feasible and conveient to design a secure file upload page than to process incoming emails for fax delivery.
ACTS when used here is an abuse of notation. More properly, they are known as single-slot coin denomination tones and were used in ACTS, among other things.
In December 2019, Asterisk source files, centered around dsp.c, were successfully forked to add MF and ACTS detection support to Asterisk.
Credits: Dylan Cruz, Howard Harte, Joshua Stein, Naveen Albert
Detection support is not integrated, but rather a separate program that can be called at will when a detector is needed. In other words, if you need an ACTS detector, you can bring one into the call and then get rid of it, much like how ACTS detectors are used for PSTN (non-COCOT) payphones.
Thanks to MF and ACTS support, it is now possible to have Project MF in modern Asterisk!
ZIP Download: detect.zip
The ZIP folder contains the following directories:
The _arm folder contains code for the ARM architecture (e.g. Raspberry Pi). The x86 folders are for x86/i386.
The contents of the appropriate subfolder of the detect folder should be extracted to /etc/asterisk/scripts/detect. You will need to choose the subfolders specific to your architecture. So, if you are running x86, you would extract detect/x86/mf to /etc/asterisk/scripts/detect/mf — don't preserve the x86 or arm in your file hierarchy — choose the architecture you need and place its subfolders right into /etc/asterisk/scripts/detect/
Note that the detector application is named mf for both the MF and ACTS detectors. Only the folder name distinguishes the two; the executable name should not be changed, and there is no extension.
ACTS tones are used for payphone coin signalling on modern non-COCOTs, succeeding the gong-style signalling used in 3-slot payphones. MF and 2600 are part of the multifrequency and singlefrequency signaling systems. DP is audible dial pulsing for real-time dial pulsing, which is generally not possible with VoIP connections.
There are three actual detectors that work separately:
/etc/asterisk/scripts/detect/mf/mf — MF and 2600 Hz detector/etc/asterisk/scripts/detect/acts/acts — ACTS detector/etc/asterisk/scripts/detect/dp/dp — Dial Pulse detectorThe ACTS detector is the simplest to use. For each detected ACTS beep (each of which is worth 5 cents), it returns one $ (dollar-sign) symbol.
Likewise, the dial pulse detector will return one P for each dial pulse.
The MF/2600 detector is one detector that supports multifrequency, single frequency, and 2600 Hz (general) detection. For multifrequency 0 through 9, it returns 0 through 9. For KP, it returns * and for ST, it returns #. For every single instance of 2600, it returns one "S". Thus, one loud constant 2600 burst (such as a trunk reset) returns a single "S"; dial-pulsing 2600 Hz (i.e. single-frequency signaling) at 10pps or 20pps will produce one S per pulse, making it possible to detect single-frequency dialing in addition to single 2600 Hz tones.
Here is a simple subroutine that uses the ACTS detector (on x86/i386 architecture, but that can be changed), to listen for ACTS tones. Notice that it automatically calculates how many "$"s appeared (\x24 is the hex escape code for $).
[acts-read] ; NA 20200104 ; ARG1 = max silence, ARG2 = max duration, RETURNs # of ACTS beeps
exten => s,1,Set(ss=${STRFTIME(${EPOCH},,%s)})
same => n,Set(file=/tmp/${UNIQUEID}-${ss}.wav)
same => n,Record(${file},${ARG1},${ARG2},qx) ; q = quiet, x = ignore terminator keys
same => n,Set(beeps=${SHELL(/etc/asterisk/scripts/detect/acts/acts ${file})})
same => n,Set(beeps=${FILTER(\x24,${beeps})}) ; \x24 = hex for "$"
same => n,Set(num=${LEN(${beeps})})
same => n,NoOp(ACTS: ${beeps} -> ${num})
same => n,Return(${num})
This detector is used on the payphone trunks. So if you're thinking of using this detector to program a payphone controller it's already been done! Applications of the detectors have already been fairly rigorously exhausted for everyone's benefit, and we've made the applications that make use of these detectors available as well. If you would like to help improve these end-applications or have ideas, please contact the Business Office.
The Cadence Plan allows for the use of standardized custom ring cadences across the network. These are used most commonly for party ling (coded) ringing, busy line callback, and priority ring on calls with greater than routine precedence. The cadences and their numbering were carefully chosen to minimize conflicts with the Bellcore specifications while allowing for maximal functionality and accessibility on the network.
ATAs provisioned by the PhreakNet provisioning server are automatically programmed with the cadences below.
Grandstream ATAs typically allow for 10 cadences, while Linksys ATAs typically allow for 8 (sometimes 9) cadences.
| Cadence # | Cadence Length | Cadence Description | Grandstream | Linksys |
|---|---|---|---|---|
| 1 | 6.0 | Standard (US) | c=2000/4000; | 300(2/4) |
| 2 | 6.0 | S-L-S | c=300/200-1000/200-300/4000; | 300(.3/.2,1/.2,.3/4) |
| 3 | 6.0 | L-L | c=800/400-800/4000; | 300(.8/.4,.8/4) |
| 4 | 5.9 | S-S-L | c=400/200-300/200-800/4000; | 300(.4/.2,.3/.2,.8/4) |
| 5 | 6.0 | S-L-L | c=400/200-800/200-800/3600; | 300(.4/.2,.8/.2,.8/3.6) |
| 6 | 5.4 | S-S-S | c=200/400-200/400-200/4000; | 300(.2/.4,.2/.4,.2/4) |
| 7 | 6.0 | L-S-L | c=800/200-400/200-800/3600; | 300(.8/.2,.4/.2,.8/3.6) |
| 8 | 2.0 | Priority | c=1650/350; | 300(1.65,.35) |
| 9 | 5.9 | L-S-S | c=800/200-300/200-400/4000; | 300(.8/.2-.3/.2,.4/4) |
| 10 | 3.0 | S-S (Standard UK) | c=400/200-400/2000; | 300(.4/.2,.4/2) |
If you are using DAHDI, here are the cadence specifications for the [channels] section in chan_dahdi.conf:
[channels] cadence=2000,-4000 cadence=300,200,1000,200,300,-4000 cadence=800,400,800,-4000 cadence=400,200,300,200,800,-4000 cadence=400,200,800,200,800,-3600 cadence=200,400,200,400,200,-4000 cadence=800,200,400,200,800,-3600 cadence=1650,-350 cadence=800,200,300,200,400,-4000 cadence=400,200,400,-2000
If your ATA uses different formats for specifying cadences, please contact the Business Office and we can work with you to get your ATA set up correctly.
Subroutines like the following may be used to send the right cadence to your ATA:
[SIP-RingHeader] ; ARG1 = cadence / ARG2 = peers
exten => s,1,Set(peerstocheck=${ARG2})
same => n,Set(i=-1)
same => n(checkfree),Set(i=${LEN(${CUT(peerstocheck,&,1)})})
same => n,Set(nextpeer=${peerstocheck:0:${i}})
;same => n,Set(nextpeer=${nextpeer:4})
same => n,Set(peerstocheck=${peerstocheck:$[${i}+1]})
same => n,GotoIf($["${nextpeer:0:4}"="SIP/"]?sip)
;;;; UNSUPPORTED TECHNOLOGY ;;;;
same => n,Goto(next)
same => n(sip),Set(nextpeer=${CUT(nextpeer,/,2)})
same => n,Set(agent=${FILTER(A-Za-z0-9\x20\x2E\x2F\x2D,${SHELL(asterisk -rx 'sip show peer ${nextpeer}' | grep "Useragent" | grep -o ':.*')})})
same => n,Gosub(SIP-RingHeader-indiv,s,1(${ARG1}, ${agent:1})) ; Trim space that was after the : from agent
same => n(next),GotoIf($[${LEN(${peerstocheck})}=0]?allchecked:checkfree)
same => n(allchecked),Return()
[SIP-RingHeader-indiv] ; ARG1 = cadence / ARG2 = SIP ATA user agent
exten => s,1,NoOp(${ARG2}) ; if we know what user agent this is, we'll only send that header
same => n,GotoIf($[${REGEX("Grandstream" ${ARG2})}=1]?grandstream,1)
same => n,GotoIf($[${REGEX("Linksys" ${ARG2})}=1]?linksys,1)
same => n,GotoIf($[${REGEX("OBIHAI" ${ARG2})}=1]?obi,1)
;same => n,SIPAddHeader(Alert-Info: info=) ; this is a bad fallback
same => n,Goto(grandstream,1) ; fallback to Grandstream
exten => grandstream,1,SIPAddHeader("Alert-Info:\;info=ring${ARG1}") ; Supports 1-10
same => n,Return()
exten => linksys,1,SIPAddHeader("Alert-Info:\;info=Bellcore-r${ARG1}") ; Linksys (e.g. PAP2T), etc.
same => n,Return()
exten => obi,1,SIPAddHeader(Alert-Info: http://127.0.0.1/Bellcore-dr${ARG1:-1}) ; send only a single digit
same => n,Return()
You could then set the cadence by calling it like: same => n,Gosub(SIP-RingHeader,s,1(${EXTEN},${ARG3})) (assuming EXTEN is the ring cadence and ARG3 is the SIP peer).
The SIP header should only get sent once, so if the cadence could be changed before ringing the phone, keep track of that in a separate variable. When determining the cadence to use, consider the priority of the call (MLPP) as well.
MLPP is most commonly associated with AUTOVON, the old automatic voice network, which was used by the military for much of the Cold War. AUTOVON implemented MLPP. MLPP uses the 4th-column DTMF keys (A, B, C, and D), used as FO (flash override), F (flash), I (immediate), and P (priority). If you don't have 4th-column DTMF, you can use a silver box, such as this one.
Priority Audible Ring replaced normal ring for calls within AUTOVON. It consists of 440 Hz + 480 Hz at -16 dBm0/frequency on for 1.65 seconds and off for .35 seconds.
Preemption Tone is provided to both parties of a connection that a priority call from the AUTOVON network preempts. Preemption Tone is 440 Hz and 620 Hz at -18 dBm0/frequency steady for anywhere from three to fifteen seconds.
MLPP is fairly straightforward to use in Asterisk, and is currently used on the main tandem, which is a multi-function switch (e.g. dial 231-1111 if you are not served by this switch and don't have a foreign exchange line). If you encounter an "all circuits busy" condition, you may be able to complete your call by preempting a lower-priority call.
The following priority levels are usable by the following populations:
Note that this means PSTN callers, etc. cannot request priority of any level for any call.
If all circuits remain busy and your call is urgent, dial 0. Operator-assisted calls are completed using a different trunk group.
The MLPP/AUTOVON library is relatively small:
[autovoninit] ; Returns number of current trunk calls
exten => _[A-D0],1,NoOp(AUTOVON Precedence: ${EXTEN}) ; AUTOVON checks
same => n,Gosub(currentldcalls,s,1)
same => n,GotoIf($[${GOSUB_RETVAL}=0]?:database)
same => n,DBdeltree(autovonA) ; Reset the key families, to wipe out old, unneeded data (none of which is currently needed)
same => n,DBdeltree(autovonB)
same => n,DBdeltree(autovonC)
same => n,DBdeltree(autovonD)
same => n,DBdeltree(autovon0)
same => n(database),Set(GROUP(autovon)=${EXTEN})
same => n,Set(DB(autovon${EXTEN}/${FILTER(0-9,${UNIQUEID})})=${CHANNEL})
same => n,Return()
[autovonpreempt]
exten => s,1,GotoIf($["${autovonprioritydigit}"="0"]?done) ; can't preempt any calls
same => n,Set(callids=${DB_KEYS(autovon0)})
same => n,GotoIf($[${LEN(${callids})}>0]?0,1)
same => n(ad),GotoIf($["${autovonprioritydigit}"="D"]?done) ; can't preempt other priority calls
same => n,Set(callids=${DB_KEYS(autovonD)})
same => n,GotoIf($[${LEN(${callids})}>0]?D,1)
same => n(ac),GotoIf($["${autovonprioritydigit}"="C"]?done) ; can't preempt other immediate calls
same => n,Set(callids=${DB_KEYS(autovonC)})
same => n,GotoIf($[${LEN(${callids})}>0]?C,1)
same => n(ab),GotoIf($["${autovonprioritydigit}"="B"]?done) ; can't preempt other flash calls
same => n,Set(callids=${DB_KEYS(autovonB)}) ; so, yes, only a flash override can get to this point
same => n,GotoIf($[${LEN(${callids})}>0]?B,1)
same => n(done),Return() ; Sorry, can't preempt anything
exten => _[A-D0],1,Set(callid=${CUT(callids,\,,1)})
same => n,Set(preemptchan=${DB(autovon${EXTEN}/${callid})})
same => n(preemptcall),ChannelRedirect(${preemptchan},autovonpreempted,s,1)
same => n,GotoIf($["${CHANNELREDIRECT_STATUS}"="SUCCESS"]?success) ; SUCCESS | NOCHANNEL
same => n,Set(deleted=${DB_DELETE(autovon${EXTEN}/${callid})}) ; call isn't up anymore, so delete from DB
same => n,Goto(a0) ; try again - hunt for another call to preempt
same => n(success),Return()
[autovonpreemptfail]
exten => _[ABCD].,1,Progress()
same => n,Playback(custom/switch/autovon/autovon603&custom/switch/autovon/autovon603,noanswer) ; audio file with 603 intercept
same => n,Hangup()
[autovonpreempted]
exten => s,1,Set(GLOBAL(autovonpreempted${FILTER(0-9,${UNIQUEID})})=1)
same => n,Set(GROUP(autovon)=)
same => n(preempt),PlayTones(440+620) ; can also be defined as preemption in indications.conf
same => n,Wait(15) ; Play preemption tone to caller for 15s
same => n,StopPlayTones()
same => n,Hangup(8) ; AST_CAUSE_PRE_EMPTED
[autovonpreempted-callee]
exten => s,1,Set(CDR_PROP(disable)=1)
same => n,Hangup() ; this extension is used if none is specified b/c there was no channel (so, no chance of the call being pre-empted, so don't provide the 8 cause code)
exten => _X!,1,Wait(0.3) ; wait ever so slightly, to give the variable time to get set
same => n,ExecIf($["${$[autovonpreempted${EXTEN}]}"="1"]?PlayTones(440+620):Hangup()) ; can also be defined as preemption in indications.conf
same => n,Wait(3) ; Play preemption tone to caller for 3s
same => n,Hangup(8) ; AST_CAUSE_PRE_EMPTED
[currentldcalls]
exten => s,1,Return($[${GROUP_COUNT(A@autovon)}+${GROUP_COUNT(B@autovon)}+${GROUP_COUNT(C@autovon)}+${GROUP_COUNT(D@autovon)}+${GROUP_COUNT(0@autovon)}])
Some assumptions and simplifications are necessary for using MLPP. Since trunking is peer to peer using IAX2, scarcity is not really a thing. Thus, artificial limitations must be introduced for preemption to ever occur. However, priority ringing is useful and possible without placing artificial limitations on trunking.
To use the library, do the following:
exten => _[A-D].,1,Goto(something,${EXTEN},1))
Both should be properly handled, in a manner such as the following
same => n,Gosub(currentldcalls,s,1)
same => n,GotoIf($[${GOSUB_RETVAL}<${autovonmaxcalls}]?proceed)
same => n,Gosub(autovonpreempt,s,1) ; Attempt to preempt a call
same => n,Wait(3.2) ; may need to adjust to all group count to fall when preempted call clears
same => n,Gosub(currentldcalls,s,1)
same => n,GotoIf($[${GOSUB_RETVAL}<${autovonmaxcalls}]?proceed)
same => n,GotoIf($["${autovonprioritydigit}"=""]?acb)
same => n,GotoIf($["${autovonprioritydigit}"="0"]?acb)
same => n,Progress() ; all circuits busy and no calls preemptable
same => n,Playback(custom/switch/autovon/autovon601,noanswer) ; for priority callers with insufficient precedence to preempt
same => n,PlayTones(congestion)
same => n,Wait(30)
same => n,StopPlayTones()
same => n,Hangup()
same => n(acb),Playback(custom/allcktsbusy,noanswer)
same => n,Hangup()
same => n(proceed),Gosub(autovoninit,${autovonprioritydigit},1) ; we can proceed with the call...
On a successful call that leaves your switch, call Gosub(autovoninit,${autovonprioritydigit},1) as shown above. This stores information about the call in the database so that we can preempt this call later if needed.
Preemption handling is already built into the boilerplate code, using the F dial option.
It may be desirable to prevent certain callers from using certain priorities. As an example, on the main tandem, non-network callers may not use any priorities. Any network caller may use the D and C (Priority and Immediate) priorities. Only hosted lines on the main tandem may use the B (Flash) priority. Only the switch owner may use the A (Flash Override) priority. This arrangement is not included above, and would be done when we receive the digits _[A-D] and set the autovonprioritydigit variable. If a caller does not have the necessary privileges, he would be routed as follows: Goto(autovonpreemptfail,${EXTEN},1). The exact classes of service each node desires to use may vary and are not prescribed. It is merely a suggestion that this behavior should be restricted by some class of service accordingly.
Priority Audible Ringing and Priority Ring are enabled by sending a custom ring cadence header to the FXS port before ringing the subscriber line. This can be done by checking the value of ${autovonprioritydigit} in the dialplan. If this value is strictly equal to A, B, C, or D (but not 0 or empty), then priority ring should be used. This corresponds to cadence 8 in the Cadence Plan.
Priority Audible Ring is easy: Set(dialoptions=r(priorityring)).
To send the right ring cadence to your ATA, use same => n,Gosub(SIP-RingHeader,s,1(${EXTEN},${ARG3})). See Cadences for this subroutine.
The audio files referenced above are not included and may be recorded locally using the appropriate verbiage.
The latest copy of the verification subroutines ensure MLPP information is transmitted between nodes and will ensure both priority ringing on the called telephone (assuming correct cadence setup).
If the preemption aspect above seems a bit silly, well, it is. In a full MLPP environment, MLPP status would be kept track of per-trunk. The MLPP code is a simplified and dumbed down version of full MLPP routines that keep track of priorities for each trunk in each trunk group. Of course, in the VoIP world with IP trunking, there is only one "trunk group" really.
If you would like to be served by manual service instead of dial service, your ATA should off-hook auto-dial 950-0100, which is a free call. This is a manual operator service trunk. All your calls will go through the operator.
If you want it to go directly to Brian specifically, use 950-0101.
The following information has been compiled courtesy of Don Froula:
For those using Windows machines on their LANs, you may wish to explore a very useful program that I have been using for many years. The Windows "NetCID" program receives an IP broadcast on your LAN from an Asterisk PERL AGI script that goes out to ALL local IP addresses on your LAN on a special port, where a popup and optional sound alerts to the incoming call. The contents of the popup may be customized in the AGI script. I have five different scripts to indicate if the call is coming from the PSTN, CNET, NPSTN or other sources.
You must have PERL installed on your Asterisk machine.
The program is quite old, and a bit hard to find. It does work fine on all versions of Windows, including Windows 10.
You can download the program here. Instructions for setting up the AGI and how to call it in your dialplan are available at VoIP-Info.
In the AGI script, set the first three octets of the IP address to match those of your LAN. Leave the last octet at 255, which signifies the data is to be broadcast to all devices on the LAN. You may need to allow IP broadcasts on your router. Do NOT change the port number.
You may modify the following to customize the popup display with hard-coded text that appears at the bottom of the screen. Change nothing else. Example:
my $MSG1 = “STAT Phone Call to $extension”;
You can call the AGI script from the dialplan like this:
exten => _X.,n,AGI(ncid4.agi,${CALLERID(num)},${CALLERID(name)},${EXTEN})
Note I have multiple versions of the script to display different text at the bottom of the large-sized popup. This is ncid4.agi (for CNET) to adjust as needed.
My old router, since replaced, did have a setting that blocked IP broadcasts on the LAN, although it seems that the broadcasts should not be controllable through the router as they are peer<>peer. When I install NetCID on Windows 10, Windows defender pops up and asks if I want to allow NetCID traffic on my LAN. I don't think this is default behavior in Windows 7. This action openrd all TCP and UDP ports for the NetCID application, but in reality it only uses UDP port 42685, so opening that up should be sufficient.
I installed Asterisk as root. My /var/lib/asterisk/agi-bin/ directory is owned by root with directory permissions of 750. The ncid.agi scripts themselves are 777.
You can change the IP address to target one machine on the LAN to see if broadcasts are being disallowed on the Asterisk machine or the target PC.
The "sleep 5" commands send periodic RING indications to the NetCID app to keep the popup on the screen if the "display until ringing stops" option is set on the NetCID app.
I think there is a typo on the first line of the AGI script on the web page. Note the first line must begin with "#!/usr/bin/perl", making sure the path to the PERL executable is correct.
Here is my working CNET script:
#!/usr/bin/perl
use Socket;
open STDOUT, '>/dev/null';
fork and exit;
my $timedata = localtime(time);
my $cidnum = $ARGV[0];
my $cidname = $ARGV[1];
my $extension = $ARGV[2];
my $MSG1 = "STAT CNET Phone Call to $extension";
my $MSG2 = "RING";
my $MSG3 = "NAME $cidname";
my $MSG4 = "TTSN Call from $cidname";
my $MSG5 = "NMBR $cidnum to $extension";
my $MSG6 = "TYPE U";
my $MSG7 = "IDLE $timedata";
my $ipaddr=192.168.1.255;
my $portnum=42685;
socket(SOCKET, PF_INET, SOCK_DGRAM, getprotobyname("udp")) or die "socket: $!";
setsockopt(SOCKET, SOL_SOCKET, SO_BROADCAST, 1) or die "setsockopt: $!\n";
send(SOCKET, $MSG1, 0, sockaddr_in($portnum,$ipaddr)) or die "cannot send to $HOSTNAME($PORTNO): $!";
send(SOCKET, $MSG2, 0, sockaddr_in($portnum,$ipaddr)) or die "cannot send to $HOSTNAME($PORTNO): $!";
send(SOCKET, $MSG3, 0, sockaddr_in($portnum,$ipaddr)) or die "cannot send to $HOSTNAME($PORTNO): $!";
send(SOCKET, $MSG4, 0, sockaddr_in($portnum,$ipaddr)) or die "cannot send to $HOSTNAME($PORTNO): $!";
send(SOCKET, $MSG5, 0, sockaddr_in($portnum,$ipaddr)) or die "cannot send to $HOSTNAME($PORTNO): $!";
send(SOCKET, $MSG6, 0, sockaddr_in($portnum,$ipaddr)) or die "cannot send to $HOSTNAME($PORTNO): $!";
sleep(5);
send(SOCKET, $MSG2, 0, sockaddr_in($portnum,$ipaddr)) or die "cannot send to $HOSTNAME($PORTNO): $!";
sleep(5);
send(SOCKET, $MSG2, 0, sockaddr_in($portnum,$ipaddr)) or die "cannot send to $HOSTNAME($PORTNO): $!";
sleep(5);
send(SOCKET, $MSG7, 0, sockaddr_in($portnum,$ipaddr)) or die "cannot send to $HOSTNAME($PORTNO): $!";
close(SOCKET);
exit;
There are quite a few options that can be set in the NetCID application, but you need to open them when from the tiny icon in the system tray in the lower right corner of the Windows desktop. Right click on the little TV-looking icon and some options that can be checked or unchecked will pop up. Choose "Configure" for many more. You may need to click the "^" to see the full list in the system tray.
You might try running the script from a Linux terminal window as a PERL script directly, rather than as an SGI script through Asterisk for debugging. That would eliminate a few variables.
perl /var/lib/asterisk/agi-bin/ncid.agi 5555555 "John Smith" 5554444
That invocation pops a window up on all my PCs in the house.
Potential Problems:
The script copied from the web site has open and close double quotes which are apparently not recognized by perl on my system. I found it when I tried to invoke the script from the command line and got error messages about an unrecognized character on a certain line. I changed all the open close double quotes to regular double quotes and all was well. It works from the command line and more importantly, from Asterisk as intended.
Note: This section is currently outdated. See Coin Trunks on the PhreakNet Portal for the most up to date info.
PhreakNet has several coin and coinless payphone trunks for both single-slot and 3-slot payphones. These trunks are designed for use with payphones on regular loop-start ATA lines with no additional hardware configurations. In other words, they are designed for payphones that have no smarts in them and won't act like payphones on their own. For those with a non-COCOT payphone and just an ATA and few other resources, these trunks can be used to bring your payphone to life!
To use the trunk, have the your payphone immediately connect to one of the following numbers below, depending on which kind of trunk you want for your payphone. If you have an ATA hosted by somebody else, you can have the ATA off-hook hotdial the number (e.g. (<:9500903>S0) — Grandstream users would specify { 9500903 } for the digit map and need to configure hotline dialing on the "Lines" tab). If you have an Asterisk switch, you should have a separate incoming context in extensions.conf for each kind of payphone trunk you want to use, which only allows calls to the the number below corresponding with that trunk (thus, the payphone trunk would be specified by the dialplan context specified in sip.conf). This is more secure, because a payphone caller will not be able to flash at payphone trunk dialtone and simply dial calls directly another way (or use a different kind of coin trunk, if all the coin trunks were dialable from that context). Linksys ATAs configured for hotline dialing may also prevent callers from flashing out of the payphone trunk, but Grandstream ATAs will not.
Have your ATA off-hook auto dial to Asterisk, and have Asterisk immediately complete a call if appropriate.
The payphone trunks are fully integrated with the toll ticketing (billing) system. The charges for payphone calls will always equal or exceed the charges that appear on your bill, so the coin revenue from a payphone on these payphone trunks will more than pay for the charges that appear on the bill for the line a payphone is on. Thus, you don't need to worry about charges. All you need to do is make sure your payphone sends proper 7-digit network caller ID (as it should anyways). Based on that, the payphone trunk will determine what rates are appropriate for calls made through the trunk. The charges will be very similar to calls made directly (i.e. not using a payphone trunk) from that number.
The local rate (initial deposit) on these payphone trunks is 10 cents. While information/directory assistance is free normally on PhreakNet, it costs 25 cents from payphones.
The way payphone rates are determined is either a flat rate greater than any possible charge for a call of that type OR a specific rate rounded up to the nearest $0.05 based on the station rate charges to a number are assessed.
Payphone operators (automated) handle select calls (e.g. long-distance). Long-distance can generally be dialed direct at 112 (or dial 0 for local calls or ask for long-distance).
These trunks are designed to be 99% plug and play with ~ZERO configuration on the part of the payphone owner (a small adjunct circuit in the physical vicinity of the phone is needed to monitor the line for MF tones and apply +/- 130V to do collect and return; however, the trunks themselves work fine without such a circuit, you'll just have to make your phone operate "piggy bank style" and not be able to get coins returned). These trunks are the equivalent of the CO-type trunks used for payphones.
See Coin Trunks on the PhreakNet Portal for a detailed listing.
The Charge-A-Call trunk is designed specifically for Charge-A-Call and other coinless payphones. It is integrated with PhreakNet TSPS and allows for seamless third-number billing. To use Charge-A-Call, you will need an InterLinked PIN, which can be set or reset in your InterLinked account settings. Calling card numbers are 14 digits, in the format 1NNXXXXXPPPPPP, corresponding to 1 + the 7-digit phone number + 6-digit InterLinked PIN. The only difference is that instead of using # to dial sequence calls, dial ** instead.
The reason for the leading 1 is two-fold: a) TSPS calling card numbers were 14 digits, and 13 is kind of an odd number. 6 digits is a standard amount for a PIN, and since numbers are 7 digits, that adds up to 13. So, an additional "1" is inserted first for now. In the future, there may be other uses for this "information digit", but for now, the only valid value is 1.
WECo style plays a second dial tone upon callee answer, indicating coins should be deposited, whereas Automatic Electric muted the mouthpiece and DTMF pad until coins were deposited. The Automatic Electric post-pay trunk relies on the caller to determine whether or not he wishes to talk, or use the keypad, and thus pay for the call. If he doesn't, there is no charge for the call, but it is limited in duration to a reasonable ringback (between 1 and 3 minutes). If/when a coin is deposited, the caller will be able to speak and dial/use the keypad again. We recognize this will allow free calls to listen-only numbers (e.g. time and temperature numbers).
We recognize that it is possible to "phreak" all of the trunks above by using a redbox or similar device capable of reproducing ACTS tones and 3-slot bell gongs. Consequently, payphone trunk usage is limited to verified, legitimate network callers (e.g. CVS code 70). This is necessary because of the real possibility of toll fraud, and it is a choice deliberately made to minimize our losses. All coins deposited into payphones using the payphone trunks are kept by the payphone owner (like with a COCOT; we don't get any share in the profits, even though we're the "telephone company" — at the same time, we still foot the bill as the payphone provider. If you would like to donate to this project to offset our expenses, please contact us!
The following publications have been created for your convenience. They are actual size and ready to print. These are the recommended accessories for your PSTN payphone:
Advertisement:
Single Slot Lower Instruction Card:
Single Slot Upper Instruction Card:
The following instruction cards are designed for use with semi post-pay coin phones. However, the PSTN trunks use ACTS, which is dial-tone first, not post-pay.
Single Slot Lower Instruction Card:
Single Slot Upper Instruction Card:
StepNet is an additional layer on top of PhreakNet, not a separate network.
The idea is that, instead of the call completing directly peer-to-peer, the call "steps" through the network, adding an interesting soundscape to the call and tandeming in a hierarchical manner similar to the way calls complete on the PSTN, where trunking is not peer to peer and calls must traverse multiple nodes for long distance calls.
A dialplan code repository of approved, standard, and exceptionally fully documented StepNet code for members would also be a good idea. — Brian Clancy
StepNet functionality is built into the boilerplate code. You will need to uncomment the relevant lines in iax.conf and then call the Business Office to enabling tandeming through your node.
In order to make StepNet routing more interesting, some kind of vintage signaling audio should be audible when a StepNet call is being tandemed.
Here are a few extensions that would do the trick:
These can all be found in the "Vintage Add-Ons" section of this documentation.
Other audio files needed for StepNet tandems are available as a standardized ZIP file downloadable below. The ZIP file contains all the ULAW files you need; no need for each node owner to convert them using SoX when we can do it once and also reduce the download size!
ZIP file containing standardized StepNet tandem audio files: click here to download.
Extract the audio files inside to the following location: /var/lib/asterisk/sounds/en/custom/stepnet/ (you will need to create the stepnet folder). The files are named sn1, sn2, sn3.
The ${RAND(min,max)} function in Asterisk will allow you to randomly play some of these audio files in the dialplan.
If you have physical ANI equipment that might fail, you may wish to take advantage of Operator Number Identification.
The routing lookup will automatically send ANI fails to a "TSP operator" for Operator Number Identification (ONI). The operator will key the number into the trunk and release the call. If a human operator is not available, an automated operator will handle the call, so the service is available 24/7.
Calls that require ONI should have the ANI II digits set to 1 if the line is an 8-party line or 2 if ANI was attempted but an ANI fail occured. The dialplan and central lookup will automatically route the call for ONI. There is no special handling required.
We do have human operators who are frequently on-duty. When the operator lines are staffed, calls to operator services (i.e. 0, 411, 611, 555-1212) will be answered by an operator who can help you with long-distance calling, information/directory assistance, or troubleshooting your phone line. The proper numbers to call are documented in the "Numbering Plan" section of this documentation.
With the exception of the Business Office line, if the on-duty operator is, well, off-duty, or otherwise unavailable, calls will automatically be forwarded to an automatic operator who will help you. The voice of these operators is the late Brian Clancy. If you'd prefer, you can also dial an automatic operator directly, bypassing the regular network operator. Again, the proper numbers are documented in the "Numbering Plan" section.
The long-distance and information operators use speech recognition technology coupled with speech-to-text processing to power your request. Though not known for working well with a wide variety of voices, we're quite pleased with how well they work (it is perhaps a bit ironic that Brian Clancy, who has a British accent, sometimes has trouble getting "himself" to recognize himself when calling an automatic operator). Our speech-to-text processing is powered by IBM Watson (see the "Further Add-Ons" section for more on this).
The automated operators work as follows: certain phrases are translated to numbers, and the rest of the translation is discarded. This results in extremely accurate operator assistance. As long as you enunciate your number clearly, operator Brian will be able to place your call for you. In addition to using numerals (such as 0, 1, 2, etc.), you can also use exchange names. If all goes well, it will be interpreted as part of the number.
Our long-distance operators also support service inquiries. If you ask for time and temperature, you will be connected with POPCORN. If you ask for the temperature, you will be connected with 511. If you ask for information, you'll be connected with Information. The automatic operator's high reliability is due, in part, to listening for and expecting only certain key phrases, and discarding the rest. Thus, we can expect a standardized response every time and can parse the request very accurately. Thus, if you say "Get me the police" or "Operator, could you get me the time and temperature, please?", the automatic operator will successfully be able to place your call since everything actionable is extracted and any extraneous text is discarded.
The Information operator, on the other hand, takes the reverse approach. Here, a caller could ask for any number of things that are in the Directory. It is therefore not possible to listen for certain phrases and ignore the rest. Rather, we must do the opposite: detect certain likely phrases (such as "hello", "operator", "information", "please", etc.), discard them from the translation, and then do a lookup in the directory using a separate API. Hence, if the caller is extraneous with his words, unlike the regular long-distance operator, who will not mind at all, the Information agent may not be able to find what you're looking for, as extra words could be counted as part of the lookup. That being said, we have anticipated many of the most common phrases and words. For best results, however, we recommend being succint. "Hello, information? Could you get me the number for the muzak listen line, please?" is perfectly acceptable. "Hello, ouch, I just stubbed my toe, boy that hurt! Oh, hello? This is information, ain't it? Well what do you know! Might you by chance happen to have the number for the, uh, muzak listen line, perhaps?" is not. A bit far-fetched, perhaps, but hopefully you see our point.
Speech-to-text processing is not done for the automatic repair agent. Instead, the repairman will collect your information and, at a later point in time, your inquiry will be reviewed by a service technician. To expedite a ticket, you can try calling our business office during regular hours.
Again, all the numbers described in this section are available in the "Numbering Plan" section of this documentation.
Some general notes that apply to all operator calls:
Paging numbers are available in the 549 exchange. Simply list your pager gateway email address in your InterLinked Account Settings; then call the Business Office for a pager number, no charge. Pager numbers can be either the original type (page only), or the later type (numeric message).
Dial 117 for telegrams, or log in to the user portal.
If you receive a telegram, you will be phoned at the number listed for delivery. You can confirm delivery of the telegram by viewing it online or answering the telegram call. Delivery will be attempted periodically until successful.
You can schedule one-time wake-up calls or recurring, snoozable wakeup calls. One-time wakeup calls can be scheduled at LIncoln9-1414.
Asterisk natively supports video, so time to end that Zoom call! However, there are some limitations and caveats to keep in mind. Unlike as with audio, Asterisk does not do any transcoding whatsoever of video. This means that you are essentially restricted to using a single video codec, as never the twain shall meet. We recommend H.264, since this is most robustly supported by Asterisk; for instance, only H.264 can be recorded; VP8 cannot be. Additionally, most SIP clients with video support typically support H.264.
The quality of live videos can be quite good, but the quality of recordings may leave something to be desired.
The following dialplan applications support video:
Echo — pretty straightforward
Voicemail — this just sounds awkward to us...
Record — do NOT try to record to a .h264 file! Instead, just record to a .wav file as usual. A .h264 file of the same name will automatically be created in the same location. Note that this just contains raw h264 frames. You'll need to combine the h264 and wav files with ffmpeg file if you want a combined audio + video file.
Playback — yes, you can now stream movies using Asterisk! Playback works exactly the opposite of Record. You specify the filename (without the extension, as usual), and Playback will stream the audio - and the video, if it finds one! So you should be able to invert these operations by using Record and then playing back what you recorded using Playback. Note that if you want to play some different video, you'll need to first separate it into the audio stream and the h264 video stream.
ConfBridge — of course, otherwise video support wouldn't be terribly useful
Not all SIP clients support video, but some do. The one that we recommend is MicroSIP. It's one of the most popular softphone applications out there, and it runs on any version of Windows NT.
However, using video with MicroSIP isn't entirely intuitive. The key thing to note is that you need to disable single call mode. Otherwise, there won't be any video support, and there's no hint as to why that is.
If you are using single-call mode, there isn't a button labeled "Video Call" on the pop-out panel, but you can click the video button to the left of the "Call" button after keying in a number. For shortcut buttons, you can change the action from "Call" to "Video Call" to automatically make the INVITE with video support every time (easiest option).
Note that upon doing this, it seems that video support needs to be indicated at the time the SIP INVITE is made to Asterisk. If you're off-hook auto-dialing with MicroSIP, that means as soon as you get dial tone from Asterisk, you need to indicate that you have video support. The remote end doesn't need to send video immediately, but if you don't tell Asterisk you support video from the get go, video support can't be enabled later.
Currently, you need to click "Video Call" in the pop-out panel that seems to only appear after you've made one call when using the application. So make any call using MicroSIP, and then the ancillary window should pop up and you'll see a "Video Call" option. That's what you'll need to allow video.
Finally, you also need to enable video support in the channel driver you are using - whether SIP or PJSIP.
For SIP, add:
videosupport=yes allow=h264
For PJSIP, add simply:
allow=h264
This needs to be done for any and all peers for which video support is desired.
This allows the H.264 video codec to be used for calls.
Now that you have a SIP client that supports H.264, and Asterisk is configured to allow H.264 for calls, you can take advantage of video in the dialplan. For video to work on a call between two parties, the caller needs to make the call with video support, and the caller needs to receive the SIP INVITE with video support available.
Note that if you use Originate, this means you must explicitly add the h264 codec to the allowed list of codecs (default is simply slin).
If using ConfBridge, the video_mode bridge setting may be useful for controlling video behavior in the bridge.
If video is not working, the first thing to do is get a SIP debug of a call to or from an endpoint. Incoming INVITEs for call originate must have H264 (or the codec being used) in the INVITE. Otherwise, there is no video support. Likewise, calls to endpoints must offer H264. Otherwise, no video support. MicroSIP will have an "Answer with Video" option available if video support is contained in the INVITE on an incoming call.
The PhreakNet System Practices are a collection of documents modeled after the Bell System Practices. Each practice or specification contains information on a specific aspect of the network, beyond the level of detail provided in this documentation. Some documents are classified or intended for internal usage only. These documents are the property of PhreakNet and are not for use or circulation outside of PhreakNet.
PSPs are circulated for internal use only. The latest copies are available through the PhreakNet user portal, to authorized users.
First, at a minimum, you will need to add the following to your iax.conf:
[cnet] type=user context=from-cnet
This is the most basic section possible that defines an IAX2 user (i.e. to receive incoming calls — a peer is for outgoing calls, and we won't need to define one since outgoing calls just use the full, direct IAX2 URI. A friend is both, but we don't need a peer, so we can just use a user). You could add username=cnet, but this is implicit due to the section name being cnet. Authentication and encryption options are omitted here.
This assumes that cnet is your C*NET IAX username; adjust this accordingly if you already a C*NET IAX username that is different.
The above also assumes you already have your [general] section configured. If you don't, this extract from the boilerplate iax.conf is a good place to start:
[general] bindport=4569 relaxdtmf=yes ; If your server has issues with DTMF this option may help bandwidth=high ; allows for high-quality codecs like ulaw/g722 to be used. This does NOT mean you have an excellent Internet connection! disallow=all ; allow only G711 or better codecs allow=g722 ; HD voice (G.722) allow=ulaw ; PCM G.711 uLaw (North America) allow=alaw ; PCM G.711 aLaw (Europe, non-NANPA) jitterbuffer=no tos=0x12 delayreject=yes ; for increased security against brute force attacks autokill=yes ; prevent stalling on call setup for unavailable hosts encryption=yes ; Encryption is disabled by default. This *allows* it to be used (it does not force it) trunk=yes ; More efficient when multiple IAX2 calls are up between two nodes. authdebug = yes ; Make troubleshooting easier maxcallnumbers_nonvalidated = 64 ; If you need to support nodes that don't do call tokens, set a limit or your server can be attacked. calltokenoptional=0.0.0.0/0.0.0.0 requirecalltoken=no
A quick word about the last three settings: a lot of C*NET nodes are fairly old, by Asterisk standards (e.g. 15+ years old), and some do not support call tokens, authentication, encryption, and other "modern" aspects of the IAX2 protocol. You may elect to require calltokens for all users, including your C*NET user, but this will prevent some older systems from being able to call you. The approach used above doesn't globally require call tokens, but does add the restriction that only 64 "non validated" calls can be up at any given time, significantly reducing the security risk and attack surface by not requiring call tokens.
Ultimately, there is no single standard here, and if you know that it's unlikely that 15+ year old obsolete Asterisk systems will not be calling your node, you can probably remove the maxcallnumbers_nonvalidated and calltokenoptional and just set requirecalltoken=yes. If you elect to allow calls without requiring call tokens, protect yourself and set a conservative maxcallnumbers_nonvalidated limit. 64 should be quite generous. This is compatible with older nodes but presents a smaller security risk, thus giving you the best of both worlds as much as possible. Anybody who tells you to use requirecalltoken=no without caveats is giving you bad advice which could endanger your system.
There is such a configuration as requirecalltoken = auto. This applies per user, so it might not do what you would think it might do. What this means is that as soon as call is made to a given user and that incoming call is from an Asterisk system that supports call tokens, call tokens will permanently be required for that user. Since all calls from all nodes on C*NET will come into this single user, and since most C*NET nodes do support call tokens, this is effectively the same as requirecalltoken = yes. In practice, there should never be a reason to use requirecalltoken = auto.
Similar caution should be used with other settings as well. If you elect to use authentication and (but not or) encryption, this will apply to all incoming calls, and some older C*NET nodes may be unable to place calls to your node. In particular, forceencryption=yes is not likely to be widely compatible. For a highly compatabible C*NET node, the configuration provided above will suffice.
The approach you will adopt to handle C*NET calls will differ based on whether you want to provide access to the same extensions on both networks or not. In the easiest case, if your US C*NET office code matches your PhreakNet office code, so that the only difference between the two numbers on both networks is that your C*NET numbers have a 1 before them, the following will be sufficient:
[from-cnet]
exten => _X!,1,Gosub(cnet-verify,${EXTEN},1)
same => n,Goto(external-users,${EXTEN:-7},1) ; strip leading 1 from received number
cnet-verify is part of the verification subroutines. It will screen all incoming calls and assign a 2-digit code to the call. Legitimate C*NET calls will have the channel variable clidverif equal to 20. Anything else is a spoofed, spam, or illegitimate call and could be easily rejected at the owner's discretion. See Verification for more details. (You can also use the app_verify module if you wish.)
As you can see, the last line assumes you are using the same numbers on both networks. Change the destination context if you want to have different thousand block allocations. While using the same numbers may be easier, differentiating between the two networks makes your node more unique. Make changes as needed, e.g. ${EXTEN:-4} if you want to use only the last 4 digits for routing purposes in your dialplan.
You will need to register for a C*NET office code if you don't already have one. All the instructions you need to get setup are on the C*NET website.
To dial out, you can use this sample dialcnet subroutine:
[dialcnet] ; CNET NA 20190219, adapted from BJC v1.01 - no caching, subroutine ; ARG1 = full internationalized C*NET number, numerals only
exten => s,1,Set(LOCAL(enum)=${ENUMLOOKUP(+${ARG1},ALL,,1,std.ckts.info)}) ; Asterisk 1.4+
same => n,GotoIf(${ISNULL(${enum})}?no_uri)
same => n,GotoIf($["${enum:0:3}"="iax"]?iax)
same => n,GotoIf($["${enum:0:3}"="sip"]?sip)
same => n,GotoIf($["${enum:0:3}"="h32"]?h323)
same => n(no_uri),PlayTones(congestion) ; CCBCAD
same => n,Wait(10)
same => n,Return()
same => n(iax),Set(LOCAL(dialstr)=IAX2/${enum:5})
same => n,Goto(dialstr)
same => n(sip),Set(LOCAL(dialstr)=SIP/${enum:4})
same => n,Goto(dialstr)
same => n(h323),Set(LOCAL(dialstr)=H323/${enum:5})
same => n(dialstr),Dial(${dialstr},,g)
same => n,Return()
In theory, the above subroutine is written to look for IAX2, SIP, and H323 URIs. In practice, C*NET, like most private hobbyist networks, uses IAX2 almost exclusively. (The original IAX protocol is also long obsolete.)
WARNING: You should not use the default BJC macro provided on the C*NET website. Macros are obsolete in Asterisk and should be avoided in general, and this particular macro is known to contain an infinite loop (around lines 53-55). The caching mechanism it uses was helpful back when the C*NET ENUM server was a lot less reliable, but isn't really necessary nowadays anyways. You'll be much better off with a) a simpler dialplan context and b) a subroutine.
You should ensure your outgoing Caller ID is a valid international C*NET caller ID (e.g. 15551212). A 7-digit caller ID for country code 1 is not valid — it should be 8-digits. There are two approaches you can use:
[dialcnet]
[dialcnet] subroutine that does this.
You can call the above subroutine with the following syntax:
exten => _1NXXXXXX,1,Gosub(dialcnet,s,1(${EXTEN}))
same => n,Hangup()
exten => _011X.,1,Gosub(dialcnet,s,1(${EXTEN:3}))
same => n,Hangup()
This allows 1+ dialing for country code and 011 + full international C*NET number for all other numbers.
If you want to dial using just 7 digits to numbers in C*NET country code 1, you can add this:
exten => _NXXXXXX,1,Gosub(dialcnet,s,1(1${EXTEN}))
same => n,Hangup()
If you don't want to dial 011 before international numbers, you could use a catch-all rule, like this:
exten => _X!,1,Gosub(dialcnet,s,1(${EXTEN}))
same => n,Hangup()
You can create a dialplan context (e.g. [to-cnet]) with these pattern-matching extensions in them and use something like Goto(to-cnet,${EXTEN},1) to make outbound C*NET calls.
Interested in a free DID? IPComms will give you one! It will even come with two incoming channels that allow unlimited incoming minutes (with the restriction that you can only have 2 incoming calls at a time). The only catch is the number is randomly assigned to you; the area code in which your DID is located is completely random as well. You can sign up with IPComms on its website. The signup link takes you to a social media page, but you don't need to be a registered member there; that's merely where the form is located.
Unfortunately, IPComms has indefinitely suspended their Free DID program. Existing DIDs will continue to work, but newcomers will be unable to acquire one.
Note that to get your free DID setup, you will receive a call from IPComms during business hours. This goes without saying, but make sure your number is accurate!
They will then ask you for some basic information: full name and email address.
Once they hang up, you will receive an email later with your login information — you will need this!
Unlike hobbyist telephone networks, the vast majority of commercial PSTN offerings use SIP trunking as opposed to IAX trunking. Open up sip.conf and add the following statement in your [general] context:
register => 2125551212:password@freedid.ipcomms.net/ipcomms
The phone number goes first, followed by a colon and then your password. The rest is pretty self-explanatory. The very last "ipcomms" at the end after the slash is the destination SIP context, which you will add below like so:
[ipcomms] secret=password defaultuser=2125551212 host=freedid.ipcomms.net allow=ulaw context=from-ipcomms dtmfmode=rfc2833 insecure=port,invite type=peer directmedia=no trustrpid=yes
That's all the SIP configuration needed! At the Asterisk CLI, type sip reload to reload SIP and register with IPComms.
Now, calls from IPComms will come into your Asterisk switch, but they still need to be routed. Add the following to extensions.conf:
[from-ipcomms] ; This is the incoming context for IPComms SIP calls
exten => 2125551212,1,Progress()
same => n,Set(Var_TO=${CUT(CUT(SIP_HEADER(To),@,1),:,2)}) ; this works with SIP but not PJSIP. PJSIP should go to extension of DNIS.
same => n,Gosub(pstn-us-verify,s,1)
;same => n,Answer()
;same => n,SendDTMF(1) ; for Google Voice
same => n,Gosub(mfer,start,1(2125551212))
same => n,Goto(from-pstn,s,1)
[from-pstn]
exten => s,1,Goto(phreaknet-dialtone,${mainphreaknetdisa},1)
First, change the number of the extension to your 10-digit DID.
Since we're seeing 2125551212 in a couple places, you may want to define a global variable called IPCOMMSDID1 in your [globals] context and use that in lieu of the number itself throughout your dialplan. However, you won't be using the DID itself very much. Unlike network calls, calls to your DID are all coming to the "same extension". Your internal extensions can't be dialed directly. Thus, you'll need to have this go to your node's DISA if you want external callers to be able to reach a specific destination of their choosing; your extensions can't be directly dialed from the PSTN. (This is because you only have 1 PSTN DID; if you have an NNX-X on PhreakNet, you have 1,000 DIDs!)
The second and third-to-last lines here are optional and can be omitted. The SendDTMF is necessary if you have a Google Voice number forwarding to one of your DIDs. This is not an IPComms thing at all; due to the way answer supervision works with Google, you will usually need to provide progress, wait a few seconds (about 4), then Answer it, then send DTMF 1. This context omits the Wait statement, but you may need to add that if Google Voice calls forwarded to your IPComms DID aren't getting answered properly by Asterisk.
Finally, the mfer subroutine MFs your IPComms DID. This is a slight nostalgic touch; while we think it's a nice addition for PSTN callers to hear on their way in, you can omit this (and certainly should if you don't have the required subroutines, which are available elsewhere in this documentation).
Finally, we have chosen here to send the caller to the [from-pstn] context, which in turn directs the caller to the node's DISA (you may need to adjust the extension from DTXB to the one your DISA uses). We have a separate [from-pstn] context for the simple reason that you can have multiple DIDs, each of which should have its own incoming context as the processing needed initially is slightly different. However, you can then send callers to a common PSTN context and from there onward to wherever you'd like them to go. This way, if you decide you'd like to have PSTN callers enter, say, an IVR instead of a DISA, you only need to change the reference in [from-pstn], as opposed to within each of your DID contexts.
CallCentric used to have a free DID plan that offered 2 numbers and 3 incoming channels each with unlimited usage. Unfortunately, they discontinued it in December 2018 for new users and for existing ones in February 2019. However, they still do have a (quite reasonable) $1 DID plan that gives you 1 DID with 2 incoming channels. While that means you only get 2 incoming channels now, instead of 6, and you have to pay for it, it's not by any means a bad deal!
If interested, register with CallCentric. If you opt for the $1 per month DID, select their "Dollar Unlimited" plan. Just like with the old "Free DID" plan, numbers are from New York state area codes 631, 845, and 914. Unlike IPComms, you do get to choose the area code you want; however, the actual number itself is still randomly assigned to you.
Note that CallCentric has a 911 requirement for users located in the US. If you don't need 911 on your switch, you will need to indicate when registering, that you are not located in the United States. Otherwise, you will be forced to pay an additional free for 911 service. If you do need 911 service, make sure to provide accurate location information.
You will need to add the following line to your [general] context in sip.conf:
register => 17775551212:password@callcentric.com/callcentric
First is your 11-digit internal CallCentric number. This is not the number of your DID, if you have one! Each account is assigned an internal CallCentric extension in the pseudo-area code 777. This allows you to dial other CallCentric users for free (should you want to).
Now, beneath all that, add the following to sip.conf:
[callcentric] type=peer context=from-callcentric host=callcentric.com fromdomain=callcentric.com defaultuser=17775551212 fromuser=17775551212 secret=password insecure=port,invite disallowed_methods=UPDATE directmedia=no videosupport=no disallow=all allow=ulaw [callcentric1](callcentric) host=alpha1.callcentric.com [callcentric2](callcentric) host=alpha2.callcentric.com [callcentric3](callcentric) host=alpha3.callcentric.com [callcentric4](callcentric) host=alpha4.callcentric.com [callcentric5](callcentric) host=alpha5.callcentric.com [callcentric6](callcentric) host=alpha6.callcentric.com [callcentric7](callcentric) host=alpha7.callcentric.com [callcentric8](callcentric) host=alpha8.callcentric.com [callcentric9](callcentric) host=alpha9.callcentric.com [callcentric10](callcentric) host=alpha10.callcentric.com [callcentric11](callcentric) host=alpha11.callcentric.com [callcentric12](callcentric) host=alpha12.callcentric.com [callcentric13](callcentric) host=alpha13.callcentric.com [callcentric14](callcentric) host=alpha14.callcentric.com [callcentric15](callcentric) host=alpha15.callcentric.com [callcentric16](callcentric) host=alpha16.callcentric.com [callcentric17](callcentric) host=alpha17.callcentric.com [callcentric18](callcentric) host=alpha18.callcentric.com [callcentric19](callcentric) host=alpha19.callcentric.com [callcentric20](callcentric) host=alpha20.callcentric.com [callcentricA](callcentric) host=doll3.callcentric.com [callcentricB](callcentric) host=doll4.callcentric.com [callcentricC](callcentric) host=doll5.callcentric.com
Yes, unfortunately, you really do need all of that! You can see more about this on CallCentric's Asterisk configuration page. If you use PJSIP instead of SIP, due to its better architecture, the configuration is actually less verbose in this case.
Now, in extensions.conf, add the following:
[from-callcentric] ; This is the incoming context for CallCentric SIP calls
exten => callcentric,1,Progress()
same => n,Set(Var_TO=${CUT(CUT(SIP_HEADER(To),@,1),:,2)}) ; this works with SIP but not PJSIP. PJSIP should go to extension of DNIS.
same => n,Gosub(pstn-us-verify,s,1)
;same => n,Wait(4) ; uncomment these if you need support for Google Voice
;same => n,Answer()
;same => n,SendDTMF(1)
same => n,Gosub(mfer,start,1(2125551212))
same => n,Goto(from-pstn,s,1)
Again, if you want to use the MFer to MF your DID's number on incoming PSTN calls (i.e. inpulsing), you will need to change the argument to reflect your CallCentric DID's number. Otherwise, the same comments about SendDTMF, etc. as with the IPComms configuration apply here also.
For those curious, Var_TO here contains your DID's number, which allows you to send different DIDs to different contexts if you have multiple.
Toll free numbers can be quite useful, even for personal usage. For one, collect calls from payphones these days are a joke. It's much cheaper to have your own toll-free number you can call for use when you don't have easy free access to long distance, such as from airport courtesy phones, payphones, or residential lines without long distance.
(By the way, all PhreakNet members have toll-free access to the network. Just make sure your PIN is set up in your account so you can access TSPS from anywhere, anytime, at no charge to you.)
Many providers offer toll-free inbound services. However, as phone people, there are two important criteria you may want to use when selecting a provider. One is whether payphone calls are accepted (calls with ANI II of 27 or 70, among other sometimes restricted ANI-IIs). If this is a prime reason for getting a toll-free number, then it's no good to get a number that doesn't support payphone calls. Second, most providers don't pass along ANI II/OLI, but some do, which can be a nice perk to have. If you are setting up an ANAC, for instance, you will definitely want this — otherwise, it may not be as useful to most people.
Below, we compare many of the most popular providers and break it down. If you have further information to contribute to this table, please let us know! (You can drop a note to the mailing list or file a Docs ticket here.)
Finally, a word of warning: most payphones are NOT programmed to consider 833 as a toll free area code. Therefore, even though 833 often has some of the cooler numbers, you are encouraged to avoid purchasing any 833 numbers because in practice, 833 is not toll free. Stick to 800, 888, 877, and 866 if possible, as these are universally recognized to be toll-free area codes. Note that some providers may charge more for 800 (if available) or vanity numbers.
| Provider | NRC | MRC | Per Call | Per Min | Payphone Calls | OLI | Notes |
|---|---|---|---|---|---|---|---|
| Flowroute | $1.00 | $1.00 | $0.00530 | $0.00975 | Yes, possible surcharge, but not actually assessed | Yes | Require your driver's license and bank statement to sign up. $40 min. deposit. |
| Twilio | ? | $2.00 | $0.00 | $0.0130 | Yes! | Yes | |
| Callcentric | $3.95 | $3.95 | $0.00 | $0.0198 | Yes! | No | Max 3 included channels |
| voip.ms | $0.00 | $0.99 | $0.00 | $0.0190 | Yes! | No | |
| Vitelity | ? | ? | ? | ? | Yes | No | |
| Skyetel | $1.00 | $1.20 | $0.00 | $0.0175 | ? | ? | |
| Plivo | $0.00 | $1.00 | $0.00 | $0.0135 | Yes | ? | |
| AWS Chime SDK Voice Connector | $0.00 | $1.00 | $0.00 | $0.011910 | Yes | No | |
| Telnyx | $1.00 | $1.00 | $0.00 | $0.0150 | No! | Yes | Make sure to enable 183 Ringback |
| Anveo Direct | $0.00 | ? | $0.00 | $0.0160 | $0.864/call | ? | |
| DIDForSale | $1.00 | $1.00 | $0.00 | $0.0150 | No | ? | |
| DIDLogic | $0.00 | $0.99 | $0.00 | $0.0180 | ? | ? | |
| SignalWire | $0.00 | $0.75 | $0.00 | $0.0145 | ? | ? | |
| BulkVS | $1.00 | $0.14 | $0.0020 | $0.0055 | No! | No | Low cost option but also least versatile/useful. CNAM is not optional. $25 min. deposit. |
| Global Call Forwarding | $0.00 | $0.83 | $0.00 | $0.04 | ? | ? | Minimum $12.95 per month ($12.95 with 303 min.) |
NerdVittles is currently sponsoring a Skyetel promotion. They are offering $50 of credit for anyone interested in trying the service. Here's how to take advantage of it on your server!
Why are we recommending Skyetel? Well, apart from the fact that they're offering $50 free credit to us NerdVittles geeks, the service is extremely reliable and we think you'll really like it! It's fast and easy to use. Their customer service is really the best in the industry (we're serious, instant chats are really instant and realtime, and contacting support has about a 5 minute turnaround or less, on average!).
A few tips before getting started:
So, what's the catch? There must be one, right?
Of course there are! Two, really!
Add the following to sip.conf:
[SkyetelCA] disallow=all type=peer insecure=port,invite host=52.8.201.128 dtmfmode=rfc2833 context=from-skyetel allow=ulaw qualify=yes directmedia=no directrtpsetup=no sendrpid=no canreinvite=no [SkyetelTERM] disallow=all type=peer qualify=yes insecure=port,invite host=term.skyetel.com dtmfmode=rfc2833 context=from-skyetel allow=ulaw directmedia=no directrtpsetup=no sendrpid=no canreinvite=no [SkyetelOR] disallow=all type=peer insecure=port,invite host=52.41.52.34 dtmfmode=rfc2833 context=from-skyetel allow=ulaw qualify=yes directmedia=no directrtpsetup=no sendrpid=no canreinvite=no [SkyetelVA] disallow=all host=50.17.48.216 type=peer allow=ulaw dtmfmode=rfc2833 insecure=port,invite context=from-skyetel qualify=yes directmedia=no directrtpsetup=no sendrpid=no canreinvite=no [SkyetelHC] disallow=all host=hc.skyetel.com type=peer allow=ulaw dtmfmode=rfc2833 insecure=port,invite context=from-skyetel directmedia=no directrtpsetup=no sendrpid=no canreinvite=no [SkyetelHC1] disallow=all host=52.32.223.28 type=peer allow=ulaw dtmfmode=rfc2833 insecure=port,invite context=from-skyetel directmedia=no directrtpsetup=no sendrpid=no canreinvite=no [SkyetelHC2] disallow=all host=52.4.178.107 type=peer allow=ulaw dtmfmode=rfc2833 insecure=port,invite context=from-skyetel directmedia=no directrtpsetup=no sendrpid=no canreinvite=no
Now, on to extensions.conf!
Now, in order to dial out using Skyetel, add the following to your [internal-users] context:
exten => _1NXXXXXXXXX,1,Dial(SIP/SkyetelTERM/${EXTEN},45)
same => n,Dial(SIP/SkyetelOR/${EXTEN},45)
same => n,Dial(SIP/SkyetelCA/${EXTEN},45)
same => n,Dial(SIP/SkyetelVA/${EXTEN},45)
same => n,Hangup()
That's it! Now, you have over 50 hours of free long-distance at your disposal!
Instructions exist for implementing Google Voice on IncrediblePBX; however, this guide will target vanilla Asterisk users since instructions targeting native Asterisk are virtually nonexistent. Implementing Google Voice on vanilla Asterisk can be done, but we ran into many roadblocks along the way. The process is rather complicated, so buckle up!
Google Voice requires the use of PJSIP, rather than SIP. You will need to install or reinstall Asterisk with the proper PJSIP modules already on your system. Fortunately, this is not as complicated as it sounds.
The first step is making sure PJSIP is installed as per the first part of these instructions. This assumes you have Asterisk 13.8 or later on your system.
cd /usr/src
dircd asterisk-13.24.0./contrib/scripts/install_prereq./configure --with-pjproject-bundled
make && make installOkay, now the tricky stuff is done! (Well, some of it anyways.) You don't need to copy any files over to your switch again. None of the configuration files or audio files were modified. However, Asterisk now has the PJSIP dependencies it needs loaded.
You will need to configure tokens for use with Asterisk. Navigate to this page; start at "Configuring GV Trunk with Motif in the GUI" to generate the oauth refresh token only. The script is preset to use the guide's Client ID; if you want to use your own then you will need to edit the script.
Run the following from the shell:
cd /root wget http://9142978376.com/newfiles/GV/gvsip-naf.tar tar xvf gvsip-naf.tar rm -f gvsip-naf.tar cd gvsip-naf ./install-gvsip
This does take a while to install; don't worry!
You should at some point be prompted now to enter your Google Voice information; do so as instructed.
Run:
sed -i 's|obihai.telephony.goog|voice.telephony.goog|' /etc/asterisk/pjsip_custom.conf sed -i 's|obihai.telephony.goog|voice.telephony.goog|' /root/gvsip-naf/install-gvsip asterisk -rx "core restart when convenient"
Helpful Resources:
Up until now, these instructions have all been IncrediblePBX instructions that work without any hitches on vanilla Asterisk. The rest of this tutorial is more specific to vanilla Asterisk.
fail2ban can be used to block SIP spam in Asterisk, which, combined with changing the SIP bindport away from 5060, can very effectively eliminate spam. fail2ban builds on top of iptables by automatically adding iptables DROP entries to your system.
The process essentially comes down to:
touch /var/log/asterisk/security
/etc/asterisk/logger.conf, enable the security log by uncommenting it
/etc/asterisk/fail2ban/jail.local, creating the file if needed:
[DEFAULT] bantime = 1h ignoreip =[sshd] enabled = true [asterisk-iptables] # if more than 4 attempts are made within 6 hours, ban for 24 hours enabled = true filter = asterisk action = iptables-allports[name=ASTERISK, protocol=all] logpath = /var/log/asterisk/security maxretry = 4 findtime = 21600 bantime = 86400
service fail2ban restart. Note that if the security file does not exist yet, fail2ban will crash (hence the touch command)
fail2ban-client status asterisk-iptables
For something a bit more SIP-centric, you can also give apiban a go. While it's not as straightforward to get going with as fail2ban, it's more targeted, proactive, and effective.
Most spam calls to Asterisk systems are directed at the [public] context. Consequently, here is a relatively novel (but incredibly simple) addition to your dialplan that can significantly cut back on spam calls to your switch:
[public]
exten => _X!,1,Log(NOTICE, Unauthorized call: ${CALLERID(all)} at "${CHANNEL(peerip)}" to ${EXTEN})
same => n,System(iptables -A INPUT -s ${CHANNEL(peerip)} -j DROP)
same => n,Hangup()
You shouldn't intentionally use the [public] context for anything, so it's a pretty safe bet to assume that any call arriving at that context is malicious. If you add the above to your dialplan, once a spam caller makes a call to any extension in your [public] context, he will be banned from your server forever — well, at least until the next time it reboots (see the iptables section in Appendix A for more on this).
Alternately, just set allowguest=no in sip.conf. If you are using PJSIP instead of SIP, anonymous calls are not allowed at all by default.
Of course, this context in extensions.conf alone is not enough. You will need to create a couple iax contexts in iax.conffor public calls as well, like so:
[pubic] type=user context=public [guest] type=user context=public callerid="Guest IAX User"
Many spam calls arrive at the [guest] iax context, so make sure you include both of these. While IAX spam (or SPIT, spam over Internet telephony) is nowhere near as common as SIP spam, if you do get any spam calls, these contexts should take care of them. If you used our starter code for sip.conf in the "Getting Started" section, your server is automatically setup to reject unauthenticated SIP calls.
Previously, calls to your [public] or [guest] iax context would have been rejected by your server as being nonexistent. Now, the calls will be accepted, and the IP address of the server originating the call will be blocked with iptables. Neat! Of course, although most node owners will want to block calls such as these, you have no obligation to do so. One novel use for spam calls is using them for crosstalk. Rather than banning IP addresses who make spam calls, you could add incoming spam channels to a connection that allows live, unique crosstalk to be generated. Talk about novel! (If you're interested in this concept, see the "Crosstalk" section in Vintage Add-Ons.)
In addition to using the switchhook to flash to initiate a 3-way call, you can use Asterisk's 3-way calling capabilities (as opposed to your telephone's) to solve this:
Set the following in features.conf:
[general] atxfernoanswertimeout = 60 ; Timeout for answer on attended transfer default is 15 seconds. atxferabort = *1 ; cancel the attended transfer atxfercomplete = *2 ; complete the attended transfer, dropping out of the call atxferthreeway = *3 ; complete the attended transfer, but stay in the call. This will turn the call into a multi-party bridge atxferswap = *4 ; swap to the other party. Once an attended transfer has begun, this option may be used multiple times [featuremap] blindxfer => #1 ; Blind transfer (default is #) -- Make sure to set the T and/or t option in the Dial() or Queue() app call! disconnect => *0 ; Disconnect (default is *) -- Make sure to set the H and/or h option in the Dial() or Queue() app call! atxfer => *2 ; Attended transfer -- Make sure to set the T and/or t option in the Dial() or Queue() app call!
Now, while in a call, you can press *2 to initiate an attended transfer. If you three-way a call in, you can use *0 to kick it out, provided you add the appropriate Dial() options.
Custom shell scripts can greatly extend the power of Asterisk. For example, time and temperature scripts allow us to run the network time and temperature services. You can do an infinite number of things with shell scripts that interface with Asterisk.
When modifying shell scripts, encoding issues can cause problems.
If you are using Notepad++ on Windows, in the lower-right hand corner, you will see a display that says "Windows (CR LF)". This is perfectly fine for most files. However, if you create and/or modify a shell script in Notepad++, right-click this and change it to "Unix (LF)" before saving the file. Otherwise, the shell interpreter will be unable to parse your script.
In addition, make sure FileZilla is set to binary transfer mode, not ASCII transfer mode. We cover how to do this in more detail in the "Initial Configuration" section.
There is a festival daemon program out there for use with the Festival() dialplan application. We don't recommend using it due to the high resource requirements. Instead, it's generally better to use the text2wave program to do TTS as needed, e.g.:
same => n,System(echo "${FILTER(0-9A-Za-z\x20,${ARG1})}" | /usr/bin/text2wave -scale 1.5 -F 8000 -o /tmp/${file}.wav)
same => n,Playback(/tmp/${file})
Note the above is only a demonstration and you will certainly need to adequately filter and sanitize any user input.
The automated operators are powered by IBM Watson, which allows 100 free minutes of speech recognition per month. If you have a need for speech-to-text in your dialplan, IBM Watson is a highly reliable service that works quite seamlessly with Asterisk.
To get started with IBM Watson Speech to Text, visit its website.
The following shell script can be used for speech-to-text:
#!/bin/bash curl -X POST -u "apikey:APIKEY" --header "Content-Type: audio/wav" --data-binary @/var/lib/asterisk/sounds/stt/$1.wav "https://api.us-south.speech-to-text.watson.cloud.ibm.com/instances//v1/recognize?model=en-US_NarrowbandModel" >/var/lib/asterisk/sounds/stt/$1.txt #Extract transcript results from JSON response TRANSCRIPT=`cat /var/lib/asterisk/sounds/stt/$1.txt | grep transcript | sed 's#^.*"transcript": "##g' | sed 's# "$##g' > /var/lib/asterisk/sounds/stt/stt-$1.txt` sed -e :a -e N -e `s/\n/ /` ta /var/lib/asterisk/sounds/stt/stt-$1.txt >/var/lib/asterisk/sounds/stt/transcripted-stt-$1.txt rawtext=`cat /var/lib/asterisk/sounds/stt/transcripted-stt-$1.txt` echo $rawtext
Save this script as /etc/asterisk/scripts/stt.sh. Now, run the following from the command line:
chmod 777 /etc/asterisk/scripts/stt.sh
mkdir /var/lib/asterisk/sounds/stt/
To use the shell script, add the following context to your dialplan:
[stt]
exten => s,1,Set(stt=${UNIQUEID}.${ARG1})
same => n,Record(/var/lib/asterisk/sounds/stt/${stt}.wav,3,30,qx)
same => n,Set(text=${SHELL(sh /etc/asterisk/scripts/stt.sh ${stt})})
same => n,Return(${text})
Now, simply call Gosub(stt,s,1(1)) whenever you need speech-to-text. The speech-to-text result will automatically be returned from the subroutine; you will need to use GOSUB_RETVAL to catch it. If you need speech-to-text more than once per call, your next subroutine call should be Gosub(stt,s,1(2)), and so forth. Otherwise, the otherwise-saved transcript results for speech-to-text conversions will be overwritten.
You can load Evan Doorbell recordings onto your Asterisk system for private or public listening pleasure. If you want to do more than a few, however, it becomes quicker to perform batch operations when working with Evan Doorbell's large collection of recordings. Here is one method you can use to make your life easier.
Special thanks to Anthony Hoppe for the Linux scripts and many of the suggestions used here. The Excel instructions and VBA module were added by Naveen Albert.
Part A: Downloading Files
Public Function GetURL(c As Range) As String
On Error Resume Next
GetURL = c.Hyperlinks(1).Address
End Function
=GetURL($A1) — make sure you change A1 to the cell address containing the FLAC URL. The $ before the A should be kept, as it prevents Excel from automatically changing the column as you drag the formula down.ed.txtYou now have a text file containing the full hyperlinks for all the Evan Doorbell FLAC (high-quality) recordings on a particular page! All that's left now is to actually download them. Here, we will move from Windows to Linux:
mkdir eded directory on your Asterisk machine. You can use an SFTP client, like FileZilla, to do this. Or, if it's easier, transfer the file to your web server and download the file directly to the ed directory on your Asterisk server.cd /root/ed/
wget -i ed.txt
Part B: Converting Files
/root/ed/ed.txt by running rm /root/ed/ed.txt/root/ directory:
#!/bin/bash
path=$1
files=($(ls -1 -p $1 | grep -v /))
mkdir $path/originals
for f in "${files[@]}"
do
echo "Working on file $f"
length=$(soxi -d $path/"$f")
fn=$(basename "$f")
fn="${f%.*}"
sox -v 0.68 $path/$f -r 8000 -c 1 --type ul "$path"/"$fn".ulaw
mv $path/$f $path/originals
echo "$fn" $length >> $path/durations.txt
done
If you do this in Windows using Notepad++, be sure to change the encoding in the lower right to Unix (LF). Change the file permissions in Unix to 777.ed_ulaw.sh (full path is /root/ed_ulaw.sh)If you have HD VoIP sets that support G.722, you may want to use the following script instead:
#!/bin/bash
mkdir originals
for f in *.flac
do
mv -v "$f" "${f// /_}"
done
for f in *.flac
do
echo "Working on file $f"
ffmpeg -i "$f" -filter:a volumedetect -f null /dev/null > output.txt 2>&1
maxVol=$(grep max_volume output.txt)
diffVol=$(echo "-14 - ${maxVol:53:4}" | bc)
fn=$(basename "$f")
fn="${f%.*}"
ffmpeg -i "$f" -ac 1 -ar 16000 -acodec g722 -filter:a "volume="$diffVol"dB" "$fn".g722
mv "$f" originals
length=$(soxi -d $path/"$fn".g722)
echo "$fn" $length >> $path/durations.txt
done
Save this as ed_g722.sh — note that you only need to use this script or the other script. Pick one!rm /root/ed/ed.txt
chmod 777 /root/ed_ulaw.sh (replace _ulaw with _g722 if you're using the second script)
/root/ed_ulaw.sh /root/ed/ (replace _ulaw with _g722 if you're using the second script)
mv /root/ed/durations.txt /root/
rm -rf /root/ed/originals/
mv /root/ed/ /var/lib/asterisk/sounds/en/custom/playback/ed/production/ — adjust path as needed, but moves these recordings into an Asterisk-ready playback location
tar -czvf production.tar.gz /var/lib/asterisk/sounds/en/custom/playback/ed/production/ — compresses recordings into an archive for backup purposes (SFTP this to your local PC when done) — adjust path as needed
Note: If you get errors and durations are not sent to the text file, run ed_wav.sh first to get the durations, then use ed_ulaw.sh to cut the size of those .wav files in half by turning them into .ulaw files.
Part C: Metadata
CONCATENATE(CELL1,CHAR(10),CELL2,CELL3,CHAR(10),CELL4) to do this. CHAR(10) adds a line break to the concatenation. There's no one size fits all formula for this. You'll need to create a separate column and combine several columns, like this: =CONCATENATE("Tape ",$D2," (",$G2,")",CHAR(10),$H2). Make sure that WRAP TEXT is on for cells where you combine data that includes line breaks.File Name, and fill in the first cell with =LEFT(TRIM(RIGHT(SUBSTITUTE($D2,"/",REPT(" ",LEN($D2))),LEN($D2))),FIND(".",TRIM(RIGHT(SUBSTITUTE($D2,"/",REPT(" ",LEN($D2))),LEN($D2)))&".")-1) — this column should now be populated with the raw names of the files, excluding the directory path.durations.txt and copy and paste it into your Excel sheet.Name/Length. If you didn't start in Row 1 and the table shifts down one cell, select the entire table, hit CTRL+X to move the table and move the entire table one row up. This table should be aligned exactly with the table to the left.Length, and fill in the first cell with =RIGHT($K2,LEN($K2)-FIND(" ",$K2)) — this column should now be populated with just the lengths of each recording.File Name and sort the table on the right by Name/Length.File Name match the beginning of the contents of Name/Length on an exact row by row basis (obviously the latter column contains the durations in the same column as well, just ignore this). If all rows in both tables match, you're good to go. If not, you have duplicate entries somewhere. This could be because some Evan Doorbell pages may have duplicate recordings listed. Delete any duplicates and resort and scan the table again until both tables match.Duration. Copy the contents of the Length column in the second table. Right-click in the first row under the Duration heading and choose the second option, which should have a "123" icon — this is paste by Values. This copies the durations of each file as text, rather than formulae.That's it! You now have all the metadata, including the pure filename and length of each recording, in one Excel table! At this point, you can discard the table on the right (the second, smaller table), though it really doesn't hurt to keep it around.
Part D: Dialplan
[edrecording]
exten => _[0-9A-Za-z].,1,ControlPlayback(custom/playback/ed/${EXTEN},60000,9,7,#,8,0)
same => n,Hangup()
[evandoorbell]
include => evandoorbell. If not, you can always add the following in that exchange instead: exten => _X!,1,Goto(evandoorbell,${EXTEN:-4},1)#. This will contain the dialable extension number of your recordings. Go through all the recordings you downloaded and assign logical extension numbers. This should be done in chunks, i.e. recordings belong to a series should have consecutive ascending extensions. This will require some thoughtful planning and time.Dialplan. In this column, we will dynamically generate the dialplan code needed for all these recordings. You do have the filenames in a separate column now, so it would be far easier now than otherwise to manually copy and paste these into new extensions, but that's still a lot of work, don't you think?Dialplan column, populate the cell with =CONCATENATE("exten => ",$A2,",1,Goto(edrecording,production/",$E2,",1)"). A2 references the column containing your extension numbers and E2 references the column containing your raw file name. Change these if that is not the case. Otherwise, the entire column should be populated with dialplan code!# column so your extensions are in ascending order.Dialplan column into your Asterisk dialplan file.Fortunately, getting this all into the Directory is the easy part — just use the mass upload feature!
Although Asterisk can natively play WAV files and MP3 files, these tax the system more heavily than do files designed specifically for use with Asterisk. μLaw (pronounced mu-law, or, frequently but erroneously, u-law), is the codec used in the PSTN (high-quality) and it is what we recommend using for audio files as well. The codec used for mobiles, gsm, is more compressed but poorer quality. Space will not be an issue: WAV files that are 50MB+ can be compressed to just a few MB so we recommend using μLaw files unless you have a good reason to use a different audio codec.
You will need to use the sox utility to convert audio from WAV files to μLaw files. The utility is available for both Linux and Windows so you can either convert the files directly on the server or do them on your local PC and then upload them to the server. If you are working with particularly large WAV files, it is recommended you use the latter approach, as otherwise you will have to transfer extremely large WAV files to the server, only to highly compress them and discard the large WAV files.
The general format for converting WAV files is as follows (from the regular shell, not the Asterisk CLI):
sox input.wav --rate 8000 --channels 1 --type ul output.ulaw lowpass 3400 highpass 300
This optimizes your audio specifically for use with telephone systems. Although much information is lost, the end-result generally still sounds quite good.
You will need to adjust input and output respectively to the full path to your audio files. If you use an FTP client like FileZilla to transfer the audio file cbcad.wav to /var/lib/asterisk/sounds/en/custom/, you will need to type the following instead:
sox /var/lib/asterisk/sounds/en/custom/cbcad.wav --rate 8000 --channels 1 --type ul /var/lib/asterisk/sounds/en/custom/cbcad.ulaw lowpass 3400 highpass 300
As you might imagine, this can become quite tedious if you are using this for a large number of audio files. You can run the following script from the command-line to convert all WAV files in a folder to μLaw files:
for f in *.wav; do
sox $f --rate 8000 --channels 1 --type ul $f.ulaw lowpass 3400 highpass 300
done
The script above must be run in the same directory as the WAV files in question. Navigate to the directory first, e.g. cd /var/lib/asterisk/sounds/en/custom/wav/
The only problem now is all files will end up with the file extension .wav.ulaw, which is not what you want. You can rename the output file using the MV command:
mv cbcad.wav.ulaw cbcad.ulaw
You can integrate this into your script in such a way that the file extensions are truncated first before the sox command is run, so that way files do not manually need to be renamed afterward, but that is beyond the scope of this documentation.
C:\Users\%username%\Documents\.sox-14.4.2-win32 to, simply, sox.That's it! Now, as on Linux, you can use sox from the command line by using the command line. To do this, open Command Prompt. Then type cd Documents\sox\ (assuming by default you were in your user profile directory). Now type sox /?, and you should see a list of options. You can try using the following command to manually convert files:
C:\Users\%username%\Documents\sox\sox input.wav --rate 8000 --channels 1 --type ul output.ulaw lowpass 3400 highpass 300
Of course, it is much easier to do a batch convert of files. By creating a simple batch script, you can avoid having to use the command line at all to use SoX!
First, created a folder called bin in your sox directory. Its full path should be C:\Users\%username%\Documents\sox\bin\.
Now, open a text editor and copy and paste the following into it:
@echo off
cd C:\Users\%username%\Documents\sox\bin\
forfiles /S /M *.wav /C "cmd /c rename @file @fname"
for /f "delims=|" %%f in ('dir /b "C:\Users\%username%\Documents\sox\bin\"') do "C:\Users\%username%\Documents\sox\sox.exe" "C:\Users\%username%\Documents\sox\bin\%%f" --rate 8000 --channels 1 --type ul "C:\Users\%username%\Documents\sox\bin\%%f.ulaw" lowpass 3400 highpass 300
You will need to adjust the paths accordingly for your system.
Save the file with a .bat extension, e.g. sox.bat in a convenient location (the sox folder would make sense).
Now, to use your script, simply copy the WAV files you need converted to C:\Users\%username%\Documents\sox\bin\. Then, double-click sox.bat to run the script. The script will automatically truncate the file extensions of all the wav files and then convert all of them to μLaw files. Unlike with other cases in which the original WAV file was left intact, your WAV files will still be left intact but the file extensions will be missing. If you wish to keep the WAV files, you should copy, rather than move the WAV files into the bin directory before running your script. Then, you can simply delete the extension-less files afterward and copy the μLaw files over to your Asterisk server.
You can manually create iptables rules with or without fail2ban for granular control over your firewall. We recommend configuring and using fail2ban if possible, but you may wish to add a few manual rules from time to time.
To view your iptables rules at any time, enter the following:
iptables -L -n -v
To view how many times each rule has been used (to get an idea of which IP addresses are spamming you the most), enter:
iptables -nvL --line-numbers
of course, the above will only work if you already have a rule blocking an IP address.
There are a few different types of rules you can use. This one blocks a particular port:
iptables -A INPUT -p udp --destination-port PORT -j DROP
For example, to block port 5060 (if you changed your SIP bindport), replace PORT with 5060.
To block a specific IP address, use the following:
iptables -A INPUT -s IP -j DROP
if you change your mind, you can easily delete the rule:
iptables -D INPUT -s IP -j DROP
You can also block entire ranges of IP addresses by specifying the subnet. By default, iptables -A INPUT -s 192.168.1.1 -j DROP is the same as iptables -A INPUT -s 192.168.1.1/32 -j DROP.
Hence, to block all of 192.168.1.*, you would enter:
iptables -A INPUT -s 192.168.1.0/24 -j DROP
To block all of 192.168.*.*, you would enter:
iptables -A INPUT -s 192.168.0.0/16 -j DROP
To block all of 192.*.*.* (often used for blocking entire countries), use
iptables -A INPUT -s 192.0.0.0/8 -j DROP
If you notice spammers using multiple similar but different IP addresses, you can use this method to effectively and quickly block entire ranges of IP addresses.
Note that iptables rules are cleared when/if your server is rebooted. To save your iptables rules, you'll need to do the following:
cd /etc/
mkdir iptables
You only need to do the above once. Here's how to save your rules:
sudo iptables-save > /etc/iptables/rules.v4
To restore your rules after a reboot, do the following:
sudo iptables-restore < /etc/iptables/rules.v4
You'll want to run iptables-save after you make any changes to your iptables rules so that they're backed up. You can write a script to automatically restore your iptables rules upon startup if you wish.
If you changed your SIP bindport but are still noticing spammer activity in the Asterisk CLI, you can block their IP addresses as dicated above. Authentication attempts to your server itself (e.g. SSH connections) are logged in /var/log/auth.log. However, don't try to block every malicious IP address you see here — you'll only wear yourself out. Tools like fail2ban are designed to automatically keep on top of spammers and attackers. For further resources on defending your Asterisk system, see some of the VoIP resources on the PhreakNet Resources page.
Operating a provisioning server allows you to remotely provision and manage ATAs. These can be your ATAs or those of your users. A provisioning server can be involved and frustrating to set up initially, but is a good investment if you are supporting dozens of ATAs "out in the field", in which case it may be expected or desirable that you can remotely manage them.
At a high level, here's how the process works:
Provisioning can be used to deploy generic templates with a few settings or to control every aspect of ATA configuration, including SIP credentials. This is a secure and easy way to set ATAs up, since all a user needs to do is enter the provisioning endpoint.
Here are some general things / lessons learned to keep in mind:
In this guide, we'll be covering how to accomplish this using the LAMP stack: (Debian) Linux + Apache web server + MySQL/MariaDB + PHP. In particular, we'll be going through Apache-specific configuration using a free Let's Encrypt certificate. You could use a different application language or DBMS (database management system) fairly easily.
A good practice is to "bootstrap" ATAs on a config request via http, on regular port 80. This won't hand out any sensitive information, but good things to do here are tell the ATA how to request the https config, how to get the latest firmware, and configure a syslog server for debugging. Setting the resync/upgrade period to 1 minute or less will ensure the ATA immediately bootstraps and then moves on to stage 2, the https portion. Common to any https config is adding, inside a Directory block, the SSLRequireSSL directive, to require SSL.
This process differs by vendor, so we'll break it down in that manner.
SSLEngine on SSLCertificateFile /etc/letsencrypt/live/provision.example.com/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/provision.example.com/privkey.pem SSLProtocol all SSLCipherSuite ALL:@SECLEVEL=1 # TLSv1 or better SSLInsecureRenegotiation on # required for some older ATAs SSLOptions -StrictRequire +StdEnvVars SSLVerifyClient require # you must use this in production #SSLVerifyClient optional_no_ca # if you are just testing, use this SSLVerifyDepth 1 SSLCACertificateFile /etc/ssl/private/grandstream.crt
The SSLCipherSuite directive restricts ciphers to those use in TLS 1.0 or better (e.g. SSLv2/3 are not permitteed).
+StdEnvVars will provide your application (e.g. PHP) with all the relevant SSL server variables. By default, these aren't available, since there are a lot. If you're using PHP, run something like print_r($_SERVER); to get an idea of the kinds of information available.
To do MTLS (that is, validate client certificates against the Grandstream CA), you'll need the Grandstream root CA cert, which you can get by contacting Grandstream support via a new ticket.
fs.grandstream.com is the endpoint of GAPS (Grandstream Automated Provisioning Server). The way it works is companies can provide Grandstream with a list of MACs and their provisioning endpoint, and Grandstream will redirect provisioning requests to fs.grandstream.com thither, for those MAC addresses. This allows for truly "zero-touch" provisioning, since the ATA will automatically try to request a config from GAPS in a factory default state.
However, we won't be using GAPS in this case. (If you're using GAPS, I suspect you know what you're doing, since you're supporting thousands of ATAs, so what are you doing here?)
firmware.grandstream.com is the actual endpoint for firmware upgrades, and should support HTTPS as well as HTTP.
Assuming you've provided a hostname for your provisioning server, Grandstream ATAs will make GET requests to the following endpoints on your server:
/cfg000a000a00aa
/cfg000a000a00aa.xml
/cfg.xml
/cfght802.xml - newer HTs only
We've used dummy MAC addresses here — what you'll see is the 12-digit alphanumeric MAC address, all lower case, as shown above.
The first request is for a the proprietary binary format.
The requests afterwards are for standard XML configs. The idea is that it'll try to get a MAC-specific config first, intended only for it, and fall back to a generic config template otherwise.
Newer Grandstream ATAs will also request something like /cfght802.xml, with the product number. The strange thing is that this config is only requested after cfg.xml, so the order isn't strictly most specific to most generic, because it flips around at the end. Thus, relying on this config may not be feasible.
Grandstream ATAs will request these configs (assuming no pre/post-fixes are defined) in this order, until they successfully receive a valid config they can use.
It's up to Apache and your application layer to route these and statically provide or dynamically generate and provide (e.g. using your database) the necessary config. There's no formulaic or "default" way to do this.
For MTLS, SSL_CLIENT_S_DN_CN will contain the MAC address, all uppercase, for newer Grandstreams. For older ones, a common name (e.g. VPN) is used instead. You should perform the stringest verification possible, e.g. make sure the DN_CN matches the request URI and the user agent, if possible. For older ATAs, you may only be able to ensure the user agent matches the request URI and ensure the client certificate presented validates against the Grandstream CA cert.
During testing, you'll likely need to factory reset your ATA — refer to the product manual for reset instructions.
SSLEngine on SSLCertificateFile /etc/ssl/private/cisco.crt SSLCertificateKeyFile /etc/ssl/private/cisco.key SSLProtocol all SSLCipherSuite ALL:@SECLEVEL=1 # TLSv1 or better SSLInsecureRenegotiation on # required for some older ATAs SSLOptions -StrictRequire +StdEnvVars SSLVerifyClient require # production # SSLVerifyClient optional_no_ca # testing SSLVerifyDepth 2 # no more than 2 SSLCACertificatePath /etc/ssl/private/phone_root_certificates #SSLCACertificateFile /etc/ssl/private/phone_root_certificates/Sipura_Technology_Client_Root_Authority_1.crt
If you are using SSLCACertificatePath, you may need to run chown -R www-data /etc/ssl/private/phone_root_certificates/ to make the Apache user "own" the files, since those are loaded dynamically. Also, ensure you have the right files that this directive expects.
Cisco provisioning has the added caveat that Cisco ATAs will only handshake with Cisco certs. Thus, notice we're not using our regular Let's Encrypt certificate, but a Cisco-signed certificate.
Some good background about the process is available on the Cisco community forums. Instructions on generating your csr file are also available. Basically, you'll need to run the following:
openssl genrsa -out2048 openssl req -new -key -out
The certificate signing request process nowadays is automated. Once you've run those commands, navigate to the Cisco portal and upload your CSR. You'll probably want a SHA1 cert, which they still offer as of now, but SHA256 is also available and better for newer ATAs (you could just grab both). The certificate will be valid for 1 year maximum.
Finally, you'll also need the Cisco root certificates to do MTLS and verify clients. You'll need to contact Cisco to get these.
There aren't really any defaults you should rely on for Cisco rules. Instead, you should explicitly provide full URLs, including the protocol and hostname and full request path. There are variables you can use in your rules that will aide in routing, such as $MA for the device's MAC address. See pg. 74 of this provisioning guide for a complete list of macro expansion variables.
That said, newer ATAs such as the SPA-112 may go in this order (depending on Profile Rules):
/spa.cfg
/spa000a000a00aa.cfg
Cisco provisioning rules work the opposite of Grandstream rules. Grandstream rules will start and go down the list until it receives a valid config, then stop. Cisco will start and go down the list, stopping only when it fails to get a valid config. Thus, rules should go from least-specific to most-specific, which is the opposite order of Grandstream rules. In your bootstrap config, keep this in mind. For permanent, MAC-specific, configs, it really only makes sense to provide one profile rule, since Cisco ATAs will attempt to request all of them, assuming they are all valid.
For MTLS, SSL_CLIENT_S_DN_CN will contain, among other things, the MAC address. SSL_CLIENT_S_DN_ST will contain only the MAC address, all lowercase. This is the case for all Cisco ATAs — they all uniquely identify themselves in their client certificates.
The 79xx Cisco series is an older line from Cisco. In comparison to newer SIP hardphones, 79xx phones only supported (unencrypted) TFTP for provisioning, and they can't be provisioned or configured really any other way.
These phones support 3 protocols: SCCP (Skinny), SIP, and MGCP. So there are a few ways you could use them, in increasing order of functionality:
--cisco option to PhreakScript)
--sccp option to PhreakScript)
The Polycom SoundPoint 331 is a SIP hardphone. This guide focuses specifically on this model, but it generalizes to a large number of Polycom phones from this era.
This guide will allow you to bootstrap the phone, e.g. use the phone to allow configuration via the web interface, and then use the web interface to allow configuration using an automated dynamic provisioning method.
456.
A Polycom phone will make requests for the following files:
Here, 0004f2ffffff represents the MAC address of the phone, which is all lowercase.
More details here: https://community.polycom.com/t5/VoIP-SIP-Phones/FAQ-What-files-does-my-phone-download-or-upload-and-why/td-p/30582
The Polycom 331 only supports SHA1 certs, not SHA256 - otherwise, you may see something like: ParamParser|Parameter identifier is out of range: "14791"(14791).
4.0.15 is the latest UC firmware supported by the 331. Do NOT use the 4.1.x firmware as this only supports Lync, not SIP! (e.g. the firmware in the GitHub repo below is wrong.)