Friday, October 26, 2007

Встроенные функции gcc для атомарных операций

В gcc 4.1.0 появились специальные встроенные функции, предназначенные для выполнения атомарных операций. Более подробно о них написано тут.
Например, следующий код берет адрес позиции указателя в определенном массиве и инкрементирует указатель (после операции он указывает на следующий элемент в массиве):
 cur_pos = __sync_fetch_and_add (&pos, sizeof(u_char));

В gcc3 этих функций нет.

Wednesday, October 24, 2007

Определение порядка прохождения пакетов по различным пакетным фильтрам в FreeBSD

Порядок загрузки модулей, осуществляющих фильтрацию пакетов, определяет, в каком порядке будут проходить пакеты через них (это определяется тем, когда модуль зарегистрировал хук у pfil'a).
Как происходит передача пакета хуку pfil'om:
for (pfh = pfil_hook_get(dir, ph);
        pfh != NULL;
        pfh = TAILQ_NEXT(pfh, pfil_link)) {
            if (pfh->pfil_func != NULL) {
                rv = (*pfh->pfil_func)(pfh->pfil_arg, &m, ifp, dir, inp);
                if (rv != 0 || m == NULL)
                       break;
            }  
}
То есть, перебираются все хуки, начиная с TAILQ_FIRST и им передается пакет в качестве параметра.
Если пакет дропается, то дальше по цепочке он не передается (это надо помнить при записи данных о дропнутых пакетах в лог).
Регистрируются хуки таким образом:
    /*
     * insert the input list in reverse order of the output list
     * so that the same path is followed in or out of the kernel.
     */
    if (flags & PFIL_IN)
        TAILQ_INSERT_HEAD(list, pfh1, pfil_link);
    else
        TAILQ_INSERT_TAIL(list, pfh1, pfil_link);
То есть, для входящего трафика модуль, добавивший свой хук последним, будет обрабатывать пакеты первым, и наоборот - для исходящего модуль, добавивший свой хук первым будет обрабатывать пакеты первым.
Теперь надо определиться с порядком загрузки модулей в ядро:
модули при загрузке присоединяются к определенным подсистемам в ядре: эти подсистемы описаны в файле sys/kernel.h:
нас интересуют
    SI_SUB_PROTO_IF     = 0x8400000,    /* interfaces*/
    SI_SUB_PROTO_DOMAIN = 0x8800000,    /* domains (address families?)*/
    SI_SUB_PROTO_IFATTACHDOMAIN = 0x8800001,    /* domain dependent data init*/
Системы загружаются по очереди, то есть, чем меньше номер, тем раньше загрузится подсистема и тем раньше к ней присоединится модуль. Сам модуль может присоединиться к подсистеме, указывая ряд различных позиций (согласно аргументу order в функции DECLARE_MODULE):
enum sysinit_elem_order {
    SI_ORDER_FIRST      = 0x0000000,    /* first*/
    SI_ORDER_SECOND     = 0x0000001,    /* second*/
    SI_ORDER_THIRD      = 0x0000002,    /* third*/
    SI_ORDER_MIDDLE     = 0x1000000,    /* somewhere in the middle */
    SI_ORDER_ANY        = 0xfffffff /* last*/
};
Таким образом, смотрим на подсистему и порядок подключения к подсистеме у каждого интересующего модуля:
pf:
DECLARE_MODULE(pf, pf_mod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_FIRST);
ipfw:
DECLARE_MODULE(ipfw, ipfwmod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY);
ipfilter:
DECLARE_MODULE(ipfilter, ipfiltermod, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY);

Согласно порядку загрузки подсистем, имеем  SI_SUB_PROTO_DOMAIN -> SI_SUB_PROTO_IFATTACHDOMAIN (ipfilter -> (ipfw, pf)), согласно порядку присоединения модулей к подсистеме имеем окончательный порядок загрузки модулей: ipfilter -> pf -> ipfw.
Таким образом, для входящего трафика:
ipfw -> pf -> ipfilter -> stack
для исходящего:
stack -> ipfilter -> pf -> ipfw

С другой стороны, pf часто загружают в качестве kld, а не компилируют в ядро статически, тогда, если kldstat показывает модуль pf.ko, то загрузился он после ipfw, и порядок прохождения пакетов тоже изменился:
pf -> ipfw -> ipfilter -> stack - для входящего
stack -> ipfilter -> ipfw -> pf - для исходящего

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



Немного о mercurial

Так как в настоящее время я все больше для своих наработок использую  mercurial, то для тех, кто с этой rcs не знаком я написал некоторые рекоммендации (предполагается знание хотя бы cvs):


Коротко как использовать mercurial:


идея распределенного хранилища проста - каждая рабочая копия - это целиком хранилище. Для создания хранилища в рабочей копии используем команду


hg init <PATH>


Далее добавляем файлы и каталоги:


cd <PATH>


hg add *


Для помещения хранилища на удаленную машину (аналог клиент-сервера) используем:


hg push ssh://<machine>/<PATH>


но предварительно на удаленной машине надо сделать hg init <PATH>


(можно также использовать вместо push clone). После этого мы имеем 2 одинаковых репозитария. Для коммита в локальный репозитарий используем обычный hg commit. Для синхронизации - hg push. Следующее действие - извлечение рабочей копии из репозитария (checkout) делается следующим образом:


hg clone <PATH> <DEST>, где <PATH> может быть ssh://machine/<PATH>


в каталоге <DEST> создается рабочая копия репозитария и сам репозитарий (каталог .hg). Чтобы получить изменения из общего репозитария можно воспользоваться командой pull, которая делает обратное push - вытаскивает из удаленного репозитария копию и синхронизирует с локальным репозитарием:


hg pull <PATH>, как обычно <PATH> может быть удаленным (ssh)


Остальные команды похожи на cvs, но всегда надо помнить о том, что ты работаешь с _локальным_ репозитарием и о том, что локальный репозитарий необходимо синхронизировать командой push (commit) или pull (checkout) в зависимости от характера изменений.


Полезные ссылки:


Tuesday, October 23, 2007

unreal ircd + codepage patch

Существует достаточно много irc серверов, пригодных для установки в небольшой сети или же для корпоративного пользования, однако, если смотреть с точки зрения функциональности, интеграции с сервисами и поддержки кириллических кодировок выбор не так велик: тот же rusnet-ircd, присутствующий в портах не работает с ircservices, альтернативы которым в портах, по крайней мере, нет. Мой выбор пал на irc/unreal (http://www.unrealircd.com). Существует патч для этого сервера, позволяющий рекодировать irc протокол, используя iconv: http://irc.mgts.by/wiki/index.php/UnrealIRCd. Однако, у этого патча есть два больших недостатка: он не пригоден для использования внутри портов, и он не работает для amd64 (любой 64-х битной архитектуре) из-за неверного предположения о размере size_t. Я немного изменил патч, исправив эти недостатки.
patch-codepage

ng_fixttl - netgraph модуль, исправляющий ttl пакетов

Данный модуль создавался в целях обеспечения простенькой защиты от использования nat-роутеров пользователями сети. Естественно, обходится данная защита очень просто, но со своей задачей она-таки справляется. У нас ng_fixttl используется совместно с ng_ipfw:

ipfw add netgraph 2 ip from any to $host

При этом необходимо помнить о sysctl net.inet.ip.fw.one_pass, который определяет, будет ли правило netgraph эквивалентно allow, или же пакет будет возвращаться в ipfw (на следующее за правилом netgraph правило), или же сразу же будет отдаваться сетевому стеку (если эта переменная установлена в 1). 

ng_fixttl.tar.gz

Премодерируемые конференции в innd

Итак, имеем настроенный inn. Имеем настроенный MTA.

* Создаем новую группу: ctlinnd newgroup testgroup m
* Прописываем approver'а в etc/moderators:
testgroup:moderator@hostname
* Где moderator@hostname - валидный почтовый адрес, куда будут приходить посты в группу. Я его сделал локальным, не знаю, можно ли иначе, без доступа к inews.
* Устанавливаем MUA.
* Устанавливаем procmail (для formail)
* Пишем скрипт, похожий на этот:
#!/bin/sh
SUFFIX=$$
formail \
-I"NNTP-Posting-Host" \
-I"X-Trace" \
-I"X-Complaints-To" \
-I"NNTP-Posting-Date" \
-I"Xref" \
-I"Date-Received" \
-I"Received" \
-I"Posted" \
-I"Posting-Version" \
-I"Relay-Version" \
-I"Approved: moderator@hostname" | sed -e '/From .*/d' > /tmp/article.${SUFFIX}

NNTPSERVER=localhost /usr/local/news/bin/inews -h /tmp/article.${SUFFIX}

rm -f /tmp/article.${SUFFIX}
* Отправляем нужные статьи при помощи пайпа к post.sh

Настройка gmirror в FreeBSD

Последовательность операций такова (FreeBSD >= 5.3 ):
1. Инсталируем FreeBSD
2. Ребутимся,загружаясь вновь с install CD
3. Переходим в fixit mode (для FreeBSD < 5.4 нужен CD2)
4. Выполняем следующие операции:
# chroot /dist
# mount_devfs devfs /dev
# gmirror load
# gmirror label -v -b round-robin gm0 /dev/ad0
# gmirror insert gm0 /dev/ad1
# mount /dev/mirror/gm0s1a /mnt
# echo ‘geom_mirror_load=”YES”‘ >> /mnt/boot/loader.conf
5. Правим fstab (sed или ed)
# sed “s,ad0,mirror/gm0,” /mnt/etc/fstab > /mnt/etc/fstab.new
# mv /mnt/etc/fstab.new /mnt/etc/fstab
6. Ребутимся, загружаясь с жесткого диска
7. Ждем некоторое время, пока mirror просинхронизируется (минимальная установка в 100 Mb синхронизировалась минут 15).
8. Вынимаем любой из дисков; наслаждаемся :)

Monday, October 22, 2007

First post

Решил вести свои заметки в таком стиле, чтобы в будущем упростить их поиск и извлечение информации.