Podczas pisania artykułu na temat freeradiusa, znalazłem kilka ciekawych informacji niezbyt powiązanych jako tako z tematem freeradiusa ale jakże użytecznych pod kątem zastosowania. Jakiś czas temu dokonałem zakupu adaptera wifi TP-Link TL-WN722n -- potrzebowałem zewnętrznej karty sieciowej do mojego lapka, bo ten z kolei ma na pokładzie niezbyt użytecznego broadcoma. Chodziło mi głównie o pozyskanie odpowiedniej karty w celu przeprowadzania szeregu testów, których nie mogłem w standardzie wykonać korzystając z wbudowanej w mój laptop karty wifi. Jak się później okazało, zakupiony adapter posiada też dodatkowy ficzer -- tryb AP, który umożliwia przerobienie zwykłej maszyny z debianem na Access Pointa sieci wifi. W prawdzie ta karta nie może się równać z routerami wifi, bo te zwykle mają więcej anten, z których każda jest lepszej jakości, co przekłada się na lepszy zasięg i transfer ale daje ona nam możliwość połączenia dwóch i więcej maszyn w sieć -- zwykle karty wifi nie posiadają trybu AP, a jedynie tryb STA (czasem też i monitor), co uniemożliwia komunikację.

Jeśli nie wiemy czy nasza karta wifi potrafi przełączyć się w tryb AP, możemy to sprawdzić przez wydanie poniższego polecenia:

root:~# iw list
Wiphy phy0
...
   Supported interface modes:
      * IBSS
      * managed
      * AP
      * AP/VLAN
      * monitor
      * mesh point
      * P2P-client
      * P2P-GO
...

Adapter TP-Link TL-WN722n wymaga dodatkowo doinstalowania firmware:

[   95.976030] usb 1-3: new high-speed USB device number 2 using ehci-pci
[   96.124912] usb 1-3: New USB device found, idVendor=0cf3, idProduct=9271
[   96.124919] usb 1-3: New USB device strings: Mfr=16, Product=32, SerialNumber=48
[   96.124923] usb 1-3: Product: USB2.0 WLAN
[   96.124927] usb 1-3: Manufacturer: ATHEROS
[   96.124930] usb 1-3: SerialNumber: 12345
[   96.244516] cfg80211: Calling CRDA to update world regulatory domain
[   96.333668] usb 1-3: ath9k_htc: Firmware htc_9271.fw requested
[   96.334049] usbcore: registered new interface driver ath9k_htc
[   96.344163] usb 1-3: firmware: failed to load htc_9271.fw (-2)
[   96.344176] usb 1-3: Direct firmware load failed with error -2
[   96.344180] usb 1-3: Falling back to user helper
[   96.344926] usb 1-3: ath9k_htc: USB layer deinitialized

Na maszynie, do której podepniemy wspomniane urządzonko, musimy zainstalować również odpowiednie oprogramowanie. Poniżej jest lista potrzebnych nam pakietów:

# aptitude install hostapd dnsmasq firmware-atheros crda

Oprogramowanie, które właśnie zainstalowaliśmy, jest używane również przez OpenWRT i to dokładnie w tym samym celu, w którym my zamierzamy je wykorzystać na debianie. Jeśli chcemy połączyć tylko dwie maszyny ze sobą, to niekoniecznie potrzebujemy pakietu dnsmasq -- możemy skonfigurować klienta statycznie. Natomiast, jeśli w grę wchodzi więcej maszyn, to praktycznym rozwiązaniem byłoby zaprzęgnąć serwer DHCP, który automatycznie będzie konfigurował klientów.

Jeśli nie będziemy korzystać z dnsmasq, ustawiamy ręcznie konfigurację interfejsu w /etc/network/interfaces na maszynie klienckiej:

#auto wlan0
#allow-hotplug wlan0
iface wlan0 inet static
   address 192.168.20.200
   network 192.168.20.0/24
   netmask 255.255.255.0
   broadcast 192.168.20.255
   wpa-driver nl80211
   wpa-debug-level -1
   wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

W debianie pakiet hostapd jest skompilowany domyślnie z obsługą trybu N i nie musimy sobie głowy zawracać rekompilacją źródeł. Na wypadek gdybyśmy mieli nieszczęście trafić na pakiety bez obsługi trybu N, warto wiedzieć, gdzie ewentualnie zmienić konfigurację. Niekoniecznie trzeba pobierać i kompilować źródła ręcznie [1] -- możemy wykorzystać debianowe, czyli pobrać je przy pomocy apt-get source i w pliku wpa-1.1/debian/config/hostapd/linux odhashować poniższe linijki:

...
CONFIG_DRIVER_NL80211=y
...
CONFIG_IEEE80211N=y
...

