Sunday, April 17, 2011

script - checking Betamax rates with a cronjob

This little script can be extended or modified with your own sip providers. It is useful for me to keep and eye open with one of the providers that I'm currently using.

#!/bin/bash

LAST_RATE=$(cat ./md5_12voip.txt | awk '{print $1}')
lynx --dump http://www.12voip.com/en/calling-rates.html | \
grep -E 'Sweden|Spain' | md5sum > ./md5_12voip.txt
NOW_RATE=$(cat ./md5_12voip.txt | awk '{print $1}')

if [ $LAST_RATE = $NOW_RATE ]; then
echo "no change on rates"
else
export DISPLAY=:0 && zenity --info --text 'Betamax 12voip rates changed \
for Sweden or Spain, check page: http://www.12voip.com/en/calling-rates.html'
fi


Monday, April 04, 2011

Setting up services on la Fonera / Accton MR3201A

I was wondering if writing this post in English, Spanish or French, probably French would be the most appropriated to keep up my learning but then it would become longer to write it up. Spanish, my mother tongue is the easiest, but to be honest English is probably the most useful one to reach more people, it is the kind of the universal language, something like mathematics for Science.

Nowadays there is common sense on having the last hardware, the last software, the quickest cpu, the biggest disk, and sometimes we forget that to build up great services it is not necessary; cheap hardware and open opensource one is the perfect mix for our needs.

It has been some time since a had around a little router Accton MR3201A, this router is almost the same hardware (if not the same) as the one it uses la Fonera. I wanted to use this little piece of hardware to separate some services from my computer, and make them independent to hangs, reboots or other kind of issues that my computer might have.

For that reason, I decided to use the mini-router as a linux box handling the next services:
  • VPN server (pptp)
  • Firewall (iptables)
  • Voice over ip and PBX (Asterisk)
  • IRC bouncer (miau)
  • Bandwidth monitor (bwm)
  • Samba client (cifs)
  • Ssh server (dropbear)
  • Mail server (ssmtp)
  • Wireless router (wireless-tools)
Just to be clear, our purpose is have all that software running on top of the next hardware:

CPU: 183.50 mhz
RAM: 16 MB
Flash: 8 MB


Cool isn't it?

So lets do some exercise with your hands and prepare your fingers to do some typing :-)

First thing we need to do is install the base system, as the resources we are going to use are quite tight, I decided to use OpenWrt, the kamikaze version that it is already adapted for this type of hardware:

OPENWRT
W I R E L E S S F R E E D O M
KAMIKAZE (8.09.2, r18961) -------------------------
* 10 oz Vodka Shake well with ice and strain
* 10 oz Triple sec mixture into 10 shot glasses.
* 10 oz lime juice Salute!
---------------------------------------------------

So, to have the router flashed I used the Gargoyle flashing method, all the instructions are explained at http://www.gargoyle-router.com/wiki/doku.php?id=fon_flash
With the very nice application fon flash.

That process will end up giving to you a fully functional linux box where you can log in and configure your wireless options and iptables firewall.
Once of the first things you might want to do is update the repository with:

opkg update

Then we are ready to install all the packages that will help us get all the services up.

VPN PPTP SERVER:

One of the first things I wanted to have running was a VPN server, for being able to browse securely the internet while conected to Open wireless networks avoiding any type of man in the middle attack. Also I wanted to keep the vpn server separate from my computer, placing it inside a DMZ network making even more difficult to compromise my personal data in the rare event of breaking my PPTP password with a dictionary attack.

So lets install the package:

opkg install pptpd

After installing it, we need to configure the vpn settings and configure the firewall (iptables)
For PPTP vpn will have to adapt the next files

/etc/ppp/options.pptpd
and
/etc/chap-secrets

root@OpenWrt:/etc/ppp# cat options.pptpd
#we can debug and use logfile to debug issues, it is very useful
#debug
#logfile /tmp/pptp-server.log
auth
name "pptp-server"
lcp-echo-failure 3
lcp-echo-interval 60
default-asyncmap
mtu 1482
mru 1482
nobsdcomp
nodeflate
#noproxyarp
#nomppc
mppe required,no40,no56,stateless
require-mschap-v2
refuse-chap
refuse-mschap
refuse-eap
refuse-pap
#your local vpn server will resolve dns
ms-dns 192.168.1.12
#plugin radius.so

root@OpenWrt:/etc/ppp# cat chap-secrets
#USERNAME PROVIDER PASSWORD IPADDRESS
yourusername pptp-server yourpassword 192.168.3.55

