Страница 1 из 2
					
				Два канала
				Добавлено: 2010-06-15 8:24:52
				 anton4
				Народ помогите придумать решение есть два интерфейса (шлюза в инет) нужно сделать проброс на каждом интерфейсе 443 и 9091 порта на компьютер в локальной сети. Как это лучше сделать. Желательно средствами pf.
Я делаю так:
Код: Выделить всё
rdr proto $protogroup from any to any port $rdr_port -> $localip
nat on $int_1 proto $protogroup from $localip to any port $rdr_port -> $int_1
nat on $int_2 proto $protogroup from $localip to any port $rdr_port -> $int_2
Но работает только проброс с 1 интрефейса, а со второго таймаут.
 
			
					
				Re: Два канала
				Добавлено: 2010-06-15 12:14:44
				 EARL
				Почитай маны по pf на тему reply-to
			 
			
					
				Re: Два канала
				Добавлено: 2010-06-15 12:34:31
				 anton4
				Вы бы хоть сказали в чем ошибка моя?
			 
			
					
				Re: Два канала
				Добавлено: 2010-06-15 12:38:34
				 Al
				anton4 писал(а):Народ помогите придумать решение есть два интерфейса (шлюза в инет) нужно сделать проброс на каждом интерфейсе 443 и 9091 порта на компьютер в локальной сети. Как это лучше сделать. Желательно средствами pf.
Я делаю так:
Код: Выделить всё
rdr proto $protogroup from any to any port $rdr_port -> $localip
nat on $int_1 proto $protogroup from $localip to any port $rdr_port -> $int_1
nat on $int_2 proto $protogroup from $localip to any port $rdr_port -> $int_2
Но работает только проброс с 1 интрефейса, а со второго таймаут.
 
reply-to +убери нат, +убери any - больше конкретики - меньше гемора потом.
 
			
					
				Re: Два канала
				Добавлено: 2010-06-15 13:14:28
				 anton4
				Код: Выделить всё
rdr on $int_ext2 inet proto $protogroup to $int_ext2 port 443 tag Chanell2 -> \
$ip port 443
rdr on $int_ext2 inet proto $protogroup to $int_ext2 port 9091 tag Chanell2 -> \
$ip port 9091
rdr on $int_ext1 inet proto $protogroup to $int_ext1 port 443 tag Chanell1 -> \
$ip port 443
rdr on $int_ext1 inet proto $protogroup to $int_ext1 port 9091 tag Chanell1 -> \
$ip port 9091
## отвечаем через тот же интерфейс, через который пришел пакет.
## по сути меняем для помеченный пакетов route.
pass in on $int_ext1 reply-to ($int_ext1 $ext_gateway1) inet proto $protogroup \
    tagged Chanell1 keep state
pass in on $int_ext2 reply-to ($int_ext2 $ext_gateway2) inet proto $protogroup \
    tagged Chanell2 keep state
## Разрешаем все исходящие соединения на данном интерфейсе
pass out on $int_ext1 keep state
pass out on $int_ext2 keep state
Так?
 
			
					
				Re: Два канала
				Добавлено: 2010-06-15 13:25:17
				 Al
				Ну, один из вариантов.
Работает?
Может, еще пригодится на первом интерфейсе на выходе отлавливать пакеты с тагом второго и репекидывать их на второй route-to. Аналогично со вторым.
			 
			
					
				Re: Два канала
				Добавлено: 2010-06-15 13:26:59
				 Al
				Не, ступил.
Работает?
			 
			
					
				Re: Два канала
				Добавлено: 2010-06-15 14:36:08
				 anton4
				Проверить смогу только в 17 00 по мск, отпишусь обязательно.
			 
			
					
				Re: Два канала
				Добавлено: 2010-06-15 16:40:22
				 anton4
				неработает
			 
			
					
				Re: Два канала
				Добавлено: 2010-06-16 7:06:47
				 Al
				tcpdump?
			 
			
					
				Re: Два канала
				Добавлено: 2010-06-16 8:14:54
				 anton4
				Окно для тестов не большое. с 17.00 до 18.00 по мск.
Поэтому хотелось бы сразу уточнить кое какие детали.
1. Как наиболее грамотно отследить причину, из за которой не работает? tcpdump -i fxp0? и тупо смотреть куда идут пакеты?
Может есть какой-то более точный способ?
2. Почему мне советовали убрать нат? Этот момент не совсем понятен. С натом и рдром работал хотябы редирект по основному интерфейсу.
			 
			
					
				Re: Два канала
				Добавлено: 2010-06-16 8:23:34
				 Al
				Конфиг целиком покажи.
			 
			
					
				Re: Два канала
				Добавлено: 2010-06-16 8:35:41
				 anton4
				cat /etc/pf.conf
Код: Выделить всё
int_volgalink = "fxp1"
int_local = "re0"
int_utk = "fxp0"
myip = "{------}"
myinetip = "{--------- ----------}"
nonblockport = "{443 9091 80}"
rdr_port = "{443 9091}"
ibank2ip="192.168.2.2"
protogroup = "{ tcp udp }"
ext_gateway1="--------"
ext_gateway2="--------"
set skip on lo0
set loginterface $int_volgalink
set loginterface $int_utk
set state-policy if-bound
scrub in all
#rdr on $int_coltel proto $protogroup from any to $rdr_ip1 port $rdr_port1 -> $rdr_ip1 port 45002
#pass quick on $int_coltel
#rdr on $int_coltel proto $protogroup from any to any port $rdr_port2 -> $rdr_ip2
#rdr on tun0 proto $protogroup from any to any port $rdr_port1 -> $rdr_ip1
#rdr pass proto $protogroup from any to any port $rdr_port -> $ibank2ip 
#nat on $int_utk proto $protogroup from $ibank2ip to any  -> $int_utk 
rdr on $int_utk inet proto $protogroup to $int_utk port 443 tag Chanell2 -> \
$ibank2ip port 443
rdr on $int_utk inet proto $protogroup to $int_utk port 9091 tag Chanell2 -> \
$ibank2ip port 9091
rdr on $int_volgalink inet proto $protogroup to $int_volgalink port 443 tag Chanell1 -> \
$ibank2ip port 443
rdr on $int_volgalink inet proto $protogroup to $int_volgalink port 9091 tag Chanell1 -> \
$ibank2ip port 9091
#rdr pass proto $protogroup from any to any port $rdr_port -> $ibank2ip
#nat on $int_local proto $protogroup from $int_volgalink to $ibank2ip port $rdr_port -> $int_local
#nat on $int_local proto $protogroup from $int_utk to $ibank2ip port $rdr_port -> $int_local
#nat on $int_utk proto $protogroup from $ibank2ip to any port $rdr_port -> $int_utk
#nat on $int_volgalink proto $protogroup from $ibank2ip to any port $rdr_port -> $int_volgalink
#nat on $int_local proto $protogroup from $ibank2ip to any port $rdr_port -> $int_local
#rdr-anchor miniupnpd
#anchor miniupnpd
antispoof for $int_volgalink inet
antispoof for $int_local inet
antispoof for $int_utk inet
block quick inet6 all
pass quick on $int_local from any to any
pass in on $int_volgalink reply-to ($int_volgalink $ext_gateway1) inet proto $protogroup \
    tagged Chanell1 keep state
pass in on $int_utk reply-to ($int_utk $ext_gateway2) inet proto $protogroup \
    tagged Chanell2 keep state
pass out on $int_volgalink keep state
pass out on $int_utk keep state
pass proto tcp from any to any \
    port { smtp, pop3 } keep state
pass proto tcp from any to any port 53
pass quick from any to any
#pass quick on $int_volgalink  proto $protogroup from any to $myinetip port $nonblockport
#pass quick on $int_utk  proto $protogroup from any to $myinetip port $nonblockport
#pass quick on $int_volgalink proto $protogroup from $myinetip to any
#pass quick on $int_utk proto $protogroup from $myinetip to any
#pass quick on $int_volgalink  proto icmp from any to any
#pass quick on $int_utk  proto icmp from any to any
#block all
#pass all
 
			
					
				Re: Два канала
				Добавлено: 2010-06-16 9:03:01
				 Al
				cat /etc/pf.conf
int_volgalink = "fxp1"
int_local = "re0"
int_utk = "fxp0"
myip = "{------}"
myinetip = "{--------- ----------}"
# Если память не изменяет, параметры разделяются запятой
nonblockport = "{443 9091 80}"
rdr_port = "{443 9091}"
ibank2ip="192.168.2.2"
protogroup = "{ tcp udp }"
ext_gateway1="--------"
ext_gateway2="--------"
set skip on lo0
set loginterface $int_volgalink
set loginterface $int_utk
# Уверен, что надо?
set state-policy if-bound
scrub in all
#rdr on $int_coltel proto $protogroup from any to $rdr_ip1 port $rdr_port1 -> $rdr_ip1 port 45002
#pass quick on $int_coltel
#rdr on $int_coltel proto $protogroup from any to any port $rdr_port2 -> $rdr_ip2
#rdr on tun0 proto $protogroup from any to any port $rdr_port1 -> $rdr_ip1
#rdr pass proto $protogroup from any to any port $rdr_port -> $ibank2ip 
#nat on $int_utk proto $protogroup from $ibank2ip to any  -> $int_utk 
# Про таги см. ниже.
rdr on $int_utk inet proto $protogroup to $int_utk port 443 tag Chanell2 -> \
$ibank2ip port 443
rdr on $int_utk inet proto $protogroup to $int_utk port 9091 tag Chanell2 -> \
$ibank2ip port 9091
rdr on $int_volgalink inet proto $protogroup to $int_volgalink port 443 tag Chanell1 -> \
$ibank2ip port 443
rdr on $int_volgalink inet proto $protogroup to $int_volgalink port 9091 tag Chanell1 -> \
$ibank2ip port 9091
#rdr pass proto $protogroup from any to any port $rdr_port -> $ibank2ip
#nat on $int_local proto $protogroup from $int_volgalink to $ibank2ip port $rdr_port -> $int_local
#nat on $int_local proto $protogroup from $int_utk to $ibank2ip port $rdr_port -> $int_local
#nat on $int_utk proto $protogroup from $ibank2ip to any port $rdr_port -> $int_utk
#nat on $int_volgalink proto $protogroup from $ibank2ip to any port $rdr_port -> $int_volgalink
#nat on $int_local proto $protogroup from $ibank2ip to any port $rdr_port -> $int_local
#rdr-anchor miniupnpd
#anchor miniupnpd
antispoof for $int_volgalink inet
antispoof for $int_local inet
antispoof for $int_utk inet
block quick inet6 all
pass quick on $int_local from any to any
# Есть ли смысл в тагах? Ведь трафик делится по входящим интерфейсам. Допиши фром ту для наглядности)
pass in on $int_volgalink reply-to ($int_volgalink $ext_gateway1) inet proto $protogroup \
    tagged Chanell1 keep state
pass in on $int_utk reply-to ($int_utk $ext_gateway2) inet proto $protogroup \
    tagged Chanell2 keep state
# флаги S/SA не помешали бы.
pass out on $int_volgalink keep state
pass out on $int_utk keep state
pass proto tcp from any to any \
    port { smtp, pop3 } keep state
pass proto tcp from any to any port 53
# А это что и зачем?
pass quick from any to any
Дальше смотришь ncpdump"ом где пакеты затыкаются. Более информативного стандартного инструмента нет. 
+pflog.
 
			
					
				Re: Два канала
				Добавлено: 2010-06-16 9:07:11
				 Al
				anton4 писал(а):Окно для тестов не большое. с 17.00 до 18.00 по мск.
Поэтому хотелось бы сразу уточнить кое какие детали.
1. Как наиболее грамотно отследить причину, из за которой не работает? tcpdump -i fxp0? и тупо смотреть куда идут пакеты?
Может есть какой-то более точный способ?
2. Почему мне советовали убрать нат? Этот момент не совсем понятен. С натом и рдром работал хотябы редирект по основному интерфейсу.
1. Да +int_if. Нет. +pflog
2. Редирект должен работать без ната.
 
			
					
				Re: Два канала
				Добавлено: 2010-06-16 9:36:57
				 anton4
				
# Если память не изменяет, параметры разделяются запятой
nonblockport = "{443 9091 80}"
Память все же изменяет, с запятой выдает ошибку.
# Уверен, что надо?
set state-policy if-bound
Код: Выделить всё
set state-policy
* Определяет манеру работы PF с таблицей состояний (см. Keeping State). if-bound - правила привязаны к интерфейсу, на котором открыты. Если трафик соответствует записи, но пересекает интерфейс указанный в ней, то соответствия не произойдет. Тогда пакет должен соответствовать фильтрующему правилу или скинут/отброшен.
* group-bound - также, как и с параметром if-bound, за исключением того, что принимаются интерфейсы одной грунны - например все ppp интерфейсы.
* floating - записи могут соответствовать пакету на любом интерфейсе. Пока пакет соответствует записи не имеет значения, через какой интерфейс он проходит и он будет пропущен. Является значением по умолчанию.
Думаете стоит вообще убрать?
# Есть ли смысл в тагах? Ведь трафик делится по входящим интерфейсам. Допиши фром ту для наглядности)
pass in on $int_volgalink reply-to ($int_volgalink $ext_gateway1) inet proto $protogroup \
tagged Chanell1 keep state
pass in on $int_utk reply-to ($int_utk $ext_gateway2) inet proto $protogroup \
tagged Chanell2 keep state 
Этот момент не понятен имеется ввиду from any to $me?
# флаги S/SA не помешали бы.
pass out on $int_volgalink keep state
pass out on $int_utk keep state
Код: Выделить всё
Определяет флаги, которые должны быть установлены в заголовке TCP при использовании proto tcp. Флаги определяются как flags check/mask. Например: flags S/SA - PF будет смотреть на S и A (SYN и ACK) флаги и соответствовать правилу, если установлен флаг SYN.
Погуглил про флаги нашел как их ставить, примерное описание, но так и не понял что это даст, если можно поясните...
# А это что и зачем?
pass quick from any to any
Это уже просто в конце жест отчаяния  

 
			
					
				Re: Два канала
				Добавлено: 2010-06-16 10:14:16
				 Al
				anton4 писал(а):
# Если память не изменяет, параметры разделяются запятой
nonblockport = "{443 9091 80}"
Память все же изменяет, с запятой выдает ошибку.
 
lan_port="{137:139, 445, 9100}"
на первом же попавшемся. Странно. Может, пробелы? хм...
anton4 писал(а):
# Уверен, что надо?
set state-policy if-bound
Код: Выделить всё
set state-policy
* Определяет манеру работы PF с таблицей состояний (см. Keeping State). if-bound - правила привязаны к интерфейсу, на котором открыты. Если трафик соответствует записи, но пересекает интерфейс указанный в ней, то соответствия не произойдет. Тогда пакет должен соответствовать фильтрующему правилу или скинут/отброшен.
* group-bound - также, как и с параметром if-bound, за исключением того, что принимаются интерфейсы одной грунны - например все ppp интерфейсы.
* floating - записи могут соответствовать пакету на любом интерфейсе. Пока пакет соответствует записи не имеет значения, через какой интерфейс он проходит и он будет пропущен. Является значением по умолчанию.
Думаете стоит вообще убрать?
 
Ну, так прозрачней на первый взгляд. Есть стейт, значит пропускать. Тюнинг можно оставить на потом)
anton4 писал(а):
# Есть ли смысл в тагах? Ведь трафик делится по входящим интерфейсам. Допиши фром ту для наглядности)
pass in on $int_volgalink reply-to ($int_volgalink $ext_gateway1) inet proto $protogroup \
tagged Chanell1 keep state
pass in on $int_utk reply-to ($int_utk $ext_gateway2) inet proto $protogroup \
tagged Chanell2 keep state 
Этот момент не понятен имеется ввиду from any to $me?
 
Ту эни для начала. Ведь сначала сработает редирект.
Я думаю, тут таги излишни. Да и вообще незачем.
anton4 писал(а):
# флаги S/SA не помешали бы.
pass out on $int_volgalink keep state
pass out on $int_utk keep state
Код: Выделить всё
Определяет флаги, которые должны быть установлены в заголовке TCP при использовании proto tcp. Флаги определяются как flags check/mask. Например: flags S/SA - PF будет смотреть на S и A (SYN и ACK) флаги и соответствовать правилу, если установлен флаг SYN.
Погуглил про флаги нашел как их ставить, примерное описание, но так и не понял что это даст, если можно поясните...
 
При таких флагах правило будет срабатывать только на трафик,который генерит сервер, если память не изменяет.
anton4 писал(а):
# А это что и зачем?
pass quick from any to any
Это уже просто в конце жест отчаяния  

 
))))
Убери лучше.
А дальше ncpdump + pflog и смотреть трассу пакетов от начала до конца.
 
			
					
				Re: Два канала
				Добавлено: 2010-06-17 8:00:00
				 anton4
				Резюмируя вчерашний тест.
1. Рдр не работает вообще.
2. Рдр не работает без ната об этом говорится во всех руководствах.
3. Pflog почему-то молчит
4. Tcpdump очень мусорный grep https помогает но толку мало так как тот факт что пакеты приходят на интерфейс я и так знал.
Есть ли какие нибудь предложения?
			 
			
					
				Re: Два канала
				Добавлено: 2010-06-17 8:30:59
				 Al
				anton4 писал(а):Резюмируя вчерашний тест.
1. Рдр не работает вообще.
2. Рдр не работает без ната об этом говорится во всех руководствах.
3. Pflog почему-то молчит
4. Tcpdump очень мусорный grep https помогает но толку мало так как тот факт что пакеты приходят на интерфейс я и так знал.
Есть ли какие нибудь предложения?
1. ....
2. Покажите руководство. Ооочень интересно.
3. Запускали скриптом? В блокирующих правилах log добавляли?
4. man tcpdump. А то, какие пакеты уходят в локалку и какие возвращаются вам не интересно? Второй внешний тоже не интересно?
Код: Выделить всё
# Macros: define common values, so they can be referenced and changed easily.
ext_if="bge1"
int_if="bge0"
vpn_if="ng0"
# EDIT it
internal_addr="192.168.34.1"
# EDIT it
external_addr="..."
# EDIT it
vpn_addr="192.168.200.162"
# наша сеть
# EDIT it
table <corp_nets> { 192.168.34.0/24 }
table <bad_nets> { 10.0.0.0/8, 172.16.0.0/12, 169.254.0.0/16, 192.0.2.0/24, 224.0.0.0/4, 240.0.0.0/4}
admins_port=" { 7000, 3306, 5005, 5006, 30}"
# админские компы
table <admins_ip> { 192.168.92.80, 192.168.92.98 }
# типы icmp, которые пропускаем
icmp_types = "{echoreq, echorep, unreach code needfrag}"
set block-policy drop
# откуда берем логи
# set loginterface $ext_if
# Normalization: reassemble fragments and resolve or reduce traffic
scrub in all
#-----------NAT RULES-----------------------------------------
nat on $ext_if inet proto {tcp, udp} from <corp_nets> to !<corp_nets> port {25, 53, 110} -> $external_addr
nat on $vpn_if inet proto {tcp, udp} from <corp_nets> to !<corp_nets> port {900, 901} -> $vpn_addr
# SBER
nat on $ext_if inet proto {tcp, udp} from <corp_nets> to any port 87 -> $external_addr
# SDM
nat on $ext_if inet proto {tcp, udp} from <corp_nets> to any port 1024 -> $external_addr
# FTP
nat on $ext_if inet proto {tcp, udp} from <corp_nets> to ... port {2102, 2101} -> $external_addr
#RDP
rdr proto {tcp, udp} from {...} to $external_addr port rdp -> 192.168.34.33 port rdp
#----------BLOCKING RULES----------------------------------------
# антиспуфинг! 
antispoof for {$ext_if, $int_if}
block log-all all
pass on lo0 all
.................
Вариант с рабочего,насколько я помню, сервера.
Где тут нат на рдп?
 
			
					
				Re: Два канала
				Добавлено: 2010-06-17 8:39:12
				 anton4
				спорить не буду сейчас подключил все три сетевые в одну сеть попробовал все работает 
Код: Выделить всё
rdr on $int_utk inet proto $protogroup to $int_utk port 443 tag Chanell2 -> \
$ibank2ip port 443
rdr on $int_utk inet proto $protogroup to $int_utk port 9091 tag Chanell2 -> \
$ibank2ip port 9091
nat on $int_utk proto $protogroup from $ibank2ip to any port $rdr_port -> $int_utk
rdr on $int_volgalink inet proto $protogroup to $int_volgalink port 443 tag Chanell1 -> \
$ibank2ip port 443
rdr on $int_volgalink inet proto $protogroup to $int_volgalink port 9091 tag Chanell1 -> \
$ibank2ip port 9091
nat on $int_volgalink proto $protogroup from $ibank2ip to any port $rdr_port -> $int_volgalink
antispoof for $int_volgalink inet
antispoof for $int_local inet
antispoof for $int_utk inet
block quick inet6 all
block all
pass quick on $int_local from any to any
## отвечаем через тот же интерфейс, через который пришел пакет.
## по сути меняем для помеченный пакетов route.
pass in on $int_volgalink reply-to ($int_volgalink $ext_gateway1) inet proto $protogroup \
    tagged Chanell1  flags S/SA keep state
pass in on $int_utk reply-to ($int_utk $ext_gateway2) inet proto $protogroup \
    tagged Chanell2 flags S/SA keep state
## Разрешаем все исходящие соединения на данном интерфейсе
pass out on $int_volgalink flags S/SA keep state
pass out on $int_utk flags S/SA keep state
Оговорюсь что на компе на который нужно прописать переадресацию прописал ШЛЮЗ до себя через freebsd.
 
			
					
				Re: Два канала
				Добавлено: 2010-06-17 9:12:01
				 Al
				Ну, заработало?
			 
			
					
				Re: Два канала
				Добавлено: 2010-06-17 9:18:39
				 Al
				Код: Выделить всё
nat on $int_volgalink proto $protogroup from $ibank2ip to any port $rdr_port -> $int_volgalink
Вот это вообще не понял...
ОС какая?
 
			
					
				Re: Два канала
				Добавлено: 2010-06-17 9:28:46
				 Al
				Кстате, где вы нашли, что редиректу нужен нат? Просто интресно почитать..
Простейший пример редиректа
http://www.rasyid.net/2008/02/03/redire ... in-pfconf/ 
			
					
				Re: Два канала
				Добавлено: 2010-06-17 10:06:30
				 anton4
				Код: Выделить всё
rdr on $int_if proto tcp from $int_net to $ext_if port 80 -> \
   $server 
no nat on $int_if proto tcp from $int_if to $int_net
nat on $int_if proto tcp from $int_net to $server port 80 -> \
   $int_if
Инициализационный пакет от клиента будет снова преобразован, когда будет пробрасываться обратно через внутренний интерфейс, замена клиентского исходного адреса на внутренний адрес брандмауэра. Внутренний сервер будет отвечать обратно брандмауэру, который может сделать обратно NAT и RDR преобразования, когда пробрасывается локальному клиенту. Эта конструкция сложный комплекс, потому что он создаёт два отдельных стейта для каждого отражённого соединения. Необходимо принять меры для предотвращения работы NAT с другим трафиком, например соединения из внешних хостов (через другие перенаправления) или трафик самого брандмауэра. Обратите внимание, что rdr правило показанное выше заставляет TCP/IP стэк просматривать пакеты прибывающие на внутренний интерфейс с адресом назначения во внутреннию сеть.
Al писал(а):Код: Выделить всё
nat on $int_volgalink proto $protogroup from $ibank2ip to any port $rdr_port -> $int_volgalink
Вот это вообще не понял...
ОС какая?
 
На сервере FreeBSD 8   На $ibank2ip Win2003. Правило для трансляции, что непонятного?
 
			
					
				Re: Два канала
				Добавлено: 2010-06-17 10:27:24
				 Al
				anton4 писал(а):Код: Выделить всё
rdr on $int_if proto tcp from $int_net to $ext_if port 80 -> \
   $server 
no nat on $int_if proto tcp from $int_if to $int_net
nat on $int_if proto tcp from $int_net to $server port 80 -> \
   $int_if
....
Al писал(а):Код: Выделить всё
nat on $int_volgalink proto $protogroup from $ibank2ip to any port $rdr_port -> $int_volgalink
Вот это вообще не понял...
ОС какая?
 
На сервере FreeBSD 8   На $ibank2ip Win2003. Правило для трансляции, что непонятного?
 
Не думаете, что это немного не ваш случай? 
1. Редирект на внутреннем интерфейсе трафика, идушего с локальной сети на внешний интерфейс, на  $server. Который, скоре всего, тоже в локалке.
2. Нат с локальной сети на локальном интерфейсе в адрес локального интерфейса
При этом, скорее всего, $server  тоже находится в локалке. Что бы не было треугольника, испольуется нат. Для редиректа сквозь сервер совершенно другая история.
Я вам уже прислал ссылку. 
Не понятно, зачем. см. ссылку выше.