понедельник, 19 октября 2009 г.

Postfix + Procmail для виртуальных ящиков


В дальнейшем предполагается, что виртуальные почтовые ящики расположены в директориях вида: /var/virtmail/domainname/username и принадлежат пользователю virtmail

В файле master.cf описываем транспорт procmail (все - в одну строку):

procmail unix - n n - - pipe flags=RO user=virtmail argv=/usr/bin/procmail -t -o SENDER=${sender} -m USER=${user} DOMAIN=${domain} /etc/procmailrc

включаем этот транспорт для виртуальных пользователей в main.cf:

virtual_transport = procmail

procmail_destination_recipient_limit = 1

Последняя опция означает, что письмо, адресованное нескольким получателям, будет "превращаться" во много писем - каждое с одним получателем. Иначе procmail не вполне правильно разбирается с такими множественными письмами.

Теперь самое интересное - что писать в /etc/procmailrc:

SHELL=/bin/sh

PATH=/bin:/usr/bin

MAILDR=/var/virtmail/${DOMAIN}/${USER}/

# на всякий случай создадим эту папку

DUMMY=`test -d $MAILDR | mkdir -m 700 $MAILDR`

# тут какие-то правила, ради которых и прикручивается procmail

# ...


# и последнее правило - куда класть почту по умолчанию:

:0:

${MAILDR}


По ходу экспериментов было замечено, что хранение имени почтовой директории в "стандартной" переменной MAILDIR приводило к необъяснимому поведению при вызове внешней команды - потому было выбрано "усеченное" имя.

вторник, 23 июня 2009 г.

Странная работа резольвера в Xubuntu 9.04


В Xubuntu 9.04 (не из коробки, а после рядя миграций из одной сети в другую) был обнаружена странная работа резольвера: команда
$ host some.host.somedomain.net
находит ip-адрес, а ping (или напр. firefox) при попытке обратиться к этому хосту, говорят, что хост не найден.
Методом тыка было предположено, что проблема - в файле /etc/nsswitch.conf (т.к. утилиты работы с DNS, такие как host, должны его игнорировать, а "нормальные" сетевые команды - наоборот - использовать).
Строка hosts в этом файле из коробки выглядит нечеловечески страшно:
hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4
Что-то не нравился мне этот mdns4_minimal - да еще и return после него - потому меняем на более понятное:
hosts: files dns
после перезагрузки проблема больше не наблюдалась.

понедельник, 4 мая 2009 г.

ПППингвины over Ethernet


Настраиваем PPPoE на Linux

Сервер

Для опытов использовалась OpenSUSE 11.1
Необходимо поставить следующие RPM: ppp, rp-ppoe и freeradius-client. Про то, как настраивать авторизацию на сервере RADIUS уже написано тут.
Проверить, как работает авторизация можно командой
# radexample
(да, именно с правами root - иначе она не сможет прочесть файл конфигурации, но в этом не признается - и выдаст Authentication FAILURE)
Проверив, что все работает, нужно в файле /etc/radiusclient/radiusclient.conf нужно убрать следующие строки (pppd на них сильно ругается):
radius_deadtime 0
bindaddr *
Если мы уберем эти строки заранее, ничего страшного не случится, но от radexample толку не ждите - она выпадет в кору.
Файл параметров сервера /etc/ppp/pppoe-server-options предельно прост:
+chap
-pap
auth
proxyarp
plugin radius.so
Запускается сервер командной строкой:
# pppoe-server -I eth1 -L 10.11.12.13
(стартовый скрипт для него придется сочинять самим)
  1. Первый параметр - интерфейс, на котором ждем подключения клиентов. Он должен быть поднят - иначе pppoe-server не поднимется IP адрес этому интерфейсу может быть как присвоен, так и не присвоен.
  2. Второй параметр - адрес, который будет отдаваться клиентам как адрес конца тоннеля (насколько мне удалось выяснить, он может быть как равен адресу нашего интерфейса - если таковой присвоен - так и не равен ему - на работу это не влияет).
