How To Set Up A FreeBSD Wireless Access Point

This document will guide you on how to use a FreeBSD system as a wireless access point. This is intended to supplement the FreeBSD Handbook and not replace it.

Getting FreeBSD to act as a wireless access point involves the following steps:

  • Make sure your installation includes hostapd and named (BIND)
  • Recompile your kernel for pf support
    • pf is not the only way to do this, but I strongly prefer pf to the ipfw/ipfilter and have written the How-To to use it
  • Configure NAT (and any firewall rules)
  • Install isc-dhcp3-server
  • Configure daemons and start them

Hardware Requirements/Notes:

  • One network card to connect to the upstream. This is the external network interface (ext_if). In this How-To it will be fxp0. Yours may differ.
  • One wireless card to provide wireless services. I prefer Atheros-based cards, whatever FreeBSD supported card you have is fine, though (wifi_if). In this How-To it will be ath0. Yours may differ.
  • Optionally, an additional wired network card (int_if) for wired LAN access (via crossover cable or a network switch/hub). Not necessary, but my system provides both wirless and wired LAN access. In this How-To it will be fxp1. yours may differ.

Downloadable sample configuration files are available at http://tun0.net/ascii/config/freebsd_access_point/.

Getting Started

Before we proceed, it's a good idea to connect the FreeBSD system you wish to make an access point to the Internet. Connecting to the Internet (or whatever upstream connection you have) is beyond the scope of this document. There is an entire chapter on Network Communication in the FreeBSD Handbook.

For the sake of simplicity, please execute all commands provided on this site as root. The majority of them will require root privileges anyway. To become root, type su, enter the root password and hit enter.

Check if you have BIND

BIND is usually distributed with FreeBSD, however, just to make sure BIND is present on your system, execute the following command:

which named

If that tells you named not found, then you will have to install BIND.

sudo pkg_add -r bind9

Check if you have hostapd

Check for hostapd using the which command:

which hostapd

The hostapd program is part of the base FreeBSD system. If it is not present, you may have a minimal system. You can use the FreeBSD installer to add more distribution sets or just update your system from sources and obtain it that way.

Check if you have kernel sources

You will need to build a custom kernel since the base kernel does not offer the OpenBSD Packet Filter (pf). This is a simple and relatively quick process and will be discussed later.

ls -l /usr/src/sys

If the above tells you No such file or directory or outputs no data, then you will need to obtain kernel sources. This is well explained in the Synchronizing Your Source section of the FreeBSD Handbook.

Recompile Your Kernel

The process of recompiling your kernel and including PF support is well documented in the FreeBSD Handbook. I shall summarize the process below.

Go to the kernel configuration directory and start your own kernel configuration based on the GENERIC (default, stock) kernel.

cd /usr/src/sys/`uname -m`/conf
cp GENERIC CUSTOM

You may edit the above how ever you wish as long as you know what you're doing. You can consult the /usr/src/sys/conf/NOTES file for explanations on any kernel option. Just make sure that you add the following lines for PF support. You may use vi, your favorite text editor, or just echo it into the file.

echo "device pf
device pflog
device pfsync" >> CUSTOM

Optionally, if you wish to take advantage of PF's traffic shaping abilities (ALTQ), I'd recommend adding the following lines to your custom kernel configuration:

options         ALTQ
options         ALTQ_CBQ        # Class Bases Queuing (CBQ)
options         ALTQ_RED        # Random Early Detection (RED)
options         ALTQ_RIO        # RED In/Out
options         ALTQ_HFSC       # Hierarchical Packet Scheduler (HFSC)
options         ALTQ_PRIQ       # Priority Queuing (PRIQ)
options         ALTQ_NOPCC      # Required for SMP build

Now execute the following commands to build and install the new kernel.

cd /usr/src
make buildkernel KERNCONF=CUSTOM
make installkernel KERNCONF=CUSTOM

Finally, reboot so that you can use the new kernel.

shutdown -r now

Overview on Wireless Access Point Network

We will be setting up a system as follows:

  • fxp0 - ext_if - external card that connects to cable/DSL modem, WAN, etc.
  • fxp1 - lan_if - internal card that provides wired LAN access.
  • ath0 - wifi_if - internal wireless card for wireless access point connections.
If you're aiming for only a wireless LAN, you can omit all references to fxp1 and lan_if. In configuration files simply delete $lan_if from all files. Conversely, for wired only setups, remove all references to $wifi_if and ath0.

The network will be confgiured as follows:

  • fxp0 - ext_if - DHCP configured from upstream (e.g. let cable modem provide an IP)
  • fxp1 - lan_if - static IP, 192.168.0.1; wired subnet will be 192.168.0.0/24; clients on LAN configured via DHCP
  • ath0 - wifi_if - static IP, 192.168.1.1; wireless subnet will be 192.168.1.0/24; clients on WLAN configured via DHCP

Configure the interfaces

Get an IP for the ext_if (the external interface)

dhclient fxp0

Set the IP on lan_if

ifconfig fxp1 inet 192.168.0.1 netmask 255.255.255.0

