Samba file sharing

samba

Samba is a file and print server for Windows-based clients using TCP/IP as the underlying transport protocol. In fact, it can support any SMB/CIFS-enabled client. One of Samba’s big strengths is that you can use it to blend your mix of Windows and Unix machines together without requiring a separate Windows NT/2000/2003 Server.

On OpenBSD, the Samba configuration file is /etc/samba/smb.conf. There are some changes we want to make to the original file. Assume we want to run Samba for machines located on our LAN, 192.168.0.0./24 and this machine has the IP address 192.168.0.1.

hosts allow = 192.168.0.0./24 127.0.0.1
interfaces = 192.168.0.1

socket options = TCP_NODELAY
encrypt passwords = yes

Now we have to add a directory we want to share. Assume we have a directory /data that we want to make public and writeable to everyone who can login to Samba.

[data]
    comment = Data
    path = /data
    read only = no
    public = yes

Now we have to set the password for a user to be able to login to Samba.

/usr/local/bin/smbpasswd username

Packet Filter (PF)

pf

Packet Filter (PF) is OpenBSD’s system for filtering TCP/IP traffic and doing Network Address Translation. PF is also capable of normalizing and conditioning TCP/IP traffic and providing bandwidth control and packet prioritization.

To enable PF, we have to edit /etc/rc.conf.

pf=YES

To be able to do NAT, we have to edit /etc/sysctl.conf as well.

net.inet.ip.forwarding=1

The main pf configuration file is /etc/pf.conf. We can use shorthands for interfaces, port numbers and addresses we use in this file, e.g.

internet_if="xl0"
lan_if="rl0"

services_tcp="{ 22, 53, 80 }"
services_udp="{ 53 }"

non_routeable_ips="{ 127.0.0.0/8, 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 255.255.255.255 }"
broadcast_ip="255.255.255.255"

Assume we have two interfaces, one of which is connected to the Internet, the other connected to a LAN. Performing NAT for the machines on the LAN is done like this.

nat on $internet_if from $lan_net to any -> $internet_ip

By default, we can deny all traffic. Specifying more specific rules later in the configuration file gives us the opportunity to allow certain traffic. For example, we may want to allow traffic from and to our LAN.

block all

pass in quick on $fixed_if from $fixed_net to any keep state
pass out quick on $fixed_if from any to $fixed_net keep state

Network Time Protocol (NTP)

clock

The Network Time Protocol (NTP) is used to synchronize the time of a computer client or server to another server or reference time source, such as a radio or satellite receiver or modem. It provides accuracies typically within a millisecond on LANs and up to a few tens of milliseconds on WANs relative to Coordinated Universal Time (UTC) via a Global Positioning Service (GPS) receiver, for example. Typical NTP configurations utilize multiple redundant servers and diverse network paths in order to achieve high accuracy and reliability.

The NTP subnet in early 2003 includes well over a hundred public primary (stratum 1) servers synchronized directly to UTC by radio, satellite or modem and located in every continent of the globe, including Antarctica. Normally, client workstations and servers with a relatively small number of clients do not synchronize to primary servers. There are well over a hundred public secondary (stratum 2) servers synchronized to the primary servers and providing synchronization to a total well over 100,000 clients and servers in the Internet.

There are two programs that are used here: ntpd and ntpdate. The ntpd program operates by exchanging messages with one or more configured servers at designated poll intervals. When started, whether for the first or subsequent times, the program requires several exahanges from the majority of these servers so the signal processing and mitigation algorithms can accumulate and groom the data and set the clock. The ntpdate program can be run manually as necessary to set the host clock, or it can be run from the host startup script to set the clock at boot time. This is useful in some cases to set the clock initially before starting the NTP daemon ntpd. It is also possible to run ntpdate from a cron script. However, it is important to note that ntpdate with contrived cron scripts is no substitute for the NTP daemon, which uses sophisticated algorithms to maximize accuracy and reliability while minimizing resource use.

On OpenBSD, the NTP software is not installed by default, so we will have to do this first.

cd /usr/ports/net/ntp
make install

Now we have to edit the configuration file /etc/ntp.conf. This file contains the names of servers we want to synchronize to and the networks of clients we allow access to this server.

server ntp.example.com prefer
server ntp.example.org
server ntp.example.net

restrict 192.168.0.0 mask 255.255.255.0 nomodify nopeer
restrict 10.0.0.0 mask 255.255.255.0 nomodify nopeer

OpenBSD starts ntpd automatically if it can find the daemon at /usr/local/sbin/ntpd. However, it does not call ntpdate at startup. So if you want that to happen, edit rc.conf.local.

ntpdate_flags="ntp.example.com"

Dynamic Host Configuration Protocol (DHCP)

network

The Dynamic Host Configuration Protocol (DHCP) is an Internet protocol for automating the configuration of computers that use TCP/IP. DHCP can be used to automatically assign IP addresses, to deliver TCP/IP stack configuration parameters such as the subnet mask and default router, and to provide other configuration information such as the addresses for printer, time and news servers.

For the DHCP client (dhclient), we have to edit the file /etc/dhclient.conf. The DHCP server my ISP is using wants to know my hostname, so we send this. In addition to our IP address we want to know the subnet mask, the broadcast address and the gateway.

send host-name "hostname";
request subnet-mask, broadcast-address, routers;

OpenBSD automatically runs dhclient if a network interface is configured to use DHCP. For example, to use DHCP on the interface xl0, edit /etc/hostname.xl0

dhcp

For the DHCP server (dhcpd), we have to edit the file /etc/dhcpd.conf. Assume dhcpd is located at a machine that is gateway for two LANs, the first being 192.168.0.0/24 and the second 10.0.0.0/24. There is a nameserver at 192.168.0.1 which serves the example.com domain.

option domain-name "example.com";
option domain-name-servers 192.168.0.1;

subnet 192.168.0.0 netmask 255.255.255.0 {
   option routers 192.168.0.1;
   range 192.168.0.10 192.168.0.99;
}

subnet 10.0.0.0 netmask 255.255.255.0 {
   option routers 10.0.0.1;
   range 10.0.0.128 10.0.0.254;
}

OpenBSD does not start dhcpd automatically, so we have to edit /etc/rc.conf.local

dhcpd_flags="-q"

BIND DNS server

network

BIND (Berkeley Internet Name Domain) is an implementation of the Domain Name System (DNS) protocols and provides an openly redistributable reference implementation of the major components of DNS, including a DNS server (named), a DNS resolver library and tools for verifying the proper operation of the DNS server. The BIND DNS Server is used on the vast majority of name serving machines on the Internet, providing a robust and stable architecture on top of which an organization’s naming architecture can be built. The resolver library included in the BIND distribution provides the standard APIs for translation between domain names and Internet addresses and is intended to be linked with applications requiring name service.

Assume we want to run DNS services for the domain example.com. Note that we need to register this domain name and tell the registrar that the DNS server for this domain is the machine running BIND. We also want to run DNS services for the IP range 192.168.0.0/24. Note that we would use more than one nameserver in real-life situations, but for this example we only use one nameserver. On OpenBSD with BIND 9, the first file we edit is /var/named/etc/named.conf

zone "example.com" {
   type master;
   file "master/example.com";
};

zone "0.168.192.in-addr.arpa" {
   type master;
   file "master/0.168.192.in-addr.arpa";
};

The file /var/named/master/example.com contains the translation from names to IP addresses in the example.com domain.

@ IN  SOA  ns.example.com.  hostmaster.example.com. (
   2003060101 ; Serial (yyyymmddxx)
   86400      ; Refresh (1 day)
   7200       ; Retry (2 hours)
   604800     ; Expire (7 days)
   86400 )    ; Minimum (1 day)

IN      NS      ns.example.com.

example.com.    IN      A       192.168.0.1
www     IN      CNAME   example.com.
ftp     IN      CNAME   example.com.

host1   IN      A       192.168.0.1
host2   IN      A       192.168.0.2
host3   IN      A       192.168.0.3

The file /var/named/master/0.168.192.in-addr.arpa contains translations from IP addresses in the range 192.168.0.0/24 to names (in our case in example.com).

@ IN  SOA  ns.example.com.  hostmaster.yahoo.com. (
   2003060101 ; Serial (yyyymmddxx)
   86400      ; Refresh (1 day)
   7200       ; Retry (2 hours)
   604800     ; Expire (7 days)
   86400 )    ; Minimum (1 day)

IN      NS      ns.example.com.

1       IN      PTR     host1.example.com.
2       IN      PTR     host2.example.com.
3       IN      PTR     host3.example.com.

Apache virtual hosts

apache

Assume we want to serve webpages for two domains, example.com and example.org and these pages should be available with and without the ‘www’, so from www.example.com, example.com, www.example.org and example.org. In addition, clients connecting directly to our IP address, instead of using these domain names, should get an error message (404 Not Found) or short warning html message. These clients are probably just worms trying to spread through our webserver, so we don’t want to waste bandwidth on them. We start off by making some directories.

