Demo de marcación automática con Asterisk para Campus Party

Cuando salga esta nota, yo estaré impartinedo una conferencia en Campus Party 2010 sobre marcación automática usando Asterisk.

Hice un pequeño programa en perl llamado “joder.pl” que hace exactamente lo que su nombre dice.

Pones un número a marcar y el lapso en segundos y marca a un teléfono victima y repite esto hasta que interrumpes el programa.

Es una versión muy simplificada de un marcador, pero es para mostrar las posibilidades infinitas para crear programas interesantes…

Antes que nada es necesario tener una instalación de Asterisk operando y con lo siguiente en sus archivos de configuración:

en el archivo /etc/asterisk/manager.conf deben de tener algo así:

[general]
displaysystemname = yes
enabled = yes
;webenabled = yes
port = 5038
bindaddr = 0.0.0.0
 
[test]
secret = test
writetimeout = 100000
read = system,call,log,verbose,command,agent,user
write = system,call,log,verbose,command,agent,user

En el archivo de dialplan de Asterisk conocido como /etc/asterisk/extensions.conf debera estar algo así:

[dial]
exten => 666,1,Playback(tt-monkeys)
exten => 666,n,hangup

Al invocar el programa así:

./joder.pl 56581111 30

El programa marca a la Profeco y cada 30 segundos hace lo mismo, al contestar toca un audio de “changos”, hasta que interrumpimos el programa con un control+C.

En este caso estamos usando un API de Asterisk conocidop como AMI (Asterisk Manager Interface).

El programa se deja para fines didácticos y no nos hacemos responsables de su uso, y menos del gasto telefónico que esto genere.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
#!/usr/bin/perl
#====================================================================#
# Program => joder.pl                                  (In Perl 5.x) #
#====================================================================#
# Autor         => Fernando "El Pop" Romo         (pop@cofradia.org) #
# Creation date => 10/Aug/2010                                       #
#--------------------------------------------------------------------#
# Info => This program is a litle demostration of automatic dialing. #
#         take the phone argument and make a lot of disturbing       #
#         calls.                                                     #
#--------------------------------------------------------------------#
#               (c) 2010 - Fernando Romo / Incuvox                   #
#--------------------------------------------------------------------#
# This code are released under the GPL License. Any change must be   #
# report to the authors                                              #
#====================================================================#
 
# Load Modules
use strict;
use POSIX;
use IO::Socket;
use Socket;
use Fcntl;
 
# signal traps
$SIG{PIPE} = 'IGNORE';
$SIG{INT} = $SIG{TERM} = $SIG{HUP} = 'Terminate';
 
# Number to dial
my $Number_To_Dial = $ARGV[0];
my $Delay          = $ARGV[1];
 
# Socket handler for Asterisk
my $asterisk_handler;
 
# Flags to connect to Asterisk
my $manager_connect_flag = 1;
 
#--------------------------------------------------------------------
# [Pop] Developer Note: The Sys_Parms() load the necesary values from
# the Parameter table in the DB. I left this values comment for test
# and documentation purposes.
#--------------------------------------------------------------------
my %Parm = ();
 
# Dial parametrs
$Parm{dialer}{timeout}          = 30000;        # Dial Timeout
$Parm{dialer}{absolute_timeout} = 180;          # absolute max time of a call in seconds, 0 = no limit
$Parm{dialer}{caller_id}        = "5556581111"; # Caller_ID to report to carrier (for SIP trunking)
 
#  Asterisk manager parameters
$Parm{asterisk}{host}     = "127.0.0.1"; # IP address of * Server
$Parm{asterisk}{port}     = 5038;        # * manager port
$Parm{asterisk}{user}     = "test";      # * Manager user
$Parm{asterisk}{pass}     = "test";      # * Manager password
$Parm{asterisk}{events}   = 1;           # Flag to request event log to * manager
$Parm{asterisk}{trunk}    = "Zap/g1";    # Outgoing calls resource
$Parm{asterisk}{context}  = "dial";      # Context of the dial
$Parm{asterisk}{exten}    = "666";       # Context of the dial
#--------------------------------------------------------------------
 