Make sure the service is running with:
root@OpenWrt:/etc/ppp# ps aux | grep pp
977 root 1136 S pptpd

and enable it at boot time with:

/etc/init.d/pptpd enable

Once you have the service running it will be necessary to adapt your firewall rules, opening port 1723 and protocol 47 from the wan side and also adding some forwarding rules to let the vpn clients access the Internet, so for that you can configure your firewall user rules.

root@OpenWrt:/etc/init.d# cat /etc/firewall.user
# This file is interpreted as shell script.
# Put your custom iptables rules here, they will
# be executed with each firewall (re-)start.
iptables -A input_wan -p tcp --dport 1723 -j ACCEPT
iptables -A input_wan -p 47 -j ACCEPT

iptables -A input_rule -i ppp+ -j ACCEPT
iptables -A forwarding_rule -i ppp+ -j ACCEPT
iptables -A forwarding_rule -o ppp+ -j ACCEPT
iptables -A output_rule -o ppp+ -j ACCEPT

Unless I have missed something, thats all to have the vpn server running. I used it a lot to connect from my Android phone using the built vpn application.

IRC BOUNCER:

From time to time I like to connect to specific channels on the IRC to ask or answer some questions on specific channels. I hate to leave a question
open without answer or waiting someone reply and have to disconnect myself from the channel for whatever reason. I also don't like to make noise on the channel by showing constant connection or disconnection messages. That's why I like to use an IRC bouncer, it keeps my channels always connected and put me on sleep as necessary saving all the chat history, making it independent if I connect from the phone, my computer or any other device I connect from.

So, to install it:

opkg install miau

and then we need to configure miaurc file, in my case I only set up some of the options, you may want to adapt it to your needs.
If we egrep showing only the lines that I used we can see:

root@OpenWrt:/etc/miau# cat miaurc | egrep -v "^#" | egrep -v "^$"
nicknames = {
"yournickname"
}
realname = "Name"
username = "username"
password = "yourpassword"
listenport = "yourport"
servers = {
"irc.freenode.net":"8001"
}
connhosts = {
"*":"yes"
}
channels = {
"#ubuntu"
"#mysql"
"#arduino"
"#openwrt"
"#android"
"#android-dev"
}
rejoin = "true"
leave = "false"
onconnect = {
"p":"nickserv":"identify yourpassword"
}


Again, if you want to provide access you will have to configure iptables, in my case I added separate rules for each client, so we enable access based on mac address for connections with source on the wan interface editing the file /etc/config/firewall

config rule
option src wan
#your mac address
option src_mac 00:e0:00:00:00:9a
option target ACCEPT


and then reload the firewall with: /etc/init.d/firewall reload

At this point, it is good to explain how is my personal setup, as it might be different from yours, but knowing mine you will be able to adapt it for your needs.
My network looks like:
You can see the network setup better Here.


ASTERISK PBX

One of the most important services I wanted to have running on our little box was Asterisk, a fully open source telephony system that allows you almost anything related with IP telephony.

Jumping from one country to another makes me avoid the crazy rates that main telephony providers offer us. Not only that, I want to improve the way telephony works to adapt ip telephony to me and not adapt myself to telephony, yes I know this sounds like a commercial, but it is true.
I want to have my own personalized voicemail, start it during the night or after some seconds, route the call to another phone, send me an email with the message attached as soon it is received and if I'm not at home. Receive on the same phone calls from different numbers and route outgoing calls with the provider that I prefer or the cheapest one depending on the nature of the call. And all those features are provided by Asterisk.

So lets review how is my asterisk setup. Currrently I have two incoming numbers, my French landline and a Spanish virtual number(DID) that allows my Spanish friends and family call me with landline cost, something that in Spain usually is free if you call from another landline.
Outgoing calls are routed differently depending if the call is to Sweden, Spain, France or any other place in the world.
Voicemail is configured to speak french if the call is received from France, if the call comes from Spain it will speak spanish and English from any other part in the world. Also the voicemail will send me and email with the saved voice attached as a file and all its details in the exact moment the message is left.

As we are using tiny resources I had to setup all asterisk voices and sounds from the different languages out of the system by mounting a samba share stored in my main computer. This is the only extra resource required from outside as the sound files and stored messages need more space than the one available in la Fonera. Newer type of foneras comes with usb interfaces, so it would be very easy to setup extra storages setting a usb key, but the Accton router that I use don't have usb port, so I mount the samba share using cifs.

