суббота, 14 июня 2008 г.

Спам

Надо хорошенечко обдумать заметку Леонида Кантера на ЖЖ:

среда, 11 июня 2008 г.

Linux. Сказ про образы Audio дисков

Оригинал.

Наткнулся в сундуке на audio сокровища. Решил наконец разгрести, а поскольку все оказалось не совсем просто, законспектировал.

пятница, 30 мая 2008 г.

Шаттлворту риспект (взято с opennet)

Вслед за ЮАР, Бразилия и Индия подали апелляцию на решения комиссии ISO стандартизировать OOXML.

пятница, 9 мая 2008 г.

Роуты в VPN на WinXP

С удивлением обнаружил очередную "интересную" философию мелкомягких. Встала задача вбить руками в PPTP-туннель роут. И попытка это сделать по человечески - указав в качестве шлюза второй конец тунеля - не удалась. Оказалось нужно указывать свой конец тунеля, который в адекватной логике уже никуда не ведет. Ну да Бог с ними, с убогими на мозги.... Воистину "Мы изобрели новый протокол. Мы называем его TCP/IP. (c) Microsoft"

воскресенье, 27 апреля 2008 г.

Picasa 2.7 for Linux

Скачал. Поставил. Решил отписать мнение.
Равно как и в версии 2.2 основная проблема на мой взгляд (иными словами - то, что меня не устраивает) - в режиме слайд-шоу изображение не масштабируется на весь экран, а отображается маленькой в центре экрана. Уже только из-за этого продолжаю сидеть на F-Spot. Который, к слову сказать, умеет экспортировать в picasaweb. :)

PPTP VPN-server on Linux

Вдоволь накушавшись проблем с mpd+dummynet на новых FreeBSD (новых = 6.3 и 7.0), да и просто, чтобы не терять квалификации, решил соорудить PPTP VPN-Server на базе Linux. И по старой памяти и долгим летам саппорта был выбран RHEL 5.1, а если быть точным - CentOS 5.1. Интересно - возможно в будущем будет смысл сколотить подобное на Ubuntu LTS одной из версий.

Чтобы не изобретать велосипеда - было решено попытаться реализовать все то, что имелось в работающих серверах на базе FreeBSD с mpd. А именно - обжимать клиентские каналы ответом от freeradius (см. ng_car), обжимать несколько ай-пи в одну трубу (см. dummynet), сбрасывать клиента с линии ответом от радиус (см. mpd-drop), собирать детальную статистику по трафику в формате netflow (см. ng_netflow).


Итак - в распоряжении у нас был iproute2 вместе со своим tc и htb, pppd, модуль ifb, perl, accel-pptp. Причем accel-pptp был выбран не случайно - использование обычного poptop с его user-level обработкой gre-трафика было способно уложить на лопатки даже при относительно незначительном трафике относительно мощный сервер.

В первую очередь необходимо было добиться работы самого pptp. Был стянут архив исходников accel-pptp с SourceForge, распакован и сделан make server_install. Незначительно поправлены конфиги. В итоге /etc/ppp/options.pptpd:

plugin radius.so
plugin radattr.so
name pptpd
refuse-pap
require-chap
nobsdcomp
nodeflate
novj
novjccomp
nologfd
ms-dns
ms-dns
mtu 1496
mru 1496
lcp-echo-failure 6
lcp-echo-interval 10
и /etc/pptpd.conf:
option /etc/ppp/options.pptpd
connections 500
localip

