среда, 15 августа 2012 г.

Заработавший rp_filter в CentOS 6.3

Продолжающиеся разборки со свежеустановленной CentOS 6.3 принесли новые неожиданные результаты. Примерная конфигурация такая:
Компьютер администратора имеет ip-адрес 10.1.1.101 в сети 10.1.1.0/24;
Сервер (как раз CentOS 6.3 x86_64) имеет интерфейс eth0 адресом 10.1.1.201 в той же сети и eth1 адресом 10.1.2.201 в сети 10.1.2.0/24.
Маршрутизация между этими сетями настроена, с роутера все три адреса успешно пингуются.
С компьютера администратора пингуется 10.1.1.201, но никак не пингуется 10.1.2.201.
В принципе такое поведение нельзя назвать неправильным - на интерфейсе eth1 оказывается пакет, который по всем правилам должен был прийти на eth0 - и ответа на него не посылается. Другое дело, что за прошлую жизнь админ так привык к неправильному поведению, что правильное ему кажется неудобным. Поиск по настройкам sysctl достаточно скоро находит виновного:
net.ipv4.conf.eth1.rp_filter = 1
Из документа http://linuxgazette.net/issue77/lechnyr.html как раз и явствует что:
The rp_filter can reject incoming packets if their source address doesn't match the network interface that they're arriving on, which helps to prevent IP spoofing.
Установка:
net.ipv4.conf.eth1.rp_filter = 0
приводит к тому, что желанный пинг появляется.
А напоследок - как всегда - самое смешное. В CentOS 5-ой ветки, на которых автор этих строк собственно и успел пристраститься к "неправильным" пингам, установки net.ipv4.conf.*.rp_filter по умолчанию - точно такие же, как и в 6.3. Только не вызывают они заявленного поведения. Одно из двух - либо давно объявленную фичу наконец-то заставили работать, либо где-то таится еще какая-то настройка, которая говорит системе, реагировать ей на rp_filter - или нет.

вторник, 14 августа 2012 г.

Неуловимый LANG в CentOS 6.3

При установке CentOS 6.3 с образа minimal меня удивили сообщения на русском языке (при установке был явно выбран английский). Переменная LANG действительно содержала ru_RU.UTF-8, но рекурсивный поиск в /etc и $HOME не давал ответа, каким образом подобное значение устанавливается - такой подстроки просто-напросто не было в файлах этих директорий. Проблема выглядела невероятной, пока не был произведен рекурсивный поиск слова LANG. Ответ нашелся в файле /etc/ssh/sshd_config:
AcceptEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE \\
 LC_MONETARY LC_MESSAGES
(Это одна строка - переноса в оригинальном файле нет)
Т.е. получается, что установки языка передавались на сервер с моего компьютера по ssh. Действительно, если убрать LANG из этой строки, то при следующем входе в систему языком сообщений делается английский.
Следует добавить, что аналогичные настройки имеются и в клиентском файле /etc/ssh/ssh_config:
SendEnv LANG LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE \\
LC_MONETARY LC_MESSAGES
Так что, вероятно, наиболее правильным решением проблемы является как раз изменение SendEnv на том компьютере, откуда производится вход по ssh - а то вдруг другие администраторы сервера захотят видеть русский интерфейс? Хотя - с другой стороны - а что им мешает явно установить LANG в своих профайлах?
Ну а самое смешное заключается в том, что данная строка имеется в /etc/ssh/sshd_config и в более ранних версиях CentOS (например, в 5.3) - но там она почему-то никак на язык консольных сообщений не влияет. 

четверг, 26 июля 2012 г.

HTTP basic авторизация из таблицы MySQL

Некая closed-source биллинговая система хранит логины и пароли для онлайн-плательщиков в таблице менеджеров, причем пароли зашифрованы с помощью MySQL-функции PASSWORD(). Если бы там был plaintext или банальный crypt, ничего бы не стоило периодически создавать из этой таблицы файл htpasswd - и не мучиться. А так придется водружать на апач mod_auth_mysql. Настройка его достаточно тривиальна. В httpd.conf (или в любой из conf-файлов, вкладываемых в него) добавляем такие строки:

LoadModule mysql_auth_module modules/mod_auth_mysql.so
<Directory /var/www/protected/dir/>

    AuthName "MySQL authenticated zone"
    AuthType Basic
    AuthMYSQLEnable on
    AuthMySQLHost my.db.ho.st
    AuthMySQLUser apache
    AuthMySQLPassword PaSsW0Rd
    AuthMySQLDB mybilldb
    AuthMySQLUserTable paysys
    AuthMySQLPwEncryption scrambled
    require valid-user

<Directory>

Наиболее интересна тут опция AuthMySQLPwEncryption - она задает метод шифрования паролей в базе. Значение scrambled как раз означает результат работы MySQL-функции PASSWORD() (причем поддерживаются как старый 16-символьный формат, так и новый 41-символьный). Еще возможные значения: none, crypt, md5, aes и sha1.
И последнее. mod_auth_mysql не поддерживает проверку логинов/паролей произвольным запросом к БД (как это разрешается, например, во freeradius) - нужно обязательно иметь таблицу с именем, указанным в AuthMySQLUserTable, содержащую поля user_name (AuthMySQLNameField по умолчанию) и user_password (AuthMySQLPasswordField по умолчанию). Можно указать еще условие WHERE в опции AuthMySQLUserCondition, но лично мне более гибким кажется путь создания в базе представления:

$ mysql -u root mybilldb -p


mysql> create view paysys as select login as user_name, pass as user_password from managers where payments > 0 and archive = 0 and template = 0;
mysql> grant select on mybilldb.paysys to 'apache'@'my.apache.ho.st' identified by 'PaSsW0Rd';

Полную справку по опциям mod_auth_mysql можно прочитать тут: http://modauthmysql.sourceforge.net/CONFIGURE

пятница, 4 мая 2012 г.

Обуздание неистового DHCP в Debian 6


Случаются ситуации, когда интрефейс, конфигурируемый по DHCP, не единственный в системе - и настройки маршрутизации и DNS, получаемые автоматически, не должны перезаписывать статических настроек с других интерфейсов. Ниже приводятся два способа, как можно побороться с этой проблемой в Debian 6:

Первый способ. Требует установки дополнительных пакетов.
Для того, чтобы маршрут по умолчанию не перезаписывал значение, сконфигурированное на другом интерфейсе, ставим пакет ifmetric - и в файле /etc/network/interfaces указываем для наших интерфейсов числовые значения metric. Чем значение ниже, тем выше приоритет маршрута через данный интерфейс.
Для того, чтобы DNS и доменное имя, полученные по DHCP, не перезаписывали насмерть файл /etc/resolv.conf, ставим пакет resolvconf - и в файле /etc/network/interfaces в разделе статического интерфейса добавляем строки:
  dns-nameservers A.A.A.A B.B.B.B
 dns-search mydom1.ru mydom2.ru

Второй способ. Правим файл /etc/dhcp/dhclient.conf
В нем есть длинная строчка, начинающаяся со слова request.
Удалив из нее слова: routers, domain-name, domain-name-servers, domain-search, host-name и rfc3442-classless-static-routes, мы как раз запретим запрос этих параметров по DHCP. Способ безусловно проще, но менее гибкий - в случае проблем со статическим интерфейсом мы остаемся вообще без DNS и без маршрута по умолчанию.

А если не лень чуть-чуть попрограммировать, можно изменять поведение DHCP-интерфейса с помощью скриптов, указываемых в соответствующем разделе /etc/network/interfaces в параметрах up и down. Например, нижеприводимый скрипт применяет маршрут, отдаваемый DHCP сервером как маршрут по умолчанию, только к определенному списку сетей:

#!/bin/sh
PATH=/bin:/sbin:/usr/bin:/usr/sbin
mynet="10.0.0.0/8 172.16.1.0/24"
case "$MODE" in
start)
gw=`ip route show dev $IFACE | 
  awk '{if ($1 == "default") {print $3; exit(0)}}'`
if [ -n "$gw" ]
then
ip route delete default dev $IFACE
for n in $mynet
do
ip route add $n via $gw dev $IFACE
done
fi
;;
stop)
for n in $mynet
do
ip route delete $n dev $IFACE
done
;;
esac

суббота, 28 апреля 2012 г.

Хост VirtualBox на сервере CentOS без GUI