I use the next opkg packages for that:
cifsmount - 1.5-2 -
kmod-fs-cifs - 2.6.26.8-atheros-1 -

And I mount the filesystem at boot time with:

root@OpenWrt:/etc/init.d# cat cifs
#!/bin/sh /etc/rc.common
# Example script
# Copyright (C) 2007 OpenWrt.org

START=10
STOP=15

boot() {
echo boot
# commands to run at boot
# continue with the start() section
start
}
start() {
echo "mounting /mnt/internet"
mount.cifs //myserverip/share /mnt/internet -o user=user,pass=xxxxxx
}
stop() {
echo "unmounting /mnt/sharedmount"
umount /mnt/sharedmount
}

Remember to enable it on boot:

/etc/init.d/cifs enable

Then on the mounted device I store all the voices, and tell asterisk to look for them making symlinks at:

root@OpenWrt:/jffs/usr/lib/asterisk/sounds# ls -l
-rw-r--r-- 1 root root 611 Jan 9 2009 CHANGES-asterisk-core-en-1.4.14
-rw-r--r-- 1 root root 122 Oct 27 2008 CREDITS-asterisk-core-en-1.4.14
-rw-r--r-- 1 root root 16118 Jan 9 2009 LICENSE-asterisk-core-en-1.4.14
-rw-r--r-- 1 root root 19440 Oct 27 2008 core-sounds-en.txt
lrwxrwxrwx 1 root root 23 Dec 30 2009 en -> /mnt/sharedmount/sounds/en
lrwxrwxrwx 1 root root 21 Dec 30 2009 es -> /mnt/sharedmount/sounds/
lrwxrwxrwx 1 root root 23 Dec 30 2009 fr -> /mnt/sharedmount/sounds/fr

Language specific files can be found at:

Time!!!, now that I see those dates 2009, I remember that I had to setup the time to be syncronized as for some reason the device was loosing the time on each reboot, for doing that what I did is setup a cron job using rdate built in command from Openwrt.

root@OpenWrt:/etc/init.d# cat S51crond
#!/bin/sh
# start crond
/usr/sbin/crond -c /etc/spool/cron/crontabs

root@OpenWrt:/etc/init.d# crontab -l
0 0 * * * /usr/sbin/rdate 128.138.140.44

Asterisk is very powerful and also once you get use to the language it uses is very easy to setup, basically you will have to deal only with a bunch of files: sip.conf, extensions.conf and voicemail.conf

Due to the cifs mount I had also to change the default directory used by asterisk, by editing:
root@OpenWrt:/etc/asterisk# cat asterisk.conf
[directories]
astetcdir => /etc/asterisk
astmoddir => /usr/lib/asterisk/modules
astvarlibdir => /usr/lib/asterisk
astdatadir => /usr/lib/asterisk
astagidir => /usr/lib/asterisk/agi-bin
;astspooldir => /var/spool/asterisk
;had to add below line
astspooldir => /mnt/sharedmount/var/spool/asterisk
astrundir => /var/run/
astlogdir => /var/log/asterisk
[...]

Also another file that you might want to take a look if you're having troubles while making audio codec translations is modules.conf inside /etc/, I had to enable a couple of connections to have the right translations up. Basically I had to enable conversion from codec alaw to linear pcm. My sip provider for the french landline is Freephonie, provider that comes by default with Internet french provider Free.fr, this provider for some reason doesn't work with gsm codec and work with allaw codec, as the voicemail messages are stored as wav files, it was necessary for asterisk to do some translations and thats why I had to enable some conversions.

root@OpenWrt:/etc/asterisk# cat modules.conf | egrep "^load"
load => codec_alaw.so ; A-law Coder/Decoder
load => codec_gsm.so ; GSM/PCM16 (signed linear) Codec Translation
load => codec_ulaw.so ; Mu-law Coder/Decoder

So, lets take a look to my main asterisk configuration files:

root@OpenWrt:/etc/asterisk# cat modules.conf | egrep "^load"
load => codec_alaw.so ; A-law Coder/Decoder
load => codec_gsm.so ; GSM/PCM16 (signed linear) Codec Translation
load => codec_ulaw.so ; Mu-law Coder/Decoder


root@OpenWrt:/etc/asterisk# cat sip.conf
[general]
language=es
defaultexpirey=1800
dtmfmode = auto