Еще необходимо указать адрес радиус-сервера в /etc/radiusclient/*.
После чего соединение успешно завелось. И встала задача реализовать шейпинг трафика по радиус параметрам. Был выбран классический вариант решения - в скрипте ip-up парсить /var/run/radattr.pppX. Тут стоит заметить - в радиус словарь к параметрам mpd был также добавлен параметр ifb_shape, который должен был содержать имя ifb-интерфейса, на котором обжат клиент. Это было необходимо для обжатия группы айпи-адресов на общую скорость. Скрипт получился следующий:
#!/usr/bin/perl

$DEV = $ARGV[0];
$REMOTE_IP = $ARGV[4];
$tc = "/sbin/tc";

open(F, "/var/run/radattr.$DEV");
@lines = ;
close(F);

%params = ();

foreach $line (@lines)
{
chomp($line);
$line =~ /(\S+) (.+)/;
$param = $1;
$value = $2;
if($param eq "mpd-limit")
{
if($value =~ /^in#1=all shape (\d+) (\d+) pass/)
{
$params{'speed_in'} = $1;
$params{'burst_in'} = $2;
}
if($value =~ /^out#1=all shape (\d+) (\d+) pass/)
{
$params{'speed_out'} = $1;
$params{'burst_out'} = $2;
}
}
if($param eq "ifb_shape")
{
$params{'ifb_shape'} = $value;
}
}

if(exists($params{'ifb_shape'}))
{
$ifb_name = $params{'ifb_shape'};
# move to ifb
`$tc qdisc del dev $DEV ingress`;
`$tc qdisc del dev $DEV root`;
`$tc qdisc add dev $DEV handle ffff: ingress`;
`$tc filter add dev $DEV parent ffff: protocol ip u32 match u32 0 0 action mirred egress redirect dev $ifb_name`;
`$tc qdisc add dev $DEV root handle 2: prio`;
`$tc filter add dev $DEV parent 2: protocol ip u32 match u32 0 0 action mirred egress redirect dev $ifb_name`;
}
else
{
if(exists $params{'speed_out'} && exists $params{'burst_out'})
{
$speed_out = $params{'speed_out'};
$burst_out = $params{'burst_out'};

`$tc qdisc del dev $DEV root`;
`$tc qdisc add dev $DEV root handle 1 htb default 30 r2q 100`;
`$tc class add dev $DEV parent 1: classid 1:2 htb rate $speed_out`;
`$tc class add dev $DEV parent 1:2 classid 1:10 htb rate $speed_out`;
`$tc qdisc add dev $DEV parent 1:10 handle 10 sfq`;
`$tc filter add dev $DEV parent 1:0 protocol ip prio 100 u32 match ip dst $REMOTE_IP/32 classid 1:10`;
}
if(exists $params{'speed_in'} && exists $params{'burst_in'})
{
$speed_in = $params{'speed_in'};
$burst_in = $params{'burst_in'};

`$tc qdisc del dev $DEV ingress`;
`$tc qdisc add dev $DEV handle ffff: ingress`;
`$tc filter add dev $DEV parent ffff: protocol ip prio 50 u32 match ip src 0.0.0.0/0 police rate $speed_in buffer 10k drop flowid :1`;
}
}

Шейпинг на ifbX был организован также при помощи скрипта. Выкладывать его не вижу смысла - для всех страждущих имеется htb.init, выполняющий по сути сходные функции.
Только вот ждала засада в CentOS на тему редиректа трафика на другое устройство. Правило честно добавлялось, но работать - не работало. Да и где-то упоминалось в интернете, что с 2.6.18 ifb работает не очень хорошо. А как известно редхат плотным партизанским отрядом засел на 2.6.18 и ни пяди не сдает. С одной стороны правильно - а с другой - могли бы организовать contrib. Итого пришлось собрать ванильное 2.6.22.19 и обновить iproute2 - и вот только тогда пришло счастье работы редиректа.

Проблема сброса пользователя с линии по ответу от радиус была решена патчем на radius, написанным специально для данной цели:
diff -r -U 3 ppp-2.4.4/pppd/plugins/radius/buildreq.c ppp-2.4.4_xxx/pppd/plugins/radius/buildreq.c
--- ppp-2.4.4/pppd/plugins/radius/buildreq.c 2004-11-14 09:26:26.000000000 +0200
+++ ppp-2.4.4_xxx/pppd/plugins/radius/buildreq.c 2008-04-20 13:16:47.276938599 +0300
@@ -288,7 +288,7 @@

int rc_acct_using_server(SERVER *acctserver,
UINT4 client_port,
- VALUE_PAIR *send)
+ VALUE_PAIR *send, VALUE_PAIR **received)
{
SEND_DATA data;
VALUE_PAIR *adt_vp;
@@ -341,8 +341,11 @@

result = rc_send_server (&data, msg, NULL);
}
+
+ // Return acct reply
+ *received = data.receive_pairs;

- rc_avpair_free(data.receive_pairs);
+// rc_avpair_free(data.receive_pairs);

return result;
}
@@ -357,12 +360,12 @@
* filled in by this function, the rest has to be supplied.
*/

-int rc_acct(UINT4 client_port, VALUE_PAIR *send)
+int rc_acct(UINT4 client_port, VALUE_PAIR *send, VALUE_PAIR **received)
{
SERVER *acctserver = rc_conf_srv("acctserver");
if (!acctserver) return (ERROR_RC);

- return rc_acct_using_server(acctserver, client_port, send);
+ return rc_acct_using_server(acctserver, client_port, send, received);
}

/*
diff -r -U 3 ppp-2.4.4/pppd/plugins/radius/radius.c ppp-2.4.4_shulik/pppd/plugins/radius/radius.c
--- ppp-2.4.4/pppd/plugins/radius/radius.c 2006-05-22 03:01:40.000000000 +0300
+++ ppp-2.4.4_shulik/pppd/plugins/radius/radius.c 2008-04-21 17:51:00.997770390 +0300
@@ -706,6 +706,34 @@
return 0;
}

+/**********************************************************************
+* %FUNCTION: radius_check_acct_reply
+* %ARGUMENTS:
+* vp -- received value-pairs
+* %RETURNS:
+* >= 0 on success; -1 on failure
+* %DESCRIPTION:
+* Parses attributes sent by RADIUS server and sets them in pppd.
+***********************************************************************/
+static int
+radius_check_acct_reply(VALUE_PAIR *vp)
+{
+ while (vp) {
+ if (vp->vendorcode == VENDOR_MPD) {
+ switch (vp->attribute) {
+ case PW_MPD_DROP_USER:
+ if (vp->lvalue == 1) {
+ lcp_close(ifunit, "Radius mpd-drop...");
+ }
+ break;
+ }
+ }
+ vp = vp->next;
+ }
+
+ return 0;
+}
+
#ifdef MPPE
/**********************************************************************
* %FUNCTION: radius_setmppekeys
@@ -845,6 +873,7 @@
UINT4 av_type;
int result;
VALUE_PAIR *send = NULL;
+ VALUE_PAIR *received = NULL;
ipcp_options *ho = &ipcp_hisoptions[0];
u_int32_t hisaddr;

@@ -897,12 +926,14 @@

if (rstate.acctserver) {
result = rc_acct_using_server(rstate.acctserver,
- rstate.client_port, send);
+ rstate.client_port, send, &received);
} else {
- result = rc_acct(rstate.client_port, send);
+ result = rc_acct(rstate.client_port, send, &received);
}

rc_avpair_free(send);
+ if(received)
+ rc_avpair_free(received);

if (result != OK_RC) {
/* RADIUS server could be down so make this a warning */
@@ -931,6 +962,7 @@
{
UINT4 av_type;
VALUE_PAIR *send = NULL;
+ VALUE_PAIR *received = NULL;
ipcp_options *ho = &ipcp_hisoptions[0];
u_int32_t hisaddr;
int result;
@@ -1049,9 +1081,9 @@

if (rstate.acctserver) {
result = rc_acct_using_server(rstate.acctserver,
- rstate.client_port, send);
+ rstate.client_port, send, &received);
} else {
- result = rc_acct(rstate.client_port, send);
+ result = rc_acct(rstate.client_port, send, &received);
}

if (result != OK_RC) {
@@ -1059,6 +1091,8 @@
syslog(LOG_WARNING,
"Accounting STOP failed for %s", rstate.user);
}
+ if(received)
+ rc_avpair_free(received);
rc_avpair_free(send);
}

@@ -1076,6 +1110,7 @@
{
UINT4 av_type;
VALUE_PAIR *send = NULL;
+ VALUE_PAIR *received = NULL;
ipcp_options *ho = &ipcp_hisoptions[0];
u_int32_t hisaddr;
int result;
@@ -1146,9 +1181,9 @@

if (rstate.acctserver) {
result = rc_acct_using_server(rstate.acctserver,
- rstate.client_port, send);
+ rstate.client_port, send, &received);
} else {
- result = rc_acct(rstate.client_port, send);
+ result = rc_acct(rstate.client_port, send, &received);
}

if (result != OK_RC) {
@@ -1156,8 +1191,19 @@
syslog(LOG_WARNING,
"Interim accounting failed for %s", rstate.user);
}
- rc_avpair_free(send);
+
+
+ if (result == OK_RC) {
+ if (radius_check_acct_reply(received) < 0) {
+ result = ERROR_RC;
+ }
+ }

+ /* free value pairs */
+ if(received)
+ rc_avpair_free(received);
+ rc_avpair_free(send);
+
/* Schedule another one */
TIMEOUT(radius_acct_interim, NULL, rstate.acct_interim_interval);
}
diff -r -U 3 ppp-2.4.4/pppd/plugins/radius/radiusclient.h ppp-2.4.4_xxx/pppd/plugins/radius/radiusclient.h
--- ppp-2.4.4/pppd/plugins/radius/radiusclient.h 2004-11-14 09:26:26.000000000 +0200
+++ ppp-2.4.4_xxx/pppd/plugins/radius/radiusclient.h 2008-04-20 13:31:32.004230642 +0300
@@ -153,6 +153,8 @@
#define PW_MS_MPPE_SEND_KEY 16 /* string */
#define PW_MS_MPPE_RECV_KEY 17 /* string */

+#define PW_MPD_DROP_USER 154 /* integer */
+
/* Accounting */

#define PW_ACCT_STATUS_TYPE 40 /* integer */
@@ -292,6 +294,7 @@
/* Vendor codes */
#define VENDOR_NONE (-1)
#define VENDOR_MICROSOFT 311
+#define VENDOR_MPD 12341

/* Server data structures */

@@ -402,8 +405,8 @@
int rc_auth_using_server __P((SERVER *, UINT4, VALUE_PAIR *, VALUE_PAIR **,
char *, REQUEST_INFO *));
int rc_auth_proxy __P((VALUE_PAIR *, VALUE_PAIR **, char *));
-int rc_acct __P((UINT4, VALUE_PAIR *));
-int rc_acct_using_server __P((SERVER *, UINT4, VALUE_PAIR *));
+int rc_acct __P((UINT4, VALUE_PAIR *, VALUE_PAIR **));
+int rc_acct_using_server __P((SERVER *, UINT4, VALUE_PAIR *, VALUE_PAIR **));
int rc_acct_proxy __P((VALUE_PAIR *));
int rc_check __P((char *, unsigned short, char *));

Последняя проблема со сбором статистика решалась при помощи fprobe-ulog. Не вижу смысла детально описывать процесс ее инсталляции.

