The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]

Каталог документации / Раздел "Безопасность" (Архив | Для печати)

Установка IPSEC соединения между компьютерами Linux (FreeS/WAN) и Windows в Transport Mode c использованием PSK.


Автор: Alexey Aksenov
Оригинал: http://www.ezh.msk.ru/article/ipsec/

Оглавление

Часть сугубо философская о смысле жизни, в которой Вини-Пух. то есть, нет, Eжик! рассуждает о смысле жизни и IPSEC.

Начнем с отвлеченных рассуждений о соединении IPSEC, его пользе и применении. Обратите внимание, что в названии статьи стоит transport mode (транспортный режим), кроме transport mode есть другой режим работы IPSEC, называемый tunnel mode (туннельный режим). В чем их отличие? Как правило, туннельный режим предполагает шифрование всего пакета, включая заголовок сетевого уровня. Туннельный режим применяется в случае необходимости скрытия информационного обмена организации с внешним миром. Например, нам нужно соединить две сети, имеющих доступ к агрессивной информационной среде (Интернету) - туннельный режим идеально подходит для решения подобных задач. При этом, адресные поля заголовка сетевого уровня пакета, использующего туннельный режим, заполняются межсетевым экраном организации и не содержат информации о конкретном отправителе пакета. При передаче информации из внешнего мира в локальную сеть организации в качестве адреса назначения используется сетевой адрес межсетевого экрана. После расшифровки межсетевым экраном начального заголовка сетевого уровня пакет направляется получателю. Транспортный же режим используется для шифрования поля данных IP пакета, содержащего протоколы транспортного уровня (TCP, UDP, ICMP), которое, в свою очередь, содержит информацию прикладных служб. Примером применения транспортного режима является установка шифрованных соединений по вышеперечисленным протоколам между двумя хостами. Для аутентификации соединения мы используем PSK (publicly shared key) - публичный общий ключ.
Установка связи c использованием IPSEC в транспортном режиме между двумя машинами, одна из которых работает с использованием операционной системы windows 2к и выше, а другая, под управлением ОС Linux и является целью этой статьи. Причем нам не важно, стоят ли эти машины рядом, или находятся в различных подсетях, на значительном расстоянии друг от друга. Надо только помнить, что между машинами не должно быть NAT'a и неправильно настроенных фаеволов. Пример использования транспортного режима: на машине с windows установлена MSSQL и машина под Linux'ом должна получать c нее данные или на машине с linux крутится Oracle или Postgres, или Mysql (или что-либо еще на ваше усмотрение, так как если нигде ничего не крутится, то зачем вообще заставлять себя читать этот текст?) и с windows машины мы должны получать доступ к этим СУБД. Короче есть работающие сервисы, которые не шифруют (или шифруют, но не так, как нам нравится) трафик, а мы должны сделать так, что добрый хакер(advanced user/super advanced lamer) не узнал наши секретные секреты. Все это нам обеспечит IPSEC.
Данное описание подразумевает, что у нас будет работать только протокол ESP (Encapsulating Security Payload) с использованием MD5 хеша и шифрования 3DES. Просьба помнить, что в транспортном режиме ESP шифрует только полезные данные, а не весь пакет (например, инкапсуляция при туннелировании),, поэтому злоумышленник может спокойно изменить заголовок. Однако это очень страшный и редкий злоумышленник, занесенный в красную книгу, работающий за очень приличные деньги. Для пресечения этого безобразия крутите AH(Authentication Header). Вообще-то в FreeS/Wan, начиная с версии 2.05, отказались от AH совсем, так как два хороших человека Niels Ferguson и Bruce Schneier привели пару аргументов в документе A Cryptographic Evaluation of IPsec, суть которых в том, что совместное использование AH и ESP, как ни парадоксально, только увеличивает вероятность взлома. Cам по себе AH обеспечивает только целостность информации за счет создания хеша пакета (включая заголовок), не обеспечивая конфиденциальности (IMHO необходимость обеспечивать целостность такого рода без шифрования передаваемых данных мало кому нужна).
У кого-нибудь может возникнуть вопрос, а почему бы для обеспечения безопасности просто не использовать stunnel например или ssh и не заморачиваться с IPSEC? Ответ прост - дело личных предпочтений =). Лично для меня что ssh, что stunnel - времянки. К тому же программы stunnel и ssh не входят в стандартную поставку windows, то есть их нужно скачать, настроить, запустить (IPSEC нужно только настроить и запустить), а в процессе настройки нужно будет прописывать правила для каждого типа соединений, причем защищаемые сервисы должны работать, используя TCP(мы, конечно же, можем инкапсулировать UDP в TCP используя netcat. Вы себя еще нормально чувствуете? Описываемые кошмары нормально воспринимаются?). Конечно, сервисов на каждом сервере у нас достаточно, как и самих серверов, так что скоро приходится запускать по паре stunnel на серверах (один в режиме server, другой в режиме client) или десяток другой ssh сессий. Вообщем, нас спасет IPSEC, который шифрует весь трафик (хотя можно и не весь - это как вы фильтры настроите). Вот как. Надеюсь, что IPSEC может помочь с решением пары ситуаций, убедил? Если нет, тогда настраивайте, пробуйте, а там сами решите - не нужно оно вам или все-таки нужно. (Конечно, читая данный абзац, можно вспомнить и о PPTP, и о L2TP и вообще, о чем-то своем родном и близком, но мы все же возьмем себя в руки и продолжим нашу кровавую дедективу)

