Как Я и обещал — пишу о том, как создать домашний сервер на базе FreeBsd. В сумме роутер должен уметь, как минимум раздавать интернет по wi-fi и по кабелю, пропускать Multicast для IP-TV, отлично отсеивать шлак (firewall) и справляться с большими нагрузками, от которых обычные роутеры валятся (для меня связующим звеном стала невозможность качать быстро файлы по DC++ из-за того, что родители постоянно сидели на торрентах).
Итак, приступим. Пусть будет так, что у вас уже установлена Freebsd 8.0 или любой другой версии. Пусть она даже только что установлена и без заточки ядра под свои нужды (да, нам придется пересобирать ядро, но в этом нет ничего страшного).
Конкретизирую, Я выбрал именно Freebsd, так как она по моим заверениям является самой защищенной и быстрой ОС. К тому же мне нравится файловая структура этой ОС, а так же то, что все ставится из исходных кодов (пусть из портов, но оно компилируется под мое железо = Я выигрываю в скорости).
Первым шагом в этом нелегком деле будет сборка ядра, для того, чтобы включить поддержку IPFW (нашего фаервола):
наша архитектура процессора — i386. Для остальных — просто подставляйте свою.
- Код: выделить все
# cd /usr/src/sys/amd64/conf
/usr/src/sys/amd64/conf# cp GENERIC MYKERNEL
/usr/src/sys/amd64/conf# nano MYKERNEL
Перед нами предстал файл конфигурации ядра. Можно конечно разглагольствовать на тему «Сделайте dmesg и в соответствии с выданным оставьте только те устройства, которые вам действительно необходимы», но мы не будем. Да, вы выиграете в скорости работы ОС (чем меньше ядро — тем лучше), но я не буду рассказывать об этом.
Итак, добавим следующее в файл конфигурации ядра:
- Код: выделить все
options IPFIREWALL
options IPFIREWALL_VERBOSE
options IPFIREWALL_VERBOSE_LIMIT=5
options IPFIREWALL_FORWARD
options IPDIVERT
options DUMMYNET
options IPFIREWALL_DEFAULT_TO_ACCEPT
device if_bridge
Подробности всех этих опций есть здесь. После этого выполним команды:
- Код: выделить все
/usr/src/sys/amd64/conf# cd ../../../
/usr/src/# make buildkernel KERNCONF=MYKERNEL && \
make installkernel KERNCONF=MYKERNEL
и идем пить чай/готовить ужин жене. В общем — это надолго. У меня заняло где-то часа полтора.
После того, как мы наконец-то собрали ядро можно приступать к первоначальной настройке интерфейсов.
Хотелось бы отвлечься от темы в сторону выбора оборудования. Если вы ещё не закупились сетевой карточкой wi-fi — хорошо. Потому что, если это не так — возможно вы получите незабываемое удовольствие от того, что она у вас просто не определится. Я настоятельно советую — берите D-link DWA-520. Его чип строится на базе Atheros'ов, которые с Freebsd работают на ура. Моя же старая карточка (с чипом от realtek каким-то) даже не определилась. Если же хотите перебирать windows драйвера и подцеплять их к вашему сетевому адаптеру — хозяин барин. Да, и DWA-520 отлично ладит с 108 Мбит/сек, что не может не радовать (конечно же, в режиме turbo).
Ладно, думаю, что сборка ядра займет у вас действительно много времени, поэтому на сегодня пока что хватит. В следующем посте — настройка интерфейсов, подводные камни при организации bridge wi-fi и lan в freebsd, hostapd и dhcp.
Итак — мы собрали ядро c необходимыми параметрами и устройством if_bridge.
По команде ifconfig -a мы увидим все сконфигурированные и не сконфигурированные интерфейсы в системе:
- Код: выделить все
# ifconfig -a
rl0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
options=8<VLAN_MTU>
ether 00:1e:8c:0f:ff:ff
inet 172.16.56.63 netmask 0xffffffc0 broadcast 172.16.56.255
media: Ethernet autoselect (100baseTX <full-duplex>)
status: active
ath0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 2290
ether 00:24:01:03:01:2a
media: IEEE 802.11 Wireless Ethernet autoselect mode 11g <hostap>
status: no carrier
rl1: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> metric 0 mtu 1500
options=8<VLAN_MTU>
ether 00:0f:ea:4d:25:24
media: Ethernet autoselect (100baseTX <full-duplex>)
status: no carrier
plip0: flags=8810<POINTOPOINT,SIMPLEX,MULTICAST> metric 0 mtu 1500
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> metric 0 mtu 16384
options=3<RXCSUM,TXCSUM>
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x5
inet6 ::1 prefixlen 128
inet 127.0.0.1 netmask 0xff000000
nd6 options=3<PERFORMNUD,ACCEPT_RTADV>
Отлично. Мы будем работать с интерфейсами rl1 и ath0, которые являются LAN и WI-FI соответственно. rl0 — это интерфейс, который смотрит во внутреннею локальную сеть провайдера. К нему мы вернемся только тогда, когда будем настраивать маршрутизацию с помощью IPFW.
Итак, добавим в /etc/rc.conf конфигурацию нашей локальной сети:
- Код: выделить все
cat /etc/rc.conf
hostname="megarouter.local"
gateway_enable="YES" #обязательный параметр
inetd_enable="YES" #не обязательный параметр, но лучше оставить на всякий пожарный. Потом может пригодиться
sshd_enable="YES" #хотим же мы уметь удаленно управлять нашим "роутером"?
ifconfig_rlinet #настройка интерфейса на внешнюю сеть.
firewall="/sbin/ipfw" #путь до ipfw.
firewall_enable="YES"
firewall_script="/etc/firewall.sh"
firewall_logging="YES"
hostapd_enable="YES" #запускаем hosapd для wifi (тем кто Wi-Fi не использует - можно отключить) Собираем их портов.
defaultrouter="172.16.56.1" #путь до "основного шлюза" для внешнего интерфейса.
dhcpd_enable="YES"
dhcpd_conf="/usr/local/etc/dhcpd.conf"
dhcpd_ifaces="bridge0" #интерфейс, по которому dhcpd будет работать
if_ath_load="YES"
ifconfig_ath0="up"
wlans_athwlan0"
cloned_interfaces="bridge0"
ifconfig_bridge0="inet 192.168.1.1 netmask 255.255.255.0 addm wlan0 addm rl1 up"
create_args_wlan0="wlanmode hostap"
ifconfig_wlan0="up ssid freebsdap mode 11g channel 10"
ifconfig_rl1="up"
natd_enable="YES" #запускаем natd
natd_interface="rl0"
natd_flags="-m -u -f /etc/natd.conf"
Вроде бы с основами все.
Теперь конфигурация dhcp сервера, который будет выдавать ip:
- Код: выделить все
option domain-name "router.local";
option domain-name-servers 8.8.8.8, 8.8.4.4;
default-lease-time 720000;
max-lease-time 720000;
min-lease-time 720000;
ddns-update-style none;
authoritative;
log-facility local7;
subnet 192.168.1.0 netmask 255.255.255.0 {
range 192.168.1.2 192.168.1.250;
option routers 192.168.1.1;
option subnet-mask 255.255.255.0;
option netbios-name-servers 192.168.1.1;
option netbios-dd-server 192.168.1.1;
option netbios-node-type 8;
option broadcast-address 192.168.1.255;
}
Все. Теперь запускаем dhcpd и после перезагрузки мы уже раздаем IP направо и налево по указанному в rc.conf интерфейсу.
Осталось только настроить hostapd, который отвечает за безопасность нашего wi-fi:
- Код: выделить все
interface=wlan0
driver=bsd
logger_syslog=-1
logger_syslog_level=2
logger_stdout=-1
logger_stdout_level=2
debug=4
dump_file=/tmp/hostapd.dump
ctrl_interface=/var/run/hostapd
ctrl_interface_group=wheel
ssid=freebsdap
wpa=1
wpa_passphrase=p@ssw0rd
wpa_key_mgmt=WPA-PSK
wpa_pairwise=TKIP CCMP
Здесь тоже все предельно понятно, по-моему.
Итак, осталась самая малость. Это файл конфигурации ipfw. У меня он находится в /etc/firewall.sh:
- Код: выделить все
#!/bin/sh
# для начала вводим переменные - для нашего же удобства, чтобы не
# вводить по сотне раз одно и то же, а потом искать, почему не работает,
# и в итоге выяснять, что ошибся IP адресом в одном из правил
FwCMD="/sbin/ipfw" # собственно, где лежит ipfw
LanOut="xl0" # внешний интерфейс
LanIn="sis0" # внутренний интерфейс
IpOut="222.222.222.222" # внешний IP адрес машины
IpIn="192.168.20.254" # внутренний IP машины
NetMask="24" # маска сети (если она разная для внешней
# и внутренней сети - придётся вводить ещё
# одну переменную, но самое забавное, что
# можно и забить - оставить 24 - всё будет
# работать, по крайней мере, я пробовал -
# работало на 4-х машинах, в разных сетях,
# с разными масками - настоящими разными! но -
# это неправильно.)
NetIn="192.168.20.0" # Внутренняя сеть
# Сбрасываем все правила:
${FwCMD} -f flush
# Проверяем - соответствует ли пакет динамическим правилам:
${FwCMD} add check-state
# Разрешаем весь трафик по внутреннему интерфейсу (петле)
# Вообще я во многих местах читал, что без него может ничего не заработать вообще
# и прочие страшилки. Работает - почта, apache, .... А вот squid - не работает :)
# так что без него и правда - никуда.
${FwCMD} add allow ip from any to any via lo0
# рубим попытки lo0 куда-то лезть и откуда-то лезть на lo0 (вот честно - ни
# одного пакета по этим правилам не зарубилось за всё время... Может в этом
# моё счастье? :))
${FwCMD} add deny ip from any to 127.0.0.0/8
${FwCMD} add deny ip from 127.0.0.0/8 to any
# Вводим запреты:
# режем частные сети на внешнем интерфейсе - по легенде он у нас
# смотрит в интернет, а значит пакетам этим браться неоткуда на нём.
# рубим частные сети
${FwCMD} add deny ip from any to 10.0.0.0/8 in via ${LanOut}
${FwCMD} add deny ip from any to 172.16.0.0/12 in via ${LanOut}
${FwCMD} add deny ip from any to 192.168.0.0/16 in via ${LanOut}
${FwCMD} add deny ip from any to 0.0.0.0/8 in via ${LanOut}
# рубим автоконфигурируемую частную сеть
${FwCMD} add deny ip from any to 169.254.0.0/16 in via ${LanOut}
# рубаем Multicast рассылки
${FwCMD} add deny ip from any to 240.0.0.0/4 in via ${LanOut}
# рубим фрагментированные icmp
${FwCMD} add deny icmp from any to any frag
# рубим широковещательные icmp на внешнем интерфейсе
${FwCMD} add deny log icmp from any to 255.255.255.255 in via ${LanOut}
${FwCMD} add deny log icmp from any to 255.255.255.255 out via ${LanOut}
# а тут собственно Firewall и начался:
# отправляем всех на frox
${FwCMD} add fwd ${IpIn},2121 tcp from ${NetIn}/${NetMask} to any 21 via ${LanOut}
# отправляем всех на squid (в данном случае - прокси прозрачный)
${FwCMD} add fwd 127.0.0.1,3128 tcp from ${NetIn}/${NetMask} to any 80 via ${LanOut}
# пропускаем трафик через трансляцию сетевых адресов (NAT)
${FwCMD} add divert natd ip from ${NetIn}/${NetMask} to any out via ${LanOut}
${FwCMD} add divert natd ip from any to ${IpOut} in via ${LanOut}
# рубим трафик к частным сетям через внешний интерфейс
# заметьте - эти правила отличаются от тех, что были выше!
${FwCMD} add deny ip from 10.0.0.0/8 to any out via ${LanOut}
${FwCMD} add deny ip from 172.16.0.0/12 to any out via ${LanOut}
${FwCMD} add deny ip from 192.168.0.0/16 to any out via ${LanOut}
${FwCMD} add deny ip from 0.0.0.0/8 to any out via ${LanOut}
# рубим автоконфигурируемую частную сеть
${FwCMD} add deny ip from 169.254.0.0/16 to any out via ${LanOut}
# рубаем Multicast рассылки
${FwCMD} add deny ip from 224.0.0.0/4 to any out via ${LanOut}
# рубаем Multicast рассылки
${FwCMD} add deny ip from 240.0.0.0/4 to any out via ${LanOut}
# разрешаем все установленные соединения (если они установились -
# значит по каким-то правилам они проходили.)
${FwCMD} add allow tcp from any to any established
# разрешаем весь исходящий трафик (серверу-то в инет можно? :))
${FwCMD} add allow ip from ${IpOut} to any out xmit ${LanOut}
# разрешаем DNS снаружи (нам же надо узнавать IP по именам машин?)
${FwCMD} add allow udp from any 53 to any via ${LanOut}
# разрешаем DNS входящий снаружи - если на этой машине работает named
# и держит какую-то зону. В остальных случаях - не нужно
${FwCMD} add allow udp from any to any 53 via ${LanOut}
# разрешаем UDP (для синхронизации времени - 123 порт)
${FwCMD} add allow udp from any to any 123 via ${LanOut}
# разрешаем ftp снаружи (оба правила - для пассивного режима)
# для узнавания диапазона портов по которому будет работать, лезем в
#/usr/home/lissyara/>sysctl net.inet.ip.portrange.first
# net.inet.ip.portrange.first: 49152
# /usr/home/lissyara/>sysctl net.inet.ip.portrange.last
# net.inet.ip.portrange.last: 65535
${FwCMD} add allow tcp from any to ${IpOut} 21 via ${LanOut}
#Можно извернуться примерно так, если есть желание, но я предпочитаю руками
#${FwCMD} add allow tcp from any to ${IpOut} \
#`sysctl net.inet.ip.portrange.first | awk '{print $2}'`-\
#`sysctl net.inet.ip.portrange.last | awk '{print $2}'` via ${LanOut}
${FwCMD} add allow tcp from any to ${IpOut} 49152-65535 via ${LanOut}
# разрешаем некоторые типы ICMP трафика - эхо-запрос,
# эхо-ответ и время жизни пакета истекло
${FwCMD} add allow icmp from any to any icmptypes 0,8,11
# открываем снаружи 80 порт - если у нас есть WWW сервер на машине
${FwCMD} add allow tcp from any to ${IpOut} 80 via ${LanOut}
# открываем снаружи 25 порт (SMTP) если на машине крутится почта
#${FwCMD} add allow tcp from any to ${IpOut} 25 via ${LanOut}
# открываем снаружи 22 порт - если надо будет ходить на машину по ssh
${FwCMD} add allow tcp from any to ${IpOut} 22 via ${LanOut}
# открываем снаружи 143 порт(если надо смотреть почту снаружи по IMAP)
${FwCMD} add allow tcp from any to ${IpOut} 143 via ${LanOut}
# открываем снаружи 110 порт (если надо смотреть почту снаружи по POP)
${FwCMD} add allow tcp from any to ${IpOut} 110 via ${LanOut}
# по поводу следующих трёх правил, для tcp, udp и icmp - их можно
# заменить одним правилом:
#${FwCMD} add allow ip from any to any via ${LanIn}
# но для удобства наладки и контроля происходящего я предпочитаю три отдельных
# правила, хотя могут быть грабли - например, протокол gre не пройдёт -
# придётся стругать отдельное правило для него, типа
#${FwCMD} add allow gre from any to any via ${LanIn}
# итак:
# разрешаем весь tcp трафик внутри локальной сети (на внутреннем интерфейсе)
${FwCMD} add allow tcp from any to any via ${LanIn}
# разрешаем весь udp трафик внутри локальной сети (на внутреннем интерфейсе)
${FwCMD} add allow udp from any to any via ${LanIn}
# разрешаем весь icmp трафик внутри локальной сети (на внутреннем интерфейсе)
${FwCMD} add allow icmp from any to any via ${LanIn}
# запрещаем всё и всем. Если тип фаервола не open, то это правило добавится
# автоматически, но всё же ну его. Лучше сам. Надёжней.
${FwCMD} add deny ip from any to any
Конфигурацию для ipfw я брал отсюда, за что lissyar'е отдельное огромное спасибо.
Итак, после перезагрузки мы получаем полноценный, работоспособный роутер, который готов служить нам верой и правдой достаточно долго. Я же ещё добавил на него nginx, proftpd, который отвечает у меня за файловую помойку и samba.