Make sure drivers are loaded for the wireless interface. For Atheros based cards you'll need the following single, one-line command:

for d in {if_ath,ath_rate,ath_hal}; do kldload $d; done

For any wireless card, including Atheros cards, make sure we have all the proper wireless modules loaded. The following is a long line, but it is a single, one-line command:

for d in {wlan_wep_load,wlan_tkip_load,wlan_ccmp_load,wlan_xauth_load,wlan_acl_load}; do kldload $d; done

Set the IP on wifi_if (ath0) using the single, one-line command:

ifconfig ath0 inet 192.168.1.1 netmask 255.255.255.0 ssid YOURSSID mediaopt hostap

Configure NAT (and any firewall rules)

First, let's set the system up to act as a router/gateway and enable PF. Perform the following commands as root.

sysctl -w net.inet.ip.forwarding=1
pfctl -e

Create a pf.conf for NAT and some basic firewall rules. Use vi or your favorite editor and add the following to the /etc/pf.conf file.

# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# This configuration is set for use on a machine that is a router with
# three (3) network cards:
# ext_if - connects to the upstream link (cable/dsl modem, WAN, etc.)
# wifi_if - wireless card for internal network
#           (if none present, remove all references to it in this file)
# lan_if  - wired card for internal network
#           (if none present, remove all references to it in this file)
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#------------------------------------------------------------------------
# macros
#------------------------------------------------------------------------
logopt = "log"
# interfaces
ext_if  = "fxp0"
wifi_if = "ath0"
lan_if  = "fxp1"
# publically accesible services (transport layer neutral)
pubserv = "{ 22, 443 }"
# internally accessible services (transport layer neutral)
lanserv = "{ 22, 53, 67, 80, 443 }"
# samba ports (transport layer neutral)
samba_ports = "{ 137, 138, 139 }"
# externally permitted inbound icmp types
icmp_types = "echoreq"
# internal network
lan_net = "{ 192.168.0.0/24, 192.168.1.0/24 }"
# hosts granted acces to samba (cifs/smb) shares
smb_net = "{ 192.168.0.0/27, 192.168.1.0/27, 192.168.0.90, 192.168.1.90 }"
# block these networks
table  { 0.0.0.0/8, 10.0.0.0/8, 20.20.20.0/24, 127.0.0.0/8, \
        169.254.0.0/16, 172.16.0.0/12,  192.0.2.0/24, 192.168.0.0/16, \
        224.0.0.0/3,    255.255.255.255 }
#------------------------------------------------------------------------
# options
#------------------------------------------------------------------------
# config
set block-policy return
set loginterface $ext_if
set skip on lo0
# scrub
#scrub all reassemble tcp no-df
#scrub in all fragment reassemble
scrub out all random-id
#------------------------------------------------------------------------
# redirection (and nat, too!)
#------------------------------------------------------------------------
# network address translation
nat on $ext_if from $lan_net to any -> ($ext_if)
#------------------------------------------------------------------------
# firewall policy
#------------------------------------------------------------------------
# restrictive default rules
block all
block return-rst  in  $logopt on $ext_if proto tcp all
block return-icmp in  $logopt on $ext_if proto udp all
block             in  $logopt on $ext_if proto icmp all
block             out $logopt on $ext_if all
# trust localhost
pass in  quick on lo0 all
pass out quick on lo0 all
# anti spoofing
block drop in  $logopt quick on $ext_if from  to any
block drop out $logopt quick on $ext_if from any to 
antispoof for { $lan_if, $wifi_if, $ext_if }
# anti fake return-scans
block  return-rst  out on $ext_if proto tcp all 
block  return-rst  in  on $ext_if proto tcp all 
block  return-icmp out on $ext_if proto udp all
block  return-icmp in  on $ext_if proto udp all 
# toy with script kiddies scanning us
block in $logopt quick proto tcp flags FUP/WEUAPRSF 
block in $logopt quick proto tcp flags WEUAPRSF/WEUAPRSF 
block in $logopt quick proto tcp flags SRAFU/WEUAPRSF 
block in $logopt quick proto tcp flags /WEUAPRSF 
block in $logopt quick proto tcp flags SR/SR 
block in $logopt quick proto tcp flags SF/SF 
# open firewall fully
# warning: insecure. 'nuff said.
#pass in  quick all
#pass out quick all
# allow permitted icmp
pass in inet proto icmp all icmp-type $icmp_types keep state
# allow permitted services
pass in on $ext_if            inet proto tcp       from any      to any port $pubserv flags S/SA keep state
pass in on {$lan_if $wifi_if} inet proto {tcp udp} from $lan_net to any port $lanserv            keep state
pass in on {$lan_if $wifi_if} inet proto {tcp udp} from $smb_net to any port $samba_ports        keep state
# permit access between LAN hosts
pass in  from $lan_net to $lan_net keep state
pass out from $lan_net to $lan_net keep state
# permit full outbound access 
# warning: potentially insecure. you may wish to lock down outbound access.
pass out from any to any keep state