к оглавлению
 

Часть практическая linux'овая, в которой мы устанавливаем FreeS/WAN v1.99 в gentoo linux, а некоторые, особо смелые, делают небольшой, но очень симпатичный финт ушами под чутким руководством Ежа.

/ЗЫ. Пользователи других дистрибутивов могут изменить данный раздел в соответствии со своими требованиями/
FreeS/WAN установлен =)

Далее проверяем работоспособность FreeS/WAN и, если все хорошо, редактируем ipsec.conf и ipsec.secrets.

ipsec.conf

# basic configuration
config setup
    interfaces="ipsec0=<интерфейс>"
    klipsdebug=none
    plutodebug=none
    plutoload=%search
    plutostart=%search
    uniqueids=yes

conn lin-win
    left=<linux_ip>
    right=<windows_ip>
    type=transport
    pfs=no
    auth=esp
    auto=start

Где <интерфейс> это ваш интерфейс, например eth0 (причем у меня это был 802.1d бридж, состоящий из двух физических интерфейсов eth2 и eth3, созданный соответственно с помощью bridge-utils), <linux_ip> - IP адрес интерфейса, <windows_ip> - IP адрес windows машины.

ipsec.secrets

<linux_ip> <windows_ip>: PSK "<key>"

Где <key> это ваше секретное слово (PSK - publicly shared key), <linux_ip> - IP адрес интерфейса, <windows_ip> - IP адрес windows машины(можно указать %any для всех машин).

Далее делаем:

echo "0" > /proc/sys/net/ipv4/conf/<интерфейс>/rp_filter

или

sysctl -w 'net.ipv4.conf.<интерфейс>.rp_filter=0'

это у нас отключает так называемый Reverse Path Filtering. Принцип действия этого механизма: Если ответ на текущий пакет не может уйти через тот же интерфейс (когда приходит через один интерфейс, а уходит через другой), пакет отфильтровывается. Мы эту штуку отключаем, что в принципе иногда ужасает некоторых товарищей.
Что бы все было нормально нужно:
  1. при настройке внимательно читать документацию
  2. устанавливать политики IPSEC Require! чтоб незашифрованный трафик был просто-напросто запрещен
  3. использовать такую замечательную вещь как iptables, которая умеет выбирать пакеты не только по портам и адресам, но и по протоколам! (и я надеюсь, вы обычно настраиваете защиту от IP Spoofing)
  4. использовать еще более замечательную вещь - голову =) эта вещь даже круче iptables! Пользуйтесь!
Теперь небольшой, но очень симпатичный финт ушами =) Если у нас linux машина одновременно является гейтвейем windows машины, то. .то информация предназначенная непосредственно linux машине посылается как и положено, зашифрованная IPSEC, а информация, которая должна маршрутизироваться пересылается в незашифрованном виде (учитывая, что это транспортный режим, я вроде ничего удивительного не сказал, вроде оно так и должно быть - типа "трава зеленая"). А теперь пробуем пинговать что-нибудь далекое. Ха! Шутка! Пакеты идут так: windows ---> <interface> ---> internet ---> <ipsec> ---> windows, то есть незашифрованные пакеты для маршрутизации отсылаются linux машине на обычный интерфейс, а из Интернета linux возвращает их через ipsec интерфейс. Это фича. Поэтому те, кому надо делают например так:

iptables -t mangle -A PREROUTING -i <внешний интефейс> -j MARK --set-mark 1
ip rule add fwmark 1 table 100
ip route add table 100 dev <interface>

, где <interface> - интерфейс, на который вешали ipsec и <внешний интефейс> - это интерфейс подключенный к другим сетям. (в моем случае такими интерфейсами являлись eth0, eth1 и все ppp - ppp+ )

к оглавлению
 

Часть практическая windows'овая, в которой мы ничего не делаем, кроме настройки IPSEC соединения.

/ЗЫ. Данные настройки описываюся для WinXP, но IMHO в Win2k особых отличий быть не должно/

Создаем политику безопасности IPSEC

Открываем Control-Panel -> Administrative Tools -> Local Security Policy и щелкаем правой кнопкой мышки на IP Security Polices on Local Computer, как это показано на рис.1.
Затем выбираем меню Create IP Security Policy. На вкладке IP Security Policy Name задайте любое понятное вам название - например "win-lin". Оставляем пункт Activate the default response rule выбранным. На вкладке Default Response Rule Authentication Method выбираем опцию Use this string to protect the key exchange (preshared key) и задаем наш <key>, как это показано на рис.2 и создаем политику.

к оглавлению
 

Добавляем правило безопасности в нашу политику.

На вкладке <Имя> Properties нажимаем кнопку Add и добавляем новое правило как это показано на рис.3.
На вкладке Tunnel End point ничего не трогаем - оставляем выбранным правило This rule does not specify a tunnel (все-таки мы настраивает транспортный режим, а не туннельный). На вкладке Network Type выбираем Local area network (LAN). Затем на вкладке Authentication Method выбираем опцию Use this string to protect the key exchange (preshared key) и задаем наш <key>.

к оглавлению
 

Добавляем фильтр для трафика, который будем шифровать.

На вкладке IP Filter List выбираем Add и добавляем новый фильтр. У вас должно появиться окно аналогичное рис.4.
Выбираем имя фильтра и нажимаем Add, после чего появляется IP Filter Wizard. На вкладке IP Traffic source оставляем выбранным вариант My IP Address, а на вкладке IP Traffic Destination выбираем A specific IP Address, как это показано на рис.5.
и задаем <linux_ip>. Вкладку IP Protocol Type не трогаем(оставляем any) и создаем фильтр. Должно получиться что-то типа рис.6. и затем выбираем вновь созданный фильтр на вкладке IP Filter List.

к оглавлению
 

Добавляем фильтр действий (Filter Action).

На вкладке Filter Action, которая служит для определения действий, происходящих при попытках зашифрованных/не зашифрованных соединений, создаем новый фильтр, нажав на кнопку Add. На вкладке Filter Action Name задаем имя фильтра. На вкладке Filter Action General Option оставляем Negotiate security. На вкладке Communicating with computer that do not support IPSec оставляем выбранной опцию Do not communicate with computer that do not support IPSec, как это показано на рис.7.
На следующей вкладке IP Traffic Security выбираем пункт Custom и нажимаем на кнопку Settings, и выбираем, соответственно, алгоритм ответственный за целостность данных MD5, а алгоритм ответственный за шифрование 3DES - рис.8. Session key settings - добавить по вкусу, однако, лучше не перебарщивать. Создаем фильтр и выбираем его на вкладке Filter Action. И, наконец то, создаем правило безопасности.

к оглавлению
 

Заключительная настройка IPSEC.

Если вы все правильно сделали (должно получиться что-то вроде рис.9) и запустили IPSEC на машине с linux, то у вас скоро все заработает. Закрываем вкладку <Имя> Properties, нажав на кнопку Close.

к оглавлению
 

Часть кульминационная, в которой мы запускаем IPSEC соединение.

