LinuxQuestions.org
Visit Jeremy's Blog.
Go Back   LinuxQuestions.org > Linux Answers > Security
User Name
Password

Notices


By Kristijan at 2007-04-13 19:24
Introduction

Operating System: NetBSD (Any OS (OpenBSD/FreeBSD) which supports PF and AuthPF can be used)
Prior Knowlede: Basic Linux/BSD understanding / Basic concept of networking / Basic concept behind DHCP & DNS.

Whilst I work in the I.T field, I am no expert on network security, firewalls etc...This how-to is just documentation of the day to day stuff I enjoy dabbling in.

The formatting in the forums makes it a bit difficult to read, so if you prefer, there is a version on my website - http://www.kristijan.org/?q=node/499




Current & New Network Setup

This how-to is a follow on from the DHCP DNS & Firewall with NetBSD tutorial I wrote back in October 2006 which you can find here (http://kristijan.org/?q=node/58). Sections of this how-to will reference back to the older how-to, but this will be noted. The aim of this how-to is to add the wireless AP into my wired network, but restrict direct access to services, othewr LAN nodes and the Internet until authentication is granted.

Prior to following this guide, I recommend reading the following two links:

http://www.openbsd.org/faq/pf & http://www.openbsd.org/faq/pf/authpf.html


What the new network layout will look like

The access point will be physically connected to my gateway (krusty) via ethernet.

Gateway interfaces:
  • sip0 - 10.0.0.0/8 - ADSL modem bridge</li>
  • fxp0 - 192.168.0.0/24 - Wired LAN</li>
  • fxp1 - 192.168.1.0 - Wireless LAN</li>
I’ve assigned the wireless AP an IP address of 192.168.1.2. All wireless nodes will hang off of the 192.168.1.0/24 network, whilst all my physical nodes will hang off of the 192.168.0.0/24 network. The reason for this is so later on, I can easily create firewall rules to cater for each type of node.

New network layout - http://www.kristijan.org/images/random/kristijan-network.png




Setting up DHCP

To cater for the new subnet range (192.168.1.0), we need to let DHCP know of the new range, and also the interface to listen on for incoming requests.

Below is the full /etc/dhcpd.conf with the changes in bold.

Code:
# Server Configuration

authoritative;
ddns-update-style interim;
ignore client-updates;

key "rndc-key" {
        algorithm hmac-md5;
        secret "*jffq-31-1sfmkasf";
};

# Client Configuration

default-lease-time 604800;
max-lease-time 604800;

subnet 192.168.0.0 netmask 255.255.255.0 {
        do-forward-updates true;
        range 192.168.0.50 192.168.0.100;
        option subnet-mask 255.255.255.0;
        option domain-name-servers 192.168.0.10;
        option domain-name "in.kristijan.org";
        option routers 192.168.0.10;
}

subnet 192.168.1.0 netmask 255.255.255.0 {
        do-forward-updates true;
        range 192.168.1.10 192.168.1.30;
        option subnet-mask 255.255.255.0;
        option domain-name-servers 192.168.1.1;
        option domain-name "in.kristijan.org";
        option routers 192.168.1.1;
}


# Zone we are allowing DHCP to update

zone 0.168.192.in-addr.arpa. {
        primary 127.0.0.1;
        key rndc-key;
}

zone in.kristijan.org. {
        primary 127.0.0.1;
        key rndc-key;
}

zone 1.168.192.in-addr.arpa. {
        primary 127.0.0.1;
        key rndc-key;
}
The breakdown of this file was explained in the first tutorial, so I won’t go into the detail here.

We also need to let the DHCP daemon know the new interface to listen on. You can do this by editing the /etc/rc.conf file.

Code:
dhcpd_flags="-q fxp0 fxp1"
**Note: - fxp0 and fxp1 are the interfaces on my NetBSD gateway. They may differ on yours.

To take on the new changes, DHCPD needs to be restarted. Since /etc/rc.conf is read at boot time, it’s best you restart the gateway so that the new interface (fxp1) is now listening for requests.




Setting up DNS

BIND also needs to be aware of the new subnet range, and also how to deal with the dynamic updates which come from DHCP.

Below is the full /etc/named.conf with the changes in bold.

Code:
# Server Settings

controls {
       inet 127.0.0.1 allow { localhost; } keys { rndc-key; };
};

include "/etc/rndc.key";

options {
        version "Bind";
        directory "/etc/namedb";
        allow-query { lan; };
        listen-on { lan; };
};

acl lan {
        127.0.0.1;
        192.168.0/24;
        192.168.1/24;
};

# Zone Information

zone "." {
        type hint;
        file "root.cache";
};

zone "localhost" {
        type master;
        file "localhost";
};

zone "127.IN-ADDR.ARPA" {
        type master;
        file "127";
};

zone "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.int" {
        type master;
        file "loopback.v6";
};

zone "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa" {
        type master;
        file "loopback.v6";
};

zone "0.168.192.in-addr.arpa" {
        type master;
        file "0.168.192";
        allow-update { key rndc-key; };
};

zone "in.kristijan.org" {
        type master;
        file "in.kristijan.org";
        allow-update { key rndc-key; };
};

zone "1.168.192.in-addr.arpa" {
        type master;
        file "1.168.192";
        allow-update { key rndc-key; };
};
The breakdown of this file was explained in the first tutorial, so I won’t go into the detail here.

/etc/namedb/1.168.192

A new zone file is needed to cater for the 192.168.1.0/24 network.

Code:
$ORIGIN .
$TTL 3600       ; 1 hour
1.168.192.in-addr.arpa  IN SOA  krusty.in.kristijan.org. kristijanmilos.gmail.com. (
                                28         ; serial
                                3600       ; refresh (1 hour)
                                3600       ; retry (1 hour)
                                3600       ; expire (1 hour)
                                3600       ; minimum (1 hour)
                                )
                        NS      krusty.in.kristijan.org.
$ORIGIN 1.168.192.in-addr.arpa.
2                       PTR     wlan.in.kristijan.org.
There is only a single entry for the time being, as wlan.in.kristijan.org is the only node that we know of. The rest of this file will be populated via DHCP when new wireless nodes enter the network.

/etc/namedb/0.168.192

Code:
$ORIGIN .
$TTL 3600       ; 1 hour
0.168.192.in-addr.arpa  IN SOA  krusty.in.kristijan.org. kristijanmilos.gmail.com. (
                                30         ; serial
                                3600       ; refresh (1 hour)
                                3600       ; retry (1 hour)
                                3600       ; expire (1 hour)
                                3600       ; minimum (1 hour)
                                )
                        NS      krusty.in.kristijan.org.
$ORIGIN 0.168.192.in-addr.arpa.
1                       PTR     bart.in.kristijan.org.
10                      PTR     krusty.in.kristijan.org.
2                       PTR     homer.in.kristijan.org.
3                       PTR     lisa.in.kristijan.org.
4                       PTR     xbox.in.kristijan.org.
This line now needs to be added into the 0.168.192 file as we are now dealing with multiple subnets. The same line is present in the 1.168.192 files.

/etc/namedb/in.kristijan.org

Code:
$ORIGIN .
$TTL 3600       ; 1 hour
in.kristijan.org        IN SOA  krusty.in.kristijan.org. kristijanmilos.gmail.com. (
                                51         ; serial
                                3600       ; refresh (1 hour)
                                3600       ; retry (1 hour)
                                3600       ; expire (1 hour)
                                3600       ; minimum (1 hour)
                                )
                        NS      krusty.in.kristijan.org.
$ORIGIN in.kristijan.org.
bart                    A       192.168.0.1
homer                   A       192.168.0.2
krusty                  A       192.168.0.10
                        A       192.168.1.1
lisa                    A       192.168.0.3
wlan                    A       192.168.1.2
xbox                    A       192.168.0.4
The same needs to be done for the in.kristijan.org file.

To take on these new changes, you need to restart BIND.

Code:
/etc/rc.d/named restart
Once BIND has been restarted, you can check /var/log/messages for any errors, and to ensure all the zone files are correctly loaded. Below is the output from my /var/log/messages log file of BIND starting up.

Code:
Apr 11 21:56:45 krusty named[213]: starting BIND 9.3.0
Apr 11 21:56:45 krusty named[213]: found 1 CPU, using 1 worker thread
Apr 11 21:56:45 krusty named[213]: loading configuration from '/etc/named.conf'
Apr 11 21:56:45 krusty named[213]: listening on IPv4 interface fxp0, 192.168.0.10#53
Apr 11 21:56:45 krusty named[213]: listening on IPv4 interface fxp1, 192.168.1.1#53
Apr 11 21:56:45 krusty named[213]: listening on IPv4 interface lo0, 127.0.0.1#53
Apr 11 21:56:46 krusty named[213]: command channel listening on 127.0.0.1#953
Apr 11 21:56:46 krusty named[213]: zone 127.IN-ADDR.ARPA/IN: loaded serial 1
Apr 11 21:56:46 krusty named[213]: zone 0.168.192.in-addr.arpa/IN: loaded serial 30
Apr 11 21:56:46 krusty named[213]: zone 1.168.192.in-addr.arpa/IN: loaded serial 28
Apr 11 21:56:46 krusty named[213]: zone 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa/IN: loaded serial 1
Apr 11 21:56:46 krusty named[213]: zone 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.int/IN: loaded serial 1
Apr 11 21:56:46 krusty named[213]: zone localhost/IN: loaded serial 1
Apr 11 21:56:46 krusty named[213]: zone in.kristijan.org/IN: loaded serial 51
Apr 11 21:56:46 krusty named[213]: running
Apr 11 21:56:46 krusty named[213]: zone localhost/IN: sending notifies (serial 1)
Apr 11 21:56:46 krusty named[213]: zone 127.IN-ADDR.ARPA/IN: sending notifies (serial 1)
Apr 11 21:56:46 krusty named[213]: zone 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.int/IN: sending notifies (serial 1
)
Apr 11 21:56:46 krusty named[213]: zone 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa/IN: sending notifies (serial
1)
Apr 11 21:56:46 krusty named[213]: client 127.0.0.1#65534: received notify for zone 'localhost'
Apr 11 21:56:46 krusty named[213]: client 127.0.0.1#65534: received notify for zone '127.IN-ADDR.ARPA'
Apr 11 21:56:46 krusty named[213]: client 127.0.0.1#65534: received notify for zone '1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0
.0.0.0.ip6.int'
Apr 11 21:56:46 krusty named[213]: client 127.0.0.1#65534: received notify for zone '1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0
.0.0.0.ip6.arpa'



AuthPF and /etc/pf.conf

The objective here is to have my NetBSD gateway running as an authenticating gateway for all wireless nodes. When a new wireless node connects to the AP, it receives an address from DHCP, and the only traffic allowed in through the interface is DNS, and SSH to the gateway only.

Once authenticated, the wireless node is allowed full access to the network and the internet. Any user that is not authenticated, and attempts to browse www traffic, will be redirected to my Apache webserver and shown an “Authentication Required” message.

Setting up AuthPF

First thing that needs to be done is to create a user account which will be used for wireless nodes to authenticate against the gateway, assign it's shell to authpf and set its password.

**Note: - /usr/sbin/authpf is where the shell resides on NetBSD, this may differ on your distribution.

Code:
useradd –m –s /usr/sbin/authpf authgw
passwd –l authgw
AuthPF requires the authpf.conf file to be present in /etc/authpf directory, even if the file is empty and authpf.rules is the file which will contain our specific rules. NetBSD also keeps track of authenticated IP addresses in /var/authpf. The directory doesn’t exist, so it needs to be created.

Let go ahead and create all the necessary files and directories.

Code:
mkdir /var/authpf
mkdir /etc/authpf
touch /etc/authpf/authpf.conf
touch /etc/authpf/authpf.rules
/etc/authpf/authpf.rules

This file contains the rules that will be loaded once the user authenticates.

Code:
wi_if = "fxp1"

pass in quick on $wi_if from $user_ip to any keep state
What this rules does, is allow traffic travelling into the fxp1 interface from the IP addresses of the authenticated user to any destination. $user_ip is a macro which is provided by AuthPF, which contains the IP addresses of the authenticated user.

/etc/pf.conf

We now need to edit the current PF rule set, to accommodate for our changes.

Below is the full /etc/pf.conf with the changes in bold. This is my entire pf.conf file, so it contains other rules which are not related to this tutorial.

Code:
##########
# Macros #
##########

ext_if="ppp0"
int_if="fxp0"
wi_if="fxp1"
adsl_if="sip0"

homer="192.168.0.2"
krusty="192.168.1.1"
auth_web="192.168.0.10"

routable="{ 192.168.0.0/24, 192.168.1.0/24 }"
nonroutable="{ 127.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8, 169.254.0.0/16, 192.0.2.0/24, 0.0.0.0/8, 240.0.0.0/4 }"

###########
# Options #
###########

set block-policy drop
set loginterface $ext_if

#########
# Scrub #
#########

scrub no-df random-id fragment reassemble

##########
# Tables #
##########

table <authpf_users> persist

###########
# NAT/RDR #
###########

nat on $ext_if from $routable to any -> ($ext_if)
nat on $adsl_if from $routable to any -> ($adsl_if)

# Azureus
rdr on $ext_if proto tcp from any to any port 61980 -> $homer port 61980
rdr on $ext_if proto udp from any to any port 61980 -> $homer port 61980

# WWW redirect for non-AuthPF users
rdr on $wi_if proto tcp from ! <authpf_users> to any port 80 -> $auth_web

################
# Filter Rules #
################

pass out quick keep state
pass quick on lo0

# Azureus
pass in quick on $ext_if proto tcp from any to any port 61980 flags S/SA keep state
pass in quick on $ext_if proto udp from any to any port 61980

# SSH
pass in quick on $ext_if proto tcp from any to any port 22 flags S/SA keep state

# Non routable
block drop in quick on $ext_if from $nonroutable to any
block drop out quick on $ext_if from any to $nonroutable

# DNS, SSH & WWW-redirect for wireless so user can AuthPF
pass in quick on $wi_if proto udp from 192.168.1.0/24 to any port 53
pass in quick on $wi_if proto tcp from 192.168.1.0/24 to $krusty port 22 flags S/SA keep state
pass in quick on $wi_if proto tcp from ! <authpf_users> to any port 80 flags S/SA keep state

# AuthPF anchor
anchor "authpf/*"

# Drop All
block in quick on $wi_if
block in quick on $ext_if
Breakdown of the changes.

Macros
  • wi_if="fxp1" - The new NIC in the gateway</li>
  • krusty="192.168.1.1" - Krusty IP address</li>
  • auth_web="192.168.0.10" - IP address of Apache webserver</li>
  • routable="{ 192.168.0.0/24, 192.168.1.0/24 }" - Added in the new subnet range</li>
Tables
  • table <authpf_users> persist - Creates the authpf_users table, which all authenticated users will go into

NAT/RDR
  • rdr on $wi_if proto tcp from ! <authpf_users> to any port 80 -> $auth_web - Redirects all port 80 (www) traffic from users who are not in the authpf_users table, to my Apache webserver

Filter Rules
  • pass in quick on $wi_if proto udp from 192.168.1.0/24 to any port 53 - Allows DNS queries through from users on the 192.168.1.0/24 network
  • pass in quick on $wi_if proto tcp from 192.168.1.0/24 to $krusty port 22 flags S/SA keep state - Allows SSH only to the gateway from users on the 192.168.1.0/24 network
  • pass in quick on $wi_if proto tcp from ! <authpf_users> to any port 80 flags S/SA keep state - Allows WWW requests to be redirected from non-authenticated users
  • anchor "authpf/*" - Where the AuthPF rules will be placed from the authenticated user
  • block in quick on $wi_if - Block in all other traffic from the 192.168.1.0/24 network

Now with all the changes in place, you can reload the current pf.conf file.

Code:
pfctl –f /etc/pf.conf



Testing the setup

To test the new setup, you are going to need a wireless device capable of obtaining an address via DHCP. A laptop would be the most common device in this situation.

To debug the entire process, you may want to tail the /var/log/messages file to watch things as they happen.

Code:
tail –f /var/log/messages
Set the laptop’s wireless adapter to obtain an address via DHCP, and re-authenticate to the access point. At this point you should be able to do the following:
  • Obtain an address from DHCP within the 192.168.1.10 – 192.168.1.30 range
  • Resolve DNS queries
  • Any web browser requests will be redirected to the Apache server
  • Apart from SSH into the gateway (krusty), all other traffic (e.g. PING, SSH to other machines, WWW over the Internet) will be dropped

From the laptop, SSH into krusty with the authgw user id.

Linux/BSD

Code:
ssh authgw@krusty
Windows

I recommend using PuTTy - http://www.chiark.greenend.org.uk/~sgtatham/putty/

Once authenticated, you should now be able to do the following:
  • Browse any pages over the Internet
  • SSH into any other nodes
  • PING any local nodes and Internet addresses

As soon as you loose or terminate the SSH session as the authenticated user, the rules will be dropped from the PF filter and you should have restricted access till you re-authenticate.


  



All times are GMT -5. The time now is 05:58 PM.

Main Menu
Advertisement
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration