воскресенье, 26 июля 2009 г.

Домашний сервер. Часть вторая — сборка.

И года не прошло, а всего лишь месяц и у меня появилась возможность заняться своим новым домашним сервером и дописать статью.
В первой статье я рассказал о выборе комплектующих, а здесь я покажу как это все выглядит и что из этого получилось.
Куда все будет собираться - инвиновский корпус bm639:
Free Image Hosting at www.ImageShack.us
Если вам захочется использовать дополнительную плату расширения, например мне нужна будет вторая сетевушка, чтобы использовать сервер как шлюз, тогда вам понадобятся их низкопрофильные варианты:
Free Image Hosting at www.ImageShack.us
Теперь ядро всей системы, материнская плата от Intel D945GCLF2D со встроенным процессором Atom 330, что приятно - эта плата имеет встроенную гигабитную(!) сетевушку:
Free Image Hosting at www.ImageShack.us
Средство хранения данных - жесткий диск WD10EVDS. В принципе, выбранный корпус позволяет использовать два жестких диска, второй диск можно вставить в 5-ти дюймовый отсек, так что в теории выбранная конфигурация позволяет хранить до 4Тб данных:
Free Image Hosting at www.ImageShack.us
А теперь все собранное вместе:
Free Image Hosting at www.ImageShack.us
Самым большим удивлением для меня было то насколько это все вместе громко работает. Вы можете убедиться в этом сами (видео снималось только ради звука, так что извините за качество картинки :):

Всего в системе 3 кулера + шум от жесткого диска. На кулер блока питания я особо не мог повлиять, да в принципе он самый тихий из троицы, а вот остальные два (кулер на корпусе и на северном мосте) я решил заменить. Кулер северного моста я, сначала, планировал заменить на пассивный HR-05, но оказалось что он не войдет по высоте да и по ширине ему будет тесновато. В итоге я его просто подключил через регулятор скорости и установил его на 2000 об/м (изначально было 4000 об/м). Кулер системного блока был заменен на Enermax UCEV8, этот кулер сам меняет скорость вращения в зависимости от температуры (500 об/м при температуре меньше 45 градусов и 1500, если больше):
Free Image Hosting at www.ImageShack.us
Результат получился довольно хорошим:

Получился довольно приятный домашний сервер:
Free Image Hosting at www.ImageShack.us
И на последок несколько результатов тестов производительности:
  • Под Windows XP:
    • PCMark05 - 2207
    • WinRar (встроенный тест):
      • Один поток - 233 Kb/s
      • Многопоточный режим - 568 Kb/s
      • Одновременно 4-е однопоточных теста - 157+158+157+158=630 Kb/s
  • Под Fedora 11:
    • Компиляция lighttpd 1.4.23 (./configure --without-pcre --without-bzip2):
      • Время выполнения - 1:18 (эту же операцию Core2Duo-8200 за 0:23, P-II 400 за 3:23)
      • Время выполнения 4-х параллельных компиляций - 2:13, 2:14, 2:14, 2:14

среда, 24 июня 2009 г.

3Com® Gigabit Switch 5 3CGSU05A.

Вслед за модернизацией домашнего сервака, проапгрейдил домашнюю сеть до гигабитной. В качестве свича остановился на трикомовском гигабитнике.
Свич оказался меньше, чем казался на фотографии на сайте.

Вживую он выглядит поприличее чем на фото.

И наконец-то он в действии.

пятница, 19 июня 2009 г.

Домашний сервер. Часть первая — выбор комплектующих.

Сейчас мой домашний сервер представляет из себя комп с процессором Pentium 400Mhz и 384Mb памяти. Главные задачи, которые я ставил перед собой, были сделать его еще тише, меньше по размерам и быстрее.
Сначала я подобрал комплектующие.

