пятница, 26 декабря 2008 г.

deb-пакет: тема arctic для dokuwiki

Воспользовавшись краткой статьёй по ссылке Как мне сделать собственный .deb пакет? и информацией из man deb-control собрал deb-пакет с темой arctic для dokuwiki. Возможно криво. Можно взять здесь: dokuwiki-arctic-theme_0.0.20081104_all.deb

вторник, 16 декабря 2008 г.

DNAT и Policy Based Routing (portmapping и два канала)

На системе с OpenVZ столкнулся с любопытной проблемой. Вообще-то OpenVZ здесь не при чём, эта проблема заключалась в архитектуре сети.

Итак, имеется маршрутизатор с двумя внешними соединениями на интерфейсах ppp0 и ppp1. На обоих интерфейсах настроен MASQUERADE. На этом же маршрутизаторе есть внутренний интерфейс eth0, смотрящий в локальную сеть 10.16.7.0/24. В локальной сети находится несколько серверов и другие компьютеры.
 ppp0 .--------.           .-----> web (10.16.7.2)
<-----O        | eth0      |
      | router |-----------|-----> proxy (10.16.7.3)
<-----O        | 10.16.7.1 |
 ppp1 `--------'           `-----> samba (10.16.7.4)
Правила MASQUERADE добавляются в таблицы таким образом:
# iptables -t nat -A POSTROUTING -o ppp0 -s 10.16.7.0/24 -j MASQUERADE
# iptables -t nat -A POSTROUTING -o ppp1 -s 10.16.7.0/24 -j MASQUERADE
Не буду вдаваться в подробности тарифов и таблиц маршрутизации, намеренно упрощу изложение. Допустим что сеть 172.16.0.0/16 является внешней и принадлежит провайдеру. Обращаться к этой подсети, за исключением адреса 172.16.0.1, выгодно через интерфейс ppp1. Ко всем остальным адресам, включая 172.16.0.1, выгодно обращаться через интерфейс ppp0.

Таким образом команды для создания этой таблицы маршрутизации должны быть такими:
# ip route add 172.16.0.1 dev ppp0
# ip route add 172.16.0.0/16 dev ppp1
# ip route add default dev ppp0
С трафиком из подсети 10.16.7.0/16 всё просто - он в любом случае будет замаскирован под IP-адрес того интерфейса, через который он пойдёт.

С трафиком с самого маршрутизатора во внешнюю сеть дела обстоят чуть сложнее. Маршрутизатор обладает двумя внешними IP-адресами и потому для исходящих соединений может выбирать адрес совершенно произвольно. Поэтому может случиться так, что соединение выберет в качестве исходного IP-адреса адрес на интерфейсе ppp0, а трафик в соответствии с таблицей маршрутизации будет уходить через интерфейс ppp1. Любой провайдер фильтрует трафик от клиентов, запрещая отправлять пакеты с того IP-адреса, который не принадлежит конкретно этому клиенту. Поэтому такие неправильные соединения будут автоматически блокированы.

Чтобы этого не случилось, к маршрутам можно добавлять предпочитаемые исходные IP-адреса. Это можно сделать такими командами:
# ip route add 172.16.0.1 dev ppp0 src ppp0_IP
# ip route add 172.16.0.0/16 dev ppp1 src ppp1_IP
# ip route add default dev ppp0 src ppp0_IP
Где ppp0_IP и ppp1_IP - IP-адреса на соответствующих интерфейсах.

Идём далее. На маршрутизаторе может быть запущен некий сервис, допустим ssh. К нему может быть необходимо подключаться как через интерфейс ppp0, так и через интерфейс ppp1. При этом возвратные пакеты к клиенту будут опять-таки отправляться в соответствии с таблицей маршрутизации, то есть может повториться вышеописанная ситуация.

Чтобы этого не произошло, нужно создать две таблицы маршрутизации, которые будут применяться для маршрутизации пакетов от сервиса ssh к клиентам.

