воскресенье, 10 декабря 2017 г.

Как "привязать" исходящий трафик некоторого приложения к определенному source IP

Часто сказки народов севера начинаются со слова "как". Название статьи тоже начинается со слова "как" - сейчас поясню, что это название под собой подразумевает.
Краткое описание задачи - есть прокси сервер (haproxy), на котором работают несколько публикаций, каждая на своем IP адресе. Необходимо проверить работоспособность TLS бэкенда одной из публикации. Казалось бы все просто:

$ openssl s_client -connect backend_ip:port -showcerts

ОС попытается открыть соединение с основного IP сервера, но в нашем случае нужно соединение открыть с IP публикации. Для telnet есть возможность указать адрес, с которого нужно установить соединение:

$ telnet -b server_ip backend_ip port

А для openssl - нет. Можно выкрутиться с помощью iptables - сделать банальный source NAT. Чтобы ненароком не затронуть остальные коннекты и, как следствие, не усложнять правило условиями - добавим ограничение по UID пользователя:

# iptables -t nat -A POSTROUTING -m owner --uid-owner user_id -j SNAT --to-source server_ip


Как видите, можно легко привязать к определенному IP bash скрипт или сделать обертку для запуска ПО, которое лишено возможности выбора source IP.

суббота, 21 октября 2017 г.

Медленная синхронизация времени.

Ситуация была следующая: старый сервер на Suse 11, время ушло на несколько минут вперед. Поправить время скачком совсем не вариант, т.к. на нем финансовое приложение, и что может получиться - одному богу известно. Быстрое гугление не дало результатов, пришлось читать маны. Засим выкладываю свой рецепт.

Ntpd нужно потушить и запустить руками:

ntpd -g -x -d

 Где:
-g - стандартно ntpd не будет синхронизировать время, если есть большая разница времени между сервером и клиентом, по умолчанию это разница установлена в 1000с. Данная опция убирает это ограничение.
-x - ntpd подгоняет плавно время, если смещение меньше порогового значения (по умолчанию 128мс), если больше - выставляет скачком. Данная опция заставляет ntpd подгонять плавно время во всех случаях.
-d - режим отладки, просто больше выводится информации в консоль.

Время синхронизации зависит от значений minpoll\maxpoll - интервал опроса. При стандартном minpoll 6 (секунды, количество составляет степень 2, т.е. 64с) подстройка времени занимает 2000 секунд на каждую секунду смещения.

понедельник, 25 апреля 2016 г.

Как осуществить балансировку исходящей почты.

Балансировка исходящей почты может пригодиться, когда в качестве следующего получателя (next-hop) письма есть несколько серверов. Для одного домена можно указать несколько MX записей и/или несколько IP адресов (Round robin DNS). Этот вариант широко распространен для публичного интернета. Однако, этот вариант не подходит, если вы не имеете возможность менять DNS зону. Или к примеру, для почтового сервера используемого внутри LAN: пересылка всех писем может осуществляется на next-hop, который указан в (или для определенных случаев в таблице transport). Уточню, в postfix в директиве relayhost нельзя указать перечень серверов. Усложним задачу: необходимо определять доступность next-hop серверов. Сделать требуемое позволит haproxy. Его можно развернуть на этом же почтовом сервере. Haproxy будет слушать на loopback'е, перенаправляя входящий трафик на сервера next-hop. Помимо пересылки трафика он так же будет мониторить доступность серверов. Пример конфигурации haproxy:

# cat /etc/haproxy/haproxy.cfg
global
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon

# turn on stats unix socket
stats socket /var/lib/haproxy/stats

defaults
log global
option tcplog
option log-health-checks
option dontlognull
option redispatch
retries 3
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout check 10s
maxconn 3000

listen stats gwip:5111
mode http
stats enable
stats hide-version
stats auth admin:password
stats uri /admin?stats
stats show-desc server.domain.com

listen base_relay 127.0.0.1:5222
mode tcp
balance roundrobin
option smtpchk HELO server.domain.com
server nexthop1 ip1:25 check inter 5000 fall 3 rise 3
server nexthop2 ip2:25 check inter 5000 fall 3 rise 3
server nexthop3 ip3:25 check inter 5000 fall 3 rise 3
server nexthop4 ip4:25 check inter 5000 fall 3 rise 3