Т.к. репозитории CentOS не содержат пакетов VirtualBox, то RPM для RHEL5 берется с https://www.virtualbox.org/wiki/Linux_Downloads - каких-то невероятных зависимостей он не требует, только для установки модулей ядра необходимо иметь kernel-devel.
Ниже описывается работа с виртуальными машинами с помощью CLI утилиты VBoxManage. Подробная справка по ее опциям (на английском) имеется здесь: https://www.virtualbox.org/manual/ch08.html
Смотрим допустимые типы машин:
$ VBoxManage list ostypes
Создаем и регистрируем машину для solaris:
$ VBoxManage createvm --name sol11 --ostype OpenSolaris_64 --register --basefolder $HOME/vbox-sol11/
(последняя опция необязательна, но мне кажется, лучше всегда явно задавать, где будут храниться наши машины).
Какие ресурсы выделены машине по умолчанию, можно увидеть командой:
$ VBoxManage list -l vms
Наверняка нам захочется что-нибудь поменять. Придаем машине 2 процессора, 1 Гб памяти, системные часы, идущие по Гринвичу, и вторую сетевую карту типа bridge (первая типа nat создается автоматически):
$ VBoxManage modifyvm sol11 --memory 1024 --cpus 2 --rtcuseutc on --nic2 bridged --bridgeadapter2 eth1
(последняя опция указывает сетевой интерфейс хост-машины, к которому прицепится виртуальный интерфейс).
Если машин много, лучше смотреть настройки конкретной машины командой:
$ VBoxManage showvminfo sol11
Дисковый контроллер (в нашем случае - SCSI) добавляется командой:
$ VBoxManage storagectl sol11 --name scsi0 --add scsi
Создаем жесткий диск на 10 Гб (тип образа по умолчанию - vdi):
$ VBoxManage createhd --filename $HOME/vbox-sol11/sd0 --size 10240
и прицепляем его на контроллер:
$ VBoxManage storageattach sol11 --storagectl scsi0 --medium $HOME/vbox-sol11/sd0.vdi --port 1 --type hdd
Потом прицепляем образ загрузочного CD-ROM:
$ VBoxManage storagectl sol11 --name ide0 --add ide
(IDE контроллер пришлось создать, потому что диск типа dvddrive почему-то отказался присоединяться к SCSI)
$ VBoxManage storageattach sol11 --storagectl ide0 --medium $HOME/tmp/oi-dev-151a-text-x86.iso --device 0 --port 0 --type dvddrive
На время инсталляции придадим машине RDP-консоль:
$ VBoxManage modifyvm sol11 --vrde on --vrdeport 3389 --vrdeaddress 10.10.10.10
(две последних опции необязательны)
Для того, чтобы работал VRDP возможно придется установить Extension Pack - скачивается он там же, откуда мы брали rpm, и ставится командой:
$ VBoxManage extpack install
Теперь машину можно запускать:
$ VBoxManage startvm sol11 --type headless
Остановка машины:
$ VBoxManage controlvm sol11 poweroff
(еще возможные действия: acpipowerbutton, acpisleepbutton, pause, reset, resume, savestate)
Отцепить ненужный более cdrom можно командой:
$ VBoxManage storageattach sol11 --storagectl ide0 --port 0 --device 0 --medium none
(вместо none можно сделать emptydrive - такая операция допустима на запущенной машине).
Если понадобится проброс ssh c NAT-интерфейса на порт хост-машины (в данном случае 127.0.0.1:2222), то он делается так:

$ VBoxManage modifyvm sol11 --natpf1 sshd,tcp,127.0.0.1,2222,,22

пятница, 9 сентября 2011 г.

Радиус-обманка для тестирования ISG


При тестировании одной биллинговой системы (какой - не скажу - не хочу рекламировать откровенно недоделанный продукт) долго не могли определить - кто виноват в запуске дублирующихся сессий ISG - биллинг или Cisco. Вот и возникла идея создать некую "дурилку" - радиус-сервер, отдающий фиксированные ответы, выглядящие с точки зрения ISG как правильные. Создавалось это чудовище за полчаса из свежеустановленного freeradius-1.1.3 (платформа - CentOS 5.6).
Для начала добавляем нашу циску и локалхост (для упрощения тестирования) в /etc/raddb/clients.conf:



client 10.1.60.4 {
secret = mysecr
shortname = tstnas
nastype = cisco
}
client 127.0.0.1 {
        secret = mysecr
        shortname = localhost
        nastype = other
}

А сами ответы помещаем в /etc/raddb/users:

# сперва - пользователи
usr1145 Password == "d038bec6", Service-Type == Framed-User
        Session-Timeout = 86400,
        Framed-Protocol = PPP,
        Framed-IP-Address = 10.1.70.101,
        Framed-IP-Netmask = 255.255.255.255,
        Acct-Interim-Interval = 300,
        Cisco-AVPair = "accounting-list=BILL",
        Filter-Id = "Consum.out",
        Cisco-Account-Info = "ALOCAL",
        Cisco-Account-Info += "NLOCAL",
        Cisco-Account-Info += "AWORLDIN",
        Cisco-Account-Info += "NWORLDIN",
        Cisco-Account-Info += "AWORLDOUT",
        Cisco-Account-Info += "NWORLDOUT"


usr1146 Password == "f577acec", Service-Type == Framed-User
        Session-Timeout = 86400,
        Framed-Protocol = PPP,
        Framed-IP-Address = 10.1.70.102,
        Framed-IP-Netmask = 255.255.255.255,
        Acct-Interim-Interval = 300,
        Cisco-AVPair = "accounting-list=BILL",
        Filter-Id = "Consum.out",
        Cisco-Account-Info = "ALOCAL",
        Cisco-Account-Info += "NLOCAL",
        Cisco-Account-Info += "AWORLDIN",
        Cisco-Account-Info += "NWORLDIN",
        Cisco-Account-Info += "AWORLDOUT",
        Cisco-Account-Info += "NWORLDOUT"  


# потом - реавторизация препейд-сервиса
usr1145 Password == "cisco", Service-Type == Framed-User, Cisco-Service-Info == "NWORLDIN"
        Cisco-Control-Info = "QV1234567895",
        Idle-Timeout = 90


usr1146 Password == "cisco", Service-Type == Framed-User, Cisco-Service-Info == "NWORLDIN"
        Cisco-Control-Info = "QV1234567896",
        Idle-Timeout = 90


# и наконец - сами сервисы
WORLDIN Password == "cisco", Service-Type == Dialout-Framed-User
        Cisco-AVPair = "ip:traffic-class=output access-group name world-out priority 40",
        Cisco-AVPair += "ip:traffic-class=in default drop",
        Cisco-AVPair += "ip:traffic-class=out default drop",
        Cisco-Service-Info = "IALL-INET-IN",
        Cisco-Service-Info += "MC",
        Cisco-Service-Info += "TP",
        Cisco-AVPair += "prepaid-config=BILL",
        Acct-Interim-Interval = 300


WORLDOUT Password == "cisco", Service-Type == Dialout-Framed-User
        Cisco-AVPair = "ip:traffic-class=input access-group name world-in priority 30",
        Cisco-AVPair += "accounting-list=BILL",
        Cisco-AVPair += "ip:traffic-class=in default drop",
        Cisco-AVPair += "ip:traffic-class=out default drop",
        Cisco-Service-Info = "IALL-INET-OUT",
        Cisco-Service-Info += "MC",
        Cisco-Service-Info += "TP",
        Acct-Interim-Interval = 1800


LOCAL   Password == "cisco", Service-Type == Dialout-Framed-User
        Cisco-AVPair = "ip:traffic-class=input access-group name local-in priority 20",
        Cisco-AVPair += "ip:traffic-class=output access-group name local-out priority 20",
        Cisco-AVPair += "accounting-list=BILL",
        Cisco-AVPair += "ip:traffic-class=in default drop",
        Cisco-AVPair += "ip:traffic-class=out default drop",
        Cisco-Service-Info = "ILOCAL-NET",
        Cisco-Service-Info += "MC",
        Cisco-Service-Info += "TP",
        Acct-Interim-Interval = 1800

И теперь можно, запустив на нашем импровизированном радиус-сервере:
cos56# tcpdump -i eth0 -n -vvvv -s 1204 port 1812 or port 1813
или на циске:
c7200# terminal monitor
c7200# debug radius auth
c7200# debug radius acc
(а еще лучше - для полноты картины - и то, и другое) наблюдать за поднимающимися сессиями. Думаю, тот, кто дочитал до этого места, не нуждается в рассказе о том, как запускать pppd (8).

вторник, 26 апреля 2011 г.

Нелегкая борьба с multipath


Имеется - блейд-сервер IBM HS22, единственным диском для которого является том на хранилище EMC CLARIION. Задача: настроить multipath-доступ к этому тому (по умолчанию, имея два оптических свича и два порта на каждом, мы видим этот том в виде 4 дисков /dev/sd[a-d]).
В CentOS 5.5 вроде имеется паспортное средство установки системы с multipath - надо при инсталяции ввести командную строку ядра linux mpath - но этот путь, мягко выражаясь, не совсем работает - т.е. система прекрасно устанавливается  на устройство /dev/mapper/mpath0, но грузиться с него отказывается - не может найти корневой раздел. 
В debian 6.0 дела чуть лучше - действуем так:
  1.  ставим систему, как обычно (я ставил на /dev/sda, но, вероятно, можно с тем же успехом ставить на любой другой диск).
  2. добавляем пакеты для multipath и пересобираем initrd:
    # apt-get install multipath-tools-boot multipath-tools firmware-qlogic
    # update-initramfs -u
  3. перегружаемся - и ищем имя multipath-устройств:
    $ ls /dev/mapper
    3600601600a02a004b0085add64e011
    3600601600a02a004b0085add64e011-part1
    3600601600a02a004b0085add64e011-part2
    control
    Имена, заканчивающиеся на part[12] и есть наши разделы. Прописываем их в /etc/fstab и в  /boot/grub/grub.cfg (там, где root=UUID=...) - вероятно, для второго действия есть более элегантный способ, но я плохо разбирась в grub2.

    После этого перегружаемся - и все должно работать. Состояние дискового массива можно посмотреть командой (и попроверять работоспособность, по очереди отключая питание на оптических свичах):

    # multipath -ll
     
 В итоге - мораль - если нужен беспроблемный мультипас из коробки, лучше ставить Vmware ESXI - тоже своего рода линукс...