;Register and get calls from Telsome, to our number 965xxxxxxx
register => username:password@voip3.telsome.com
;Register and get calls from Free.fr, to our number 095xxxxxxx
register => username:password@freephonie.net
disallow=all
allow=ulaw
allow=alaw
allow=speex

[telsome]
type=friend
qualify=yes
secret=xxxxxxxxx
username=965xxxxxx
host=voip3.telsome.com
dtmfmode=rfc2833
canreinvite=no
disallow=all
allow=ulaw
allow=alaw
allow=gsm
insecure=port,invite
fromdomain=voip3.telsome.com
context=incoming

[1000]
type=peer
qualify=yes
dtmfmode=rfc2833
callerid="one pc" <1000>
language=es
context=myphones
host=dynamic
secret=xxxxxxx
disallow=all
allow=ulaw
allow=alaw
allow=gsm
dtmfmode=rfc2833
;nat=yes
mailbox=1000@default


[1001]
type=peer
qualify=yes
dtmfmode=rfc2833
callerid="android phone" <1001>
;language=es
context=myphones
host=dynamic
secret=xxxxx
disallow=all
allow=ulaw
allow=alaw
allow=gsm
dtmfmode=rfc2833
;nat=yes
mailbox=1001@default

[1002]
type=peer
qualify=yes
dtmfmode=rfc2833
callerid="peque" <1002>
;language=es
context=myphones
host=dynamic
secret=xxxxx
disallow=all
allow=ulaw
allow=alaw
allow=gsm
dtmfmode=rfc2833
;nat=yes

[justvoip]
type=peer
host=sip.justvoip.com
fromdomain=sip.justvoip.com
fromuser=965xxxxxxxxxx
username=xxxxxxxx
secret=xxxxxxxx
qualify=yes
canreinvite=no
dtmfmode=rfc2833
context=from-justvoip
incominglimit=1
;language=es
disallow=all
allow=ulaw
allow=alaw
allow=gsm

[12voip]
type=peer
host=sip.justvoip.com
fromdomain=sip.12voip.com
fromuser=965xxxxxxxx
username=xxxxxxxxxx
secret=xxxxxxxxxx
qualify=yes
canreinvite=no
dtmfmode=rfc2833
context=from-12voip
incominglimit=1
;language=es
disallow=all
allow=ulaw
allow=alaw
allow=gsm


[freephonie-out]
type=peer
host=freephonie.net
username=095xxxxxxx
fromuser=095xxxxxxx
secret=xxxxx
qualify=yes
nat=yes

[freephonie-in]
type=peer
qualify=yes
host=freephonie.net
context=fromfree

Lets see the extensions.conf

root@OpenWrt:/etc/asterisk# cat extensions.conf
[...]

[general]
static=yes
writeprotect=no
clearglobalvars=no

[globals]
; Global variables goes here

;[incoming]
; Nothing should land here yet, but every context should end in
; a Hangup(), so we do that.
;exten => s,1,Hangup()


[myphones]
; When we dial something from the phones we just added in
; sip.conf, Asterisk will look for a matching extension here,
; in this context.

; First Phone, extension 1000. If 1000 is called, here is
; where we land, and the device registered with the
; name 1000, is dialed, after that Asterisk hangs up.
;we call extension for 14 seconds after that the spanish voicemail goes on
exten => 1000,1,Dial(SIP/1000,14)
exten => 1000,2,Set(CHANNEL(language)=es)
;s will skip the vm-intro message and u will talk the unavailable message
exten => 1000,3,VoiceMail(1000@default,s,u)
exten => 1000,4,PlayBack(vm-goodbye)
exten => 1000,n,Hangup()

; The same goes for Second Phone, extension 1001
exten => 1001,1,Dial(SIP/1001,15)
exten => 1001,2,VoiceMail(1001@default)
exten => 1001,3,PlayBack(vm-goodbye)
exten => 1001,n,Hangup()

; The same goes for Android Phone, extension 1002
exten => 1002,1,Dial(SIP/1002)
exten => 1002,n,Hangup()

; Testing extension, prepare to be insulted like a
; Monthy Python knight
exten => 201,1,Answer()
exten => 201,n,Playback(tt-monkeys)
exten => 201,n,Hangup()

; Voicemail
exten => 8,1,VoiceMailMain(s${CALLERIDNUM})
exten => 8,2,Hangup