Кратко по листингу:
  • listen stats gwip:5111 — блок описания графического интерфейса статистики и управления haproxy, gwip должен быть ip сервера. Не забудьте поменять пароль!
  • listen base_relay 127.0.0.1:5222 — блок описания балансировки исходящей почты.
    • balance roundrobin — политика балансировки соединений, название говорит само за себя.
    • option smtpchk HELO server.domain.com — проверка доступности серверов next-hop на седьмом уровне модели OSI, укажите свое имя сервера.
    • server nexthop1 ip1:25 check inter 5000 fall 3 rise 3 — информация по next-hop серверу, его имя — nexthop1, ip — ip1, и параметры проверки:
      • inter - временной интервал проверки, 5000 мс.
      • fall - количество неудачных попыток подряд, после чего сервер исключается из списка балансировки соединений.
      • rise - количество удачных попыток подряд, после чего сервер возвращается в список.

Теперь осталось только поменять в конфигурации postfix адрес в директиве relayhost на 127.0.0.1:5222. Данная статья хорошо сочетается с этой публикацией. Могу добавить, что в моем случае количество проходящих писем составляет более миллиона в сутки.

воскресенье, 22 ноября 2015 г.

Имя сетевого устройства

Старое название интерфейсов, такое как к примеру eth0, кануло в лету (ну почти, иногда старые имена можно встретить). В RHEL7 используются следующие варианты схем наименования сетевого интерфейса, в порядке применения:
  1. Имя, предоставляемое аппаратным обеспечением (Firmware или BIOS), включающее порядковый номер, для устройств, расположенных на материнской плате, к примеру eno1. Если выбор имени не произведен, используется схема 2.
  2. Имя, предоставляемое аппаратным обеспечением (Firmware или BIOS), включающее порядковый номер слота PCI Express, к примеру ens1. Если выбор не произведен, используется схема 3.
  3. Имя формируется из физического положения точки подключения устройства, к примеру enp2s0. Иначе используется схема 5.
  4. Имя включает MAC устройства, к примеру enx94de80a44f0c. Эта схема по умолчанию не используется.
  5. Старая схема, где имя присваивается ядром в порядке обнаружения интерфейса, к примеру eth0 и т.д.
Это поведение по умолчанию.

Новые имена сами по себе содержат полезную информацию. Принятое соглашение о наименовании следующее: первые два символа отражают тип интерфейса:
  1. en — Ethernet.
  2. wl — беспроводная локальная сеть, WLAN.
  3. ww — беспроводная глобальная сеть, WWAN.
Далее следует тип, отражающий схему наименования, описанную выше:
  1. o<index> индекс для устройств расположенных на материнской плате.
  2. s<slot>[f<function>][d<dev_id>] сначала идет номер PCI Express слота, далее f<function> - номер функции у многофункционального PCI устройства (я не встречал таких плат) и последним идет идентификатор устройства.
  3. p<bus>s<slot>[f<function>][d<dev_id>] расположение устройства на PCI шине. Домен PCI (p<bus>) указывается только если он отличен от нулевого (это можно увидеть в больших системах). Номер функции и номер устройства аналогично предыдущему примеру.
  4. p<bus>s<slot>[f<function>][u<port>][..][c<config>][i<interface>] расположение устройства на USB шине, причем учитывается вся цепочка портов.
  5. x<MAC> MAC адрес.
Нужно отметить, что имя не может быть более 15 символов, это ограничение ядра.

В случае использования VLAN добавляется следующее соглашение о имени интерфейса:
  1. vlan<vlanid> — имя с полным номером vlanid, к примеру vlan0012 или имя с сокращенным vlanid — vlan12
  2. device_name.<vlanid> - имя интерфейса и VLAN ID в полном или сокращенном виде, к примеру ens3.0012 или ens3.12
Как бы глупо это не звучало, но помимо описанных соглашений о наименовании, есть еще одно, используемое при помощи утилиты udev — biosdevname (насколько я понял, возникло это соглашение по инициативе DELL и используется на их серверах). Оно имеет силу только при наличии установленного пакета biosdevname и при указании biosdevname=1 при загрузке системы. Переименования будут производится только для встроенных интерфейсов. При этом:
  1. Встроенные интерфейсы будут иметь имя типа em[123...]
  2. Интерфейсы, подключенные по шине PCI — p<slot>p<ethernet port>, к примеру p3p4
Чтобы окончательно не запутаться в теоретической части, рассмотрим более глубоко процесс присваивания имени интерфейсу по шагам. Ниже пример того что происходит, когда в системе появляется новый интерфейс:

# udevadm monitor
...
KERNEL[27783.869667] add /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7.4/1-7.4:1.0/net/eth0 (net)
...
KERNEL[27783.879674] move /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7.4/1-7.4:1.0/net/enp0s20u7u4 (net)
UDEV [27783.892038] add /devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7.4/1-7.4:1.0/net/enp0s20u7u4 (net)
...

Т.е. сначала интерфейс появился со старым, знакомым именем eth0, а далее стал enp0s20u7u4. Нетрудно заметить, что новое имя сразу отображает что это адаптер Ethernet (en), подключенный к USB шине через usb хаб (в имени два usb порта u7u4). Достаточно удобно.

Посмотрим, что выполняет udev над интерфейсом:

  • Шаг первый:
# udevadm test /sys/devices/pci0000:00/0000:00:14.0/usb1/1-7/1-7.4/1-7.4:1.0/net/enp0s20u7u4
...
PROGRAM '/lib/udev/rename_device' /usr/lib/udev/rules.d/60-net.rules:1
starting '/lib/udev/rename_device'

Что происходит: правило udev /usr/lib/udev/rules.d/60-net.rules при помощи /lib/udev/rename_device, просматривает конфигурационные файлы сетевых интерфейсов - /etc/sysconfig/network-scripts/ifcfg-*, и если есть соответствие MAC адреса добавляемого интерфейса и адреса в директиве HWADDR, то имя интерфейса устанавливается в соответствии с директивой DEVICE.
Сейчас воспользуемся небольшой хитростью, чтобы процесс применения правил udev был более наглядным. Создадим конфигурационный файл ifcfg-tstif0 с именем tstif0 для нашего адаптера и вставим адаптер. Интерфейс в системе станет tstif0. Теперь удалим конфигурационный файл, и посмотрим на обработку правил еще раз, но уже для интерфейса tstif0, в конечном итоге мы должны будем получить имя enp0s20u7u4.
Запустим еще раз, первое правило не отработает, т.к. конфигурационный файл мы удалили:

PROGRAM '/lib/udev/rename_device' /usr/lib/udev/rules.d/60-net.rules:1
starting '/lib/udev/rename_device'
'/lib/udev/rename_device' [5023] exit with return code 0

  • Шаг второй, смотрим дальше:
PROGRAM '/sbin/biosdevname --policy physical -i tstif0' /usr/lib/udev/rules.d/71-biosdevname.rules:22
starting '/sbin/biosdevname --policy physical -i tstif0'
'/sbin/biosdevname --policy physical -i tstif0' [5024] exit with return code 2

Правило /usr/lib/udev/rules.d/71-biosdevname.rules реализует выше рассмотренное соглашение о именах при использовании biosdevname. Уточнение, это правило работает, если в системе установлен biosdevname, при загрузке не был использован параметр biosdevname=0, и если имя не было назначено на предыдущем шаге.

  • Шаг третий:
IMPORT builtin 'net_id' /usr/lib/udev/rules.d/75-net-description.rules:6
IMPORT builtin skip 'usb_id' /usr/lib/udev/rules.d/75-net-description.rules:8
IMPORT builtin 'hwdb' /usr/lib/udev/rules.d/75-net-description.rules:8

На этом этапе правилом /usr/lib/udev/rules.d/75-net-description.rules, заполняются следующие директивы описания устройства: ID_NET_NAME_ONBOARD, ID_NET_NAME_SLOT, ID_NET_NAME_PATH и ID_NET_NAME_MAC. Не все директивы могут быть заполнены, поскольку не все устройства могут иметь требуемую информацию.

  • Шаг четвертый:
IMPORT builtin 'path_id' /usr/lib/udev/rules.d/80-net-setup-link.rules:5
IMPORT builtin 'net_setup_link' /usr/lib/udev/rules.d/80-net-setup-link.rules:9
Config file /usr/lib/systemd/network/99-default.link applies to device tstif0
NAME 'enp0s20u7u4' /usr/lib/udev/rules.d/80-net-setup-link.rules:11

Вот оно правило, которое устанавливает имя для интерфейса в данном случае - /usr/lib/udev/rules.d/80-net-setup-link.rules. Что по этому правило происходит: если интерфейс не был переименован на предыдущих шагах, и если не задан параметр ядра net.ifnames=0, то имя интерфейса устанавливается в соответствии с порядком по приоритету из полученных ранее директив: ID_NET_NAME_ONBOARD, ID_NET_NAME_SLOT, ID_NET_NAME_PATH. Если ни одна из директив не определена, то интерфейс остается не переименованным, т.е. старый вариант именования — eth0.
Для понимания, посмотреть возможные имена можно так:

# udevadm info /sys/class/net/tstif0 | grep ID_NET_NAME
E: ID_NET_NAME=enp0s20u7u4
E: ID_NET_NAME_MAC=enx00101402bca7
E: ID_NET_NAME_PATH=enp0s20u7u4

Можно заметить, что почти все пункты (за исключением 5 — старого именования) из стандартного соглашения о наименовании реализуются в правилах udev: 75-net-description.rules и 80-net-setup-link.rules. Можно возразить, а где наименование по MAC адресам? Включение его можно произвести правкой правила 80-net-setup-link.rules. Скопируйте его:

# cp /usr/lib/udev/rules.d/80-net-name-slot.rules /etc/udev/rules.d

И добавьте строку выделенную курсивом на листинге:

# grep -v "^#\|^$" /etc/udev/rules.d/80-net-name-slot.rules
ACTION!="add", GOTO="net_name_slot_end"
SUBSYSTEM!="net", GOTO="net_name_slot_end"
NAME!="", GOTO="net_name_slot_end"
IMPORT{cmdline}="net.ifnames"
ENV{net.ifnames}=="0", GOTO="net_name_slot_end"
NAME=="", ENV{ID_NET_NAME_MAC}!="", NAME="$env{ID_NET_NAME_MAC}"
NAME=="", ENV{ID_NET_NAME_ONBOARD}!="", NAME="$env{ID_NET_NAME_ONBOARD}"
NAME=="", ENV{ID_NET_NAME_SLOT}!="", NAME="$env{ID_NET_NAME_SLOT}"
NAME=="", ENV{ID_NET_NAME_PATH}!="", NAME="$env{ID_NET_NAME_PATH}"
LABEL="net_name_slot_end"

Не уверен, что данный вариант именования удобен.

Итак, мы обсудили несколько соглашений о наименовании сетевых интерфейсов, рассмотрели по шагам, как происходит выбор имени, попутно узнали, что net.ifnames=0 отключает новую схему наименования, и последнее замечание: не используйте имена из пространства ядра - ethX в схеме с присвоением имен через файлы ifcfg-*.



воскресенье, 15 ноября 2015 г.

Перезагрузка сервера без нервов

Последнее поколение серверов с большим количеством аппаратных ресурсов, тратят много времени на проверку оборудования при старте системы. Порой это может занять 20 минут и более. Для систем, где окно техобслуживания составляет не больше часа, обновление ОС может быть очень затруднено. Выйти из положения позволяет kexec. Kexec - это системный вызов, который загружает в память новое ядро и производит загрузку ОС с этим ядром. Фактически, kexec выполняет функцию загрузчика ОС. Естественно данный процесс загрузки отличается от нормального тем, что не производится инициализация оборудования на аппаратном уровне (UEFI), за счет этого и достигается выигрыш времени.
Синтаксис команды для загрузки нового ядра:

kexec -l kernel-image --append=command-line-options --initrd=initrd-image

где:

  • -l - путь к новому ядру
  • --append - параметры, используемые при загрузке, можно использовать текущие параметры, содержащиеся в /proc/cmdline, для этого вместо этого параметра укажите --reuse-cmdline
  • --initrd - путь к initrd/initramfs образу.

После чего необходимо дать команду на запуск нового ядра:

kexec -e

Пример:

# kexec -l /boot/vmlinuz-3.10.0-229.20.1.el7.x86_64 --reuse-cmdline --initrd=/boot/initramfs-3.10.0-229.20.1.el7.x86_64.img
# kexec -e

четверг, 5 ноября 2015 г.

Имя хоста

Имена бывают трех типов:

  • статическое (static) — то, которое задает пользователь, хранится в /etc/hostname;
  • временное (transient) — имя,  полученное посредством DHCP или mDNS, если статическое имя установлено и оно отлично от localhost, то будет использоваться статическое имя;
  • прелестное (pretty) — имя, которое можно использовать для описания хоста, к примеру «Super duper server», хранится в /etc/machine-info. Может быть полезно, когда имена машин однотипны. Больше всего умиляет, что названия как в физике, типа «прелестный кварк».

Статическое и временное имена должны состоять из символов: a-z, A-Z, 0-9, дефиса, подчеркивания и точки, длина не должна превышать 64 символа.
Посмотреть текущие имена можно следующим образом:

$ hostnamectl status

Установить все имена сразу можно командой:

# hostnamectl set-hostname имя

Если нужно изменить определенное имя, то нужно добавить --pretty, --static или --transient, к примеру:

# hostnamectl set-hostname "Super duper server" --pretty

Заметки о RHEL7



Друзья/коллеги/читатели, пишу ряд статей об использовании RHEL7. Я сознательно не рассматриваю абсолютно все возможные пути конфигурирования или выполнения базовых операций. К примеру, в статьях точно не будут рассмотрены варианты конфигурирования с помощью графической оболочки NetworkManager. Источники данных, в большинстве своем, официальные документы с сайта вендора.
Ниже будут ссылки на статьи для удобства.

Имя хоста
Имя сетевого устройства