Уменьшить размеры можно только используя маленькие комплектующие :) поэтому я остановился на форм факторе mini-ITX. Для начала был выбран корпус, который я искал в ассортименте корпусов Inwin. К сожелению у них совсем небольшой выбор mini-ITX корпусов, но то что было вполне мне подошло, мой выбор пал на bm639. Встроенный в корпус блок питания выдает 120W с таким особо не разгуляешься, но для моих задач этого более чем достаточно.
Соответствуя моим условиям, все внутренности сервера должны быть тихими и, желательно, с пониженным энергопотреблением. Итак, в качестве процессора я решил брать Atom, более чем подходящий по всем параметрам, а так как я хотел все таки побыстрее, то искал Atom 330. Из материнских плат с таким процессором я нашел претендентов от Intel, Gygabyte и парочки нонеймов. Претендента от Gygabyte я отбросил, так как имел несколько раз неприятные глюки с их комплектующими, поэтому решил брать плату от Intel, хотя с интеловскими мамками особо и не работал. Из двух интеловских плат я выбрал модель без излишеств Intel Desktop Board D945GCLF2D.
Про память сказать особо нечего, я взял по максимуму сколько поддерживала материнская плата - 2Gb.
Осталось разобраться с винтом. Жесткие диски я просмотрел у всех основных производителей. Здесь победил WD cо своей серией Green Power. Они имеют пониженное энергопотребление и скорость врашения шпинделя 5400, что обеспечивает более тихую работу. Сначала я хотел брать 500Gb винт, но по акустическим параметрам лучше выглядел террабайтник WD10EVDS, который я в итоге и взял.
Все это я написал пока скачивалась Windows 7 64-bit для установки на новую систему. Ставить буду только для тестов, в итоге, все таки, на серваке обоснуется Fedora 11 :)
Во второй части статьи я выложу фотоотчет по сборке.

Вторая часть - Сборка.

четверг, 18 июня 2009 г.

Обновление домашнего сервера.

Наконец-то руки добрались до обновления моего домашнего сервака. Вместо старенького Pentium II 400Mhz у меня будет Atom 330 :), благодаря этой платке Intel Desktop Board D945GCLF2D. Корпус взял этот. Ну а ставить буду одиннадцатую федору. Наверное займусь этим в выходные еще ведь надо докупить мозгов и винт.

четверг, 26 марта 2009 г.

Vim. Spaces vs Tabs.

Vim замечательный редактор, в котором почти все поддается настройке. Процесс редактирования почти никогда не обходится без использования отступов, как правило они выполняются табуляцией, но иногда требуется делать это некоторым количеством пробелов. Так например в языке программирования python рекомендуется делать отступы при помощи 4 пробелов. Vim позволяет легко переключаться с отступов по табам на отступы пробелами, за эти параметры отвечают 3 настройки:

  • expandtab

  • shiftwidth

  • softtabstop


На следующей схемке показано, за что каждый из параметров отвечает:

(нажимаем tab)
|<-softtabstop->|<-softtabstop->|
| |
print('ok') | (нажимаем enter)
|<-shiftwidth-->|<--shiftwidth->|
def is_vim_best(): | |
if(1 == 1): | |
if(2 == 2): |
return 'yes'

print('is vim best? - ' + is_vim_best())

Тоесть, expandtab - включает замену табов на пробелы (:set expandtab для включения и :set noexpandtab для выключения), в значении softtabstop хранится количество пробелов, на которое подменяется таб (:set softtabstop=4), когда нажимается таб, в shiftwidth хранится количестов пробелов, на которое заменяется отступ, когда выполняется авто-отступ или операции << >>.

среда, 25 марта 2009 г.

Используем 2+ провайдера с применением модуля CONNMARK

Еще один способ использования нескольких каналов в интернет, теперь с использованием модуля CONNMARK. Когда я с ним начинал знакомится все выглядело довольно просто, но в процессе настройки я столкнулся со множеством подводных камней.
Допустим мы имеем следующие правила маршрутизации:
#!/bin/bash

IF1=eth1
IF2=eth2
IP1=xx.xx.xx.xx
IP2=xx.xx.xx.xx
P1=xx.xx.xx.xx
P2=xx.xx.xx.xx
P1_NET=xx.xx.xx.xx/24
P2_NET=xx.xx.xx.xx/24
PC=xx.xx.xx.xx

ip route add $P1_NET dev $IF1 src $IP1 table T1
ip route add default via $P1 table T1
ip route add $P2_NET dev $IF2 src $IP2 table T2
ip route add default via $P2 table T2

ip route add $P1_NET dev $IF1 src $IP1
ip route add $P2_NET dev $IF2 src $IP2

ip route add default via $P1 metric 10

ip rule add from $IP1 table T1
ip rule add from $IP2 table T2

ip rule add fwmark 2 table T2

Здесь IF - интерфейсы нашего роутера, смотрящие к провайдерам, IP - внешние айпишники, P - шлюзы, P_NET - провайдерские подсети, PC - ПК во внутренней сети.
Допустим на PC у нас работает SMTP сервер, и необходимо чтобы он обрабатывал соединения поступающие на любой из внешних адресов. Для этого понадобятся правила DNAT:
$IPTABLES -t nat -A PREROUTING -i $GLOBAL_ETH_PRIM -d $GLOBAL_IP_PRIM -p tcp --dport 25 -j DNAT --to-destination $PC
$IPTABLES -t nat -A PREROUTING -i $GLOBAL_ETH_SEC -d $GLOBAL_IP_SEC -p tcp --dport 25 -j DNAT --to-destination $PC

И следующий набор правил:
$IPTABLES -t mangle -A PREROUTING -i $LOCAL_ETH -m state --state ESTABLISHED -j CONNMARK --restore-mark
$IPTABLES -t mangle -A FORWARD -i $GLOBAL_ETH_PRIM -m state --state NEW -j CT
$IPTABLES -t mangle -A FORWARD -i $GLOBAL_ETH_SEC -m state --state NEW -j CT

В первой строке мы восстанавливаем маркер, установленный модулем CONNMARK, причем необходимо явно указать, что применяется это к пакетам идущим из внутренней подсети, либо добавить в таблицы маршрутизации пути к локальной подсети, иначе некорректно будут отрабатыватся правила DNAT. Все новые пакеты отправляются на маркировку в пользовательскую цепочку CT вот она:
$IPTABLES -t mangle -N CT

$IPTABLES -t mangle -A CT -i $GLOBAL_ETH_PRIM -p tcp --dport 25 -j CONNMARK --set-mark 1
$IPTABLES -t mangle -A CT -i $GLOBAL_ETH_SEC -p tcp --dport 25 -j CONNMARK --set-mark 2

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

понедельник, 23 марта 2009 г.

Twit. Правильное продолжение.

Исправляю предыдущий вариант скрипта. Как я уже сказал правильно будет анализировать ответ от сервера (по правде говоря мне сказали).
Итак, теперь с помощью xsl-файла twit.xsl:

<?xml version='1.0'?>
<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
<xsl:template match='/'>
<xsl:value-of select='status/id'/>
</xsl:template>
</xsl:stylesheet>

Буду проверять существует ли в ответе id нового сообщения.

#!/bin/sh
# Made by rsk -- http://rsk.me


# Imports $TPASS, $TUSER
. ~/.twit/pass
XSLPATH=/etc/twit/twit.xsl


echo "Type in your message..."


MSG="$(perl -e'$_=<>,print')"

