Аннотация |
В этом документе описывается работа с подсетями при помощи протокола Прокси-ARP (Address Resolution Protocol). Моя цель - сделать так, чтобы подсеть из нескольких компьютеров была видна в другой подсети, использующей протокол IP. (Я называю такую конфигурацию суб-подсетью). В результате все должно выглядеть так, как будто машины локальной подсети (далее сеть 0) подключены к главной сети(далее сеть 1). Это все будет работать только в том случае, если все машины соединены при помощи Ethernet-совместимых устройств (т.е. не будет работать с SLIP/PPP/CSLIP и т.п..) |
Создание этого документа и моего способа использования Прокси-ARP, было бы невозможно без помощи:
Andrew Tridgell, который реализовал поддержку подсетей в ARP в Linux - он лично помогал мне при настройке всего этого
Мини-HOWTO "Прокси-ARP" (Al Longyear)
Мини-HOWTO "Несколько Ethernet-сетей" (Don Becker)
Исходный текст программы arp(8) и man-страница (Fred N. van Kempen и Bernd Eckenfels)
Конфигурация подсетей, при которых необходимо использование Прокси-ARP, достаточно специфична.
У меня была радио-Ethernet-ISA-8бит-карта. Мне было необходимо подключить ее к нескольким машинам одновременно. Я мог использовать ее на Linux-машине (правда мне для этого пришлось писать драйвер, но это тема для отдельного разговора). В общем, от меня требовалось установить вторую карту в Linux-машину, и некоторым образом объединить две подсети.
Предположим (в качестве примера), что сеть 0 - это локальная сеть Ethernet, подключенная к Linux при помощи NE2000-совместимой карты на интерфейсе eth0. Сеть 1 - это главная сеть, подключенная к Linux при помощи радио-Ethermet-карты на интерфейсе eth1. Машина A - это Linux с обоими интерфейсами. Машина B - любая TCP/IP-машина в сети 0, а машина C - такая же машина в сети 1.
В обычном случае я должен был сделать следующее:
Использовать IP-мост (см. Мини-HOWTO: Мосты), чтобы передавать пакеты между интерфейсами. К сожалению, у радио-Ethernet-карт нет режима "promisc" (они не могут перехватывать весь трафик сети 1). Это связано с маленькой скоростью передачи (2Мбит/сек), а также с тем, что нам совсем не надо обрабатывать весь трафик сети 1. Более того, мосты достаточно хорошо загружают систему!
С другой стороны, я мог использовать подсети и IP-маршрутизацию для передачи данных между подсетями (см. Мини-HOWTO: "Подсети IP"). Это решение подходит только для IP-протокола - ядро Linux будет обрабатывать лишь IP-пакеты, а остальным протоколам (например AppleTalk) потребуются дополнительные программы. Это также потребует новой IP-подсети, что не всегда возможно.
В этом случае я не мог получить новую подсеть, поэтому мне пришлось настроить все так, как будто все машины сети 0 подключены к сети 1. Вот здесь и понадобился Прокси-ARP. Для работы с другими (не-IP) протоколами использовались соответствующие программы - например для маршрутизации пакетов AppleTalk использовался netatalk.
На самом деле Прокси-ARP необходим только для передачи пакетов из сети 1 в сеть 0. Обратно пакеты идут при помощи стандартной IP-маршрутизации.
В данном случае у сети 1 была 8-битная маска (255.255.255.0). Для сети 0 я использовал 4-битную маску (255.255.255.240), тем самым получив возможность иметь в ней 14 адресов (2 ^ 4 = 16, минус 0-ой и 15-ый). Заметьте что эта подсеть может иметь любое количество бит, которое должно быть меньше количества бит главной сети (т.е. 2, 3, 4, 5, 6 или 7 бит в моем случае)
Все IP-адреса сети 0 (всего их 16) являются подмножеством адресов сети 1. Очень важно, чтобы ни у одной машины в сети 1 не было адреса, входящего в пространство сети 0! В моем случае я "зарезервировал" для сети 0 адреса сети 1, оканчивающиеся на 64 .. 79. В данном примере, адреса 64 и 79 не могут использоваться машинами: 64 - этой адрес сети 0, а 79 - это широковещательный адрес сети 0.
Машине A выделены два IP-адреса, один в адресном пространстве сети 0 для настоящего Ethernet-интерфейса (eth0), а второй в пространстве сети 1 (не сети 0) для интерфейса радио-карты (eth1).
Предположим, что машине C (в сети 1) необходимо послать пакет машине B (в сети 0). Машина C, считая что находится в одной подсети с машиной B, посылает в сети 1 широковещательный запрос с целью узнать Ethernet-адрес машины B. Машина B не получит этот запрос - она не находится в одной физической сети с машиной C - но этот запрос увидит машина A.
Вот здесь и начинается волшебство. Код arp в ядре Linux в машине A, будучи правильно настроен (Прокси-ARP для подсетей), определяет, что ARP-запрос идет из интерфейса сети 1 (eth1), а соответствующий IP-адрес находится в сети 0. В этом случае машина A в ответе на запрос укажет свой собственный Ethernet-адрес.
Машина C сделает запись в своем ARP-кэше, в котором укажет, что IP-адресу машины B соответствует Ethernet-адрес машины A (в данном случае, адрес радио-Ethernet карты). После этого машина C сможет послать пакет машине B на этот Ethernet-адрес, и его получит машина A.
Получив такой пакет, машина A определит, что его получатель не она, а машина B. Код IP-маршрутизации ядра Linux машины A попытается передать пакет машине B в соответствии со своей таблицей маршрутизации (в которой указано, какому интерфейсу, какая сеть соответствует). Однако, IP-адрес машины B соответствует одновременно и сети 0, и сети 1.
Вот здесь происходит вторая часть волшебства. Маска подсети на интерфейсе 0 имеет в двоичном представлении больше единиц (то есть, более конкретизирована), чем маска подсети интерфейса 1. Вследствие этого, код маршрутизации сопоставит этот пакет с интерфейсом eth0, игнорируя соответствие адреса в пакете сети 1 (из которой, собственно, этот пакет и пришел).
Теперь машине A необходим "настоящий" физический (Ethernet) адрес машины B (предположим, что его нет в ARP-кэше). Машина A посылает ARP-запрос, но, в этот раз, код arp в ядре Linux определяет, что запрос идет не из сети 1, и не посылает в ответ прокси-адрес интерфейса eth1. Вместо этого, запрос производится в сети 0 (интерфейс eth0) - этот запрос увидит машина B и пошлет в ответ свой (настоящий) физический (Ethernet) адрес. Теперь машина A может переслать пакет (шедший от машины C) машине B.
Машина B получает пакет от машины C (через машину A) и ей надо послать ответ. В этот раз машина B определяет, что машина C находится в другой подсети (маска 255.255.255.240 подсети машины B исключает из ее адресного пространства все машины, не входящие в сеть 0). В машине B маршрут по умолчанию указывает на машину A - она посылает пакет через машину A. Теперь код маршрутизации пакетов машины A определяет, что IP-адрес получателя (машины C) находится в сети 1, и она посылает этот пакет машине C через радио-Ethernet-интерфейс eth1.
Аналогично (и даже немного проще) происходит с пакетами любых машин обеих сетей, предназначенными для машины A.
Очевидно, что, если другая машина (D) в сети 0 пошлет ARP-запрос относительно физического адреса машины B, машина A получит этот запрос с сети 0 и не пошлет в ответ прокси-адрес интерфейса eth1, определив, что запрос идет из сети 0.
Заметьте, что в машинах B и C (и D) не требуется каких-то специальных IP-настроек. В моем случае - это была дикая смесь из Sun, Macintosh и PC-машин в сети 0, подключенных к остальному миру через Linux-машину A.
Маленькое дополнение: заметьте, что физические (Ethernet) адреса, полученные машинами A, B, C (и D), помещаются в ARP-кэш, и последующие пакеты не вызовут повторной процедуры ARP-запрос-ответ. ARP-кэш обычно удаляет записи с адресами после 5 минут их бездействия.
Я настроил работу Прокси-ARP с подсетями в ядре Linux версии 2.0.30, но мне сказали, что все это работало еще в пору ядер 1.2.x.
Первое, что надо запомнить: код ARP можно разделить на две части: первая часть входит в ядро - она посылает и получает ARP запросы и ответы, обновляет содержимое ARP-кэша и т.п.; вторая часть - это команда arp(8), позволяющая администратору изменять содержимое ARP-кэша, а остальным пользователям его просматривать.
Первая проблема, с которой я столкнулся, состояла в следующем - программа arp(8), входившая в мой дистрибутив Slackware 3.1, была настолько стара(1994 года выпуска!!!), что вообще не могла работать с кодом arp в ядре (главное доказательство этого - очень странный результат работы команды "arp -a").
Команда arp(8) входит в состав пакета "net-tools-1.33a", который можно взять, практически, где угодно, в том числе и по адресу ftp.linux.org.uk:/pub/linux/Networking/base/ (этот адрес я взял из файла README из этого пакета). Она работает нормально, вместе с ней поставляется нормальная версия man-страниц, в которых все объяснено значительно подробнее, чем в старых.
Получив свежую версию команды arp(8), все изменения я внес в скрипт /etc/rc.d/rc.inet1 (это в Slackware - в других случаях все может быть немного по-другому). Сначала нам надо сменить широковещательный адрес, адрес и сетевую маску интерфейса eth0:
NETMASK=255.255.255.240 # это для 4-битной сети NETWORK=x.y.z.64 # наш номер сети (замените x.y.z на настоящие цифры вашей сети) BROADCAST=x.y.z.79 # широковещательный адрес (в моем случае) |
Затем добавляем настройку второй Ethernet-карты (после загрузки всех необходимых модулей с драйвером):
/sbin/ifconfig eth1 (name on net 1) broadcast (x.y.z.255) netmask 255.255.255.0 |
Теперь добавляем запись в таблицу маршрутизации:
/sbin/route add -net (x.y.z.0) netmask 255.255.255.0 |
Вам также, возможно, понадобится сменить адрес шлюза, используемого по умолчанию.
Теперь настало время добавить строку, включающую Прокси-ARP:
/sbin/arp -i eth1 -Ds ${NETWORK} eth1 netmask ${NETMASK} pub |
Здесь мы указываем коду ARP добавить в кэш статическую запись (опция s) для сети ${NETWORK}. Опция -D указывает ARP использовать адрес интерфейса eth1 (вторая запись eth1), что позволяет нам не выяснять физический адрес интерфейса eth1, чтобы вписать его сюда вручную. Опция netmask указывает ARP, что мы работаем с подсетью (т.е. Прокси для всех (IP-адресов) & ${NETMASK} == ${NETWORK} & ${NETMASK}). Опция pub означает, что ARP должен "опубликовать" эту ARP-запись, т.е., что это прокси-запись, и ее надо посылать в ответ на поиск всех IP-адресов этой подсети. Опция -i eth1 означает, что ARP должен отвечать только на запросы, идущие с интерфейса eth1.
Если нам повезет, после загрузки все машины подсети 0 появятся в сети 1. Вы можете проверить на машине A настройку Прокси-ARP, используя следующую команду: (имена и адреса изменены)
bash$ /sbin/arp -an Address HWtype HWaddress Flags Mask Iface x.y.z.1 ether 00:00:0C:13:6F:17 C * eth1 x.y.z.65 ether 00:40:05:49:77:01 C * eth0 x.y.z.67 ether 08:00:20:0B:79:47 C * eth0 x.y.z.5 ether 00:00:3B:80:18:E5 C * eth1 x.y.z.64 ether 00:40:96:20:CD:D2 CMP 255.255.255.240 eth1 |
Вы можете просмотреть содержимое "файла" /proc/net/arp.
Последняя строка - это прокси-запись для подсети. Флаги CMP означают, что запись является статической (введена вручную), и должна быть опубликована. Эта строка будет использоваться только при получении запроса с сети 1, если IP-адрес соответствует сети 0. Заметьте, что команда arp(8) автоматически определила физический адрес интерфейса eth1, и подставила его в соответствующее место (опция -Ds).
Вы также можете проверить правильность таблицу маршрутизации. Ниже приведена моя таблица (имена и адреса снова изменены):
#/bin/netstat -rn Kernel routing table Destination Gateway Genmask Flags Metric Ref Use Iface x.y.z.64 0.0.0.0 255.255.255.240 U 0 0 71 eth0 x.y.z.0 0.0.0.0 255.255.255.0 U 0 0 389 eth1 127.0.0.0 0.0.0.0 255.0.0.0 U 0 0 7 lo 0.0.0.0 x.y.z.1 0.0.0.0 UG 1 0 573 eth1 |
Эту же таблицу вы увидите, взглянув на файл /proc/net/route.
Заметьте, что первая запись является подмножеством второй, но таблица маршрутизации отсортирована в порядке приоритета, поэтому строка eth0 будет обрабатываться до строки eth1.
Существуют и другие способы работы с этими подсетями, кроме Прокси-ARP. О некоторых из них я уже упомянул выше (мосты и маршрутизация):
IP-Маскарадинг (см. мини-HOWTO "IP-Маскарадинг"). При его использовании, сеть 0 будет скрыта за машиной A от остальной части Интернет. При попытке машин сети 0 связаться с остальным миром через машину A, адреса отправителей и номера портов в пакетах будут заменены на машине A так, как будто она сама связывается с внешним миром. Это достаточно красивое решение, но машины сети 1 не смогут связаться с машинами сети 0, потому что для сети 1 сеть 0 не существует. Это, конечно, увеличивает защищенность сети 0, но при этом теряется возможность работы машин сети 1 с машинами сети 0.
Другой способ - IP-туннель, но он поддерживается не всеми операционными системами, поэтому я решил его не использовать.
Использовать Прокси-ARP без подсетей. Теоретически это возможно, просто вам придется в ARP-кэше указать все машины подсети 0 по отдельности, вместо указания ссылки на всю сеть.
Наверно, здесь можно воспользоваться и IP-алиасингом, но я об этом не думал.
Еще один пример применения Прокси-ARP в подсетях можно найти здесь же, в Австралийском Национальном Университете. Эта та самая конфигурация, для которой Andrew Tridgell и написал работу с подсетями в Прокси-ARP. Однако, Andrew говорит, что, на самом деле в мире существует еще несколько подобных конфигураций (подробностей у меня нет).
Это была лаборатория, в которой студентов обучают, как настраивать TCP/IP в машинах, включая и настройку шлюза. Там имеется сеть класса C, и Andrew была нужна "подсеть" для безопасности, контроля трафика и образовательных целей, упомянутых выше. Он сделал это при помощи стандартного Прокси-ARP, а затем до него дошло, что иметь одну запись в ARP-кэше значительно проще, чем иметь по одной записи для каждой машины.. И вот... появился Прокси-ARP для подсетей!
Copyright 1997 by Bob Edwards <Robert.Edwards@anu.edu.au>
Voice: (+61) 2 6249 4090
Unless otherwise stated, Linux HOWTO documents are copyrighted by their respective authors. Linux HOWTO documents may be reproduced and distributed in whole or in part, in any medium physical or electronic, as long as this copyright notice is retained on all copies. Commercial redistribution is allowed and encouraged; however, the author would like to be notified of any such distributions. All translations, derivative works, or aggregate works incorporating any Linux HOWTO documents must be covered under this copyright notice. That is, you may not produce a derivative work from a HOWTO and impose additional restrictions on its distribution. Exceptions to these rules may be granted under certain conditions; please contact the Linux HOWTO coordinator at the address given below. In short, we wish to promote dissemination of this information through as many channels as possible. However, we do wish to retain copyright on the HOWTO documents, and would like to be notified of any plans to redistribute the HOWTOs. If you have questions, please contact the Linux HOWTO coordinator, at <linux-howto@metalab.unc.edu> via email.
Авторские права на русский перевод этого текста принадлежат ╘ 2000 ASPLinux Все права зарезервированы.
Этот документ является частью проекта Linux HOWTO.
Авторские права на документы Linux HOWTO принадлежат их авторам, если явно не указано иное. Документы Linux HOWTO, а также их переводы, могут быть воспроизведены и распространены полностью или частично на любом носителе физическом или электронном, при условии сохранения этой заметки об авторских правах на всех копиях. Коммерческое распространение разрешается и поощряется; но так или иначе автор текста и автор перевода желали бы знать о таких дистрибутивах.
Все переводы и производные работы, выполненные по документам Linux HOWTO должны сопровождаться этой заметкой об авторских правах. Это делается в целях предотвращения случаев наложения дополнительных ограничений на распространение документов HOWTO. Исключения могут составить случаи получения специального разрешения у координатора Linux HOWTO с которым можно связаться по адресу приведенному ниже.
Мы бы хотели распространить эту информацию по всем возможным каналам. Но при этом сохранить авторские права и быть уведомленными о всех планах распространения HOWTO. Если у вас возникли вопросы, пожалуйста, обратитесь к координатору проекта Linux HOWTO по электронной почте: <linux-howto@metalab.unc.edu>, или к координатору русского перевода Linux HOWTO компании ASPLinux по адресу <linux-howto@asplinux.ru>