Load the above configuration with the following command:

pfctl -Fa -f /etc/pf.conf

Install and configure the ISC DHCP server

To dynamically assign IP addresses to clients on your LAN/WLAN, you'll need the ISC DHCP server.

pkg_add -r isc-dhcp3-server

Next edit it's configuration file, /usr/local/etc/dhcpd.conf:

###
### GLOBAL SETTINGS
###
ddns-update-style none;
always-broadcast on;
default-lease-time 7200;
max-lease-time 7200;
authoritative;
option domain-name-servers 192.168.1.1;
option domain-name "localnet.localdomain";
option netbios-name-servers 192.168.1.1;
###
### WIRED LOCAL AREA NETWORK
###
subnet 192.168.0.0 netmask 255.255.255.0 {
	#
	# NOTES:
	# (1) allocation of endings 100-199 by DHCP is 
	# inteded for clients that are not specified
	# later in this file.
	# (2) allocation is done in increments of 10
	# and this is done intentionally.
	#
	range 192.168.0.100 192.168.0.199;
	option broadcast-address 192.168.0.255;
	option subnet-mask 255.255.255.0;
	option routers 192.168.0.1;
}
###
### WIRELESS NETWORK 
###
subnet 192.168.1.0 netmask 255.255.255.0 {
	# NOTE: See: wired->range.notes
        range 192.168.1.100 192.168.1.199;
        option broadcast-address 192.168.1.255;
        option subnet-mask 255.255.255.0;
        option routers 192.168.1.1;
}
###
### ASSIGN SPECIFIC IP ADDRESSES TO SPECIFIC HOSTS BASED ON MAC ADDRESS
### (optional)
###
## host foo
#host foo {
#        hardware ethernet XX:XX:XX:XX:XX:XX;
#        fixed-address 192.168.0.XYZ;
#}
## host bar
#host bar {
#        hardware ethernet XX:XX:XX:XX:XX:XX;
#        fixed-address 192.168.1.XYZ;
#}

Configure hostapd

Edit /etc/hostapd.conf as follows:
interface=ath0
driver=bsd
logger_syslog=-1
logger_syslog_level=0
logger_stdout=-1
logger_stdout_level=0
debug=3
dump_file=/tmp/hostapd.dump
ctrl_interface=/var/run/hostapd
ctrl_interface_group=wheel
#### IEEE 802.11 related config ####
ssid=YOURSSID
macaddr_acl=0
auth_algs=1
#### IEEE 802.1X related config ####
ieee8021x=0
#### WPA/IEEE 802.11i config #####
wpa=1
wpa_passphrase=ENTER_YOUR_PASSPHRASE_HERE
wpa_key_mgmt=WPA-PSK
wpa_pairwise=CCMP TKIP

Make our settings permanant via rc.conf

We don't want to manually configure our interfaces or start our daemons manually each time, so we'll put it all into /etc/rc.conf:

### GENERAL SETTINGS
gateway_enable="YES"
hostname="wifiap"
### CONFIGURATION FOR EXTERNAL INTERFACE (UPSTREAM LINK)
### example: link to cable/dsl modem
ifconfig_fxp0="DHCP"
### CONFIGURATION FOR INTERNAL WIRED NETWORK
ifconfig_fxp1="inet 192.168.0.1 netmask 255.255.255.0"
### CONFIGURATION FOR INTERNAL WIRELESS NETWORK
ifconfig_ath0="inet 192.168.1.1 netmask 255.255.255.0 ssid YOURSSID mediaopt hostap"
### CONFIGURATION FOR PACKET FILTER
### requires kernel recompile, see:
### http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/firewalls-pf.html
pf_enable="YES"                 # Set to YES to enable packet filter (pf)
pf_rules="/etc/pf.conf"         # rules definition file for pf
pf_program="/sbin/pfctl"        # where the pfctl program lives
pf_flags=""                     # additional flags for pfctl
pflog_enable="YES"              # Set to YES to enable packet filter logging
pflog_logfile="/var/log/pflog"  # where pflogd should store the logfile
### DAEMONS FOR LAN
hostapd_enable="YES"            # wireless services (clients use wpa_supplicant)
named_enable="YES"              # dns for clients
dhcpd_enable="YES"              # dhcp configure clients
sshd_enable="YES"               # so we can remotely access this box

We don't want to have to manually load kernel modules all the time either, so we'll put them into /boot/loader.conf:

wlan_wep_load="YES"
wlan_tkip_load="YES"
wlan_ccmp_load="YES"
wlan_xauth_load="YES"
wlan_acl_load="YES"

Start daemons

You can do this easily by rebooting:
shutdown -r now
If you're a true Unix zealot, however, and dislike rebooting unnecessarily, you can do the following:

/etc/rc.d/pflog start
/etc/rc.d/named start
/etc/rc.d/dhcpd start
/etc/rc.d/hostapd start

Done!

Congratulations! At this point, assuming you followed the directions and had no errors, you should have a functional wireless access point using WPA and a wired LAN that is connected to the upstream link.

Share this page:

5 Comment(s)