Для этого в файле /etc/iproute2/rt_tables пропишем две новые таблицы маршрутизации:
201     table_ppp0
202     table_ppp1
В каждую из таблиц добавим по единственному маршруту по-умолчанию в соответствующие направления следующими командами:
# ip route add default dev ppp0 table table_ppp0
# ip route add default dev ppp1 table table_ppp1
Теперь нужно указать в каких случаях какой таблицей пользоваться. Нужно чтобы пакеты с исходным адресом ppp0_IP уходили по маршрутам в таблице table_ppp0, а пакеты с исходным адресом ppp1_IP уходили по маршрутам в таблице table_ppp1. Это мы сделаем с помощью следующих команд:
# ip rule add from ppp0_IP table table_ppp0
# ip rule add from ppp1_IP table table_ppp1
Общий список всех команд для настройки Policy Based Routing в нашем примере будет таким (в первой группе команд на всякий случай явно укажем таблицу маршрутизации main):
# ip route add 172.16.0.1 dev ppp0 src ppp0_IP table main
# ip route add 172.16.0.0/16 dev ppp1 src ppp1_IP table main
# ip route add default dev ppp0 src ppp0_IP table main
# ip route add default dev ppp0 table table_ppp0
# ip route add default dev ppp1 table table_ppp1
# ip rule add from ppp0_IP table table_ppp0
# ip rule add from ppp1_IP table table_ppp1
После этого не будет проблем с трафиком с самого маршрутизатора, с трафиком из локальной сети 10.16.7.0/24, трафиком, адресованным самому маршрутизатору.

Теперь нужно сделать так, чтобы при обращении к порту 80 на внешних адресах маршрутизатора трафик перенаправлялся на локальный web-сервер, имеющий адрес 10.16.7.2.

После всего проделанного это кажется довольно простым, нужно всего лишь добавить пару правил в iptables:
# iptables -t nat PREROUTING -i ppp0 -d ppp0_IP -p tcp --dport 80 -j DNAT --to 10.16.7.2:80
# iptables -t nat PREROUTING -i ppp1 -d ppp1_IP -p tcp --dport 80 -j DNAT --to 10.16.7.2:80
Однако не стоит так торопиться, на самом деле всё чуть сложнее. Возвратный трафик от web-сервера к маршрутизатору будет обрабатываться в соответствии с правилами в таблице main и пакеты могут уйти на тот интерфейс, с которого это соединение инициировано не было.

Уже к этому этапу я достаточно намучился с большим количеством динамически изменяемых таблиц: таблицами маршрутизации, таблицами NAT и таблицами фильтрации трафика. Кроме того, при перезапуске виртуальных сред обновлялся и список интерфейсов объединённых сетевыми мостом (рассматриваемый в примере интерфейс eth0 в действительности был интерфейсом br0). Поэтому я решил: "С меня хватит!" и не стал разбираться с этой проблемой, перенеся веб-сервер на маршрутизатор.