Адреса клиента берем с RADUIS, потому в командной строке ничего не указываем.
Для того, чтобы сервер был реально полоезен, нужно разрешить на нем роутинг. В файле /etc/sysctl.conf пишем:
net.ipv4.ip_forward=1
Аналогичная конфигурация работоспособна на CentOS 5.3 и Ubuntu 9.04 (там пакет, содержащий pppoe-server, называется pppoe). Нужно заметить, что эти системы не нуждаются в прятание строк в файле /etc/radiusclient/radiusclient.conf (для CentOS ищется на http://rpmfind.net пакет radiusclient для fc или el, а в убунте есть аналогичный пакет radiusclient1).

Клиент

Опыты проводились на Ubuntu 9.04
Ничего доставлять не надо - все нужное в дистрибутиве уже есть.
Файл /etc/ppp/peers/pppoe:
user "myname"
defaultroute
replacedefaultroute
noauth
noipdefault
plugin rp-pppoe.so eth0
Последний параметр в последней строке - интерфейс, через который будем выходить на сервер. Он должен быть поднят, ip-адрес на нем может как быть, так и не быть.
Файл /etc/ppp/chap-secrets:
"myname" * "mysecret" *
myname и mysecret - это (как вы догадались) наши имя и пароль на RADIUS-сервере.
Соединение запускам командой:
# pppd call pppoe
Если возникли проблемы, добавляем в конфиг сервера и клиента строчку debug - и получаем довольно неплохой уровень отладочных сообщений.
Аналогичная конфигурация работает на Mandriva 2009.1

P.S. в Mandriva 2009.1 pppoe-server не вполне работоспособен - по крайней мере, мне вообще не удалось заставить его отвечать на LCP Request. Судя по всему, проблема заключается в pppd. Лечится сборкой из исходников ppp-2.4.4.XXXX.rpm для FedoraCore (pppoe плагин в него входит), а файлы в /etc/radiusclient копируются из ${RPMROOT}/BUILD/ppp-X.X.X/pppd/plugins/radius/etc (нюансы этой операции описаны в предыдущем посте).

среда, 29 апреля 2009 г.

Сервер l2tp на Linux с поддержкой RADIUS авторизации


Про настройку xl2tpd с клиентской стороны я уже писал тут, потому ограничусь только указанием принципиальных различий в конфигурации.
Опыты проводились на CentOS 5.3
Минимально необходимый /etc/xl2tpd/xl2tpd.conf в этом случае выглядит так:
[global]
access control = no
[lns default]
exclusive = no
ip range = 10.0.0.2-10.0.0.254
local ip = 10.0.0.1
require chap = yes
refuse pap = yes
require authentication = yes
pppoptfile = /etc/ppp/options.xl2tpd
Особенно надо обратить внимание на опцию require authentication = yes - без нее к RADIUS-серверу обращений не будет.
Минимально необходимое содержимое файла /etc/ppp/options.xl2tpd такое:
mtu 1410
mru 1410

nodefaultroute

lock

auth

plugin radius.so
plugin radattr.so
Чтобы номально работал radius-plugin к pppd должны сущестововать файлы в директории /etc/radiusclient. Их можно взять либо из SRPM ppp (поддиректория в каталоге BUILD: ppp-X.Y.Z/pppd/plugins/radius/etc) или установить пакет radiusclient.
В этой директории нужно подправить следующее: в файле /etc/radiusclient/servers
добавить строку, содержащую адрес RADIUS-сервера и пароль к нему:
127.0.0.1 mysecret
и тот же сервер указать в файле /etc/radiusclient/radiusclient.conf:
authserver 127.0.0.1
acctserver 127.0.0.1

Если этот файл брался из SRPM, то в нем нужно подправить еще пути к другим файлам конфигуриции клиента - все они почему-то предполагаются в /usr/local/etc/radiusclient

P.S. такой же файл options (только с прибавлением опций: +chap -pap) и те же настройки radiusclient работоспособны и при настройке демона протокола PPTP - pptpd (только он, кажется, уже немножко устарел ;)
Еще один необходимый для него файл /etc/pptpd.conf выглядит и вовсе примитивно:
option /etc/ppp/options.pptpd
localip 10.0.0.1
remoteip 10.0.0.2-254

понедельник, 27 апреля 2009 г.

Обзор команд работы с логическими томами в Linux


Ниже приводится краткая сводка команд по манипулированию логическими томами (Logical Volume) в Linux. Сразу неприятное предупреждение - при использовании логического тома в качестве корневого раздела, раздел /boot должен находиться на отдельном - не логическом (/dev/[hs]d?, /dev/md?) томе. Размер этого тома должен быть небольшим - даже для нескольких ядер вполне достаточно 32 Мб (инсталлятор CentOS зачем-то просит 75 Мб).
В дальнейших примерах предполагается ваяние группы логических томов - имя группы myvg - с именами root и swap. Имена используемых физических томов /dev/sda5, /dev/hdb1 и /dev/md0
Для использования в логических томах физические разделы должны быть проинициализированы:
# pvcreate /dev/sda5 /dev/hdb1 /dev/md0
посмотреть существующие физические тома можно командой:
# pvdisplay
Создадим группу (пока из двух физических томов):
# vgcreate myvg /dev/sda5 /dev/md0
Для использования группу нужно активизировать:
# vgchange -a y myvg
посмотреть существующие группы томов можно командой:
# vgdisplay
Добавить новый физический том можно командой:
# vgextend myvg /dev/hdb1
Удалить неиспользуемый том из группы можно командой:
# vgreduce myvg /dev/hdb1
Если в группе все тома используются, убрать данные с логического тома позволяет команда:
# pvmove /dev/hdb1
Предполаетася, что в группе томов достаточно свободного места для этой операции. Если места недостаточно, то команда должна иметь еще один аргумент - имя тома, куда мы переносим данные.
Если группа томов больше не должна жить, ее можно удалить:
# vgchange -a n myvg
# vgremove myvg
Теперь переходим к самому интересному - созданию разделов.
Создаем зеркалируемый том root размером 1 Gb и незеркалируемый том swap размером 512 Mb:
# lvcreate -n root -m 1 -L 1G myvg
# lvcreate -n swap -L 512M myvg
Создание файловой системы и монтирование осуществляется такими же командами, как для обычного раздела. Имена файлов логического тома: /dev/mapper/myvg-root или /dev/myvg/root
Просмотреть существующие логические тома можно командой:
# lvdisplay
Далее том можно изменять в размере. Вверх:
# lvextend -L +1G myvg/root
(аргумент -L может быть абсолютной величиной - или приращением)
Ежели надо увеличить на весь размер группы томов, тогда так:
# lvextend -l 100%VG myvg/root
И вниз:
# lvreduce -L 1.5G myvg/root
(во втором случае критичных данных на томе рекомендуется не иметь).
Чтобы получить реальную пользу от изменения размера томов нужно уметь менять размер файловых систем. Это делается командами:

Для ext3:

Вверх:
# umount /dev/myvg/root
# lvextend -L +1G myvg/root
# resize2fs /dev/myvg/root
# mount /dev/myvg/root

Вниз:
# umount /dev/myvg/root
# resize2fs /dev/myvg/root 2097152
# lvreduce -L -1G myvg/root
# mount /dev/myvg/root
последняя цифра второй команды - новый размер файловой системы в блоках

Для reiserfs:

Вверх:
# umount /dev/myvg/root
# lvextend -L +1G myvg/root
# resize_reiserfs /dev/myvg/root
# mount /dev/myvg/root

Вниз:
# umount /dev/myvg/root
# resize_reiserfs -s -1G /dev/myvg/root
# lvreduce -L -1G myvg/root
# mount /dev/myvg/root

Для xfs (только вверх):
# xfs_groufs /mnt
(да, прямо на примонтированной fs)

Для jfs:
# mount -o remount,resize /mnt
(тоже на примонтированной)

Если в группе томов есть свободное место, можно создать снимок тома:
# lvcreate -s -L 0.5G -n root_snap myvg/root
(размер может быть не равен размеру тома - очевидно, он должен быть равен объему данных на нем).
Со снимком можно делать все тоже самое, что с томом - только создавать на нем файловую систему едва ли надо...
Если хочется преобразовать обычный том в зеркалируемый, то это можно сделать, имея свободное место, равное размеру тома, на двух носителях (для размещения самого тома - и его копии). Сперва создаем физические тома, добавляем их в группу, а потом:
# lvconvert -m 1 vg1/root
В качестве дополнительных аргументов можно указать имена физических томов, на которых будет размещаться зеркало (если тут есть варианты).
Операция эта достаточно медленная. Зато потом можно высвободить исходный физический том (для тех, кто уже забыл - pvmove + vgreduce).
Ну, и совсем надоевший логический том можно и удалить:
# lvremove vg1/root_snap

Если что-то важное упустил, то можно почитать LVM HOWTO

P.S. т.к. тут упоминались устройства /dev/md?, для памяти приложу чуть-чуть о Software RAID в Linux.
Напр. создать RAID 5 уровня из 3 дисков и одного диска горячей замены:
# mdadm -C /dev/md0 -n 3 -x 1 -l 5 /dev/sdb1 /dev/sdc1 /dev/sdd1 /dev/sde1
Отключить один горячий диск - и подключить новый:
# mdadm /dev/md0 -r /dev/sde1 -a /dev/sdf1
Посмотреть статус RAID:
# mdadm -Q --detail /dev/md0
Здесь нужно добавить еще одно неприятное предупреждение - загрузка с Software RAID - вещь весьма проблематичная (напр. инсталятор CentOS соглашался только на загрузку с RAID1 - что в принципе объяснимо, т.к. в этом случае диски содержат копии друг друга - т.е. можно загрузиться с любого из них). Это лишний повод для выделения /boot в отдельный (не RAID) раздел.
Для того, чтобы Software RAID нормально завелся после загрузки, нужно создать файл /etc/mdadm.conf - в нашем примере - такого вот содержания:
DEVICE /dev/sd[bcde]1
ARRAY /dev/md0 level=5 spares=1 num-devices=3 devices=/dev/sdb1,/dev/sdc1,/dev/sdd1,/dev/sde1

четверг, 23 апреля 2009 г.

Стартовый скрипт для iptables в OpenSUSE 11.1

В OpenSUSE по умолчанию входит SUSEfirewall2 - фирменная настройка для iptables. О вкусах не спорят, но мне он как-то не подошел. Скрипта для запуска "просто" iptables в данном дистрибутиве нет. В принципе, задачу можно решить через Webmin - но это не наш путь. Итого - пишем сами скрипт /etc/init.d/iptables - такого, например, содержания:

#!/bin/bash

IPTAB_BIN=/usr/sbin/iptables
test -x $IPTAB_BIN || exit 5
. /etc/rc.status
rc_reset
case "$1" in
start)
echo -n "Starting iptables"
# сюда вставляем наши политики
$IPTAB_BIN -P INPUT DROP
$IPTAB_BIN -P OUTPUT ACCEPT
$IPTAB_BIN -P FORWARD DROP
# а сюда - правила
$IPTAB_BIN -A INPUT -i lo -j ACCEPT
$IPTAB_BIN -A INPUT -i eth0 -p tcp ! --syn -j ACCEPT
$IPTAB_BIN -A INPUT -i eth0 -p udp --sport 53 -j ACCEPT
$IPTAB_BIN -A INPUT -i eth0 -p tcp --dport 80 -j ACCEPT
rc_status -v
;;
stop)
echo -n "Shutting down iptables"
$IPTAB_BIN -F
$IPTAB_BIN -X
$IPTAB_BIN -Z
$IPTAB_BIN -P INPUT ACCEPT
$IPTAB_BIN -P OUTPUT ACCEPT
$IPTAB_BIN -P FORWARD ACCEPT
rc_status -v
;;
restart)
$0 stop
$0 start
rc_status
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
;;
esac
rc_exit


вторник, 24 марта 2009 г.

init.d скрипт для UTM5 на Linux


Скрипт для запуска-останова порта UTM5 (версия 5.2.1) на rpm-based Linux сложно назвать работоспособным - в нем отсутсвует крвйне нужная в хозяйстве команда restart, да и stop попросту не работает - приходится вручную искать процесс и убивать его с помощью kill -9
Скрипт был переписан заново и принял такой вид:

#!/bin/sh
# chkconfig: 2345 10 80
# description: UTM Billing System Core
trap '' 1 2 3 15

ulimit -c 0

pid_file=/var/run/utm5_core.pid
utm_exec=safe_utm5_core
err_log=/netup/utm5/log/utm5_core.log
exec_dir=/netup/utm5/bin

start() {
if [ -x $exec_dir/$utm_exec ]
then
echo "Starting utm5_core"
$exec_dir/$utm_exec start &
else
echo $exec_dir/$utm_exec no such file
fi
}

stop() {
echo "Stopping utm5_core"
pid=`ps ax -o pid,command |\
awk '{if ($2 ~ /sh$/ && $3 ~ /safe_utm5_core$/) {print $1}}'`
if [ -n "$pid" ]
then
kill -9 $pid
sleep 5
fi
pid=`ps ax -o pid,command |\
awk '{if ($2 ~ /utm5_core$/) {print $1}}'`
if [ -n "$pid" ]
then
kill -9 $pid
fi
}