mkdir /var/www/htdocs/ip_address
mkdir /var/www/htdocs/example.com
mkdir /var/www/htdocs/example.org

Last thing we have to do is edit the configuration file. On OpenBSD, the Apache configuration can be found in /var/www/conf/httpd.conf.

NameVirtualHost *

<VirtualHost *>
   DocumentRoot /htdocs/ip_address
   ErrorLog logs/ip_address-error_log
   CustomLog logs/ip_address-access_log common
</VirtualHost>

<VirtualHost *>
   ServerAdmin webmaster@example.com
   DocumentRoot /htdocs/example.com
   ServerName www.example.com
   ErrorLog logs/example.com-error_log
   CustomLog logs/example.com-access_log common
</VirtualHost>

<VirtualHost *>
   ServerAdmin webmaster@example.com
   DocumentRoot /htdocs/example.com
   ServerName example.com
   ErrorLog logs/example.com-error_log
   CustomLog logs/example.com-access_log common
</VirtualHost>

<VirtualHost *>
   ServerAdmin webmaster@example.org
   DocumentRoot /htdocs/example.org
   ServerName www.example.org
   ErrorLog logs/example.org-error_log
   CustomLog logs/example.org-access_log common
</VirtualHost>

<VirtualHost *>
   ServerAdmin webmaster@example.org
   DocumentRoot /htdocs/example.org
   ServerName example.org
   ErrorLog logs/example.org-error_log
   CustomLog logs/example.org-access_log common
</VirtualHost>

A secure network setup with FreeBSD and OpenBSD

This article was featured on Daemon News 2001-09.

Overview

This article discusses a network setup which might prove useful for people who like to put some extra effort into connecting their machines to the Internet. The goal is to build a secure client and server farm on a single IP address. Next to the clients and servers, the network contains two other components. The first one is a Network Address Translator (NAT), which makes it possible to connect more than one machine to the Internet using just one IP address. The second one is a Packet Filtering Bridge (PFB) that transparently filters IP traffic from and to the Internet.

secure-network-setup

The PFB machine – running OpenBSD 2.9 – is the only machine connected directly to the Internet. Two of its network interfaces are for the bridge itself (p1 and p2) and one is the management interface (p3). Interface p3 makes it possible for the PFB to output its logs to another server, or for an administrator to log into it to check its logs. This might not seem very secure at first sight, but the interface is actually protected as well as the clients on the LAN.

The NAT machine – running FreeBSD 4.3 – is connected with one interface to the PFB machine (n1). The other two interfaces are connected to the hubs of the clients (n2) and servers (n3). This seperation between a client and a server LAN has at least one obvious advantage. If a weakness is found in one of the services of a server, the clients are still relatively safe from attack. Otherwise, the clients would be on the same network as the compromised server and would have made an easy target for the attacker.

Theory

Let’s start with some theory about Network Address Translators (NAT) and Packet Filtering Bridges (PFB).

Theory: Network Address Translator (NAT)

Commonly, your Cable or xDSL ISP assigns you a very limited number of IP addresses (usually just one). You run into trouble if you want to connect more machines to the Internet than the number of IP addresses given to you. NAT is a technology which you can use to solve this problem to some extent. With NAT, multiple internal IP address (on the LAN) are aliased to a single public IP address (on the Internet). Requests from machines on the LAN to machines on the Internet are transformed by the NAT machine. It modifies the source address in the IP packet and sends the request in its name to the machine on the Internet. Once it gets a reply, it modifies the destination address in the IP packet to the client on the LAN.

secure-network-nat-theory

Typically, a NAT machine has two network interfaces, one on the Internet and one on the LAN. The public IP address on the Internet is assigned to you by your ISP, so you assign this IP address to the interface connected to the public network. But what about the private IP addresses on the LAN? There are some IP addresses which are available for exactly this situation. You can choose between three IP ranges:

  • 10.0.0.0/8
  • 172.16.0.0/12
  • 192.168.0.0/16

Let’s say you are using the third IP range. You would then assign one of the IP addresses in this range (e.g. 192.168.0.1) to the interface connected to the private network. Every other machine on this network is assigned one of the remaining addresses in the range. Here’s an example of the complete IP configuration of the machines involved:

IP address Subnet mask Gateway
NAT public 216.136.204.21 255.255.248.0 216.136.204.1
NAT private 192.168.0.1 255.255.255.0 No gateway
LAN machine 1 192.168.0.2 255.255.255.0 192.168.0.1
LAN machine 2 192.168.0.3 255.255.255.0 192.168.0.1

