<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>TEAM FORREST Blog &#187; Perl</title>
	<atom:link href="http://www.teamforrest.com/blog/tag/perl/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.teamforrest.com/blog</link>
	<description>Asterisk, VoIP, and IT Consulting</description>
	<lastBuildDate>Thu, 27 May 2010 19:07:58 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Automatically Block Failed SIP Peer Registrations</title>
		<link>http://www.teamforrest.com/blog/171/asterisk-no-matching-peer-found-block/</link>
		<comments>http://www.teamforrest.com/blog/171/asterisk-no-matching-peer-found-block/#comments</comments>
		<pubDate>Tue, 13 Apr 2010 12:54:33 +0000</pubDate>
		<dc:creator>Team Forrest</dc:creator>
				<category><![CDATA[VoIP]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[asterisk]]></category>
		<category><![CDATA[brute force attack]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[SIP]]></category>

		<guid isPermaLink="false">http://www.teamforrest.com/blog/?p=171</guid>
		<description><![CDATA[Previously we posted a little script for quickly checking your asterisk log for failed peer registrations. Building on that script, and with the use of iptables and cron, you can easily (and automatically) block flooding traffic from your system. Iptables, a linux command line program to filter IP traffic, provides high level packet filtering before [...]]]></description>
			<content:encoded><![CDATA[<p>Previously we posted <a href="http://www.teamforrest.com/blog/165/asterisk-failed-peer-sip-brute-force/">a little script for quickly checking your asterisk log for failed peer registrations</a>. Building on that script, and with the use of <strong>iptables</strong> and <strong>cron</strong>, you can easily (and automatically) block flooding traffic from your system. Iptables, a linux command line program to filter IP traffic, provides high level packet filtering before the traffic can be used to corrupt a program. Cron, the linux time scheduler, enables you to automatically run commands at scheduled time periods.</p>
<h2>Set up IP Tables</h2>
<p>We will not be discussing the intricacies of iptables in this post. There are excellent tutorials on iptables, and with most things linux, help is only a google away. To help identify the traffic blocked as asterisk related, a new chain will be created appropriately called&#8230; asterisk.</p>
<p>Here&#8217;s how to add the new chain:</p>
<pre class="brush: plain;">iptables -N asterisk
iptables -A INPUT -j asterisk
iptables -A FORWARD -j asterisk</pre>
<p>This will help identify hosts blocked for failed registrations.</p>
<h2>Asterisk&#8217;s Log for Failed Registrations</h2>
<p>In most cases of a sip flood attack, the host attempts registration to Asterisk. These hosts are identified in the Asterisk log (<strong>/var/log/messages</strong>) as &#8220;No matching peer found.&#8221; The following perl script scans /var/log/messages for these patterns, strips the IP address, and puts the IP address into an array.</p>
<p>After the file has been read, the IP addresses are counted (each count is a failed attempt), compared against the existing blocked hosts, and new occurrences are blocked. With this script we are blocking any host after the 4th failed attempt.</p>
<p>Here&#8217;s the script (<strong>last updated 21 APR 2010</strong>):</p>
<pre class="brush: perl;">#!/usr/bin/perl -w
use strict;
use warnings;
my (@failhost);
my %currblocked;
my %addblocked;
my $action;

open (MYINPUTFILE, &quot;/var/log/asterisk/messages&quot;) or die &quot;\n&quot;, $!, &quot;Does log file file exist\?\n\n&quot;;

while (&lt;MYINPUTFILE&gt;) {
	my ($line) = $_;
	chomp($line);
	if ($line =~ m/\' failed for \'(.*?)\' - No matching peer found/) {
		push(@failhost,$1);
	}
}

my $blockedhosts = `/sbin/iptables -n -L asterisk`;

while ($blockedhosts =~ /(.*)/g) {
	my ($line2) = $1;
	chomp($line2);
	if ($line2 =~ m/(\d+\.\d+\.\d+\.\d+)(\s+)/) {
		$currblocked{ $1 } = 'blocked';
	}
}

while (my ($key, $value) = each(%currblocked)){
	print $key . &quot;\n&quot;;
}

if (@failhost) {
	&amp;count_unique(@failhost);
	while (my ($ip, $count) = each(%addblocked)) {
		if (exists $currblocked{ $ip }) {
			print &quot;$ip already blocked\n&quot;;
		} else {
			$action = `/sbin/iptables -I asterisk -s $ip -j DROP`;
			print &quot;$ip blocked. $count attempts.\n&quot;;
		}
	}
} else {
	print &quot;no failed registrations.\n&quot;;
}

sub count_unique {
    my @array = @_;
    my %count;
    map { $count{$_}++ } @array;
    map {($addblocked{ $_ } = ${count{$_}})} sort keys(%count);
}</pre>
<h2>Schedule the script with cron</h2>
<p>The final step is to schedule your script to run every X minutes in cron. We&#8217;ve chosen to run our script every 2 minutes, but you can change this to 1 minute or any other time period you choose. Just remember&#8230; you can receive thousands of attempts within 2 minutes.</p>
<p>If you have named your script check-failed-regs.pl and placed it in your /usr/local/bin directory, your cron statement would look like this:</p>
<pre class="brush: plain;">*/2 * * * * perl /usr/local/bin/check-failed-regs.pl &amp;&gt; /dev/null</pre>
<p>Questions? Comments? We love feedback. Or, <a href="/contact.html">contact us</a> for more information.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.teamforrest.com/blog/171/asterisk-no-matching-peer-found-block/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Perl Script for Asterisk Failed Peer Registrations</title>
		<link>http://www.teamforrest.com/blog/165/asterisk-failed-peer-sip-brute-force/</link>
		<comments>http://www.teamforrest.com/blog/165/asterisk-failed-peer-sip-brute-force/#comments</comments>
		<pubDate>Mon, 12 Apr 2010 18:46:57 +0000</pubDate>
		<dc:creator>Team Forrest</dc:creator>
				<category><![CDATA[VoIP]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[asterisk]]></category>
		<category><![CDATA[brute force attack]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[SIP]]></category>

		<guid isPermaLink="false">http://www.teamforrest.com/blog/?p=165</guid>
		<description><![CDATA[I guess this might be better titled as the Quick and Dirty Perl Script&#8230; but here we go: #!/usr/bin/perl -w use strict; use warnings; my (@failhost); open (MYINPUTFILE, &#34;/var/log/asterisk/$ARGV[0]&#34;) or die &#34;\n&#34;, $!, &#34;Does log file file exist\?\n\n&#34;; while (&#60;MYINPUTFILE&#62;) { my ($line) = $_; chomp($line); if ($line =~ m/\' failed for \'(.*?)\' - No [...]]]></description>
			<content:encoded><![CDATA[<p>I guess this might be better titled as the <del datetime="2010-04-12T19:23:51+00:00">Quick and</del> Dirty Perl Script&#8230; but here we go:</p>
<pre class="brush: perl;">#!/usr/bin/perl -w
use strict;
use warnings;
my (@failhost);

open (MYINPUTFILE, &quot;/var/log/asterisk/$ARGV[0]&quot;) or die &quot;\n&quot;, $!, &quot;Does log file file exist\?\n\n&quot;;

while (&lt;MYINPUTFILE&gt;) {
	my ($line) = $_;
	chomp($line);
	if ($line =~ m/\' failed for \'(.*?)\' - No matching peer found/) {
		push(@failhost,$1);
	}
}

if (@failhost) {
	&amp;count_unique(@failhost);
} else {
	print &quot;no failed registrations.\n&quot;;
}

sub count_unique {
    my @array = @_;
    my %count;
    map { $count{$_}++ } @array;

	#print them out:

    map {print &quot;$_ = ${count{$_}}\n&quot;} sort keys(%count);

}</pre>
<p>And while we duck from @<a href="http://twitter.com/merlyn">Merlyn&#8217;s</a> criticisms (although we love his criticism), the basic usage is:</p>
<p>perl [Whatever you named it].pl messages<br />
<em> or</em> perl [Whatever you named it].pl messages.1</p>
<p><b>Results look like:</b></p>
<p>184.73.53.22 = 13586<br />
64.76.45.100 = 9895<br />
78.46.87.14 = 9960</p>
<p>Or &#8220;no failed registrations.&#8221; if you have no failed attempts.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.teamforrest.com/blog/165/asterisk-failed-peer-sip-brute-force/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Integrating Fax for Asterisk</title>
		<link>http://www.teamforrest.com/blog/156/integrating-fax-for-asterisk/</link>
		<comments>http://www.teamforrest.com/blog/156/integrating-fax-for-asterisk/#comments</comments>
		<pubDate>Tue, 17 Nov 2009 03:08:41 +0000</pubDate>
		<dc:creator>Team Forrest</dc:creator>
				<category><![CDATA[VoIP]]></category>
		<category><![CDATA[asterisk]]></category>
		<category><![CDATA[fax]]></category>
		<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://www.teamforrest.com/blog/?p=156</guid>
		<description><![CDATA[Asterisk provides an open-source solution for IP Telephony (aka VoIP). Customizing your telephone system to increase productivity remains one of Asterisk’s greatest features. Today, we will look at using Asterisk to replace your need for a fax machine. Benefits Store faxes electronically Reduce printing costs Share faxes via email Requirements Server running Asterisk (32 bit [...]]]></description>
			<content:encoded><![CDATA[<p>Asterisk provides an open-source solution for IP Telephony (aka VoIP). Customizing your telephone system to increase productivity remains one of Asterisk’s greatest features. Today, we will look at using Asterisk to replace your need for a fax machine.</p>
<h3>Benefits</h3>
<ul>
<li>Store faxes electronically</li>
<li>Reduce printing costs</li>
<li>Share faxes via email</li>
</ul>
<h3>Requirements</h3>
<ul>
<li>Server running Asterisk (32 bit compatibility needed)</li>
<li>Fax for Asterisk Software Add-on</li>
</ul>
<h2>Step One: Get the Fax for Asterisk Software License</h2>
<p>First, choose the licensing based on your needs. If you will only need to support 1 simultaneous fax <span id="more-156"></span> “session,” you may be interested in the Free Fax For Asterisk License. Digium provides the Free Fax for Asterisk software at no cost, limited one per installation of Asterisk. You can combine the Free Fax for Asterisk license with the paid Fax for Asterisk licensing if you will need additional simultaneous fax sessions.</p>
<p><em>For example, you can download and install Free Fax for Asterisk providing your system one (1) fax session. If you find you need additional simultaneous sessions, simply purchase a paid license (currently $39.99 per session).</em></p>
<p>To get the Fax for Asterisk software, go to the <a href="http://store.digium.com/">Digium Store</a>. Once “purchased” you will receive your license via email.</p>
<h2>Step Two: Download and Install the Fax for Asterisk Software</h2>
<p>Once you’ve received your license, there are many small steps needed to download, register, and install the software.</p>
<ul>
<li>Download and run the registration software (outgoing network traffic to TCP port 443 (SSL) must be allowed)</li>
</ul>
<pre>cd /root
wget http://downloads.digium.com/pub/register/x86-32/register
chmod 500 /root/register
/root/register</pre>
<ul>
<li>Complete the registration</li>
<li> Go to <a href="http://www.digium.com/en/docs/FAX/faa-download.php">http://www.digium.com/en/docs/FAX/faa-download.php</a> and discover which files to download</li>
<li> Download both the <strong>res_fax</strong> and <strong>res_fax_digium files</strong></li>
<li> Untar the res_fax file and copy it to the source file directory (<em>example res_fax-1.6.0_1.0.3-x86_32.tar.gz</em>)</li>
</ul>
<pre>tar xzvf res_fax-1.6.0_1.0.3-x86_32.tar.gz
cp /root/res_fax-1.6.0_1.0.3-x86_32/res_fax.so /usr/lib/asterisk/modules</pre>
<ul>
<li>Untar and install the res_fax_digium software (<em>example res_fax_digium-1.6.0_1.0.3-pentium4m_32.tar.gz</em>)</li>
</ul>
<pre>tar xzvf res_fax_digium-1.6.0_1.0.3-pentium4m_32.tar.gz
cp /root/res_fax_digium-1.6.0_1.0.3-pentium4m_32/res_fax_digium.so /usr/lib/asterisk/modules</pre>
<ul>
<li>Make a directory for your fax files</li>
</ul>
<pre>mkdir /var/spool/asterisk/fax</pre>
<h2>Step Three: Test if the Software Installed Correctly</h2>
<p>Restart asterisk and test if that the fax module has loaded:</p>
<pre>asterisk -rx "restart now"
asterisk -r
*CLI&gt; fax show stats</pre>
<p>If the software installed successfully, you should see something similar to:</p>
<pre>Fax Statistics:
---------------

Current Sessions     : 0
Transmit Attempts    : 0
Receive Attempts     : 0
Completed Faxes      : 0
Failed Faxes         : 0
*CLI&gt;
Digium T.38
Licensed Channels    : 1
Max Concurrent       : 0
Success              : 0
Canceled             : 0
No Fax               : 0
Partial              : 0
Negotiation Failed   : 0
Train Failure        : 0
Protocol Error       : 0
IO Partial           : 0
IO Fail              : 0
*CLI&gt;
Digium G.711
Licensed Channels    : 1
Max Concurrent       : 1
Success              : 0
Switched to T.38     : 0
Canceled             : 0
No Fax               : 0
Partial              : 0
Negotiation Failed   : 0
Train Failure        : 0
Protocol Error       : 0
IO Partial           : 0
IO Fail              : 0</pre>
<h2>Step Four: Make a dialplan</h2>
<p>Make a dialplan that fits your needs. Here’s an example for sending and receiving:</p>
<pre>[inboundfax]
exten =&gt; s,1,NoOp(**** FAX RECEIVED from ${CALLERID(num)} ${STRFTIME(${EPOCH},,%c)} ****)
exten =&gt; s,n,Set(FAXOPT(ecm)=yes)
exten =&gt; s,n,Set(FILENAME=fax-${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)})
exten =&gt; s,n,Set(FAXFILE=${FILENAME}.tif)
exten =&gt; s,n,Set(FAXOPT(ecm)=yes)
exten =&gt; s,n,Set(FAXOPT(headerinfo)=Received by MYCOMPANY ${STRFTIME(${EPOCH},,%Y-%m-%d %H:%M)})
exten =&gt; s,n,Set(FAXOPT(localstationid)=5555551212)
exten =&gt; s,n,Set(FAXOPT(maxrate)=14400)
exten =&gt; s,n,Set(FAXOPT(minrate)=2400)
exten =&gt; s,n,NoOp(FAXOPT(ecm) : ${FAXOPT(ecm)})
exten =&gt; s,n,NoOp(FAXOPT(headerinfo) : ${FAXOPT(headerinfo)})
exten =&gt; s,n,NoOp(FAXOPT(localstationid) : ${FAXOPT(localstationid)})
exten =&gt; s,n,NoOp(FAXOPT(maxrate) : ${FAXOPT(maxrate)})
exten =&gt; s,n,NoOp(FAXOPT(minrate) : ${FAXOPT(minrate)})
exten =&gt; s,n,NoOp(**** RECEIVING FAX : ${FAXFILE} ****)
exten =&gt; s,n,ReceiveFAX(/var/spool/asterisk/fax/${FAXFILE})
exten =&gt; s,n,Hangup()
exten =&gt; h,1,NoOp(FAXOPT(ecm) : ${FAXOPT(ecm)})

[outboundfax]
exten =&gt; s,1,NoOp(send a fax)
exten =&gt; s,n,Set(FAXOPT(filename)=${FAXFILE})
exten =&gt; s,n,Set(FAXOPT(ecm)=yes)
exten =&gt; s,n,Set(FAXOPT(headerinfo)=Fax from MYCOMPANY +1 555 555 1212)
exten =&gt; s,n,Set(FAXOPT(localstationid)=15555551212)
exten =&gt; s,n,Set(FAXOPT(maxrate)=14400)
exten =&gt; s,n,Set(FAXOPT(minrate)=2400)
exten =&gt; s,n,SendFAX(/tmp/${FAXFILE},d)
exten =&gt; h,1,NoOp(FAXOPT(ecm) : ${FAXOPT(ecm)})</pre>
<h2>Step Five: Test</h2>
<p>How do you test? Simple point an incoming number to inboundfax,s,1 and watch the magic happen. Faxes will be saved to /var/spool/asterisk/fax/ in tiff format.</p>
<h2>But Wait! There&#8217;s More!</h2>
<p>Sure, you could stop there, but wouldn’t it be neat to automatically email the received fax in pdf format? Using an AGI script, you can simply convert the tiff file into pdf format, attach it to an email, and off it goes!</p>
<p>Now, there are literally a thousand ways to do this. You can write your AGI scripts in the programming language of your choice; every language has it’s pros and cons. In our example, we’re going to demonstrate this process using a Perl script.</p>
<h2>Install the Pre-reqs</h2>
<p>You will want to install ghostscript to help convert the graphic files. On a centos install, this is as easy as typing <strong>yum -y install ghostscript</strong>. If you are using a different build you can install how you like or download the code directly from <a href="http://www.ghostscript.com/">http://www.ghostscript.com/</a>.</p>
<p>For the Perl pre-reqs, you will want to install a few packages from CPAN (to send mail and use smtp authentication):</p>
<pre>perl -MCPAN -e shell
install MIME::Lite
install MIME::Base64
install Authen::SASL</pre>
<p>Next create your perl script. In this case, call it <strong>receivedfax.pl</strong> and place it in /var/lib/asterisk/agi-bin:</p>
<pre>#!/usr/bin/perl
use strict;
use MIME::Lite;

my ($msg,$stdinresult);

# $ARGV[0] = msgfrom, $ARGV[1] = msgto, $ARGV[2] = cidnum, $ARGV[3] = filename,
chomp($stdinresult = <stdin>);

if ($#ARGV != 3) {
	print qq(VERBOSE "FAIL: 4 Arguments needed" 2\n);
	chomp($stdinresult = <stdin>);
	exit(0);
}

system("tiff2ps -a /var/spool/asterisk/fax/$ARGV[3].tif | ps2pdf13 -sPAPERSIZE=letter - > /var/spool/asterisk/fax/$ARGV[3].pdf");

$msg = MIME::Lite->new(
	From => "$ARGV[0]",
	To => "$ARGV[1]",
	Subject => "FAX from $ARGV[2]",
	Type => 'multipart/mixed'
);

$msg->attach(
	Type => 'TEXT',
	Data => "Greetings.\n\nYou have received a fax from $ARGV[2]. (attached)\n\nSincerely,\nCOMPANY NAME\n\n"
);

$msg->attach(
	Type => 'image/pdf',
	Path => "/var/spool/asterisk/fax/$ARGV[3].pdf",
	Filename => "$ARGV[3].pdf",
	Disposition => 'attachment'
);

MIME::Lite->send('smtp', 'SMTP.SERVER.COM', Timeout=>60,
	AuthUser=>'MAILUSER', AuthPass=>'PASSWORD');

$msg->send;

system("rm -f /var/spool/asterisk/fax/$ARGV[3].pdf");

#example: receivedfax.pl "asterisk@mydomain.com" "JohnDoe@mydomain.com" 55512345678 fax-20091115-170217</pre>
<p>Then, modify your dialplan to run the AGI script:</p>
<pre>[inboundfax]
exten => s,1,NoOp(**** FAX RECEIVED from ${CALLERID(num)} ${STRFTIME(${EPOCH},,%c)} ****)
exten => s,n,Set(FAXOPT(ecm)=yes)
exten => s,n,Set(FILENAME=fax-${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)})
exten => s,n,Set(FAXFILE=${FILENAME}.tif)
exten => s,n,Set(FAXOPT(ecm)=yes)
exten => s,n,Set(FAXOPT(headerinfo)=Received by MYCOMPANY ${STRFTIME(${EPOCH},,%Y-%m-%d %H:%M)})
exten => s,n,Set(FAXOPT(localstationid)=5555551212)
exten => s,n,Set(FAXOPT(maxrate)=14400)
exten => s,n,Set(FAXOPT(minrate)=2400)
exten => s,n,NoOp(FAXOPT(ecm) : ${FAXOPT(ecm)})
exten => s,n,NoOp(FAXOPT(headerinfo) : ${FAXOPT(headerinfo)})
exten => s,n,NoOp(FAXOPT(localstationid) : ${FAXOPT(localstationid)})
exten => s,n,NoOp(FAXOPT(maxrate) : ${FAXOPT(maxrate)})
exten => s,n,NoOp(FAXOPT(minrate) : ${FAXOPT(minrate)})
exten => s,n,NoOp(**** RECEIVING FAX : ${FAXFILE} ****)
exten => s,n,ReceiveFAX(/var/spool/asterisk/fax/${FAXFILE})
exten => s,n,Hangup()
exten => h,1,GotoIf($["${FAXOPT(ecm)}" = "no" ]?end)
exten => h,n,AGI(receivedfax.pl,from@domain.com,to@domain.com,${CALLERID(num)},${FILENAME})
exten => h,n(end),NoOp(FAXOPT(ecm) : ${FAXOPT(ecm)}) </pre>
<p>You can even create a similar script to transform a pdf into a tiff file and send via outbound fax:</p>
<pre>#!/usr/bin/perl -w
use strict;
use warnings;
sub random_name_generator($);

# usage: faxout.pl number filename
# example: faxout.pl 5555551212 myfax.pdf

if ($#ARGV != 1) {
	print qq(FAIL: 2 Arguments needed\n);
	exit(0);
}

my ($callto,$pdfname,$callfile,$filename);

$callto = $ARGV[0];
$pdfname = $ARGV[1];

my $tifname = $pdfname;
$tifname =~ s/.pdf/.tif/i;

system("gs -q -dNOPAUSE -dBATCH -sDEVICE=tiffg4 -sOutputFile=$tifname $pdfname");

if ($callto) {
	$filename = &#038;random_name_generator(12).".call";
	open (MYFILE, ">>/tmp/$filename") or die $!;
	$callfile = "Channel: Local/$callto\@outboundialcontext\n";
	$callfile = $callfile . "MaxRetries: 1\n";
	$callfile = $callfile . "RetryTime: 60\n";
	$callfile = $callfile . "WaitTime: 60\n";
	$callfile = $callfile . "Archive: yes\n";
	$callfile = $callfile . "Context: outboundfax\n";
	$callfile = $callfile . "Extension: s\n";
	$callfile = $callfile . "Priority: 1\n";
	$callfile = $callfile . "Set: FAXFILE=$tifname\n";
	print MYFILE $callfile;
	close (MYFILE);
	system("mv /tmp/$filename /var/spool/asterisk/outgoing");
}

sub random_name_generator($) {
	my ($namelength, $randomstring, @chars);
	$namelength = shift;
	@chars = ('a'..'z','A'..'Z','0'..'9');
	foreach (1..$namelength) {
		$randomstring .= $chars[rand @chars];
	}
	return $randomstring;
}</pre>
<p>Happy Coding!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.teamforrest.com/blog/156/integrating-fax-for-asterisk/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Asterisk Consulting Services</title>
		<link>http://www.teamforrest.com/blog/119/asterisk-consulting-services/</link>
		<comments>http://www.teamforrest.com/blog/119/asterisk-consulting-services/#comments</comments>
		<pubDate>Tue, 16 Jun 2009 12:38:30 +0000</pubDate>
		<dc:creator>Team Forrest</dc:creator>
				<category><![CDATA[VoIP]]></category>
		<category><![CDATA[asterisk]]></category>
		<category><![CDATA[communication]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[SIP]]></category>
		<category><![CDATA[voicemail]]></category>

		<guid isPermaLink="false">http://www.teamforrest.com/?p=119</guid>
		<description><![CDATA[Team Forrest offers Asterisk Consulting Services for a wide variety of VoIP, Call Center, and other Telephony Based needs. From small, family business to large Corporations, Team Forrest’s simple philosophy of “Help the Client” ensures we provide great service to meet your needs. Asterisk Consulting From carrier services to traditional PBX services, Team Forrest’s Asterisk [...]]]></description>
			<content:encoded><![CDATA[<p><img class="size-medium wp-image-42 alignright" title="asterisk-by-digium" src="http://www.teamforrest.com/blog/wp-content/uploads/2008/12/asterisk-by-digium-300x245.gif" alt="Asterisk is a registered trademark of Digium" /></p>
<p>Team Forrest offers Asterisk Consulting Services for a wide variety of VoIP, Call Center, and other Telephony Based needs. From small, family business to large Corporations, Team Forrest’s simple philosophy of “Help the Client” ensures we provide great service to meet your needs.</p>
<h2>Asterisk Consulting</h2>
<p>From carrier services to traditional PBX services, Team Forrest’s Asterisk Consulting Service provides you the solution you need. Services include:</p>
<ul>
<li>IVR Development</li>
<li>Custom AGI Scripting / Programming</li>
<li>OpenSER Integration</li>
<li>Calling Card Systems</li>
<li>Call Center / Sales Queue Development</li>
<li>Call Recording (call spying, call barging, whisper, etc.)</li>
<li>Database Integration (Microsoft SQL MSSQL, MySQL, Oracle, etc.)</li>
<li>Custom Solutions</li>
</ul>
<h2>Emergency Asterisk Support</h2>
<p>When a problem comes along, we provide <strong>24/7 Emergency Support </strong>to bring your system back to life. Both new and existing clients benefit from our immediate support response.</p>
<p>For immediate support please <a href="/contact/">contact</a> us or call <strong>+1 (212) 937-7844</strong>.</p>
<h2>Remote and Onsite Support</h2>
<p>Team Forrest offers <strong>immediate</strong> remote assistance across the globe. Local, onsite service is also available, with quick response to Michigan, Florida, and New York locations.</p>
<h2>Asterisk? Ask us.</h2>
<p>With Team Forrest, you get professional consulting at a great price — <strong>increased productivity</strong> at a <strong>lower cost</strong>. To see how Team Forrest can help improve your communication needs, <a href="/contact">contact us</a>. We enjoy talking with clients and look forward to seeing how we can help you.</p>
<p>Asterisk, developed and released by <a href="http://www.digium.com">Digium, Inc.</a>, is the world’s leading open source telephony engine and tool kit. Asterisk empowers communication with it’s flexibility. Whether working as a simple office telephone system, a robust Call Center platform, or anything in-between, Asterisk provides advanced features at a very low deployment cost.  Asterisk is released as open source under the GNU General Public License (GPL), and it is available for download free of charge. Asterisk is the most popular open source software available, with the Asterisk Community being the top influencer in VoIP.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.teamforrest.com/blog/119/asterisk-consulting-services/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Parking Availability, Team Forrest, and Asterisk</title>
		<link>http://www.teamforrest.com/blog/98/parking-availability-team-forrest-and-asterisk/</link>
		<comments>http://www.teamforrest.com/blog/98/parking-availability-team-forrest-and-asterisk/#comments</comments>
		<pubDate>Sun, 11 Jan 2009 16:45:29 +0000</pubDate>
		<dc:creator>Team Forrest</dc:creator>
				<category><![CDATA[VoIP]]></category>
		<category><![CDATA[AGI]]></category>
		<category><![CDATA[ann arbor]]></category>
		<category><![CDATA[asterisk]]></category>
		<category><![CDATA[government]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[news]]></category>
		<category><![CDATA[parking]]></category>
		<category><![CDATA[Perl]]></category>

		<guid isPermaLink="false">http://www.teamforrest.com/?p=98</guid>
		<description><![CDATA[Recently, Fred Posner of Team Forrest, assisted Edward Vielmetti with a simple idea — help make information accessible. In this case, the information was the availability of Parking Spots in Ann Arbor, Michigan. The Ann Arbor Downtown Development Authority (A2DDA) publishes data regarding parking spot availability on the web, however, when you’re driving to the [...]]]></description>
			<content:encoded><![CDATA[<p><img class="size-full wp-image-100 alignright" title="ann-arbor-parking-project" src="http://www.teamforrest.com/blog/wp-content/uploads/2009/01/ann-arbor-parking-project.jpg" alt="Ann Arbor Parking" /></p>
<p>Recently, Fred Posner of Team Forrest, assisted <a href="http://vielmetti.typepad.com/">Edward Vielmetti</a> with a simple idea — help make information accessible. In this case, the information was the availability of Parking Spots in Ann Arbor, Michigan.</p>
<p>The <a href="http://www.a2dda.org/">Ann Arbor Downtown Development Authority</a> (A2DDA) publishes data regarding parking spot availability on the web, however, when you’re driving to the garage navigating to a web site is the least of your worries. So, an idea was born to make parking information readily accessible — and with that, Team Forrest’s Fred Posner built a quick prototype to demonstrate how <a href="http://www.asterisk.org">Asterisk</a> (by <a href="http://www.digium.com">Digium</a>) can help rethink how data can be accessed.</p>
<p>In the prototype, a caller can select which garage to query. The system will then speak to the caller the remaining number of spaces and offer 3 options — select another garage, exit (and hear the local weather), or choose to be notified if there are fewer than 10 spaces remaining. If the caller selects the notification option, the system will automatically check once a minute (for 30 minutes) and initiate a call out to the user. The call will remind the user which garage they selected and inform them of the current number of available spaces.</p>
<p>The prototype for this project can be accessed from the Team Forrest main line, at <strong>+1 (212) 937-7844</strong>. Then, choose <strong>6</strong> for check local Ann Arbor Parking availability.</p>
<h3>About Team Forrest</h3>
<p>Team Forrest offers complete Internet Consulting services, specializing in VoIP and Asterisk solutions. Team Forrest has one simple goal: Help the client. Whether you need emergency assistance or if you are planning a deployment, Team Forrest is here to help. With over 15 years experience, our team can quickly assess your needs and help deploy the most appropriate solution.</p>
<h3>About Asterisk</h3>
<p><a href="http://www.asterisk.org">Asterisk</a> (by <a href="http://www.digium.com">Digium</a>) is the world’s leading open source telephony engine and tool kit. Asterisk empowers communication with it’s flexibility. Asterisk is released as open source under the <a href="http://www.gnu.org">GNU</a> General Public License (GPL), and it is available for download free of charge. Asterisk is the most popular open source software available, with the Asterisk Community being the top influencer in VoIP.</p>
<h4>Related Information:</h4>
<ul>
<li>Fred&#8217;s post on VoIP Tech Chat, &#8220;<a href="http://www.voiptechchat.com/voip/218/use-asterisk-cepstral-and-perl-to-get-parking-and-weather-updates/">Using Asterisk, Cepstral, and Perl to get Parking and Weather</a>.&#8221;</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.teamforrest.com/blog/98/parking-availability-team-forrest-and-asterisk/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Weather on your Polycom</title>
		<link>http://www.teamforrest.com/blog/96/weather-on-your-polycom/</link>
		<comments>http://www.teamforrest.com/blog/96/weather-on-your-polycom/#comments</comments>
		<pubDate>Tue, 06 Jan 2009 16:55:52 +0000</pubDate>
		<dc:creator>Team Forrest</dc:creator>
				<category><![CDATA[VoIP]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[polycom]]></category>

		<guid isPermaLink="false">http://www.teamforrest.com/?p=96</guid>
		<description><![CDATA[VoIP Tech Chat posted a nice little script for putting a quick, no frills weather report directly onto your Polycom Microbrowser. To view the code, download the files, or just see the script, go to VoIP Tech Chat (dot com).]]></description>
			<content:encoded><![CDATA[<p>VoIP Tech Chat <strong><a href="http://www.voiptechchat.com/voip/208/perl-script-to-put-weather-on-your-polycom-microbrowser/">posted a nice little script</a> </strong>for putting a quick, no frills weather report directly onto your Polycom Microbrowser.</p>
<p>To view the code, download the files, or just see the script, go to <a href="http://www.voiptechchat.com/">VoIP Tech Chat</a> (dot com).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.teamforrest.com/blog/96/weather-on-your-polycom/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using AGI to get Caller ID Name CNAM</title>
		<link>http://www.teamforrest.com/blog/89/using-agi-to-get-caller-id-name-cnam/</link>
		<comments>http://www.teamforrest.com/blog/89/using-agi-to-get-caller-id-name-cnam/#comments</comments>
		<pubDate>Mon, 05 Jan 2009 19:13:53 +0000</pubDate>
		<dc:creator>Team Forrest</dc:creator>
				<category><![CDATA[VoIP]]></category>
		<category><![CDATA[AGI]]></category>
		<category><![CDATA[asterisk]]></category>
		<category><![CDATA[CNAM]]></category>
		<category><![CDATA[communication]]></category>
		<category><![CDATA[Internet]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[SIP]]></category>

		<guid isPermaLink="false">http://www.teamforrest.com/?p=89</guid>
		<description><![CDATA[Everyone has them — and here&#8217;s Team Forrest&#8217;s version of a Caller ID to Name (CNAM, CIDNAME, etc.) lookup using AnyWho, Google, and 411.com. The first file is the calleridname.pl: UPDATE April 4, 2009 — Frank (user comment) let us know that AnyWho had changed their website. As a result the code has been updated. [...]]]></description>
			<content:encoded><![CDATA[<p>Everyone has them — and here&#8217;s Team Forrest&#8217;s version of a Caller ID to Name (CNAM, CIDNAME, etc.) lookup using AnyWho, Google, and 411.com. The first file is the <a title="Download CallerIDName.zip" href="http://www.teamforrest.com/tf-downloads/calleridname.zip">calleridname.pl</a>: <span id="more-89"></span></p>
<p class="alert"><strong>UPDATE April 4, 2009 —</strong> Frank (user comment) let us know that AnyWho had changed their website. As a result the code has been updated. Thanks Frank!</p>
<p class="alert"><strong>UPDATE November 18, 2009 —</strong> Robert (user comment) let us know of another change. As a result the code has been updated. Thanks Robert!</p>
<pre>#!/usr/bin/perl -w
use strict;
use LWP::UserAgent;
$|=1;

my ($cidnum,$cidname,$npa,$nxx,$station,$name);

#----------------------------------------------------------------
# get asterisk initial info
#----------------------------------------------------------------

while(&lt;STDIN&gt;) {
	chomp;
	last unless length($_);
}

#----------------------------------------------------------------
# check if we have a caller id
#----------------------------------------------------------------

if ($ARGV[0]) {
		$cidnum = $ARGV[0];
	} else {
		print qq(VERBOSE &quot;ERROR: no callerid provided&quot; 2\n);
		exit(0);
}

#----------------------------------------------------------------
# check caller id and split into npa, nxx, and station
#----------------------------------------------------------------

if(substr($cidnum,0,1) eq '1'){
	$cidnum=substr($cidnum,1);
}

if(substr($cidnum,0,2) eq '+1'){
	$cidnum=substr($cidnum,2);
}

if ($cidnum =~ /^(\d{3})(\d{3})(\d{4})$/) {
		$npa = $1;
		$nxx = $2;
		$station = $3;
	} elsif ($cidnum =~/\&lt;(\d{3})(\d{3})(\d{4})\&gt;/) {
		$npa = $1;
		$nxx = $2;
		$station = $3;
	} else {
		print qq(VERBOSE &quot;ERROR: unable to parse caller id&quot; 2\n);
		exit(0);
}

print qq(VERBOSE &quot;STATUS: CID is $npa-$nxx-$station&quot; 2\n);

#----------------------------------------------------------------
# check npa, nxx, and station for cid name
# 1 = check. 0 = skip.
#----------------------------------------------------------------

my $AnyWho = '1' ;
my $Google = '1' ;
my $www411 = '1' ;

if ($AnyWho &gt; '0') {
		print qq(VERBOSE &quot;STATUS: checking AnyWho for name lookup&quot; 2\n);
		if ($name = &amp;anywho_lookup ($npa, $nxx, $station)) {
				$cidname = $name;
				print qq(SET VARIABLE CALLERID\(name\) &quot;$cidname&quot;\n);
				print qq(VERBOSE &quot;STATUS: AnyWho said name was $cidname &quot; 2\n);
				exit(0);
			} else {
				print qq(VERBOSE &quot;STATUS: unable to find name with AnyWho&quot; 2\n);
		}
	} else {
		print qq(VERBOSE &quot;STATUS: AnyWho lookup disabled&quot; 2\n);
}

if ($Google &gt; '0') {
		print qq(VERBOSE &quot;STATUS: checking Google for name lookup&quot; 2\n);
		if ($name = &amp;google_lookup ($npa, $nxx, $station)) {
				$cidname = $name;
				print qq(SET VARIABLE CALLERID\(name\) &quot;$cidname&quot;\n);
				print qq(VERBOSE &quot;STATUS: Google said name was $cidname &quot; 2\n);
				exit(0);
			} else {
				print qq(VERBOSE &quot;STATUS: unable to find name with Google&quot; 2\n);
		}
	} else {
		print qq(VERBOSE &quot;STATUS: Google lookup disabled&quot; 2\n);
}

if ($www411 &gt; '0') {
		print qq(VERBOSE &quot;STATUS: checking www411 for name lookup&quot; 2\n);
		if ($name = &amp;www411_lookup ($npa, $nxx, $station)) {
				$cidname = $name;
				print qq(SET VARIABLE CALLERID\(name\) &quot;$cidname&quot;\n);
				print qq(VERBOSE &quot;STATUS: www411 said name was $cidname &quot; 2\n);
				exit(0);
			} else {
				print qq(VERBOSE &quot;STATUS: unable to find name with www411&quot; 2\n);
		}
	} else {
		print qq(VERBOSE &quot;STATUS: www411 lookup disabled&quot; 2\n);
}

#----------------------------------------------------------------
# return results and exit
#----------------------------------------------------------------

print qq(SET VARIABLE CALLERID\(name\) &quot;$cidnum&quot;\n);
print qq(VERBOSE &quot;STATUS: Unknown name for $cidnum &quot; 2\n);
exit(0);

#----------------------------------------------------------------
# parse anywho
# http://whitepages.anywho.com/results.php?qnpa=$npa&amp;qnpanxx=$npa$nxx&amp;qnxx=$nxx&amp;qp=$nxx$station&amp;qstation=$station
# Find More Information for First Last&lt;/a&gt;
#----------------------------------------------------------------

sub anywho_lookup {
	my ($npa, $nxx, $station) = @_;
	my $ua = LWP::UserAgent-&gt;new( timeout =&gt; 45);
	my $URL = 'http://whitepages.anywho.com/results.php';
	$URL .= qq(?qnpa=$npa&amp;qnpanxx=$npa$nxx&amp;qnxx=$nxx&amp;qp=$nxx$station&amp;qstation=$station);
	$ua-&gt;agent('AsteriskAGIQuery/1');
	my $req = new HTTP::Request GET =&gt; $URL;
	my $res = $ua-&gt;request($req);
	if ($res-&gt;is_success()) {
		if ($res-&gt;content =~ /Find More Information for (.*)&lt;\/a&gt;/) {
			my $clidname = $1;
			return $clidname;
		}
	}
	return &quot;&quot;;
}

#----------------------------------------------------------------
# parse google
# http://www.google.com/search?rls=en&amp;q=phonebook:$npa$nxx$station
# &lt;td&gt;First Name&lt;td&gt;(&lt;b&gt;$npa
#----------------------------------------------------------------

sub google_lookup {
	my ($npa, $nxx, $station) = @_;
	my $ua = LWP::UserAgent-&gt;new( timeout =&gt; 45);
	my $URL = qq(http://www.google.com/search?rls=en&amp;q=phonebook:$npa$nxx$station&amp;ie=UTF-8&amp;oe=UTF-8);
	$ua-&gt;agent('AsteriskAGIQuery/1');
	my $req = new HTTP::Request GET =&gt; $URL;
	my $res = $ua-&gt;request($req);
	if ($res-&gt;is_success()) {
		if ($res-&gt;content =~ /&lt;td&gt;(.+)&lt;td&gt;\(&lt;b&gt;$npa/) {
			my $clidname = $1;
			return $clidname;
		}
	}
	return &quot;&quot;;
}

#----------------------------------------------------------------
# parse 411
# http://www.411.com/search/Reverse_Phone?phone=$npa$nxx$station
# View map, driving directions, and more&quot;&gt;Name&lt;/a&gt;
#----------------------------------------------------------------

sub www411_lookup {
	my ($npa, $nxx, $station) = @_;
	my $ua = LWP::UserAgent-&gt;new( timeout =&gt; 45);
	my $URL = qq(http://www.411.com/search/Reverse_Phone?phone=$npa$nxx$station);
	$ua-&gt;agent('AsteriskAGIQuery/1');
	my $req = new HTTP::Request GET =&gt; $URL;
	my $res = $ua-&gt;request($req);
	if ($res-&gt;is_success()) {
		if ($res-&gt;content =~ /View map, driving directions, and more\&quot;&gt;(.*)&lt;\/a&gt;/) {
			my $clidname = $1;
			if ($clidname eq &quot;Listing Detail&quot;) {
				if ($res-&gt;content =~ /Type: &lt;strong&gt;(.*)&lt;\/strong&gt;/) {
					$clidname = $1;
					if ($res-&gt;content =~ /Location: &lt;strong&gt;(.*)&lt;\/strong&gt;/) {
						$clidname = $clidname . &quot; $1&quot;;
					}
				}
			}
			return $clidname;
		}
	}
	return &quot;&quot;;
}
</pre>
<p>This perl script will work well as an AGI script — checking AnyWho, Google, and then 411 for a caller&#8217;s name or location. If all else fails, the callerid name is set as the callerid number.</p>
<p>The perl script was designed to only use the Internet with minimal installation; so it will work without a database, Perl Asterisk module, or locally hosted NPA / NXX (phone number to region) file.</p>
<p>Team Forrest recommends using a subroutine context to get the callerid when needed; calling the script with either a <strong>GoSub</strong> or <strong>GosubIf</strong> command, such as:</p>
<pre>exten =&gt; s,n,Gosub(cidname-lookup,s,1)
exten =&gt; s,n,dial(${PHONE},30,t)
...

...
[cidname-lookup]
exten =&gt; s,1,NoOp(looking up callerid name)
exten =&gt; s,n,GotoIf($["foo${CALLERID(NAME)}" = "foo" ]?getname)
exten =&gt; s,n,GotoIf($["${CALLERID(NAME)}" = "${CALLERID(NUM)}" ]?getname)
exten =&gt; s,n,NoOp(caller id name exists as ${CALLERID(NAME)})
exten =&gt; s,n,Return
exten =&gt; s,n(getname),AGI(calleridname.pl,${CALLERID(NUM)})
exten =&gt; s,n,NoOp(Caller ID Name is now ${CALLERID(NAME)})
exten =&gt; s,n,Return</pre>
<p>Enjoy the file (<a title="Download the script" href="http://www.teamforrest.com/tf-downloads/calleridname.zip">download here</a>) and remember, Team Forrest is here to assist you will all of your Asterisk, VoIP, or technical needs.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.teamforrest.com/blog/89/using-agi-to-get-caller-id-name-cnam/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
	</channel>
</rss>