; Echo-test, it is good to test if we have sound in both directions.
; The call is answered
exten => 202,1,Answer()
; Welcome message is played
exten => 202,n,Playback(dir-welcome)
; Play information about the echo test
exten => 202,n,Playback(demo-echotest)
; Do the echo test, end with the # key
exten => 202,n,Echo()
; Plays information that the echo test is done
exten => 202,n,Playback(demo-echodone)
; Goodbye message is played
exten => 202,n,Playback(demo-thanks)
; Hangup() ends the call, hangs up the line
exten => 202,n,Hangup()

;call to Spain route through 12voip
exten => _0034[0123456789].,1,Dial(SIP/12voip/${EXTEN})
exten => _0034[0123456789].,n,Congestion()
exten => _0034[0123456789].,n,Hangup()
;calls to Sweden routed through 12voip
exten => _0046[0123456789].,1,Dial(SIP/12voip/${EXTEN})
exten => _0046[0123456789].,n,Congestion()
exten => _0046[0123456789].,n,Hangup()

;calls to France with international prefix through 12voip
;we can use also Free.fr as the output will be free as well.
exten => _0033[0123456789].,1,Dial(SIP/12voip/${EXTEN})
exten => _0033[0123456789].,n,Congestion()
exten => _0033[0123456789].,n,Hangup()

;calls to French landline without international prefix
;info taken from
;http://sinhaladweepa.ruwenzori.net/index.php/2008/06/03/configuration-asterisk-pour-freephonie-en-sip
;exten => _09.,1,Dial(SIP/freephonie-out/${EXTEN})
exten => _09.,1,Dial(SIP/12voip/${EXTEN})
exten => _09.,1,n,Congestion()
exten => _09.,1,n,Hangup()

[incoming]
;incoming context handle incoming calls from my spanish DID
;so we output the voicemail in spanish :-) after 14 seconds
exten => s,1,Log(NOTICE, Incoming call from ${CALLERID(all)})
exten => s,2,Dial(SIP/1000,14)
exten => s,3,Set(CHANNEL(language)=es)
;with the s we skip the default msg and put our unavail
exten => s,4,VoiceMail(1000@default,s,u)
exten => s,5,PlayBack(vm-goodbye)
exten => s,n,Hangup()
; End of the "incoming" context

[fromfree]
;Calls received from France goes to the french voicemail, but same extension
exten => s,1,Log(NOTICE, Incoming call from ${CALLERID(all)})
exten => s,2,Dial(SIP/1000,14)
exten => s,3,Set(CHANNEL(language)=fr)
exten => s,4,VoiceMail(1000@default)
exten => s,5,PlayBack(vm-goodbye)
exten => s,n,Hangup()

Fun!, lets take a look to the voicemail configuration that will send us the handy emails once we get a message:

root@OpenWrt:/etc/asterisk# cat voicemail.conf | egrep -v ";"
[general]
format=wav
serveremail=asterisk
attach=yes
skipms=3000
maxsilence=10
silencethreshold=128
maxlogins=3

fromstring=The Asterisk PBX
emaildateformat=%A, %B %d, %Y at %r
mailcmd=/usr/sbin/ssmtp -t

[default]
format=wav
1000 => pass,name,user@gmail.com,attach=yes
1001 => pass,name,user@gmail.com

Note that Asterisk need an external email program to send the emails, for this little router I decided to use ssmtp.

mailcmd=/usr/sbin/ssmtp -t

the configuration of ssmtp is fairly simple to use it with gmail, you only have to fill up info inside the next files:

root@OpenWrt:/etc/ssmtp# cat revaliases
# sSMTP aliases
#
# Format: local_account:outgoing_address:mailhub
#
# Example: root:your_login@your.domain:mailhub.your.domain[:port]
# where [:port] is an optional port number that defaults to 25.
root:username@gmail.com:smtp.gmail.com:587
mainuser:username@gmail.com:smtp.gmail.com:587


root@OpenWrt:/etc/ssmtp# cat ssmtp.conf | grep -v "#"
root=postmaster
mailhub=mail
rewriteDomain=
hostname=_HOSTNAME_
root=username@gmail.com
mailhub=smtp.gmail.com:587
rewriteDomain=
hostname=username@gmail.com
UseSTARTTLS=YES
AuthUser=username
AuthPass=xxxxxxxxxxxx
FromLineOverride=YES

I don't want to extend myself explaining every single line on the configuration files, please note that this configuration should be adapted to your particular needs, and as you may know linux, like other things in life is not just copy & paste, so the best way for you to understand things will be read before you type. Search, read, study and understand. ;-)