Theory: Packet Filtering Bridge

A bridge is used to connect two network segments to create a single, larger network. This is normally done to create the appearance of a single network when there are in fact two physically seperate networks. The bridge in this article is not just a simple bridge, but it functions as a packet filter as well. Devices that filter packets have rulesets that tell them which packets should be allowed and which should be blocked. Typically, a firewall is used for this job, but a disadvantage of this setup is, that the firewall is visible on the Internet. This makes it a great target to anyone trying to get into your network. If the firewall gets compromised, alle machines within the LAN are in the open, waiting to be compromised as well.

secure-network-pfb-theory

In our case, the packet filtering is done by the bridge. A normal bridge takes all packets from the network on one interface and copies them to the interface on the other network and vice versa. Our PFB examines each of these packets before they are copied to the other interface. It checks its ruleset to see if a packet should be allowed to pass or should be blocked. Unlike the NAT machine, the PFB machine doesn’t change anything in the packets themselves.

The IP configuration of the PFB and the machines on both networks is really simple. The PFB is not assigned an IP address at all. This ensures that machines on either side of the PFB are not aware of its existence. Because of this, the machines on both networks should be configured as if the two networks were really one larger one. The cool thing about this, is that the PFB can’t be reached from the Internet, making it impossible to attack it on the IP level.

Implementation

Now that we’ve seen the theory, let’s shift our attention to the implementation. As mentioned before, we are using FreeBSD 4.3 for the NAT machine and OpenBSD 2.9 for the PFB machine. We won’t go into much depth with regard to the client and server machines, although we will discuss the IP settings of these machines.

Implementation: Network Address Translator (NAT)

secure-network-nat-setup
Kernel

We want to be able to divert and filter IP packets. The FreeBSD generic kernel doesn’t allow this, so we have to make our own kernel. We do this by making a copy of the generic kernel:

cd /usr/src/sys/i386/conf
cp GENERIC NAT

Then we add the following lines to the NAT file:

options IPDIVERT
options IPFIREWALL

Now we can compile our new kernel and install it:

config NAT
cd ../../compile/NAT
make depend
make
make install

Configuration

We should now edit some configuration files to really enable the capabilities just added to the kernel. The first file is /etc/rc.conf which contains the network interface configuration as well as the services configuration:

# Host- and domainname
hostname="nat.example.com"

# Network interface connected to the PFB (n1)
ifconfig_xl0="inet 216.136.204.21 netmask 255.255.248.0"

# Network interface connected to the client LAN (n2)
ifconfig_rl0="inet 192.168.0.1 netmask 255.255.255.0"

# Network interface connected to the server LAN (n3)
ifconfig_rl1="inet 10.0.0.1 netmask 255.255.255.0"

# Default router on network interface n1
defaultrouter="216.136.204.1"

# Enable firewall capabilities
firewall_enable="YES"

# Enable gateway capabilities
gateway_enable="YES"

# Enable network address translation
natd_enable="YES"
natd_interface="xl0"
natd_flags="-f /etc/natd.conf"

The second file is /etc/natd.conf which contains the rules for the NAT daemon:

# Redirect SSH packets to the SSH server
redirect_port tcp 10.0.0.3:22 22

# Redirect HTTP packets to the HTTP server
redirect_port tcp 10.0.0.4:80 80

The third file is /etc/rc.firewall which contains the rules for the packet filter. In our case we first divert all IP packets to the NAT daemon. After that, we make sure that IP packets can only go where they are supposed to go. Strictly speaking, we don’t need the rules below the one that diverts IP packets to the NAT daemon. However, we would otherwise have to allow all IP packets, and that is something we don’t like doing:

# Flush all previous firewall rules
/sbin/ipfw -f flush

# Divert all IP packets to the NAT daemon
/sbin/ipfw add divert natd ip from any to any via xl0

# Allow all IP packets through the loopback interface by the localhost
/sbin/ipfw add allow ip from 127.0.0.1 to 127.0.0.1 via lo0

# Allow all IP packets through the public interface (n1) from and to this machine
/sbin/ipfw add allow ip from any to 216.136.204.21 in recv xl0
/sbin/ipfw add allow ip from 216.136.204.21 to any out xmit xl0

# Allow all IP packets through the client interface (n2) from and to client machines
/sbin/ipfw add allow ip from 192.168.0.1/24 to any in recv rl0
/sbin/ipfw add allow ip from any to 192.168.0.1/24 out xmit rl0

# Allow all IP packets through the server interface (n3) from and to server machines
/sbin/ipfw add allow ip from 10.0.0.1/24 to any in recv rl1
/sbin/ipfw add allow ip from any to 10.0.0.1/24 out xmit rl1

# Deny all IP packets not allowed until this point
/sbin/ipfw add deny ip from any to any

Implementation: Packet Filtering Bridge

secure-network-pfb-setup
Kernel

We want to be able to divert and filter IP packets. The OpenBSD generic kernel has support for both these features, so there is no need to make our own kernel.

Configuration

The first configuration files to edit are the ones that set the parameters for the network interfaces. File /etc/hostname.ne0 is for the network interface connected to the client LAN (p3):

inet 192.168.0.2 255.255.255.0 NONE

Files /etc/hostname.ne1 and /etc/hostname.ne2 are for the network interfaces connected to the Cable / xDSL modem and NAT machine respectively (p1 and p2). Because we won’t be giving them IP addresses, the content of these files is simply:

up

Now we should edit the file /etc/bridgename.bridge0 to enable the bridge at startup:

add ne1
add ne2
up

The last configuration file to edit is /etc/ipf.rules which contains the rules for the packet filter. As with the NAT machine, we make sure that IP packets can only go where they are supposed to go. There is a difference however: we want to protect our network from the Internet. We tell the packet filter that it is okay for the NAT machine to send IP packets to the Internet and receive replies on these packets. We also want to offer SSH and HTTP services to the Internet, so we explicitly open these ports on our bridge:

# Allow all IP through the loopback interface by the localhost
pass in quick on lo0 from 127.0.0.1 to 127.0.0.1

# Allow all IP through the LAN interface from and to LAN addresses
pass in quick on ne0 from 192.168.0.0/24 to 192.168.0.2
pass out quick on ne0 from 192.168.0.2 to 192.168.0.0/24

# Allow all IP through the bridge from the NAT machine
pass in quick on ne2 proto tcp/udp from 216.136.204.21 to any keep state
pass in quick on ne2 proto icmp from 216.136.204.21 to any keep state

# Allow SSH and HTTP through the bridge from the Internet to the NAT machine
pass in quick on ne1 proto tcp from any to 216.136.204.21 port = 22 flags S keep state
pass in quick on ne1 proto tcp from any to 216.136.204.21 port = 80 flags S keep state

# Deny IP not allowed until this point
block in quick all

Implementation: Clients and servers

secure-network-clients-servers

To complete our setup we must configure the clients and servers. Our client LAN is connected through a hub to interface n2 of the NAT machine, so all clients should be in the same subnet as n1. For the same reason, all servers should be in the same subnet as n3. The configuration looks like this:

IP address Subnet mask Gateway
Client 1 192.168.0.3 255.255.255.0 192.168.0.1
Client 2 192.168.0.4 255.255.255.0 192.168.0.1
Server 1 10.0.0.3 255.255.255.0 10.0.0.1
Server 2 10.0.0.4 255.255.255.0 10.0.0.1

Testing

From one of the client machines we will now start the test of our configuration. Let’s see if one of our clients (192.168.0.3) can reach the NAT machine (192.168.0.1):

%ping 192.168.0.1
PING 192.168.0.1 (192.168.0.1): 56 data bytes
64 bytes from 192.168.0.1: icmp_seq=0 ttl=255 time=0.560 ms
64 bytes from 192.168.0.1: icmp_seq=1 ttl=255 time=0.435 ms
...

We expect about the same result if we try to reach the NAT machine (10.0.0.1) from one of our servers (10.0.0.3). If this works OK, we should try the PFB. We can do this from the NAT machine by pinging the gateway of our ISP:

%ping 216.136.204.1
PING 216.136.204.1 (216.136.204.1): 56 data bytes
64 bytes from 216.136.204.1: icmp_seq=0 ttl=255 time=20.340 ms
64 bytes from 216.136.204.1: icmp_seq=1 ttl=255 time=21.636 ms
...

We can repeat this test from one of our clients or servers to test the NAT daemon. Notice that the Time To Live (ttl) value is 1 lower than before. This is because the NAT machine is now a hop the IP packets have to pass to reach the gateway. Our final test for our setup will be the HTTP server, which we will assume is on IP address 10.0.0.4. First, try to fetch an HTML page from the terminal of the NAT machine itself with this URL:

http://10.0.0.4/directory/file.html

If this succeeds, you can try to fetch the same HTML page from a machine on the Internet with this URL:

http://216.136.204.21/directory/file.html

The NAT machine should redirect this request to the HTTP server on IP address 10.0.0.4 and give you the same result as the test above.