I zrobić odpowiednią paczuszkę -- nie będę tutaj opisywał procesu tworzenia paczki, bo to jest temat na osobny artykuł.

Po ponownym podłączeniu adaptera do portu usb, powinniśmy mieć w systemie nowy interfejs sieciowy -- wlan0:

# ip link show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 00:16:e6:34:c4:e0 brd ff:ff:ff:ff:ff:ff
5: wlan0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether e8:94:f6:1e:15:e9 brd ff:ff:ff:ff:ff:ff

Musimy jeszcze przypisać interfejsowi wlan0 statyczny adres IP:

auto wlan0
iface wlan0 inet static
   address 192.168.20.1
   network 192.168.20.0/24
   netmask 255.255.255.0
   broadcast 192.168.20.255

Konfiguracja hostapd

Z pakietem hostapd jest dostarczany obszerny plik konfiguracyjny. Znajduje się on w /usr/share/doc/hostapd/examples/hostapd.conf.gz -- trzeba go przekopiować do /etc/hostapd/hostapd.conf :

# zcat /usr/share/doc/hostapd/examples/hostapd.conf.gz > /etc/hostapd/hostapd.conf

Edytujemy także plik /etc/default/hostapd i zmieniamy w nim:

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

Przechodzimy teraz do konfiguracji AP -- edytujemy plik /etc/hostapd/hostapd.conf i uzupełniamy w nim odpowiednie linijki:

interface=wlan0
driver=nl80211
ctrl_interface_group=0
ssid=Valar Morgulis
country_code=PL
ieee80211d=1
hw_mode=g
channel=8
auth_algs=1
ignore_broadcast_ssid=0
ap_max_inactivity=600

ieee80211n=1
require_ht=0

eapol_version=2

wpa=2
wpa_psk=363686d31b1cda24ef42b76452baf8fbca0fa55535df2f8aa04a7884a13e7946
wpa_key_mgmt=WPA-PSK WPA-PSK-SHA256
wpa_pairwise=CCMP
rsn_pairwise=CCMP
wpa_group_rekey=600
wpa_gmk_rekey=21600
peerkey=1

wps_state=0

W celu wygenerowania hasła do naszej sieci wifi, użyjemy wpa_passphrase :

# wpa_passphrase 'Valar Morgulis' 'morfik-ma-kota'
...
   psk=363686d31b1fda24ef42b86452baf8fbca0faa3f35df2f8ad04a7884213e7916
...

Istnieje możliwość sprecyzowania więcej niż jednego hasła do sieci wifi. W tym celu potrzebny będzie osobny plik, za który odpowiada parametr wpa_psk_file . My ograniczymy się do jednego hasła zakodowanego w base64.

Restartujemy daemona hostapd i sieć powinna być już widoczna przy skanowaniu pasma:

# wpa_cli scan
Selected interface 'wlan0'
OK

# wpa_cli scan_results
Selected interface 'wlan0'
bssid / frequency / signal level / flags / ssid
...
e8:94:f6:1e:15:e9       2447    -29     [WPA2-PSK+PSK-SHA256-CCMP][ESS] Valar Morgulis
...

Trzeba nam jeszcze odpowiedniej konfiguracji dla wpasupplicanta, którą to musimy dopisać do pliku /etc/wpa_supplicant/wpa_supplicant.conf :

network={
    id_str="home_wifi_static"
    priority=5
    ssid="Valar Morgulis"
    bssid=e8:94:f6:1e:15:e9
    #psk="morfik-ma-kota"
    psk=363686d31b1fda24ef42b86452baf8fbca0faa3f35df2f8ad04a7884213e7916
    proto=RSN
    key_mgmt=WPA-PSK-SHA256
    pairwise=CCMP
    group=CCMP
    auth_alg=OPEN
    scan_ssid=0
    disabled=0
}

Spróbujmy się podłączyć do sieci by sprawdzić czy wszystko jest w porządku. W tym celu odpalany wpasupplicanta w trybie debug wpisując w terminal dwie poniższe linijki:

# /sbin/wpa_supplicant -P /var/run/wpa_supplicant.wlan0.pid -i wlan0 -W -b bond0 -D nl80211,wext -c /etc/wpa_supplicant/wpa_supplicant.conf

# /sbin/wpa_cli -P /var/run/wpa_action.wlan0.pid -i wlan0 -p /var/run/wpa_supplicant -a /sbin/wpa_action

Jeśli połączenie działa jak należy, powinniśmy zobaczyć na pierwszej konsoli poniższy log:

wlan0: SME: Trying to authenticate with e8:94:f6:1e:15:e9 (SSID='Valar Morgulis' freq=2447 MHz)
wlan0: Trying to associate with e8:94:f6:1e:15:e9 (SSID='Valar Morgulis' freq=2447 MHz)
wlan0: Associated with e8:94:f6:1e:15:e9
wlan0: WPA: Key negotiation completed with e8:94:f6:1e:15:e9 [PTK=CCMP GTK=CCMP]
wlan0: CTRL-EVENT-CONNECTED - Connection to e8:94:f6:1e:15:e9 completed (auth) [id=5 id_str=]

Dodatkowo w syslogu powinniśmy ujrzeć:

Sep 21 02:44:59 morfikownia wpa_action: WPA_IFACE=wlan0 WPA_ACTION=CONNECTED
Sep 21 02:44:59 morfikownia wpa_action: WPA_ID=5 WPA_ID_STR= WPA_CTRL_DIR=/var/run/wpa_supplicant
Sep 21 02:44:59 morfikownia wpa_action: network settings not defined for default in /etc/network/interfaces
Sep 21 02:44:59 morfikownia wpa_action: ifup wlan0=default
Sep 21 02:44:59 morfikownia wpa_action: creating sendsigs omission pidfile: /run/sendsigs.omit.d/wpasupplicant.wpa_supplicant.wlan0.pid
Sep 21 02:44:59 morfikownia wpa_action: bssid=e8:94:f6:1e:15:e9
Sep 21 02:44:59 morfikownia wpa_action: ssid=Valar Morgulis
Sep 21 02:44:59 morfikownia wpa_action: id=5
Sep 21 02:44:59 morfikownia wpa_action: mode=station
Sep 21 02:44:59 morfikownia wpa_action: pairwise_cipher=CCMP
Sep 21 02:44:59 morfikownia wpa_action: group_cipher=CCMP
Sep 21 02:44:59 morfikownia wpa_action: key_mgmt=WPA2-PSK-SHA256
Sep 21 02:44:59 morfikownia wpa_action: wpa_state=COMPLETED
Sep 21 02:44:59 morfikownia wpa_action: address=c0:cb:38:01:f0:f5

Jak widać powyżej, wszystkie parametry konfiguracyjne sieci wifi są takie jak być powinny.

Konfiguracja dnsmasq

Konfiguracja serwera DHCP i DNS trzymana jest w pliku /etc/dnsmasq.conf ale zanim tam przejdziemy, zajrzyjmy pierw do pliku /etc/default/dnsmasq i upewnijmy się, że dnsmasq jest włączony.

Poniżej znajduje się konfiguracja dnsmasq:

domain-needed
bogus-priv
local=/mhouse.lh/
interface=wlan0
no-hosts
expand-hosts
domain=mhouse.lh
dhcp-range=192.168.20.100,192.168.20.250,2h
#read-ethers
dhcp-lease-max=150
dhcp-leasefile=/etc/dnsmasq.leases
dhcp-authoritative
cache-size=1000
no-negcache

W przypadku gdybyśmy chcieli statyczne lease DHCP, możemy skorzystać z pliku /etc/ethers przez odhashowanie read-ethers . Ja tam jednak wolę precyzować hosty bezpośrednio w konfiguracji dnsmasq przy pomocy wpisów takich jak ten poniżej:

dhcp-host=c0:cb:38:01:f0:f5,morfikownia,192.168.20.200,2h

Powyższa linijka przydziela hostowi o adresie MAC c0:cb:38:01:f0:f5 adres IP 192.168.20.200 i nazwę morfikownia na 2 godziny.

Na kliencie ustawiamy poniższą konfigurację interfejsu wifi w /etc/network/interfaces :

#auto wlan0
#allow-hotplug wlan0
iface wlan0 inet dhcp
    wpa-driver nl80211
    wpa-debug-level -1
    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

Restartujemy dnsmasq i łączymy się do sieci -- serwer DHCP powinien nam przydzielić odpowiedni adres:

# ifup wlan0
Internet Systems Consortium DHCP Client 4.3.1
Copyright 2004-2014 Internet Systems Consortium.
All rights reserved.
For info, please visit https://www.isc.org/software/dhcp/

Listening on LPF/wlan0/c0:cb:38:01:f0:f5
Sending on   LPF/wlan0/c0:cb:38:01:f0:f5
Sending on   Socket/fallback
DHCPDISCOVER on wlan0 to 255.255.255.255 port 67 interval 5
DHCPDISCOVER on wlan0 to 255.255.255.255 port 67 interval 6
DHCPREQUEST on wlan0 to 255.255.255.255 port 67
DHCPOFFER from 192.168.20.1
DHCPACK from 192.168.20.1
bound to 192.168.20.200 -- renewal in 2903 seconds.

Jeśli planujemy wdrożyć jakiś filtr pakietów, trzeba uwzględnić w nim regułki przepuszczające ruch na portach 53/udp (zapytania DNS) oraz 67/udp (serwer DHCP).

AP z dostępem do internetu

Stworzony w ten sposób access point nie będzie miał dostępu do internetu. W przypadku jednak gdybyśmy chcieli go podłączyć, musimy dodać kilka regułek do filtra iptables. Poniżej jest skrypt firewalla, który wszystko ustawi jak trzeba:

#!/bin/sh
### BEGIN INIT INFO
# Provides:          firewall
# Required-Start:    mountkernfs $local_fs
# Required-Stop:     $local_fs
# Should-Start:
# Should-Stop:
# Default-Start:     S
# Default-Stop:      0 6
# X-Start-Before:
# X-Stop-After:
# Short-Description: firewall configuration
# Description:       firewall configuration
### END INIT INFO

do_start ()
{
        echo 1 > /proc/sys/net/ipv4/ip_forward

        iptables -t nat -A POSTROUTING -o eth0 -s 192.168.20.0/24 -d 0/0 -j MASQUERADE

        iptables -t filter -P INPUT DROP
        iptables -t filter -P FORWARD DROP
        iptables -t filter -P OUTPUT ACCEPT
        iptables -t filter -N tcp
        iptables -t filter -N udp
        iptables -t filter -N icmp_in
        iptables -t filter -N fw-interfaces

        iptables -t filter -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
        iptables -t filter -A INPUT -i lo -j ACCEPT
        iptables -t filter -A INPUT -m conntrack --ctstate INVALID -j DROP
        iptables -t filter -A INPUT -p icmp -m conntrack --ctstate NEW -j icmp_in
        iptables -t filter -A INPUT -p udp -m conntrack --ctstate NEW -j udp
        iptables -t filter -A INPUT -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j tcp
        iptables -t filter -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable
        iptables -t filter -A INPUT -p tcp -j REJECT --reject-with tcp-reset

        iptables -t filter -A icmp_in -p icmp -i eth0 -s 192.168.1.0/24 -d 192.168.1.166 -j ACCEPT
        iptables -t filter -A icmp_in -p icmp -i wlan0 -s 192.168.20.0/24 -d 192.168.20.1 -j ACCEPT

        iptables -t filter -A udp -p udp --dport 53 -j ACCEPT -m comment --comment "DNS"
        iptables -t filter -A udp -p udp --dport 68 -j ACCEPT -m comment --comment "Allow-DHCP-Renew"
        iptables -t filter -A udp -p udp --dport 67 -j ACCEPT -m comment --comment "DHCP-Server"

        iptables -t filter -A tcp -p tcp --dport 22 -s 192.168.1.0/24 -j ACCEPT -m comment --comment "SSH"
        iptables -t filter -A tcp -p tcp --dport 22 -s 192.168.20.0/24 -j ACCEPT -m comment --comment "SSH"

        iptables -t filter -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
        iptables -t filter -A FORWARD -m conntrack --ctstate INVALID -j DROP
        iptables -t filter -A FORWARD -m conntrack --ctstate NEW -j fw-interfaces
        iptables -t filter -A FORWARD -j REJECT --reject-with icmp-host-unreachable

        iptables -t filter -A fw-interfaces -i wlan0 -o eth0 -s 192.168.20.0/24 -j ACCEPT

}

do_stop ()
{
        iptables -t filter -P INPUT ACCEPT
        iptables -t filter -P FORWARD ACCEPT
        iptables -t filter -P OUTPUT ACCEPT
        iptables -t filter -F
        iptables -t filter -X
}

case "$1" in
        start)
                do_start
        ;;
        stop)
                do_stop
        ;;
        force-reload|restart)
                do_stop && sleep 1
                do_start
        ;;
        *)
                echo "Usage: firewall {start|stop|restart}"
                exit 1
        ;;
esac

exit 0

Zapisujemy go w /etc/init.d/firewall i dodajemy do autostartu systemu:

# update-rc.d firewall defaults

I w taki oto sposób mamy pseudo router wifi z debianem na pokładzie.

Pisane w oparciu o:

http://ariandy1.wordpress.com/2013/04/18/wifi-access-point-with-tp-link-tl-wn722n-on-ubuntu-12-04/ [2]
http://forum.doozan.com/read.php?2,6300 [3]
http://wireless.kernel.org/en/users/Documentation/hostapd [4]
http://w1.fi/ [5]


Przypisy:

  1. http://w1.fi/cvs.html
  2. http://ariandy1.wordpress.com/2013/04/18/wifi-access-point-with-tp-link-tl-wn722n-on-ubuntu-12-04/
  3. http://forum.doozan.com/read.php?2,6300
  4. http://wireless.kernel.org/en/users/Documentation/hostapd
  5. http://w1.fi/