Однако для себя я отметил, что в этом случае можно было бы назначить web-серверу ещё один локальный IP-адрес, например 10.16.7.5 и направлять на него соединения с одного из интерфейсов. То есть это выглядело бы таким образом:
# iptables -t nat PREROUTING -i ppp0 -d ppp0_IP -p tcp --dport 80 -j DNAT --to 10.16.7.2:80
# iptables -t nat PREROUTING -i ppp1 -d ppp1_IP -p tcp --dport 80 -j DNAT --to 10.16.7.5:80
А для того, чтобы пакеты от веб-сервера попадали на нужный интерфейс, на маршрутизаторе можно было бы добавить ещё два правила выбора таблиц:
# ip add rule from 10.16.7.2 table table_ppp0
# ip add rule from 10.16.7.5 table table_ppp1
Правда в этом случае весь трафик с web-сервера подчинялся бы этим правилам. Приходит на ум ещё одно решение: добавить web-серверу ещё один адрес и использовать все три таблицы маршрутизации. Для этого изменим правила DNAT таким образом:
# iptables -t nat PREROUTING -i ppp0 -d ppp0_IP -p tcp --dport 80 -j DNAT --to 10.16.7.5:80
# iptables -t nat PREROUTING -i ppp1 -d ppp1_IP -p tcp --dport 80 -j DNAT --to 10.16.7.6:80
Правила выбора таблицы маршрутизации для web-сервера будут такими:
# ip add rule from 10.16.7.5 table table_ppp0
# ip add rule from 10.16.7.6 table table_ppp1
Можно, конечно, сделать ещё более тонкую настройку - ужесточить два последних правила выбора таблицы маршрутизации использовав для отбора пакетов правила iptables:
# iptables -t nat PREROUTING -i ppp0 -d ppp0_IP -p tcp --dport 80 -j DNAT --to 10.16.7.5:80
# iptables -t nat PREROUTING -i ppp1 -d ppp1_IP -p tcp --dport 80 -j DNAT --to 10.16.7.6:80
# iptables -t mangle -A PREROUTING -s 10.16.7.5 -p tcp --sport 80 -j MARK --set-mark 1
# iptables -t mangle -A PREROUTING -s 10.16.7.6 -p tcp --sport 80 -j MARK --set-mark 2
# ip add rule fwmark 1 table table_ppp0
# ip add rule fwmark 2 table table_ppp1
Можно не назначать дополнительные адреса web-серверу, а заставить web-сервер принимать соединения на двух портах: 80 и 81.
# iptables -t nat PREROUTING -i ppp0 -d ppp0_IP -p tcp --dport 80 -j DNAT --to 10.16.7.2:80
# iptables -t nat PREROUTING -i ppp1 -d ppp1_IP -p tcp --dport 81 -j DNAT --to 10.16.7.2:81
# iptables -t mangle -A PREROUTING -s 10.16.7.2 -p tcp --sport 80 -j MARK --set-mark 1
# iptables -t mangle -A PREROUTING -s 10.16.7.2 -p tcp --sport 81 -j MARK --set-mark 2
# ip add rule fwmark 1 table table_ppp0
# ip add rule fwmark 2 table table_ppp1
Итак, полностью рабочая и наиболее точная схема обработки трафика в целом будет выглядеть так:
# iptables -t nat -A POSTROUTING -o ppp0 -s 10.16.7.0/24 -j MASQUERADE
# iptables -t nat -A POSTROUTING -o ppp1 -s 10.16.7.0/24 -j MASQUERADE
# ip route add 172.16.0.1 dev ppp0 src ppp0_IP table main
# ip route add 172.16.0.0/16 dev ppp1 src ppp1_IP table main
# ip route add default dev ppp0 src ppp0_IP table main
# ip route add default dev ppp0 table table_ppp0
# ip route add default dev ppp1 table table_ppp1
# ip rule add from ppp0_IP table table_ppp0
# ip rule add from ppp1_IP table table_ppp1
# iptables -t nat PREROUTING -i ppp0 -d ppp0_IP -p tcp --dport 80 -j DNAT --to 10.16.7.2:80
# iptables -t nat PREROUTING -i ppp1 -d ppp1_IP -p tcp --dport 80 -j DNAT --to 10.16.7.2:81
# iptables -t mangle -A PREROUTING -s 10.16.7.2 -p tcp --sport 80 -j MARK --set-mark 1
# iptables -t mangle -A PREROUTING -s 10.16.7.2 -p tcp --sport 81 -j MARK --set-mark 2
# ip add rule fwmark 1 table table_ppp0
# ip add rule fwmark 2 table table_ppp1
Теперь представьте что у вас во внутренней сети работает не один сервис. А теперь представьте, что и соединений с провайдерами больше. А теперь представьте, что всё это хозяйство должно динамически изменяться при установке и падении связи с определённым провайдером. Не думаю, что вы будете в восторге от такой головной боли.

Написать статью решил потому что сегодня случайно наткнулся на статью с немного другим подходом к решению этой проблемы: http://xgu.ru/wiki/Default_gateway

В этой статье предлагается использовать дополнительный промежуточный маршрутизатор. На всякий случай приведу предлагаемую в статье схему здесь:
        GW1   GW2
         ^     ^
         |     | 
     IP1 |     | IP2
  [eth1] |     | [eth2]
        .o-----o.
        |       |
        |  gw   |
        |       |
        `-------'
10.0.3.250  |  10.0.3.254
    [eth0]  |  [eth0:1]
            | 
            |
10.0.3.249  |  10.0.3.253
    [eth1]  |  [eth1:1]
        .-------.
        |       |
        |  pgw  |
        |       |
        `-------'
            | 10.0.3.6
            | [eth0]
            |