#---------------------------------------------------------#
#  Function: Terminate()                                  #
#---------------------------------------------------------#
# Objetive: catch the {INT}  signal and close connection  #
#           to sockets and terminate program.             #
#   Params: none                                          #
#    Usage:                                               #
#          $SIG{INT}  = 'Terminate';                      #
#---------------------------------------------------------#
 
sub Terminate {
    close($asterisk_handler);         # destroy asterisk manager conection
    exit(0);                          # Exit without error
}
 
#-----------------------------------------------#
#  Function: Nonblock([TCP socket handler])     #
#-----------------------------------------------#
# Objetive: puts socket into nonblocking mode   #
#   Params: [TCP Socket Handler]                #
#    Usage:                                     #
#          Nonblock($socket);                   #
#-----------------------------------------------#
 
sub Nonblock {
    my $socket = shift;
    my $flags;
 
    $flags = fcntl($socket, F_GETFL, 0)
        or die "Can't get flags for socket: $!\n";
    fcntl($socket, F_SETFL, $flags | O_NONBLOCK)
        or die "Can't make socket nonblocking: $!\n";
}
 
#-----------------------------------------------#
#  Function: Manager_Login                      #
#-----------------------------------------------#
# Objetive: Send Login Action to Asterisk API   #
#   Params: none                                #
#    Usage:                                     #
#          Manager_Login();                     #
#-----------------------------------------------#
 
sub Manager_Login {
    my $command  = "Action: Login\r\n";
    $command .= "Username: $Parm{asterisk}{user}\r\n";
    $command .= "Secret: $Parm{asterisk}{pass}\r\n";
    $command .= "Events: ";
    if ($Parm{asterisk}{events}) {
        $command .= 'on';
    }
    else {
        $command .= 'off';
    } 
    $command .= "\r\n\r\n";
    Send_To_Asterisk(\$command);
}
 
#--------------------------------------------------#
# Function: Connect_To_Asterisk()                  #
#--------------------------------------------------#
# Objetive: connect program with asterisk manager  #
#   Params: None                                   #
#    Usage:                                        #
#          Connect_To_Asterisk();                  #
#--------------------------------------------------#
 
sub Connect_To_Asterisk {
    $asterisk_handler = new IO::Socket::INET->new( PeerAddr => $Parm{asterisk}{host},
                                                   PeerPort => $Parm{asterisk}{port},
                                                   Proto    => "tcp",
                                                   ReuseAddr => 1,
                                                   Type     => SOCK_STREAM );
    if ($asterisk_handler) {
        $asterisk_handler->autoflush(1);
        Nonblock($asterisk_handler);
        return 0;
    }
    else {
    	return 1;
    }
}
 
#--------------------------------------------------------#
# Function: Send_To_Asterisk([message])                  #
#--------------------------------------------------------#
# Objetive: Send  message to Asterik manager             #
#   Params: message, socket_handler                      #
#    Usage:                                              #
#          Send_To_Asterisk(\$message)                   #
#--------------------------------------------------------#
 
sub Send_To_Asterisk {
    my $command_ref = shift;
    unless ($$command_ref eq "" && $manager_connect_flag == 1) {
        # if the socket exists send data, if not, turn on reconnection flag
        # if (defined(getpeername($asterisk_handler))) {
        unless($asterisk_handler eq "") {
            my $rv = $asterisk_handler->send($$command_ref, 0);
            unless (defined $rv) {
                # if send fails, turn on reconnection flag
                $manager_connect_flag = 1;
            }
        }
        else {
            $manager_connect_flag = 1;
        }
    }
}
 
#---------------------------------------------------#
# Function: Dial([phone number])                    #
#---------------------------------------------------#
# Objetive: originate a phone call via the asterisk #
#                                                   #
#   Params: phone number                            #
#    Usage:                                         #
#          Dial('56581111');                        #
#---------------------------------------------------#
 
sub Dial {
    my $Number = shift;
    my $command  = "Action: Originate\r\n";
       $command .= "Channel: $Parm{asterisk}{trunk}/$Number\r\n";
       $command .= "Context: $Parm{asterisk}{context}\r\n";
       $command .= "Exten: $Parm{asterisk}{exten}\r\n";
       $command .= "Priority: 1\r\n";
       $command .= "Async: true\r\n";
       $command .= "Timeout: $Parm{dialer}{timeout}\r\n";
       $command .= "Variable: TIMEOUT(absolute)=$Parm{dialer}{absolute_timeout}\r\n";
       $command .= "Callerid: $Parm{dialer}{caller_id}\r\n\r\n";
    Send_To_Asterisk(\$command);
}
 
