NAS для хомяков по бюджету. Часть 3 — DHCP, Wireless Access Point & NAT

<img src="https://i.imgur.com/1ZbSe0e.png" class="image-center" width="400"><br> Имея на руках адаптер на базе чипа RTL8188CUS опробовал на нём настройку AP в debian stretch. Что не понравилось – довольно слабенький адаптер и скорости с него современной не выжать.<br> Настройка производилась в режиме моста:<br> <img src="https://i.imgur.com/PFonJqJ.jpg" class="image-center" width="200"><br> Довольно много времени провёл в поисках более адекватного адаптера, однако тут как выяснилось большие проблемы у Linux-based OS. Куда не плюнь везде какие-то проблемы. Вобщем остановился на ASUS PCE-AC55BT B1 на базе Intel Dual Band Wireless-AC 8260 (8260NGW). Криков о помощи с адаптером этой ревизии не нашёл, сам же чипсет имеет поддержку linux kernel 4.1+ через драйвер iwlwifi – чем чёрт как говорится не шутит.<br> Сказано – сделано, адаптер куплен, установлен физически (кстати о мифах: в PCIEx16 слот можно без переходника вставлять устройство с PCIEx1) и теперь пришла пора танцев с бубном.<br>
22 октября 2017, воскресенье 17:58
Black_Lava для раздела Блоги

Имея на руках адаптер на базе чипа RTL8188CUS опробовал на нём настройку AP в debian stretch. Что не понравилось – довольно слабенький адаптер и скорости с него современной не выжать.
Настройка производилась в режиме моста:

Довольно много времени провёл в поисках более адекватного адаптера, однако тут как выяснилось большие проблемы у Linux-based OS. Куда не плюнь везде какие-то проблемы. Вобщем остановился на ASUS PCE-AC55BT B1 на базе Intel Dual Band Wireless-AC 8260 (8260NGW). Криков о помощи с адаптером этой ревизии не нашёл, сам же чипсет имеет поддержку linux kernel 4.1+ через драйвер iwlwifi – чем чёрт как говорится не шутит.
Сказано – сделано, адаптер куплен, установлен физически (кстати о мифах: в PCIEx16 слот можно без переходника вставлять устройство с PCIEx1) и теперь пришла пора танцев с бубном.

После включения надобно установить:
su
apt-get install firmware-iwlwifi iw wireless-tools

и настроить интерфейсы. Незнаю кому как, но лично мне не понравилась схема именования интерфейсов с которой заставляет Debian работать, поэтому потребуется небольшое хирургическое вмешательство:
nano /etc/udev/rules.d/79-net-name.rules
#fixed network interface name by MAC address. 
SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="4c:cc:6a:f6:96:d9", NAME="eth0"
SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="f4:8c:50:6f:b5:6c", NAME="wlan0"

nano /etc/network/interfaces
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).
source /etc/network/interfaces.d/*
# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
#Option “hwaddress ether”  used  to change MAC attempted by provider
allow-hotplug eth0
iface eth0 inet dhcp
hwaddress ether 10:7b:ef:5d:e4:89

allow-hotplug wlan0
iface wlan0 inet static
address 192.168.0.1
netmask 255.255.255.0
network 192.168.0.0

Поднимаем интерфейсы:
ifup eth0
ifup wlan0

Переходим к настройке непосредственно точки доступа. Вот тут как раз кроются главные подводные камни. Сначала я ставил hostapd as is с репозитория. Но 300 mbps добиться на 2.4Ghz добиться не удалось упёрся в 144mbps. В ходе довольно тщательного расследования и экспериментов с hostapd.conf стало очевидно что hostapd придётся пересобирать и применять патч с opewrt:
apt-get source hostapd
apt-get build-dep hostapd
apt-get install libnl-3-dev

Правим сорцы:
cd wpa-2.4
cd hostapd
cp defconfig  .config
nano .config

Можно раскоментировать, можно очистить и вставить:
# Driver interface for Host AP driver
CONFIG_DRIVER_HOSTAP=y
# Driver interface for drivers using the nl80211 kernel interface
CONFIG_DRIVER_NL80211=y
# Use libnl 3.2 libraries (if this is selected, CONFIG_LIBNL20 is ignored)
CONFIG_LIBNL32=y
# IEEE 802.11F/IAPP
CONFIG_IAPP=y
# WPA2/IEEE 802.11i RSN pre-authentication
CONFIG_RSN_PREAUTH=y
# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
CONFIG_PEERKEY=y
# IEEE 802.11w (management frame protection)
CONFIG_IEEE80211W=y
# Integrated EAP server
CONFIG_EAP=y
# EAP Re-authentication Protocol (ERP) in integrated EAP server
CONFIG_ERP=y
# EAP-MD5 for the integrated EAP server
CONFIG_EAP_MD5=y
# EAP-TLS for the integrated EAP server
CONFIG_EAP_TLS=y
# EAP-MSCHAPv2 for the integrated EAP server
CONFIG_EAP_MSCHAPV2=y
# EAP-PEAP for the integrated EAP server
CONFIG_EAP_PEAP=y
# EAP-GTC for the integrated EAP server
CONFIG_EAP_GTC=y
# EAP-TTLS for the integrated EAP server
CONFIG_EAP_TTLS=y
# PKCS#12 (PFX) support (used to read private key and certificate file from
# a file that usually has extension .p12 or .pfx)
CONFIG_PKCS12=y
# Build IPv6 support for RADIUS operations
CONFIG_IPV6=y
# IEEE 802.11n (High Throughput) support
CONFIG_IEEE80211N=y
# IEEE 802.11ac (Very High Throughput) support
CONFIG_IEEE80211AC=y
# Remove debugging code that is printing out debug messages to stdout.
# This can be used to reduce the size of the hostapd considerably if debugging
# code is not needed.
CONFIG_NO_STDOUT_DEBUG=y
# Add support for writing debug log to a file: -f /tmp/hostapd.log
# Disabled by default.
CONFIG_DEBUG_FILE=y
# Remove support for dumping internal state through control interface commands
# This can be used to reduce binary size at the cost of disabling a debugging
# option.
CONFIG_NO_DUMP_STATE=y

nano config_file.c
Ищем в разделе static int hostapd_config_fill кусок кода с содержиым:
#ifdef CONFIG_IEEE80211N

	} else if (os_strcmp(buf, "ieee80211n") == 0) {
		conf->ieee80211n = atoi(pos);

изменяем на:
#ifdef CONFIG_IEEE80211N
	
	} else if (os_strcmp(buf, "noscan") == 0) {
		conf->noscan = atoi(pos);
	} else if (os_strcmp(buf, "ieee80211n") == 0) {
		conf->ieee80211n = atoi(pos);

cd ..
nano src/ap/ap_config.h

в разделе struct hostapd_config ищем строки вида:
	int ht_op_mode_fixed;
	u16 ht_capab;
	int ieee80211n;
	int secondary_channel;
	int require_ht;

добавляем строчку:
	int ht_op_mode_fixed;
	u16 ht_capab;
	int noscan;
	int ieee80211n;
	int secondary_channel;
	int require_ht;

nano src/ap/hw_features.c

В разделе static int ieee80211n_check_40mhz ищем строки:
{
	struct wpa_driver_scan_params params;
	int ret;

	if (!iface->conf->secondary_channel)
		return 0; /* HT40 not used */

	hostapd_set_state(iface, HAPD_IFACE_HT_SCAN);
	wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
		   "40 MHz channel");

и изменяем на:
{
	struct wpa_driver_scan_params params;
	int ret;

	if (!iface->conf->secondary_channel || iface->conf->noscan)
		return 0; /* HT40 not used */

	hostapd_set_state(iface, HAPD_IFACE_HT_SCAN);
	wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
		   "40 MHz channel");

Возвращаемся в папку hostapd и собираем hostapd:
cd hostapd
make
make install

выхлоп make install подскажет куда скомипилировались исполняемые файлы hostapd. В моём случае это /usr/local/bin/hostapd
mkdir /etc/hostapd
cp /usr/local/bin/hostapd /usr/sbin/hostapd
nano /etc/default/hostapd.conf

DAEMON_CONF="/etc/hostapd/hostapd.conf"
RUN_DAEMON="YES"

Вносим скрипт управления демоном:
nano /etc/init.d/hostapd

#!/bin/sh
### BEGIN INIT INFO
# Provides: hostapd Required-Start: $remote_fs Required-Stop: $remote_fs 
# Should-Start: $network Should-Stop: Default-Start: 2 3 4 5 
# Default-Stop: 0 1 6 Short-Description: Advanced IEEE 802.11 management 
# daemon Description: Userspace IEEE 802.11 AP and IEEE 
# 802.1X/WPA/WPA2/EAP
#			Authenticator
### END INIT INFO
PATH=/sbin:/bin:/usr/sbin:/usr/bin
DAEMON_SBIN=/usr/sbin/hostapd
DAEMON_DEFS=/etc/default/hostapd
DAEMON_CONF=/etc/hostapd/hostapd.conf
NAME=hostapd 
DESC="advanced IEEE 802.11 management"
PIDFILE=/run/hostapd.pid
[ -x "$DAEMON_SBIN" ] || exit 0
[ -s "$DAEMON_DEFS" ] && /etc/default/hostapd
[ -n "$DAEMON_CONF" ] || exit 0
DAEMON_OPTS="-B -P $PIDFILE $DAEMON_OPTS $DAEMON_CONF"

. /lib/lsb/init-functions

case "$1" in
  start)
	log_daemon_msg "Starting $DESC" "$NAME"
	start-stop-daemon --start --oknodo --quiet --exec "$DAEMON_SBIN" \
		--pidfile "$PIDFILE" -- $DAEMON_OPTS >/dev/null
	log_end_msg "$?"
	;;
  stop)
	log_daemon_msg "Stopping $DESC" "$NAME"
	start-stop-daemon --stop --oknodo --quiet --exec "$DAEMON_SBIN" \
		--pidfile "$PIDFILE"
	log_end_msg "$?"
	;;
  reload)
  	log_daemon_msg "Reloading $DESC" "$NAME"
	start-stop-daemon --stop --signal HUP --exec "$DAEMON_SBIN" \
		--pidfile "$PIDFILE"
	log_end_msg "$?"
	;;
  restart|force-reload)
  	$0 stop
	sleep 8
	$0 start
	;;
  status)
	status_of_proc "$DAEMON_SBIN" "$NAME"
	exit $?
	;;
  *)
	N=/etc/init.d/$NAME
	echo "Usage: $N {start|stop|restart|force-reload|reload|status}" >&2
	exit 1
	;;
esac

exit 0

chmod +x /etc/init.d/hostapd
update-rc.d hostapd defaults
nano /etc/hostapd/ifupdown.sh

#!/bin/sh

# Copyright (C) 2006-2009 Debian hostapd maintainers 
# 	Faidon Liambotis <paravoid@debian.org>
#	Kel Modderman <kel@otaku42.de>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# On Debian GNU/Linux systems, the text of the GPL license,
# version 2, can be found in /usr/share/common-licenses/GPL-2.

# quit if we're called for lo
if [ "$IFACE" = lo ]; then
	exit 0
fi

if [ -n "$IF_HOSTAPD" ]; then
	HOSTAPD_CONF="$IF_HOSTAPD"
else
	exit 0
fi

HOSTAPD_BIN="/usr/sbin/hostapd"
HOSTAPD_PNAME="hostapd"
HOSTAPD_PIDFILE="/run/hostapd.$IFACE.pid"
HOSTAPD_OMIT_PIDFILE="/run/sendsigs.omit.d/hostapd.$IFACE.pid"

if [ ! -x "$HOSTAPD_BIN" ]; then
	exit 0
fi

if [ "$VERBOSITY" = "1" ]; then
	TO_NULL="/dev/stdout"
else
	TO_NULL="/dev/null"
fi

hostapd_msg () {
	case "$1" in
		verbose)
			shift
			echo "$HOSTAPD_PNAME: $@" > "$TO_NULL"
			;;
		stderr)
			shift
			echo "$HOSTAPD_PNAME: $@" > /dev/stderr
			;;
		*)
			;;
	esac
}

test_hostapd_pidfile () {
	if [ -n "$1" ] && [ -f "$2" ]; then
		if start-stop-daemon --stop --quiet --signal 0 \
			--exec "$1" --pidfile "$2"; then
			return 0
		else
			rm -f "$2"
			return 1
		fi
	else
		return 1
	fi
}

init_hostapd () {
	HOSTAPD_OPTIONS="-B -P $HOSTAPD_PIDFILE $HOSTAPD_CONF"
	HOSTAPD_MESSAGE="$HOSTAPD_BIN $HOSTAPD_OPTIONS"
	
	test_hostapd_pidfile "$HOSTAPD_BIN" "$HOSTAPD_PIDFILE" && return 0

	hostapd_msg verbose "$HOSTAPD_MESSAGE"
	start-stop-daemon --start --oknodo --quiet --exec "$HOSTAPD_BIN" \
		--pidfile "$HOSTAPD_PIDFILE" -- $HOSTAPD_OPTIONS > "$TO_NULL"

	if [ "$?" -ne 0 ]; then
		return "$?"
	fi

	HOSTAPD_PIDFILE_WAIT=0
	until [ -s "$HOSTAPD_PIDFILE" ]; do
		if [ "$HOSTAPD_PIDFILE_WAIT" -ge 5 ]; then
			hostapd_msg stderr \
				"timeout waiting for pid file creation"
			return 1
		fi

		HOSTAPD_PIDFILE_WAIT=$(($HOSTAPD_PIDFILE_WAIT + 1))
		sleep 1
	done
	cat "$HOSTAPD_PIDFILE" > "$HOSTAPD_OMIT_PIDFILE"

	return 0
}

kill_hostapd () {
	HOSTAPD_MESSAGE="stopping $HOSTAPD_PNAME via pidfile: $HOSTAPD_PIDFILE"

	test_hostapd_pidfile "$HOSTAPD_BIN" "$HOSTAPD_PIDFILE" || return 0
	
	hostapd_msg verbose "$HOSTAPD_MESSAGE"
	start-stop-daemon --stop --oknodo --quiet --exec "$HOSTAPD_BIN" \
		--pidfile "$HOSTAPD_PIDFILE" > "$TO_NULL"
	
	[ "$HOSTAPD_OMIT_PIDFILE" ] && rm -f "$HOSTAPD_OMIT_PIDFILE"
}

case "$MODE" in 
	start)
		case "$PHASE" in
			pre-up)
				init_hostapd || exit 1
				;;
			*)
				hostapd_msg stderr "unknown phase: \"$PHASE\""
				exit 1
				;;
		esac
		;;
	stop)
		case "$PHASE" in
			post-down)
				kill_hostapd
				;;
			*)
				hostapd_msg stderr "unknown phase: \"$PHASE\""
				exit 1
				;;
		esac
		;;
	*)
		hostapd_msg stderr "unknown mode: \"$MODE\""
		exit 1
		;;
esac

exit 0

chmod +x /etc/hostapd/ifupdown.sh
ln -s /etc/hostapd/ifupdown.sh  /etc/network/if-pre-up.d/hostapd
ln -s /etc/hostapd/ifupdown.sh  /etc/network/if-post-down.d/hostapd

nano /etc/hostapd/hostapd.conf

interface=wlan0
driver=nl80211
ssid=Debian
hw_mode=g
macaddr_acl=0
auth_algs=1
ieee80211n=1
ht_capab=[HT40-][HT40+][SHORT-GI-40][RX-STBC1][DSSS_CCK-40]
channel=5
wmm_enabled=1
noscan=1
wpa=2
wpa_passphrase=PASSWORD
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP
rts_threshold=500
fragm_threshold=2346

Устанавливаем и настраиваем DHCP сервер:
apt-get install ics-dhcp-server
nano /etc/dhcpd/dhcpd.conf

# dhcpd.conf
#
default-lease-time 36000;
max-lease-time 72000;

ddns-update-style none;

subnet 192.168.0.0 netmask 255.255.255.0 {
range 192.168.0.10 192.168.0.100;
option domain-name-servers 8.8.8.8;
option routers 192.168.0.1;
#Set static IP by MAC:
host ml2165w  { hardware ethernet 00:15:99:e1:fe:c2; fixed-address 192.168.0.5; }
}

shutdown -r now

На данном этапе у нас должна работать точка доступа, к ней можно будет подключиться, но интернета не будет. Почему? потому что нужен NAT. Собственно на базовом уровне его и активируем:
раскомментируем строчку в /etc/sysctl.conf:
net.ipv4.ip_forward=1

nano /etc/network/if-pre-up.d/nat

#!/bin/sh
/sbin/iptables -A POSTROUTING -t nat -j MASQUERADE

chmod +x /etc/network/if-pre-up.d/nat

Вот теперь должен заработать и интернет.

Во всём этом «великолепии» есть нюансы — обновляться геморрой, собранный hostapd сыплет логами работы iwlwifi в tty1. в ssh не видно, а вот напрямую если работать напрягает. Побороть пока не получилось (пробовал играть с конфигом сборки hostapd, и с настройкой логгера в hostapd.conf).