case "$1" in
restart)
stop
start
;;
start)
start
;;
stop)
stop
;;
*)
echo "Usage: `basename $0` {start|stop|restart}" >&2
exit 64
;;
esac


Задача соответствия стандартам на init.d скрипты не ставилась - было не до эстетизма.
Тестировался на Mandriva 2009.0 и CentOS 5.2

пятница, 13 февраля 2009 г.

Перенос дампа большой базы с MySQL на PostgreSQL


Перенести большую базу (размер дампа около 10 Гб) с MySQL на PostgreSQL просто удалением несовместимостей в дампе, созданном mysqldump, и накатыванием его на psql не получается - процесс заливки дампа занимает несколько суток. Далее приводится пошаговое руководство по сокращению этого времени до пары часов.
  1. создаем дамп без данных (mysqldump -d --skip-opt --compatible=postgresql);
  2. накатывам этот дамп на psql;
  3. дампим полученнную базу - и делим полученный файл дампа на две части - в первой - только операторы CREATE TABLE, а ALTER TABLE ... ADD CONSTRAINT и CREATE INDEX - во второй. В файле дампа они расположены строго последовательно. Смысл этой операции в том, чтобы заливать данные в базу без индексов, а только потом создать индексы - так получится в разы быстрее;
  4. создаем базу заново - и накатываем на нее схему без индексов;
  5. для дампа данных придется писать скрипт. Смысл его такой: выбираем все поля table_name в таблице information_schema.tables, где table_schema равна имени нашей переносящейся базы - и для каждой из этих таблиц запускам select * into outfile;
  6. заливаем эти файлы в psql с помощью оператора copy from;
  7. накатываем вторую часть схемы - индексы - и наша база перенесена.