#======================#
#      Main block      #
#======================#
 
if ($Number_To_Dial && $Delay) {
 
    while (1) { # Main loop #
 
        if ($manager_connect_flag) {
            $manager_connect_flag = Connect_To_Asterisk();
            unless ($manager_connect_flag) {
                Manager_Login();
            } 
        }
 
        # Check if the dialer can send calls to asterisk using a semaphore
        if ($manager_connect_flag == 0) {
            if ($Number_To_Dial) {
                Dial($Number_To_Dial);
                sleep($Delay);
            }
        }
 
    } # End of main loop
 
}
else {
    print "Usage => joder.pl [Number to dial] [wait time in seconds]\n";
}
#------------- End of main block ----------

Enjoy!

Saludos… Fernando “El Pop” Romo

Tags:


3 votes, average: 2.33 out of 53 votes, average: 2.33 out of 53 votes, average: 2.33 out of 53 votes, average: 2.33 out of 53 votes, average: 2.33 out of 5 (3 votes, average: 2.33 out of 5)
You need to be a registered member to rate this post.
Loading...
Asterisk, Humor, Perl, Programacion, Tips técnicos, VoIP | RSS 2.0 |     2,081 views

RSS feed

2 Comments »

Comment by caroteno
2010-09-21 21:54:22

Que onda Pop:

Me pareció curioso tu script “joder.pl” para Campus Party y me dí a la tarea de probarlo.

Algunos comentarios:
1.- En las últimas versiones de asterisk, Zap fue totalmente remplazado por Dahdi por lo que el parámetro $Parm{asterisk}{trunk}=”Zap/g1″ hay que remplazarlo por Dahdi/g1, siendo sólo necesario para últimas versiones de asterisk.

2.- Mis pruebas fueron con asterisk versión 1.6.2.11 y de primera instancia el programa no funcionó.
Difícil detectar el problema, si tu programa no escribe ninguna salida o respuesta proveniente del servidor.
Sin embargo modificando la subrutina Send_To_Asterisk, para ver las respuestas de servidor, como sigue:

sub Send_To_Asterisk {
    my $command_ref = shift;
    my @response;
    unless ($$command_ref eq "" && $manager_connect_flag == 1) {
        # if the socket exists send data, if not, turn on reconnection flag
        # if (defined(getpeername($asterisk_handler))) {
        unless($asterisk_handler eq "") {
            my $rv = $asterisk_handler->send($$command_ref, 0);
            while (my $line = ) {
                #last if ($line eq $EOL);
                if (wantarray) {
                    $line =~ s/$EOL//g;
                    push(@response, $line) if $line;
                } else {
                    $response[0] .= $line;
                }
            }
            print @response;
            unless (defined $rv) {
                # if send fails, turn on reconnection flag
                $manager_connect_flag = 1;
            }
        }
        else {
            $manager_connect_flag = 1;
        }
    }
}

Con esta modificación pude ver la respuesta, que por lo demás no puede verse en los logs.
La respuesta fue la siguiente:

Asterisk Call Manager/1.1
Response: Success
Message: Authentication accepted

Response: Error
Message: Permission denied

Gogleando el problema, y dado que en manager.conf todo parecía correcto; encontré que, (nuevamente para las últimas versiones de asterisk) hay nuevas categorias de permisos. Ver: http://forums.digium.com/viewtopic.php?f=1&t=72805&p=140867 Particularmente el permiso “originate” agregado en /etc/asterisk/manager.conf

[test]
secret = test
writetimeout = 100000
read = originate,system,call,log,verbose,command,agent,user
write = originate,system,call,log,verbose,command,agent,user

y con ello funciónó de maravilla.

Un saludo.

 
Comment by El Pop
2010-09-22 18:19:40

Es correcto, * 1.6 y 1.8 atomizan más los permisos que en la rama 1.2, lo que mencionas es lo adecuado para estas versiones

 
Name (required)
E-mail (required - never shown publicly)
URI
Your Comment (smaller size | larger size)
You may use <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> in your comment.

Trackback responses to this post