Tuesday, February 1, 2011

OpenVPN. По горячим следам

Понадобилось мне подключить пользователей к нашей корпоративной сети. Задача не новая, но не для меня. Было решено использовать для этих целей OpenVPN.
Итак, схема сети имеет следующий вид:
WAN - Router/Gateway (ip a.1) - LAN (a/24)
На сам роутер установить OpenVPN не представляется возможным. Посему сервер будет внутри сети. После долгих проб и ошибок вылезла такая схема
WAN - Rt/Gw (ip a.1) - LAN1 (a/24) - VPN Server (ip a.2 )
На роутере сделан проброс udp порта 1194 на ip a.2.
Теперь кратко по конфигам сервера и клиента
Сервер:

vi /etc/openvpn/server.conf

port 1194

proto udp

dev tap0

#Путь к ключам
ca /etc/openvpn/easy-rsa/keys/ca.crt
cert /etc/openvpn/easy-rsa/keys/server.crt
key /etc/openvpn/easy-rsa/keys/server.key
dh /etc/openvpn/easy-rsa/keys/dh1024.pem

ifconfig-pool-persist ipp.txt

# Между адресами a.10 и a.11 будут получать IP-шники клиенты VPN
server-bridge <адрес a.2>  255.255.255.0 <адрес a.10> <адрес a.11>

client-config-dir ccd

client-to-client

comp-lzo

persist-key
persist-tun

log-append /var/log/openvpn.log

verb 3

echo 1 > /proc/sys/net/ipv4/ip_forward
Теперь о клиенте. Клиент простой, виндовый.

client.ovpn

client

dev tap

proto udp

remote 1194

# Ключи лежат в той же директории, что и client.ovpn
ca ca.crt
cert client.crt
key client.key

persist-key
persist-tun

nobind

comp-lzo

Естественно, тут все описано крайне неполно. За доп. инфо - на сайт Openvpn. Там подробно описано как делать ключи.

ЗЫ: В дальнейшем думаю разобраться, возможна ли просто password аутентификация и подключение штатными средствами винды.

Monday, January 17, 2011

Локальный кэширующий DNS сервер

Необходим для Астериска, ибо при пропадании канала при очередном DNS Lookup может зависнуть.

apt-get install bind9
vi /etc/bind/named.conf.options

acl "corpnets" {192.168.240.0/24; 127.0.0.1/8; localhost;}; //Тут прописать диапазон сетей, которые могут обращаться к нашему серверу
options {
directory "/var/cache/bind";

// If there is a firewall between you and nameservers you want
// to talk to, you may need to fix the firewall to allow multiple
// ports to talk. See http://www.kb.cert.org/vuls/id/800113

// If your ISP provided one or more IP addresses for stable
// nameservers, you probably want to use them as forwarders.
// Uncomment the following block, and insert the addresses replacing
// the all-0's placeholder.

allow-query {"corpnets";};

forwarders {
8.8.8.8; // Тут прописать корневой DNS сервер
};

auth-nxdomain no; # conform to RFC1035
listen-on-v6 { any; };
};

/etc/init.d/bind9 restart
vi /etc/resolv.conf

nameserver 127.0.0.1

Все. Наслаждаемся локальным DNS.

Wednesday, December 22, 2010

FTP сервер ProFTPd

Использую именно его, т.к. вполне простой и хорошо настраиваемый.
Первый момент - это то, что метод входа в папку на этом сервере - chroot, а значит система следит за правами доступа на файлы. Чтобы не было проблем с удалением файлов и пр., те файлы которые создаются автоматически должны иметь имя/права корректного пользователя. Либо, как делаю я 777, а потом просто разделение политик READ/WRITE настройками самого сервера.
Тут я выложу свой шаблон конфига, точнее, его отличия от дефолтного:


UseIPv6 off
IdentLookups off # Чтобы не искал DNS

ServerType standalone # Не люблю работать через inetd. Множатся сущности.
TimesGMT off # Хорошая опция :) При ней корректно отображается время файлов при просмотре.

Все остальные опции можно легко найти в мануале по Proftpd.

Friday, December 10, 2010

Про защиту астериска.

Защита астериска, особенно, если о стоит на внешнем IP - первоочередная задача. Итак...

1. Настроим сам Астериск