понедельник, 2 февраля 2009 г.

строим netflow-proxy



Задача: принимать поток netflow и передавать дальше только пакеты, соответствующие определенным условиям. Возможно решение с помощью пакета nfdump
Нам интересны три утилиты из этого пакета. Первая и главная - nfcapd - демон который будет принимать netflow-поток и сохранять его в файлы.
Важные аргументы:
  • -l dirname - директория, где будем эти файлы хранить
  • -t - интервал ротации файлов в секундах (по умолчанию - 600)
  • -x команда (в кавычках), запускаемая после ротации каждого файла. Допустимы символы расширения. Практически важен %f - имя новосозданого файла.
  • -R host/port - адрес для пересылки сдублированного потока - сама по себе интересная возможность, но нам нужна более сложная конфигурация - и мы будем возиться с предыдущей опцией. Для ее полезного использования нам нужны еще две команды из пакета:
nfdump - очень похожа на всем знакомую tcpdump (только выражения фильтра нужно брать в кавычки). Необходимые аргументы:
  • -r - файл, из которого читаем (т.е. созданный nfcapd)
  • -w - файл, куда пишем netflow (- означает stdout). Если аргумент пропущен, получаем на выходе не netflow, а человеко-читаемый вывод. Полезно для тестирования.
  • -f filename - имя файла, содержащего выражение фильтра (может быть разбито на несколько строк)
