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
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:
Con esta modificación pude ver la respuesta, que por lo demás no puede verse en los logs.
La respuesta fue la siguiente:
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
y con ello funciónó de maravilla.
Un saludo.
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