В примечании к схеме указано:
  • на шлюзе gw выполняется проброска на один из внутренних адресов, в зависимости от того, куда пришёл запрос;
  • на шлюзе pgw выполняется дальнейшая проброска внутрь сети.
Жаль, что предлагаемое решение не разложено по полочкам с приведением конкретных команд. Нужно будет подумать на досуге, а можно ли сделать это не прибегая к использованию дополнительной физической машины? Ведь сила множественных таблиц маршрутизации Linux именно в том, что на одной Linux-машине можно уместить два и более маршрутизаторов с собственными таблицами маршрутизации.

А вообще, вас не пугает такая сложность настройки довольно простой идеи разруливания трафика всего лишь двух провайдеров? После всего написанного выше среди вас ещё остались сторонники использования NAT?

Как ни крути, но NAT - это костыль. Временное решение постоянных проблем. Постоянное решение - это 128-битные адреса IPv6 и 32-битные номера автономных систем. Во всяком случае этих решений должно хватить на обозримое будущее (просто не хочу уподобляться одному человеку, однажды сказавшему "640 килобайт оперативной памяти хватит всем.") Смотрите сюда и трепещите! :)

Даёшь каждому по номеру автономной системы и по блоку IP-адресов!

воскресенье, 14 декабря 2008 г.

CD-рипперы в Linux

В репозитории Debian нашёл несколько CD-рипперов:

1. grip - CD-риппер для среды GNOME, имеет интеграцию с некоей базой данных DigitalDJ,

2. ripperx - лёгкий CD-риппер с GTK-интерфейсом,

3. sound-juicer - "Звуковыжиматель", довольно тяжёлый CD-риппер для среды GNOME. Интересен тем, что для сжатия использует аудиосистему gstreamer,

4. KAudioCreator - CD-риппер для среды KDE,

5. ripit - консольный CD-риппер, представляет собой Perl-скрипт.

Все программы, за исключением sound-juicer являются обёртками вокруг консольных программ вроде cdparanoia для снятия треков, и lame/oggenc для кодирования. При наличии доступа к Интернет программы подключаются к базе CDDB и автоматически проставляют теги, если диск был найден в базе. Можно отредактировать теги вручную, задать место расположения готовых файлов, задать способ их наименования с использованием содержимого тегов, выбрать и настроить энкодер на требуемое качество сжатия.

Ripper X не понравился тем, что не русифицирован. Английский интерфейс для меня проблемы не представляет, но зачем нарушать русскоязычную программную среду чужеродным элементом? :-)

В интерфейсе Grip не удалось найти настройки битрейта, зато они легко обнаружились в тектовом конфиге ~/.grip.

Sound Juicer вообще не богат настройками, можно выбрать только кодер и схему сжатия вроде "CD-качество", "Речь" и т.п. Нашёл XML-файл с настройками, правда нужных мне параметров там не обнаружилось. Вытягивать из программы необходимые настройки щипцами мне не очень интересно, поэтому мой выбор склонился в пользу других, лучше документированных программ. В общем чувствуется спорный подход среды GNOME к проектированию интерфейсов: прятать детали настройки с глаз долой в XML-файлы, которые плохо документированы - чем не реестр Windows? Для тех же кто не разбирается в настройках аудиокодеров вполне подойдёт.

KAudioCreator по свойствам в целом очень похож на Grip, только ориентирован на среду KDE. Из плюсов по сравнению с Grip можно отметить специальный мастер для формирования имён файлов по содержимому тегов, в Grip на этот счёт имеется страница в англоязычном файле справки.

Теперь о самой любопытной программе: ripit. Программа интересна прежде всего тем, что нисколько не уступая по возможностям и удобству остальным программам, обладает рядом довольно интересных возможностей. Во-первых она может работать в связке с довольно приличным набором рипперов и кодеров. Во-вторых, он позволяет указать количество ядер процессора, по которому будет определяться число одновременно работающих процессов-энкодеров. В-третьих, он позволяет использовать для энкодирования другие сетевые компьютеры доступные по ssh! Эта возможность мне лично кажется избыточной, поскольку современные компьютеры сжимают звук настолько быстро, что больше времени уходит на собственно считывание дорожек с компакт-диска.

Что выбирать? Ответить однозначно затрудняюсь.

Если вы простой пользователь, ничего не понимающий в тегах, кодерах, битрейтах, смело выбирайте Sound Juicer.

Если вы предпочитаете графический интерфейс, выбирайте Ripper X если вы пользуетесь каким либо Window Manager'ом, выбирайте Grip если вы пользователь GNOME, выбирайте KAudioCreator если вы используете KDE.

Если вы предпочитаете командную строку и текстовый интерфейс вас нисколько не пугает - смело выбирайте ripit. Несмотря на отсутствие графического или ncurses-интерфейса, пользоваться ею пожалуй даже удобнее, чем остальными программами.

вторник, 2 декабря 2008 г.

Разводка розетки RJ-45 на компьютер и телефон

На работе практически состоялся переезд в новый офис. Переехало около 80 рабочих мест телефон+компьютер, 7 серверов, 2 маршрутизатора, телефонная станция, 5 IP-линий связи, два телефонных потока по 7 и 10 номеров. Коммутация выполнялась на 110 панели, компьютеров - двупарными и четырёхпарными патчкордами RJ45-110, телефонов - кроссировочным кабелем.

СКС не была расчитана на такое количество народа, поэтому практически в каждой второй розетке разводили 8-парные UTP-кабели на компьютер и телефон.

На 110 панели пары идут в таком порядке: синяя, оранжевая, зелёная, коричневая.

1. Два компьютера можно развести на двойную розетку так:
на панель 110       на розетки (схема B)

синяя     -------\  оранжевая (1 разъём)
оранжевая -------/  зелёная   (1 разъём)
зелёная   -------\  оранжевая (2 разъём)
коричневая-------/  зелёная   (2 разъём)
2. Если в розетку можно задействовать под компьютер целиком, то разводка будет такой:
на панель 110       на розетку (схема B)

синяя     -------\  синяя
оранжевая --------\ оранжевая
зелёная   --------/ зелёная
коричневая-------/  коричневая
3. Если розетку можно задействовать под телефон целиком, то разводка будет такой:
на панель 110       на розетку (схема B)

синяя     ------->  синяя
оранжевая
зелёная
коричневая
Однако при этом развести розетку для телефона лучше точно так же, как и для компьютера, чтобы розетка была универсальной и её легко можно было перекоммутировать на панели для подключения компьютера.
на панель 110       на розетку (схема B)

синяя     ------->  синяя
оранжевая - - - - \ оранжевая
зелёная   - - - - / зелёная
коричневая- - - -/  коричневая
4. Теперь самый интересный вариант. Разводим телефон и компьютер. Тут есть два варианта.

4.1. Первый:
на панель 110       на розетку (схема B)

синяя     - - - ->  синяя     (1 разъём)
оранжевая --------\ оранжевая (1 разъём)
зелёная   --------/ зелёная   (1 разъём)
коричневая------->  синяя     (2 разъём)
4.2. И второй:
на панель 110       на розетку (схема B)

синяя     ------->  синяя     (1 разъём)
оранжевая --------\ оранжевая (2 разъём)
зелёная   --------/ зелёная   (2 разъём)
коричневая- - - ->  синяя     (2 разъём)
На фотографиях ниже наглядно представлена схема разводки розетки.




Я без задней мысли разводил двойные розетки по первому варианту.

Сегодня с утра начальник был очень разгневан моим безответственным поведением. Если при разводке по всем схемам 1 - 3 телефон на панели всегда оказывался на синей паре, то при разводке на двойную розетку компьютер-телефон по схеме 4.1, на панель телефон приходил коричневой парой. Это приводило к путанице и необходимости поиска телефонной пары на таких розетках.

Так вот, если кто не знает как лучше развести UTP-кабель на двойную розетку компьютер-телефон, знайте - лучше обжимать по схеме 4.2. Возможно это общепринятая практика, но мы научились на собственных шишках.

Говорят что дураки учатся на своих ошибках, а умные - на чужих. Желаю вам быть умными людьми.

Обновлено 13 марта 2010.