В linux'e даем команду /etc/init.d/ipsec start. В windows'е щелкаем правой кнопкой мыши на наше вновь созданное правило и активируем его, выбрав пункт Assign, рис.10
Параллельно в windows'e вы можете пустить ping и если пошли строчки Negotiating IP Security, то значит, системы выбирают общие типы шифрования. Если строки Negotiating IP Security не прекращаются, то вы что-то не так сделали. Обратите внимание на параметр pfs - на компьютерах, устанавливающих связь, он должен иметь одинаковые значения и т.д. - смотрите логи, разбирайтесь. Если же все заработало, то компьютеры видят друг друга идеально. Вы можете убедиться, что IPSEC действительно заработал, используя оснастку IP Security Monitor в WinXP, как это показано на рис.11. или утилиту ipsecmon.exe в win2k, или что-либо еще на ваш выбор (например, Network Monitor).
Процесс установки IPSEC соединения под linux'ом выглядит так:
Выдержка из message.log

Feb 13 12:49:05 obelisk ipsec_setup: Starting FreeS/WAN IPsec 1.99...
Feb 13 12:49:05 obelisk ipsec_setup: Using /lib/modules/2.4.24/kernel/net/ipsec/ipsec.o
Feb 13 12:49:05 obelisk klips_info:ipsec_init: KLIPS startup, FreeS/WAN IPSec version: 1.99
Feb 13 12:49:05 obelisk ipsec_setup: KLIPS debug `none'
Feb 13 12:49:05 obelisk ipsec_setup: KLIPS ipsec0 on homelan <linux_ip>/255.255.255.0 broadcast 10.255.255.255
Feb 13 12:49:05 obelisk ipsec__plutorun: Starting Pluto subsystem...
Feb 13 12:49:05 obelisk ipsec_setup: ...FreeS/WAN IPsec started
Feb 13 12:49:05 obelisk pluto[17066]: Starting Pluto (FreeS/WAN Version 1.99)
Feb 13 12:49:05 obelisk pluto[17066]: added connection description "win-lin"
Feb 13 12:49:05 obelisk pluto[17066]: listening for IKE messages
Feb 13 12:49:05 obelisk pluto[17066]: adding interface ipsec0/homelan <linux_ip>
Feb 13 12:49:05 obelisk pluto[17066]: loading secrets from "/etc/ipsec.secrets"
Feb 13 12:49:05 obelisk pluto[17066]: "win-lin" #1: initiating Main Mode
Feb 13 12:49:11 obelisk pluto[17066]: packet from <windows_ip>:500: ignoring Vendor ID payload
Feb 13 12:49:11 obelisk pluto[17066]: "win-lin" #2: responding to Main Mode
Feb 13 12:49:11 obelisk pluto[17066]: "win-lin" #2: sent MR3, ISAKMP SA established
Feb 13 12:49:11 obelisk pluto[17066]: "win-lin" #3: responding to Quick Mode
Feb 13 12:49:11 obelisk pluto[17066]: "win-lin" #3: IPsec SA established
Feb 13 12:49:15 obelisk pluto[17066]: "win-lin" #1: ignoring Vendor ID payload
Feb 13 12:49:15 obelisk pluto[17066]: "win-lin" #1: ISAKMP SA established
Feb 13 12:49:15 obelisk pluto[17066]: "win-lin" #4: initiating Quick Mode PSK+ENCRYPT+DISABLEARRIVALCHECK
Feb 13 12:49:15 obelisk pluto[17066]: "win-lin" #4: IKE message has the Commit Flag set but Pluto doesn't implement this feature; ignoring flag
Feb 13 12:49:15 obelisk pluto[17066]: "win-lin" #4: ignoring informational payload, type IPSEC_RESPONDER_LIFETIME
Feb 13 12:49:15 obelisk pluto[17066]: "win-lin" #4: sent QI2, IPsec SA established
Feb 13 12:49:15 obelisk pluto[17066]: "win-lin" #4: IKE message has the Commit Flag set but Pluto doesn't implement this feature; ignoring flag
Feb 13 12:49:15 obelisk pluto[17066]: "win-lin" #4: message ignored because it contains an payload type (ISAKMP_NEXT_HASH) unexpected in this message
Feb 13 12:49:15 obelisk pluto[17066]: "win-lin" #2: ignoring Delete SA payload
Feb 13 12:49:15 obelisk pluto[17066]: "win-lin" #2: received and ignored informational message
Feb 13 12:49:15 obelisk ipsec__plutorun: 104 "win-lin" #1: STATE_MAIN_I1: initiate
Feb 13 12:49:15 obelisk ipsec__plutorun: 010 "win-lin" #1: STATE_MAIN_I1: retransmission; will wait 20s for response
Feb 13 12:49:15 obelisk ipsec__plutorun: 003 "win-lin" #1: ignoring Vendor ID payload
Feb 13 12:49:15 obelisk ipsec__plutorun: 106 "win-lin" #1: STATE_MAIN_I2: sent MI2, expecting MR2
Feb 13 12:49:15 obelisk ipsec__plutorun: 108 "win-lin" #1: STATE_MAIN_I3: sent MI3, expecting MR3
Feb 13 12:49:15 obelisk ipsec__plutorun: 004 "win-lin" #1: STATE_MAIN_I4: ISAKMP SA established
Feb 13 12:49:15 obelisk ipsec__plutorun: 112 "win-lin" #4: STATE_QUICK_I1: initiate
Feb 13 12:49:15 obelisk ipsec__plutorun: 003 "win-lin" #4: ignoring informational payload, type IPSEC_RESPONDER_LIFETIME
Feb 13 12:49:15 obelisk ipsec__plutorun: 004 "win-lin" #4: STATE_QUICK_I2: sent QI2, IPsec SA established
Вывод tcpdump:

19:39:03.810739 <windows_ip> > <linux_ip>: ESP(spi=0x356646be,seq=0xd4c) (DF)
19:39:03.811865 <linux_ip> > <windows_ip>: ESP(spi=0x110d41a7,seq=0xde0) (DF) [tos 0x10]
19:39:03.811839 <windows_ip> > <linux_ip>: ESP(spi=0x356646be,seq=0xd4d) (DF)
19:39:03.812325 <windows_ip> > <linux_ip>: ESP(spi=0x356646be,seq=0xd4e) (DF)
Вывод ipsec look:

ipsec look
obelisk Fri Feb 13 12:56:31 MSK 2004
<linux_ip>/32 -> <windows_ip>/32 => esp0x25e409d0@<windows_ip> (0)
ipsec0->homelan mtu=16260(1500)->1500
esp0x25e409d0@<windows_ip> ESP_3DES_HMAC_MD5: dir=out src=<linux_ip> iv_bits=64bits iv=0x51fd9266fb73823c ooowin=64 alen=128 aklen=128 eklen=192 life(c,s,h)=addtime(436,0,0)
esp0x722533e4@<windows_ip> ESP_3DES_HMAC_MD5: dir=out src=<linux_ip> iv_bits=64bits iv=0xe9fbc10da8750ac4 ooowin=64 alen=128 aklen=128 eklen=192 life(c,s,h)=addtime(440,0,0)
esp0x72bdf8a9@<linux_ip> ESP_3DES_HMAC_MD5: dir=in src=<windows_ip> iv_bits=64bits iv=0xffda9d19aae5b094 ooowin=64 seq=75 bit=0xffffffffffffffff alen=128 aklen=128 eklen=192 life(c,s,h)=bytes(4350,0,0)addtime(440,0,0)usetime(440,0,0)packets(75,0,0) idle=436
esp0x72bdf8aa@<linux_ip> ESP_3DES_HMAC_MD5: dir=in src=<windows_ip> iv_bits=64bits iv=0x9f82063ca057de6e ooowin=64 seq=7162 bit=0xffffffffffffffff max_seq_diff=1 alen=128 aklen=128 eklen=192 life(c,s,h)=bytes(445730,0,0)addtime(436,0,0)usetime(436,0,0)packets(7162,0,0) idle=0
Destination Gateway Genmask Flags MSS Window irtt Iface
<nat_ip> 0.0.0.0 255.255.255.0 U 0 0 0 homelan
<net_ip> 0.0.0.0 255.255.255.0 U 0 0 0 ipsec0
<windows_ip> <windows_ip> 255.255.255.255 UGH 0 0 0 ipsec0
Посмотреть под linux'ом все незашифрованные пакеты, которыми обмениваются ваши компьютеры вы можете c помощью tcpdump - "tcpdump -i <интерфейс> not esp". Если вы настроили все правильно, то это будут только arp запросы и пакеты не имеющие отношения к <windows_ip>.

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

Для начала давайте посмотрим, что сделано и что мы должны были сделать. Мы установили IPSEC соединение, обеспечивающие шифрование между двумя нашими компьютерами. Вроде бы мы добились своей цели, однако все зависит от ситуации. Для уменьшения нештатных ситуаций (это когда все куда-то бегут и отовсюду слышится: "хакают! хакают!", хотя большинство спортсменов-бегунов имеют об этом весьма туманные представления) необходимо обязательно установить защиту от IP спуфинга на интерфейсах с выключенными rp_filter'ми. Потом мы должны быть уверенны, что наши сервера будут взаимодействовать только средствами IPSEC. В windows это может быть обеспечено отключением опции Allow unsecured communication with non-IPSec-aware computer и Accept unsecured communication, but always respond using IPSec в политике безопасности IPSEC. В linux это обеспечивается опцией auto=start, которая автоматически запускает шифрованный туннель и фильтрацией трафика с помощью iptables, разрешая взаимодействие только с помощью IPSEC, отбрасывая нешифрованный трафик:

iptables -A INPUT -p udp -i <интерфейс> -s <windows_ip> --sport 500 --dport 500 -j ACCEPT
iptables -A OUTPUT -p udp -o <интерфейс> -d <windows_ip> --sport 500 --dport 500 -j ACCEPT

iptables -A INPUT -p esp -i <интерфейс> -s <windows_ip> -j ACCEPT
iptables -A OUTPUT -p esp -o <интерфейс> -d <windows_ip> -j ACCEPT

iptables -A INPUT -i <интерфейс> -s <windows_ip> -j DROP
iptables -A OUTPUT -o <интерфейс> -d <windows_ip> -j DROP
Если необходимо, то можно добавить:

iptables -A INPUT -p ah -i <интерфейс> -s <windows_ip> -j ACCEPT
iptables -A OUTPUT -p ah -o <интерфейс> -d <windows_ip> -j ACCEPT
Так же можно добавить пару правил IDS, чтобы при обнаружении нешифрованных пакетов, не имеющих отношения к ipsec, но имеющих отношение к нашим серверам, нам выдавалось предупреждение, т.к. наличие такого типа трафика является, скорее всего, следствием любопытства какого-нибудь неосторожного травоядного животного. После того как мы разобрались со спуфингом можно вспомнить, что длинна ключа HMAC-MD5 128 бит, а длинна HMAC-SHA1 160 бит. Учитывая что в FreeS/WAN по умолчанию включена возможность автоматического выбора типа хеширования мы можем установить в windows SHA1 вместо MD5. Тогда команда ipsec look будет выдавать нам вместо ESP_3DES_HMAC_MD5 - ESP_3DES_HMAC_SHA1. Также необходимо не забывать о такой возможности как pfs. PFS (Perfect Forward Secrecy) - такая криптосистема, где шифрованный текст не дает никакой информации об открытом тексте, возможно, за исключением его длины. Это гарантия того, что (в случае асимметричного шифрования) временный ключ, вычисленный на основе открытых и секретных ключей, не будет раскрыт, даже если какой-либо из секретных ключей будет скомпрометирован. В linux'е выставляем опцию pfs=yes, в windows'e включаем master key perfect forward secrecy и session key perfect forward secrecy. Ну и напоследок давайте разберемся, через какой промежуток времени будут меняться наши ключи. Если вы внимательно смотрели логи, то могли заметить строку "ignoring informational payload, type IPSEC_RESPONDER_LIFETIME". Эта строка говорит о том, что удаленная сторона (FreeS/WAN) не хочет менять ключ, а надо бы (вольный перевод изысканий Gerrit Hannaert). Применительно к Checkpoint FW рекомендуется в FreeS/WAN установить время жизни ключа несколько меньше, чем в удаленной системе. Думаю аналогичные рекомендации можно дать и для работы с windows. То есть если вы указали в windows время жизни ключа 60 min, добавьте в ipsec.conf опцию keylife=59m (производить смену ключа через 59 минут) и все будет ok. При желании, вы можете устанавливать ipsec соединения, используя сертификаты, а не PSK. Процедура установки соединений c использованием сертификатов достаточно подробно описана в интернете для туннельного режима. Настройка транспортного режима ipsec, использующего сертификаты - аналогична. Вот вроде бы и все.
О всех замечаниях и пожеланиях пишите ezh@ezh.msk.ru.



Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру