Friday, October 26, 2007
Встроенные функции gcc для атомарных операций
Например, следующий код берет адрес позиции указателя в определенном массиве и инкрементирует указатель (после операции он указывает на следующий элемент в массиве):
cur_pos = __sync_fetch_and_add (&pos, sizeof(u_char));
В gcc3 этих функций нет.
Wednesday, October 24, 2007
Определение порядка прохождения пакетов по различным пакетным фильтрам в FreeBSD
Как происходит передача пакета хуку 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
patch-codepage
ng_fixttl - netgraph модуль, исправляющий ttl пакетов
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
* Создаем новую группу: 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
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. Вынимаем любой из дисков; наслаждаемся :)