· Technology  · 3 min read

Asterisk FreePBX Call Forwarding via *72 / *73

How to configure call forwarding on an Asterisk FreePBX system using *72 and *73 feature codes with a FXO card.

How to configure call forwarding on an Asterisk FreePBX system using *72 and *73 feature codes with a FXO card.

This article describes how to use Asterisk, FreePBX, or AsteriskNOW to forward calls using your telephone company’s *72 / *73 feature via analog FXO (POTS) channels. This is useful for forwarding calls to an after-hours answering service without dialing out on a separate line and bridging calls inside Asterisk. Bridging calls together results in a dB loss and ties up two lines per simultaneous conversation. An added advantage is that the correct caller ID passes through to the call recipient.

Note: Due to the nature of analog channels, there is no way to account for the risk of “glare” — a situation where the phone system attempts to dial at the same moment as an inbound call occurs. Always test to confirm that phones are actually forwarded or unforwarded each time you use this methodology.

Add the following to /etc/asterisk/extensions_custom.conf

[from-internal-custom]
exten => *72,1,Answer
exten => *72,n,Wait(1)
exten => *72,n(read),Read(toext,ent-target-attendant&then-press-pound,,,,)
exten => *72,n,GotoIf($
exten => *72,n,AGI(fwd.agi,${toext})
exten => *72,n,NoOp("AGI Result=${AGISTATUS}")
exten => *72,n,GotoIf($["${AGISTATUS}"="FAILURE"]?failed)
exten => *72,n,Playback(call-fwd-unconditional&is-set-to)
exten => *72,n,SayDigits(${toext})
exten => *72,n,Hangup
exten => *72,n(failed),Playback(connection-failed)
exten => *72,n,Hangup

exten => *73,1,Answer
exten => *73,n,Wait(1)
exten => *73,n,AGI(unfwd.agi)
exten => *73,n,NoOp("AGI Result=${AGISTATUS}")
exten => *73,n,GotoIf($["${AGISTATUS}"="FAILURE"]?failed)
exten => *73,n,Playback(call-fwd-unconditional&de-activated)
exten => *73,n,Hangup
exten => *73,n(failed),Playback(connection-failed)
exten => *73,n,Hangup

Add the following file named fwd.agi to /var/lib/asterisk/agi-bin/

#!/usr/bin/php -q
<?php

require 'phpagi.php';

if($argv[1])
        $fwd_no = $argv[1];

$agi = new AGI();
$not_answered = Array();

$agi->verbose("Unconditional forward", "2");

/***************** Database Configuration *******************/
$db = 'asterisk';
$dbuser = 'root';
$dbpass = '';
$dbhost = 'localhost';
/************************************************************/

$link = mysql_connect($dbhost,$dbuser,$dbpass);
if (!$link) {
    $agi->verbose('Could not connect: ' . mysql_error(),"2");
    exit(-1);
}

$db_selected = mysql_select_db("$db");
if (!$db_selected) {
    $agi->verbose('Can\'t use '.$db.' : ' . mysql_error(),"2");
    mysql_close($link);
    exit(-1);
}

$rows=mysql_query("SELECT `channel` FROM dahdichandids");
if (!$rows) {
    $agi->verbose('Invalid query: ' . mysql_error(),"2");
    mysql_close($link);
    exit(-1);
}

$num_rows = mysql_num_rows($rows);

$i_not_answered=0;
$i_not_answered_2=0;

if ($num_rows>0){
        for($i=0; $i<$num_rows; $i++){
                $row=mysql_fetch_array($rows);
                $agi->verbose("row[$i]:".$row[0], 2);
                $agi->exec_dial("DAHDI/$row[0]", "*72ww$fwd_no", "", "g");

                $dial_status = explode(" ", implode(" ",$agi->get_variable("DIALSTATUS")));
                $agi->verbose('dial_status: ' . $dial_status[2] ,"2");

                if( strcmp($dial_status[2],"ANSWER") == 0){
                        $agi->verbose('Answered',"2");
                }else{
                        $agi->verbose('Not-Answered',"2");
                        $not_answered[$i_not_answered++] = $row[0];
                }
        }

        for($i=0; $i<$i_not_answered; $i++){
                $agi->verbose("Trying unanswered channels again", "2");
                $agi->verbose("not_answered[$i]=".$not_answered[$i], "2");

                $agi->exec_dial("DAHDI/$not_answered[$i]", "*72ww$fwd_no", "", "g");

                $dial_status = explode(" ", implode(" ",$agi->get_variable("DIALSTATUS")));
                $agi->verbose('dial_status: ' . $dial_status[2] ,"2");

                if( strcmp($dial_status[2],"ANSWER") != 0){
                        $agi->verbose('Not-Answered',"2");
                        $i_not_answered_2++;
                }
        }
}

mysql_free_result($rows);
mysql_close($link);

if($i_not_answered_2 != 0){
        $agi->verbose('Calling '. $i_not_answered_2.' channel(s) was not successful',"2");
        exit(-1);
}

?>

Add the following file named unfwd.agi to /var/lib/asterisk/agi-bin/

#!/usr/bin/php -q
<?php

require 'phpagi.php';

$agi = new AGI();
$not_answered = Array();

$agi->verbose("Unforward", "2");

/***************** Database Configuration *******************/
$db = 'asterisk';
$dbuser = 'root';
$dbpass = '';
$dbhost = 'localhost';
/************************************************************/

$link = mysql_connect($dbhost,$dbuser,$dbpass);
if (!$link) {
    $agi->verbose('Could not connect: ' . mysql_error(),"2");
    exit(-1);
}

$db_selected = mysql_select_db("$db");
if (!$db_selected) {
    $agi->verbose('Can\'t use '.$db.' : ' . mysql_error(),"2");
    mysql_close($link);
    exit(-1);
}

$rows=mysql_query("SELECT `channel` FROM dahdichandids");
if (!$rows) {
    $agi->verbose('Invalid query: ' . mysql_error(),"2");
    mysql_close($link);
    exit(-1);
}

$num_rows = mysql_num_rows($rows);

$i_not_answered=0;
$i_not_answered_2=0;

if ($num_rows>0){
        for($i=0; $i<$num_rows; $i++){
                $row=mysql_fetch_array($rows);
                $agi->verbose("row[$i]:".$row[0], 2);
                $agi->exec_dial("DAHDI/$row[0]", "*73", "", "g");

                $dial_status = explode(" ", implode(" ",$agi->get_variable("DIALSTATUS")));
                $agi->verbose('dial_status: ' . $dial_status[2] ,"2");

                if( strcmp($dial_status[2],"ANSWER") == 0){
                        $agi->verbose('Answered',"2");
                }else{
                        $agi->verbose('Not-Answered',"2");
                        $not_answered[$i_not_answered++] = $row[0];
                }
        }

        for($i=0; $i<$i_not_answered; $i++){
                $agi->verbose("Trying unanswered channels again", "2");
                $agi->verbose("not_answered[$i]=".$not_answered[$i], "2");

                $agi->exec_dial("DAHDI/$not_answered[$i]", "*73", "", "g");

                $dial_status = explode(" ", implode(" ",$agi->get_variable("DIALSTATUS")));
                $agi->verbose('dial_status: ' . $dial_status[2] ,"2");

                if( strcmp($dial_status[2],"ANSWER") != 0){
                        $agi->verbose('Not-Answered',"2");
                        $i_not_answered_2++;
                }
        }
}

mysql_free_result($rows);
mysql_close($link);

if($i_not_answered_2 != 0){
        $agi->verbose('Calling '. $i_not_answered_2.' channel(s) was not successful',"2");
        exit(-1);
}

?>
  • asterisk
  • voip
  • freepbx
  • linux
Share:
Back to Blog

Related Posts

View All Posts »
Block Brute Force SSH Attempts

Block Brute Force SSH Attempts

Methods to protect your Linux server from SSH brute force attacks using iptables, fail2ban, DenyHosts, and port changes.