sip.conf
[general]
context=nocontext ; Чтобы неавторизованные/левые звонки никуда не попадали
allowguest=no ; Вообще запретить неавторизованные вызовы
match_auth_username=no
; Честно, не скажу как это влияет на защиту, но пишут, что влияет. Имеет смысл в том случае, если UserID и AuthUserID - разные
alwaysauthreject=yes ; Не выдает доп. информацию при неудачной регистрации. spwar отказывается работать.
useragent=D-Link DVG-1402S ; Или любой другой - найдите в гугле реальное железо. так вы будете меньше привлекать внимание хацкеров которые ищут астериски в инете.

users.conf
[XXX]
...
deny = 0.0.0.0/0.0.0.0

premit = <подсеть, в которой будет этот телефон>/<маска подсети>
; Не дает возможности регистрироваться экстеншенам из левых подсетей

2. Fail2Ban. Банит IP по проваленным попыткам регистрации.

apt-get install fail2ban
cd /etc/fail2ban/filter.d
vi asterisk.conf

# Fail2Ban configuration file
#
#
# $Revision: 250 $
#

[INCLUDES]

# Read common prefixes. If any customizations available -- read them from
# common.local
#before = common.conf


[Definition]

#_daemon = asterisk

# Option: failregex
# Notes.: regex to match the password failures messages in the logfile. The
# host must be matched by a group named "host". The tag "" can
# be used for standard IP/hostname matching and is only an alias for
# (?:::f{4,6}:)?(?P\S+)
# Values: TEXT
#
# HOST надо поместить в <> скобки.
failregex = NOTICE.* .*: Registration from '.*' failed for 'HOST' - Wrong password
NOTICE.* .*: Registration from '.*' failed for 'HOST' - No matching peer found
NOTICE.* .*: Registration from '.*' failed for 'HOST' - Username/auth name mismatch
NOTICE.* .*: Registration from '.*' failed for 'HOST' - Device does not match ACL
NOTICE.* .*: Registration from '.*' failed for 'HOST' - Peer is not supposed to register
NOTICE.* failed to authenticate as '.*'$
NOTICE.* .*: No registration for peer '.*' \(from \)
NOTICE.* .*: Host failed MD5 authentication for '.*' (.*)
NOTICE.* .*: Failed to authenticate user .*@.*


# Option: ignoreregex
# Notes.: regex to ignore. If this regex matches, the line is ignored.
# Values: TEXT
#
ignoreregex =

vi /etc/fail2ban/jail.conf

[asterisk-iptables]

enabled = true
filter = asterisk
action = iptables-allports[name=ASTERISK, protocol=all]
sendmail-whois[name=ASTERISK, dest=root, sender=fail2ban@example.org]
logpath = /var/log/asterisk/messages
maxretry = 5
bantime = 259200

vi /etc/asterisk/logger.conf

[general]

dateformat=%F %T

Monday, October 18, 2010

Про запись разговоров

Тут напишу про шаблон, который постоянно дорабатывается, и которым пользуюсь я.

Это касается записи в очереди, но может быть легко адаптировано к любому случаю

extensions.conf
[macro-QueueRoutine]
exten => s,1,Set(TIMESTAMP=${STRFTIME(${EPOCH},,%T)})
exten => s,n,Set(DATESTAMP=${STRFTIME(${EPOCH},,%Y:%m:%d)})
exten => s,n,Set(DB(${CHANNEL}T)=${TIMESTAMP})
exten => s,n,Set(DB(${CHANNEL}D)=${DATESTAMP})
exten => s,n,Set(MONITOR_FILENAME=${UNIQUEID})
exten => s,n,Set(AUDIOHOOK_INHERIT(MixMonitor)=yes)