И - последний штрих - команда nfreplay - посылает netflow из файла снова в сеть. Важные аргументы:
  • -H - адрес, куда будем слать netflow
  • -r filename - файл, содержащий пакеты для посылки (по умолчанию - stdin)
  • -v [59] - версия netflow
Теперь собираем все в кучу. Вызывам nfcapd с опицией -x '/path/to/myscript %f', а в этот скрипт помещаем что-то вроде:
nfdump -r $1 'src net my.ney.wo.rk/24' -w - | nfreplay -H my.nf.col.lector
rm $1

Перед тем, как подать на систему нагрузку, тестовые пакеты netflow можно создать с помощью ipcad

среда, 21 января 2009 г.

Ручная доработка CentOS 5.2 под дисковый контроллер Fibrochannel QLogic


Собственно проблемы большой нет - CentOS 5.2 из коробки успешно загружается на Blade-сервере IBM с контроллером QLogic QMI2472 - беда в том, что длится загрузка на этом железе примерно 13 (!) минут. Больше половины этого времени занимает device-mapper, вызываемый из /etc/rc.sysinit, - он что-то пытается сделать с дисками массива, недоступными данному хосту. Никаких правильных путей его загасить я не нашел - потому грубо правил сам файл - строку:
if [ -c /dev/mapper/control ]; then
заменил на:
if [ 0 = 1 -a -c /dev/mapper/control ]; then
(или у кого какие еще варинты заведомо невыполнимого условия?) - после этого загрузка явно пошустрела.
Еще одна не очень приятная особенность CentOS - она монтирует файловые системы не по имени устройства, а по LABEL (причем, LABEL - это просто точка монтирования - /, /var и т. д.) Если у нас на контроллере есть диски для нескольких хостов - то как быть? Быть так. Метку правим такой командой:
# tune2fs -L MY-UNIQUE-LABEL /dev/sd??
и потом исправляем метку со стандартной на нашу в файлах /etc/fstab (первый столбец) и /boot/grub/menu.lst (строка kernel аргумент root=LABEL=MY-UNIQUE-LABEL).

вторник, 13 января 2009 г.

Борьба с дублированием писем в Postfix/ClamSMTPD

Проблема обнаружилась такая: на postfix есть clamsmtpd и virtual_aliases_map, в которой есть запись вида:
ivanov@mydomain.ru: ivanov@mydomain.ru, petrov@mydomain.ru
(т.е. почта Иванова посылается ему - и еще Петрову), так вот, в такой конфигурации Иванов получает все нормально, а Петров - в трех экземплярах. Методом чтения инета - и научного тыка - найдено следующее решение:
в main.cf добавляем строку:
receive_override_options = no_address_mappings
в master.cf в этих двух строках добавляем выделенные красным опции:
smtp inet n - n - - smtpd -o content_filter=dummy
-o receive_override_options=


127.0.0.1:10026 inet n - n - - smtpd

-o content_filter=
-o receive_override_options=no_unknown_recipient_checks, no_header_body_checks, no_address_mappings
-o smtpd_helo_restrictions=
-o smtpd_sender_restrictions=
-o smtpd_recipient_restrictions=permit_mynetworks,reject
-o mynetworks_style=host
-o smtpd_authorized_xforward_hosts=127.0.0.0/8
(пробелы между добавлены в строку receive_override_options, чтобы поместилась в блоге - в нормальном файле этих пробелов нет; строки, продолжающие команду вызова (начинающиеся с ), должны предваряться символом табуляции).