echo -n "Sending..."
RESULT=$(curl --basic --user $TUSER:$TPASS --data status="$MSG" http://twitter.com/statuses/update.xml 2> /dev/null | xsltproc $XSLPATH - | tail -n 1)

if [ -n "$RESULT" ]; then
echo "ok";
else
echo "Sending failed!";
fi

пятница, 20 марта 2009 г.

Twit. Продолжение.

Начало.
Появился чуток свободного времени и я немного довел до ума свой скриптик постинга сообщений в твиттер из командной строки.
Во-первых я изменил способ передачи сообщения, теперь оно считывается из stdout (тут не обошлось без перломагии). А во-вторых я добавил обратную связь - теперь скрипт проверяет действительно ли сообщение дошло до твиттера.
Если с первым все понятно, то со вторым пришлось повозиться. Эту задачу я решил сравнивая последний id сообщения до и после отправки.
id сообщения я получаю применяя этот xslt-файл к http://twitter.com/statuses/user_timeline.xml (twitter api):

  1. <?xml version='1.0'?>
  2. <xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
  3. <xsl:template match='/'>
  4. <xsl:value-of select='statuses/status/id'/>
  5. </xsl:template>
  6. </xsl:stylesheet>


Он будет лежать в /etc/twit/twit.xsl.
Далее собственно сам скрипт:

  1. #!/bin/sh
  2. # Made by rsk -- http://rsk.me

  3. # Imports $TPASS, $TUSER
  4. . ~/.twit/pass
  5. XSLPATH=/etc/twit/twit.xsl

  6. echo "Type in your message..."

  7. MSG="$(perl -e'$_=<>,print')"
  8. echo "Checking last id..."
  9. LASTIDOLD=$(curl --basic --user $TUSER:$TPASS http://twitter.com/statuses/user_timeline.xml 2>/dev/null | xsltproc $XSLPATH - | grep -v ^$ | tail -n 1)

  10. echo "Sending..."
  11. curl --basic --user $TUSER:$TPASS --data status="$MSG" http://twitter.com/statuses/update.xml > /dev/null 2> /dev/null

  12. echo "Checking last id..."
  13. sleep 1
  14. LASTIDNEW=$(curl --basic --user $TUSER:$TPASS http://twitter.com/statuses/user_timeline.xml 2>/dev/null | xsltproc $XSLPATH - | grep -v ^$ | tail -n 1)

  15. if [ $LASTIDOLD -eq $LASTIDNEW ]; then
  16. echo "Sending failed!";
  17. else
  18. echo "ok";
  19. fi


Искуственную задержку в 18 строке пришлось добавить, потому что один раз id оказались одинаковыми, хотя сообщение и дошло.
Теперь осталось записать пароли в ~/.twit/pass:
  1. TUSER=user
  2. TPASS=pass
UPD. На самом деле это все неправильно :-) Надо анализировать ответ при отправке нового статуса и по ответу определять дошло ли сообщение. Обязуюсь исправить.

Используем 2+ провайдера (вторая часть)

Продолжим настройку нашего шлюза, про который я говорил в предыдущей статье. Напомню, там мы настроили правила маршрутизации, теперь нам надо заняться iptables. Сейчас мы настроим сеть состоящую из шлюза и сервера. На шлюзе будет работать SSH и DNS, а сервер у нас будет виндовый на нем у нас RDP и SMTP. Сеть будет настроена таким образом, что через любой из внешних айпишников мы сможем подключаться к любому из серверов, а SMTP сервер будет выходить наружу через основного провайдера.
Ну и конечно, же начнем с переменных, причем вынесем следующие настройки в отдельный файл, это нам сильно пригодиться в будущем:

#!/bin/bash

export GLOBAL_ETH_PRIM=eth1
export GLOBAL_ETH_SEC=eth2
export GLOBAL_IP_PRIM=10.10.10.10
export GLOBAL_IP_SEC=20.20.20.20
export MARK_PRIM=10
export MARK_SEC=20

Назовем этот файл ipt_p1.conf. А содержит он данные о том, какой из интерфейсов является главным, а какой запасным (PRIM и SEC соответственно) и значения для маркировки пакетов.
Перейдем к основному файлу конфигурации iptables, назовем его ipt.conf. Запишем переменные ;-)

#!/bin/bash
IPTABLES=/sbin/iptables
MODPROBE=/sbin/modprobe

Это для того, чтобы меньше зависеть от дистрибутива - пути к исполняемым файлам.

LOCAL_ETH=eth0
GLOBAL_ETH_P1=eth1
GLOBAL_ETH_P2=eth2
LOCAL_IP=192.168.0.1
LOCAL_NET=192.168.0.0/24
GLOBAL_IP_P1=10.10.10.10
GLOBAL_IP_P2=20.20.20.20

Тут мы описали конфигурацию нашей сети, по порядку: локальный интерфейс, интерфейсы, которые смотрят к провайдерам, локальный айпишник и подсеть, айпишники, которые выданы провайдерами.

SRV11=192.168.0.11
SRV12=192.168.0.12

А это наш сервер, для которого мы настраивали маршрутизацию на основе политик, используя метки. Как я уже говорил этот сервер на своем сетевом интерфейсе имеет два айпишника, чуть ниже я расскажу для чего это нам пригодиться.
. $1

Зацепили внешние настройки, в данном случае это будет наш файл ipt_p1.conf.
Хватит о скучном, приступим к настройке, причем попытаемся все сделать красиво:

echo "[+] Flushing existing iptables rules..."
$IPTABLES -F
$IPTABLES -F -t nat
$IPTABLES -F -t raw
$IPTABLES -F -t mangle
$IPTABLES -X
$IPTABLES -P INPUT DROP
$IPTABLES -P OUTPUT DROP
$IPTABLES -P FORWARD DROP

Очищаем все правила iptables, в первой строке говорим, что делаем, почему по английски, а чтобы не было проблем с кодировками. Последние три строчки устанавливают правила по умолчанию - все пакеты не подходящие под список правил будут просто отброшены.

$MODPROBE ip_conntrack
$MODPROBE iptable_nat

Загрузили модули ядра, которые будем использовать.
Теперь пройдемся по цепочкам iptables и заполним их необходимыми правилами:

echo "[+] Setting up INPUT chain..."

$IPTABLES -A INPUT -m state --state INVALID -j DROP
$IPTABLES -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

Используя возможности модуля state мы отбрасываем некорректные пакеты и принимаем пакеты относящиеся к уже установленным соединениям либо ко вторичными соединениям (таким как передача данных в ftp).
$IPTABLES -A INPUT -p tcp --dport 22 --syn -m state --state NEW -j ACCEPT

Принимаем подключения по SSH отовсюду.
$IPTABLES -A INPUT -i $LOCAL_ETH -s $LOCAL_NET -j ACCEPT

Локальный трафик будет ходить без ограничений, хотя это не всегда правильно.
$IPTABLES -A INPUT -i lo -j ACCEPT

Тоже на localhost.
Продолжаем с цепочкой OUTPUT:

echo "[+] Setting up OUTPUT chain..."

$IPTABLES -A OUTPUT -m state --state INVALID -j DROP
$IPTABLES -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

Эти правила аналогичны правилам в цепочке INPUT.
$IPTABLES -A OUTPUT -o $GLOBAL_ETH_PRIM -p udp --dport 53 -j ACCEPT

Мы разрешили работать нашему DNS серверу через основного провайдера
$IPTABLES -A OUTPUT -o $GLOBAL_ETH_PRIM -p tcp --dport 22 --syn -m state --state NEW -j ACCEPT

А также разрешили выходить наружу по SSH.
$IPTABLES -A OUTPUT -o $LOCAL_ETH -d $LOCAL_NET -m state --state NEW -j ACCEPT

Опять же на исходящий локальный трафик ограничений нет.
Переходим к обработке трафика из локальной сети:

echo "[+] Setting up FORWARD chain..."

$IPTABLES -A FORWARD -m state --state INVALID -j DROP
$IPTABLES -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT

Все те же два удобных правила.
$IPTABLES -A FORWARD -i $GLOBAL_ETH_P1 -d $SRV11 -p tcp --dport 25 --syn -m state --state NEW -j ACCEPT
$IPTABLES -A FORWARD -i $GLOBAL_ETH_P2 -d $SRV12 -p tcp --dport 25 --syn -m state --state NEW -j ACCEPT
$IPTABLES -A FORWARD -i $GLOBAL_ETH_P1 -d $SRV11 -p tcp --dport 3389 --syn -m state --state NEW -j ACCEPT
$IPTABLES -A FORWARD -i $GLOBAL_ETH_P2 -d $SRV12 -p tcp --dport 3389 --syn -m state --state NEW -j ACCEPT

Так у нас получается, что пакеты приходящие на первого провайдера пропускаются только на первый айпишник сервера, второго - на второй.

$IPTABLES -A FORWARD -i $LOCAL_ETH -s $SRV11 -j ACCEPT
$IPTABLES -A FORWARD -i $LOCAL_ETH -s $SRV12 -j ACCEPT

Разрашаем весь исходящий трафик с нашего сервера, опять же это не совсем правильно.
Далее идут правила NAT:

$IPTABLES -t nat -A POSTROUTING -s $SRV11 -p tcp --dport 25 -j SNAT --to-source $GLOBAL_IP_PRIM
$IPTABLES -t nat -A POSTROUTING -s $SRV12 -p tcp --dport 25 -j SNAT --to-source $GLOBAL_IP_PRIM

Все, что наш сервер попытается отправить по SMTP пойдет через основного провайдера.
И опять самое интересное нам осталось на последок. Переходим к PREROUTING, здесь то мы и воспользуемся возможностью маркировать пакеты, которая нам понадобится для маршрутизации вот в этих двух строчках:

ip rule add from $SRV11 fwmark 10 table T1
ip rule add from $SRV12 fwmark 20 table T2

Итак, наши правила:

$IPTABLES -t mangle -A PREROUTING -i $LOCAL_ETH -s $SRV11 -p tcp --dport 25 -j MARK --set-mark $MARK_PRIM
$IPTABLES -t mangle -A PREROUTING -i $LOCAL_ETH -s $SRV12 -p tcp --dport 25 -j MARK --set-mark $MARK_PRIM

Все пакеты уходящие с нашего внутреннего сервера на 25 порт мы маркируем значением $MARK_PRIM. Давайте проследим, что это нам дает: исходящий пакет маркируется значением 10, значит маршрутизироваться он будет по таблице T1, а соответствуя этой таблице пакет должен уйти через первого провайдера, в цепочке FORWARD есть разрешающее правило, поэтому пакет безпрепятственно проходит - все правильно это нам и требовалось.
Теперь нам надо разобраться с соединениями идущими к нам. Сначала, конечно же, должен отработать DNAT:

$IPTABLES -t nat -A PREROUTING -i $GLOBAL_ETH_P1 -d $GLOBAL_IP_P1 -p tcp --dport 25 -j DNAT --to-destination $SRV11
$IPTABLES -t nat -A PREROUTING -i $GLOBAL_ETH_P1 -d $GLOBAL_IP_P1 -p tcp --dport 3389 -j DNAT --to-destination $SRV11
$IPTABLES -t nat -A PREROUTING -i $GLOBAL_ETH_P2 -d $GLOBAL_IP_P2 -p tcp --dport 25 -j DNAT --to-destination $SRV12
$IPTABLES -t nat -A PREROUTING -i $GLOBAL_ETH_P2 -d $GLOBAL_IP_P2 -p tcp --dport 3389 -j DNAT --to-destination $SRV12

Вроде бы все правильно, проверяем: пакет приходит на внешний интерфейс шлюза, в зависимости от принадлежности интерфейса провайдеру, он перенаправляется на первый или второй айпишник внутреннего сервера, сервер отвечает с того же(!) айпишника, пакет на шлюзе маршрутизируется по основной таблице, проходит через FORWARD и отправляется через основного провайдера, а вот это уже не правильно, ведь пакет мог прийти и через запасного провайдера. Исправляем, добавляя правила:

$IPTABLES -t mangle -A PREROUTING -i $LOCAL_ETH -s $SRV11 -p tcp --sport 25 -j MARK --set-mark $MARK_PRIM
$IPTABLES -t mangle -A PREROUTING -i $LOCAL_ETH -s $SRV11 -p tcp --sport 3389 -j MARK --set-mark $MARK_PRIM
$IPTABLES -t mangle -A PREROUTING -i $LOCAL_ETH -s $SRV12 -p tcp --sport 25 -j MARK --set-mark $MARK_SEC
$IPTABLES -t mangle -A PREROUTING -i $LOCAL_ETH -s $SRV12 -p tcp --sport 3389 -j MARK --set-mark $MARK_SEC

Теперь на обратном пути мы маркируем пакеты в соответствии с адресом, с которого они отправляются. Далее в дело вступают таблицы маршрутизации T1 и T2, поэтому решение через какой интерфейс отправлять пакеты принимается правильное.
Все! Готово. Для применения правил выполняем команду "./ipt.conf ipt_p1.conf". Теперь наши сервера доступны, пока хотя бы один из провайдеров дает нам доступ в интернет.
Еще хотел рассказать, как можно переключаться между провайдерами и сделать парочку замечаний, но объем статьи и так уже слишком большой, видимо будет третья часть.

Скачать скрипты из первой и второй части. (зеркало)


p.s. Написано, чтобы понять самому и рассказать другим.©

среда, 18 марта 2009 г.

Используем 2+ провайдера (первая часть)

Здесь я хочу рассказать о настройке шлюза на Linux'e, для использования 2-х (и более) провайдеров интернета.
Для настройки мы будем использовать возможности iptables и утилиты ip из пакета, который как правило называется iproute2. А для решения поставленной задачи пакеты мы будем маршрутизировать на основе "policy routing" (т.е. маршрутизация на основе политик), а не "destination routing" (маршрутизация на основе адреса получателя).
Итак, приступим. Для начала определимся с переменными:

#!/bin/bash

IF1=eth1
IF2=eth2

IF - это сетевые интерфейсы, которые смотрят в интернет, через наших провайдеров

IP1=10.10.10.10
IP2=20.20.20.20

IP - это наши внешние IP-адреса, которые нам выдали провайдеры

P1=10.10.10.1
P2=20.20.20.1

P - это шлюзы по умолчанию у наших провайдеров
Policy routing позволяет выполнять маршрутизацию на основе адреса источника поэтому перечислим сервера которые будут учавствовать:

SRV11=192.168.0.11
SRV12=192.168.0.12

Здесь SRV11 и SRV12 - это два айпишника одного и тогоже сервера (это важно!), это позволяет одному серверу обрабатывать входящие соединения с двух провайдеров. Конечно же, существуют и другие варианты реализовать эту возможность, но я буду использовать именно айпишники, мне кажется для начала так будет проше.
Ну а теперь самое интересное - пишем правило для маршрутизации.
Первое что мы должны сделать это добавить свои таблицы маршрутизации, для этого необходимо отредактировать файл /etc/iproute2/rt_tables, например так:

#echo "101 T1" >> /etc/iproute2/rt_tables
#echo "102 T2" >> /etc/iproute2/rt_tables

Заполняем первую таблицу:

ip route add $P1_NET dev $IF1 src $IP1 table T1
ip route add default via $P1 table T1

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

ip route add $P2_NET dev $IF2 src $IP2 table T2
ip route add default via $P2 table T2

Затем разберемся с основной таблицей, которая называется "main". Ее мы видим, когда набираем ip route:

ip route add $P1_NET dev $IF1 src $IP1
ip route add $P2_NET dev $IF2 src $IP2
ip route add default via $P1 metric 10

Первые две строчки аналогичны предыдущим записям, только опущено "table main". В третьей строчке задается маршрут по умолчанию с указанием метрики.
На этом с маршрутизацией разобрались, чтобы посмотреть что у нас находится в таблице маршрутизации можно выполнить команду "ip route show table <имя таблицы>". Теперь приступим к правилам. Как раз по правилам и будет приниматься решения какой пакет по какой таблице будет маршрутизироваться.

ip rule add from $IP1 table T1
ip rule add from $IP2 table T2

Здесь мы указали, что если адрес источника равен первому внешнему адресу, тогда маршрутизация выполняется по таблице T1. Аналогично вторая запись.
И наконец самое интересное:

ip rule add from $SRV11 fwmark 10 table T1
ip rule add from $SRV12 fwmark 20 table T2
Используя iptables мы можем маркировать интересующие нас пакеты и маршрутизировать их на основе этих меток. Собственно здесь мы добавили два правила: для пакетов, имеющих метку 10, использовать таблицу T1, для пакетов с меткой 20 - T2. Сейчас возможно не очень понятно для чего это может потребоваться, но из правил iptables все станет ясно. Для просмотра правил выполняем "ip rule", при маршрутизации они проверяются по порядку.
Ну вот половина работы сделана осталось написать правила для iptables, об этом мы поговорим во второй части.

p.s. Написано, чтобы понять самому и рассказать другим.©