exten => h,1,StopMixMonitor
exten => h,n,Set(MEMBERINTERFACE=${CUT(MEMBERINTERFACE,/,2)})
exten => h,n,Set(TIMESTAMP=${DB_DELETE(${CHANNEL}T)})
exten => h,n,Set(DATESTAMP=${DB_DELETE(${CHANNEL}D)})
exten => h,n,GotoIf($[ "x${DATESTAMP}${TIMESTAMP}" != "x"]?DatePresent)
exten => h,n,Set(TIMESTAMP=${STRFTIME(${EPOCH},,%T)})
exten => h,n,Set(DATESTAMP=${STRFTIME(${EPOCH},,%Y:%m:%d)})
exten => h,n(DatePresent),GotoIf($[ "x${CALLERID(num)}" != "x" ]?CIDPresent)
exten => h,n,Set(CALLERID(num)=0000)
exten => h,n(CIDPresent),GotoIf($[ "x${MEMBERINTERFACE}" = "x"]?NoRec)
exten => h,n,System(sh /etc/asterisk/bin/rec.sh /home/superuser/RecordCalls ${DATESTAMP} ${TIMESTAMP} ${CALLERID(num)} ${MEMBERINTERFACE} ${UNIQUEID} I)
exten => h,n,System(rm /var/spool/asterisk/monitor/${UNIQUEID}.wav)
exten => h,n(NoRec),Set(CDR(userfield)=${MEMBERINTERFACE})
exten => h,n,Verbose(Call from 0${CALLERID(num)} was answered by ${MEMBERINTERFACE})


Более доработанный вариант скрипта, для более точного определения ответившего можно сделать, использовав описанное тут

И, собсно, сам скрипт преобразования в mp3
/etc/asterisk/bin/rec.sh

#! /bin/sh

# Recording file script. v0.5
# Arg1 - In/Out removed
# Arg1 - Directory Arg2 - who calles, Arg3 - Answered, Arg4 - Time, Arg5 - Date
# Arg1 - Directory, Arg2 - Date, Arg3 - Time, Arg4 - First number, Arg5 - Second number
# Arg1 - Directory, Arg2 - Date, Arg3 - Time, Arg4 - First number, Arg5 - Second number, Arg6 - Time Attribute
# Arg1 - Directory, Arg2 - Date, Arg3 - Time, Arg4 - First number, Arg5 - Second number, Arg6 - FileName, Arg7 - Time Attribute

MAINDIR="$1"
DATESTAMP="$2"
TIMESTAMP="$3"
FIRSTN="$4"
SECONDN="$5"
FILENAME="$6"
TIMEATTR="$7"

mkdir -p $MAINDIR
mkdir -p $MAINDIR/$DATESTAMP
case $TIMEATTR in
'D')
mkdir -p $MAINDIR/$DATESTAMP/$SECONDN
mkdir -p $MAINDIR/$DATESTAMP/$SECONDN/DayTime
lame /var/spool/asterisk/monitor/$FILENAME.wav $MAINDIR/$DATESTAMP/$SECONDN/DayTime/$TIMESTAMP--$FIRSTN.mp3
chmod 777 $TIMESTAMP--$FIRSTN.mp3
;;
*)
mkdir -p $MAINDIR/$DATESTAMP/$SECONDN
lame /var/spool/asterisk/monitor/$FILENAME.wav $MAINDIR/$DATESTAMP/$SECONDN/$TIMESTAMP--$FIRSTN.mp3
chmod 777 $TIMESTAMP--$FIRSTN.mp3
;;
esac

Суть проста, как угол дома. Файл, который пишет MixMonitor имеет формат ${UNIQUEID}.vaw
После разговора фай, в экстешнене h обрабатывается, как то, выяснение того, кто взял трубку, обработка ошибок на предмет того, что некоторых полей может не быть, вызов скрипта, который жмет в mp3 и удаление wav файла. Поле CDR(userfield) устанавливается для того, чтобы выяснить, какой абонент из очереди взял трубку.

Chmod используется, чтобы пользователи могли удалять файлы из ftp-сервера. Саму политику удаления/записи лучше настроить на самом ftp.

UPD: При трансфере отвеченного звонка лучше сделать доработку: Причем при входящем звонке нужно на канале ставить переменную, чтобы при окончании звонка в случае трансфера можно было определить, что звонок были именно входящий.

exten => h,1,StopMixMonitor
exten => h,n,GoToIf($[ "${LEN(${MONITOR_FILENAME})}" = "0"]?MixMonitorPresent)
exten => h,n,Set(FileName=${MONITOR_FILENAME})
exten => h,n(MixMonitorPresent),GoToIf($[ "${LEN(${SIPREFERREDBYHDR})}" = "0"]?NoTransferDetected)
exten => h,n,Set(FileName=${UNIQUEID})
exten => h,n(NoTransferDetected),Set(AnsweredPeer=${CUT(BRIDGEPEER,/,2)})
exten => h,n,Set(AnsweredPeer=${CUT(AnsweredPeer,-,1)})
exten => h,n,Set(MEMBERINTERFACE=${CUT(MEMBERINTERFACE,/,2)})
exten => h,n,Set(TIMESTAMP=${DB_DELETE(${CHANNEL}T)})
exten => h,n,GotoIf($[ "x${TIMESTAMP}" != "x"]?TimePresent)
exten => h,n,Set(TIMESTAMP=${STRFTIME(${EPOCH},,%T)})
exten => h,n(TimePresent),Set(DATESTAMP=${DB_DELETE(${CHANNEL}D)})
exten => h,n,GotoIf($[ "x${DATESTAMP}" != "x"]?DatePresent)
exten => h,n,Set(DATESTAMP=${STRFTIME(${EPOCH},,%Y:%m:%d)})
exten => h,n(DatePresent),GotoIf($[ "x${CALLERID(num)}" != "x" ]?CIDPresent)
exten => h,n,Set(CALLERID(num)=0000)
exten => h,n(CIDPresent),GotoIf($[ "x${MEMBERINTERFACE}" != "x"]?CheckPickup)
exten => h,n,Set(MEMBERINTERFACE=${DIALEDPEERNUMBER})
exten => h,n(CheckPickup),GotoIf($[ "${MEMBERINTERFACE}" = "${AnsweredPeer}"]?GoRec)
exten => h,n,GoToIf($[ "${LEN(${AnsweredPeer})}" != "3" ]?GoRec)
exten => h,n,Set(MEMBERINTERFACE=${AnsweredPeer})
exten => h,n(GoRec),System(sh /etc/asterisk/bin/rec.sh /home/record  ${DATESTAMP} ${TIMESTAMP} ${CALLERID(num)} ${MEMBERINTERFACE} ${FileName} Q)
exten => h,n(NoRec),System(rm /var/spool/asterisk/monitor/${FileName}.wav)
exten => h,n,Set(CDR(userfield)=${MEMBERINTERFACE})

Thursday, September 2, 2010

Про установку простенького биллинга

Опишу тут установку простенького биллинга на базе ams (Asterisk Management System).
Находится данный проект по адресу www.ampex.ru (или тут)
Итак, для начала установим на сервер с Asterisk связку apache+php+mysql. Все команды далее для Debian 5

#aptitude install mysql-server mysql-client apache2 php5 libapache2-mod-php5 php5 php5-mysql php5-gd php5-ps libmysqlclient15-dev



#/etc/init.d/apache2 restart


Да, часть модулей можно убрать, но я не настолько глубоко разбираюсь в php.
Разбирать установку ams я тут особо не буду, просто пара советов себе на будущее.
- читай файлы INSTALL и README
- для биллинга необходим ams_cdr_mysql
- Необходимо дать вебморде права на доступ и запись в /etc/asterisk
- после установки отредактировать файл /etc/asterisk/ams.conf
- Сокет mysql - =/var/run/mysqld/mysqld.sock

Если морда при установке не может прицепиться к mysql, то лучше создать базу руками:

mysql -u root -p
> CREATE DATABASE ams;
> GRANT ALL PRIVILEGES ON ams.* TO ams@localhost IDENTIFIED BY 'some_pass';
> FLUSH PRIVILEGES;

После, в вебморде в админке поправить необходимые модули.

Monday, July 26, 2010

Про сборку asterisk на свежеустановленном Debian Lenny 5.0/6.0

Что касается необходимых пакетов:

apt-get install zlib1g-dev libnewt-dev bison ncurses-dev procps flex automake build-essential autoconf libtool libssl-dev libncurses5-dev linux-headers-$(uname -r) libxml2-dev libsqlite3-dev


Сборка и установка:

Dahdi:
tar -xvf dahdi-linux-complete-XXX.tar.gz
cd dahdi-linux-complete-XXX

make (возможно надо указать make MODULES_EXTRA=dahdi_dummy)
make install
make config


Asterisk:
tar -xvf asterisk-XXX.tar.gz
cd asterisk-XXX
./configure
make menuselect
make
make install
make samples

make config

Астериск теперь на виртуальной консоли 9 (Ctrl+Alt+F9)

UPD: Примечание для Ubuntu. В скрипте safe_asterisk надо поменять #! /bin/sh на #! /bin/bash