UPD 16.04.2012: Для статистики целесообразнее использовать ipt_NETFLOW (http://sourceforge.net/projects/ipt-netflow/).
Установка достаточно не сложная:
mkdir ~/netflow
cd ~/netflow
wget -O ipt_netflow.tgz http://sourceforge.net/projects/ipt-netflow/files/latest/download
tar -xzvf ipt_netflow.tgz
cd ipt_netflow-1.7.1/
./configure
make all install
depmod

Указываем настройки для модуля. У меня так (с указанием адреса своего коллектора):
# grep ipt_NETFLOW /etc/modprobe.d/options.conf
options ipt_NETFLOW destination=x.x.x.x:20001 hashsize=2097152
В качестве коллектора используется flow-tools. Присутствует в репозитории Ubuntu.
Подгружаем модуль и смотрим, что получилось:
# dmesg | tail -n 5
[1195554.463965] ipt_netflow version 1.7.1 (2097152 buckets)
[1195554.482354] netflow: registered: /proc/net/stat/ipt_netflow
[1195554.482496] netflow: registered: sysctl net.netflow
[1195554.482560] netflow: added destination x.x.x.x:20001
[1195554.482564] ipt_netflow loaded.
Статистику видно тут:
# cat /proc/net/stat/ipt_netflow
Flows: active 0 (peak 0 reached 0d0h16m ago), mem 0K
Hash: size 2097152 (mem 16384K), metric 1.0, 1.0, 1.0, 1.0. MemTraf: 0 pkt, 0 K (pdu 0, 0).
Timeout: active 1800, inactive 15. Maxflows 2000000
Rate: 0 bits/sec, 0 packets/sec; Avg 1 min: 0 bps, 0 pps; 5 min: 0 bps, 0 pps
cpu#  stat: , sock: , traffic: , drop:
Total stat:      0      0      0,    0    0    0    0, sock:      0 0 0, 0 K, traffic: 0, 0 MB, drop: 0, 0 K
cpu0  stat:      0      0      0,    0    0    0    0, sock:      0 0 0, 0 K, traffic: 0, 0 MB, drop: 0, 0 K
cpu1  stat:      0      0      0,    0    0    0    0, sock:      0 0 0, 0 K, traffic: 0, 0 MB, drop: 0, 0 K
cpu2  stat:      0      0      0,    0    0    0    0, sock:      0 0 0, 0 K, traffic: 0, 0 MB, drop: 0, 0 K
cpu3  stat:      0      0      0,    0    0    0    0, sock:      0 0 0, 0 K, traffic: 0, 0 MB, drop: 0, 0 K
sock0: x.x.x.x:20001, sndbuf 126976, filled 1, peak 0; err: sndbuf reached 0, other 0
Осталось загнать в модуль трафик:
$iptables -A FORWARD -o eth0 -j NETFLOW
$iptables -A FORWARD -i eth0 -j NETFLOW
$iptables -A OUTPUT  -o eth0 -j NETFLOW
$iptables -A INPUT   -i eth0 -j NETFLOW

пятница, 4 апреля 2008 г.

Война с dummynet

Интересно - я первый? Или до меня куча народа наступила на грабли с использованием mpd-5.0 во FreeBSD 7.0 вместе с dummynet?

Как оказалось система почему-то не захотела жить в одном из сегментов сети. И причем именно там. Потому как переехав на стол для теста - она сразу же начинала вести себя хорошо.
Но стоило вернуться в клиентскую сеть - и паника не заставляла себя ждать. Пара-тройка минут и double fault тут как тут.

Почесал репу, подумал. Для теста был остановлен mpd5. К удивлению - паники не было. Запуск же последнего неминуемо вел в панику.

Словил пару дампов. У одного из этих и почти у всех последующих оказался побит стек в дампе. Так что отследить траблу не удавалось. Но в одном из первых дампов уцелело упоминание ipfw. А как позже выяснилось - dummynet.

По собранной информации - в 7.0-STABLE коммитились патчи, уменьшающие аппетит netgraph к стеку к концу всех его вызовов. Да и народ из freebsd-ipfw@freebsd.org посоветовал до STABLE попробовать накатится. Попробовал. Так сказать - немножко полегчало. Паниковать стали не через 3-5 минут, а через 3-4 часа, или даже 1-2 суток. Ну тут как повезет.

Далее от одного из разработчиков приехал патч, мержевший изменения из HEAD на тему убирания рекурсии из dummynet. Помимо прочего эти изменения включали в себя новую sysctl переменную net.inet.ip.dummynet.io_fast, определявшую дословно следующее - либо полностью эмулировать канал с заданной пропускной способностью - включая задержки пакетов, либо просто срезать ширину канала при необходимости.
С дефолтным значением "полной эмуляции" мы выпали в панику менее чем через час. С вторым вариантом значения живем уже 1,5 суток. Посмотрим что будет дальше - а то рука уже напоготове до лучших времен заменить dummynet на ng_ipfw + ng_car. Только бы не оказалось так, что и тут будет проблема глубины стека......

четверг, 17 января 2008 г.

Тюним mpd

Взято отсюда:
Ньюсы

а что за машина? у нас вот это:
CPU: Intel(R) Celeron(R) CPU 1.70GHz (1716.91-MHz 686-class CPU)
real memory = 125763584 (122816K bytes)
деpжит 400 интеpфейсов (пpавда, больше 300 интеpфейсов одновpеменно ни pазу не
было занято)
а вот это:
CPU: Intel(R) Pentium(R) 4 CPU 3.00GHz (2992.51-MHz 686-class CPU)
real memory = 1056108544 (1031356K bytes)
деpжит 800 интеpфейсов (максимум одновpеменных подключений - около 790).
с ng_tcpmss оба деpжат нагpузку без особых пpоблем. пеpвая машина вообще не
напpягается (10-20% cpu), втоpая, конечно, пpоседает сильнее (40-60% cpu)
нужно увеличивать kern.ipc.maxpipekva. экспеpиментально установлено, что mpd4
на один бандл нужно около 200000 байт. итого, на 300 бандлов:
echo "kern.ipc.maxpipekva=\"60000000\"" >> /boot/loader.conf
кpоме этого, на каждый бандл нужно около 8 свободных file descriptor'ов (тоже
экспеpиментальная величина):
echo "kern.maxfiles=xxxxx" >> /etc/sysctl.conf
echo "kern.maxfilesperproc=3000" >> /etc/sysctl.conf
xxxxx bigger than 3000
немалую pоль игpают такие паpаметpы ядpа, как vm.kmem_size_scale,
vm.kmem_size_max. vm.kmem_size - пpоизводная от двух упомянутых и объема
опеpативной памяти, полезна для контpоля того, сколько вы pеально отдали ядpу.
общий pецепт такой: если хотите ставить pекоpды - набивайте побольше памяти,
выделяйте больше памяти ядpу, задеpите KVA_PAGES (опция в конфиге ядpа).
напоследок - мои loader.conf и sysctl.conf на тестовой машине (512mb ram, p4
3ghz), где я тpениpуюсь в создании 1000 интеpфейсов:
# cat /boot/loader.conf
kern.maxusers="512"
kern.ipc.maxpipekva="200000000"
vm.kmem_size_max="536870912"
vm.kmem_size_scale="2"
ng_ether_load="YES"
ng_netflow_load="YES"
# cat /etc/sysctl.conf
net.inet.ip.fastforwarding=1
kern.maxfiles=65000
kern.maxfilesperproc=32000
net.inet.ip.intr_queue_maxlen=1000
в конфиге ядpа стоит опция:
options KVA_PAGES=512

mpd мной применяется такой скрипт:
for j in "" 1 2 3 4 5 6 7 8 9 10 11 12; do
for i in 0 1 2 3 4 5 6 7 8 9; do
echo $j$i
ngctl shutdown ng$j$i:
ngctl shutdown mpd$1-pptp$j$i:
done
done
в качестве параметра $1 передаётся бывший pid покойного.
после этого сервер перезагружать не требуется :-)


Уровень ядра:
intr_queue_maxlen - очередь для входящих пакетов (аналогична backlog под Linux). Изменяется при помощи sysctl: net.inet.ip.intr_queue_maxlen. Значение по умолчанию = 50, что очень мало.
intr_queue_drops - статистика по работе intr_queue_maxlen, отображает количество отброшенных пакетов из очереди. Посмотреть её можно через sysctl: net.inet.ip.intr_queue_drops.