OpenStack with FreeBSD

Standard

Recently, I come across NFV Express through the FreeBSDNews article.  The installation code is already openly available on Github.  At the first glance, the code is so amazing to be clean!  (You definitely should look at them if you know programming.)  When there is time, I will try them with my stack of FreeBSD computers…

Openstack is used to be Linux-centric, yet it is mostly written in Python scripts.  Theoretically, it is possible to make it running on any capable platforms… if you do not hate working with Python scripts.

Sorry for this short article.  This is indeed just a reminder for me to follow up.  🙂

Proxy Server with FreeBSD and Squid (Part 1)

Standard

When one has multiple machines within a cloud network, it is natural to ask for centralised network traffic, data files, credential service, etc.  In this article, I focus on centralising network traffic, in particular, the world wide web.

With the world wide web traffic centralised, the proxy server can accelerate the download processes of some frequently accessed files, such as operating system patches.

In this part, we install Squid as an opaque proxy server, and configure some clients to use it.  We will handle the transparent proxy in the next part.

Step 1: Install Squid

Installing Squid is easy as usual.  But to make it even smoother, install the SSL root certificates.

# pkg install squid ca_root_nss

The squid requires Perl which, since FreeBSD 5.0, no longer installed by default.  The package installer will handle it.

Step 2: Smoke Test

Even though there are quite a page of notice upon installing Squid, the default Squid installation is good enough to fire without configuration:

# sysrc squid_enable=YES
# service squid start

or, for the old style…

# echo squid_enable=YES >> /etc/rc.conf
# /usr/local/etc/rc.d/squid start

Step 3: Configure Squid

The Squid refers to its configuration file in “/usr/local/etc/squid”.

# ee /usr/local/etc/squid/squid.conf

 

What shall we configure?  Here are some suggestions:

  1. Configure the intranet address ranges.  By the configuration file, only networks defined as “localnet” is granted access.  For example, I only use the class A private subnet, so I disable all others.
    acl localnet src 10.0.0.0/8     
    #acl localnet src 172.16.0.0/12 
    #acl localnet src 192.168.0.0/16
    #acl localnet src fc00::/7      
    #acl localnet src fe80::/10
  2. Deny the squid accessing the so-called “localhost”.  Internal network of the squid is not supposed to be accessed by others.
    http_access deny to_localhost
  3. Configure the cache directory.  For example, here I configure a 10000 MB cache space.  There are two levels of directories, with 16 and 256 directories per level respectively.
    cache_dir ufs /var/squid/cache 10000 16 256
  4. Prefer IPv4 whenever possible.  This is great if your network is not IPv6 ready.
    dns_v4_first on

We then stop the Squid, create the cache directory, and restart.

# service squid stop
# squid -z -N
# chown -R squid:squid /var/squid/cache
# service squid start

Step 4: Update Firewall

If you are using PF firewall, you will need to update the rules to allow the port.  For example, I only use the “vtnet1” as intranet, and it is accepting port 3128 (the default squid service port).  You may refer to the configuration of the VPN notes as example.

# cat >> /etc/pf.conf << EOF
intif="vtnet1"
inttcpports="{3128}"
pass in quick on $intif inet proto tcp from any to any port $inttcpports keep state
EOF
# service pf reload

Step 5: Playing with Telnet

The title is not a typo.  We now test the system with the most geeky way—enter the HTTP request manually.  FreeBSD comes with a telnet client and it is handy for various testing.  Suppose the address is 10.65.0.1 and we connect to the port 3128 of it.  After typing the GET statement, remember to hit the enter key twice to complete the request.

# telnet 10.65.0.1 3128
GET http://www.freebsd.org/ HTTP/1.0

HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Tue, 07 Mar 2017 16:04:30 GMT
Content-Type: text/html
Content-Length: 178
Location: https://www.freebsd.org/
X-Cache: MISS from singapura-roteador
X-Cache-Lookup: HIT from singapura-roteador:3128
Via: 1.1 singapura-roteador (squid/3.5.23)
Connection: close

<html>
<head><title>301 Moved Permanently</title></head>
<body bgcolor="white">
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx</center>
</body>
</html>
Connection closed by foreign host.

The HTTP return code 301 indicates another URL for access.  What about following it?

# telnet 10.65.0.1 3128
GET https://www.freebsd.org/ HTTP/1.0

Step 6: Troubleshoot

Here are some errors you may encounter:

Unable to connect to the server: try disabling the “pf” service briefly and retry.  If it works, you will need to update your firewall rules.

Squid is not starting after enabling cache: make sure you create the cache directory and set the proper ownership with the chown command (as above) .

Getting 503 error with ERR_CONNECT_FAIL: review the error message and if the address is an IPv6 address, there could be issues with the IPv6 routing and you can consider using the “dns_v4_first” option (as above).

Getting 503 error with ERR_SECURE_CONNECT_FAIL: review the website with your own browser, ensure you have installed the common root certificates “ca_root_nss” package (as above).

Step 7: Configure Client

Since our proxy is not transparent yet, the clients have to be manually configured in order to use the proxy.  Depending on the hosts you have on the same intranet, here are the configuration methods for your reference:

Mac OS X: System Preferences > Network > Advanced > Proxies > Web Proxy / Secure Web Proxy

Internet Explorer on Windows: Tools > Internet Options > Connections > LAN Setting

Firefox on Windows: Tools > Internet Options > Network > Connections > Settings

FreeBSD shell: export “HTTP_PROXY” variable in “.cshrc”, like “setenv HTTP_PROXY http://10.65.0.1:3128&#8221;

Step 8: Is the Proxy Really Running?

There are some barbaric ways to check if the proxy is running:

Check the number of files the cache: “find /var/squid/cache | wc -l”

Check the Squid access log: “less /var/log/squid/access.log”

Step 9: To be Continued

A few weeks later, we will revisit Squid and configure the network routers to transparently direct world wide web requests to the proxy server, etc.

Later this week, we may come up with an article not related with FreeBSD.  The next FreeBSD-related article, hopefully next week, will be likely related to programming.  Stay tuned.

Configuring FreeBSD

Standard

We have come across some of my preferred customisations.  In this article, I explain how the files are being modified and their relationships with the system.  It is hoped that this will give new comers an idea why and what to configure with a fresh FreeBSD installation.

What to Configure?

To understand how FreeBSD can be configured, we first understand the parts that can be configured.  The startup process is roughly as follows and I will cover configuration of each stage in later sections, arranged according to the likeness one will use.

  1. The computer loads and execute the loader (more on step 6)
  2. The loader mounts according to the file system table (more on step 5)
  3. The loader loads the kernel into memory and execute (more on step 4)
  4. The init program is executed as the first program (not covered)
  5. The device file system is mounted (not covered)
  6. The rc program prepares the user space (more on step 1)
  7. Network neighbours are recognised (more on step 2)
  8. The periodic jobs are run (more on step 3)

Step 0: Modifying Files

Modifying a configuration file could be easy, but there are some geeky ways to do it right.

To read a configuration file, one uses the cat(1) command.  Before some fluffy haters jump out and complain, let me say, cat means concatenate.  That said, the concatenation tool is also useful dumping content of a single file.

Quite some FreeBSD configuration files are in name-value pairs, such as:

# cat /etc/rc.conf
hostname="raquel"

In these cases, the sysrc(8) tool acts as a safe shortcut to modify the files.  For example:

# sysrc -f /etc/rc.conf hostname="lea"
# cat /etc/rc.conf
hostname="lea"

You can use the same cat to pipe in the output.  The >> symbol means appending to a file; contents following the command will be appended.  (If you use > instead, you overwrite it instead.)  The << defines the termination string, the termination string will not be inserted and it will be returned to the shell.

# cat >> /etc/rc.conf << EOF
hostname="raquel"
EOF
# cat /etc/rc.conf
hostname="lea"
hostname="raquel"

Since these are just name-value pairs, it does not harm more than causing your own confusions.  The latest value assignment takes effect.

Last but not the least, for the files you want to manually edit, you can always use the ee(1) easy editor, or the visually (difficult) vi(1) editor.

Step 1: Run Command

To a new user, the most likely item to configure first is the run command.  At later stage of system start, the rc(8) starts the desired processes for the users.  Most of these configuration are done in two files.  The values desired by the user goes to “/etc/rc.conf”.  When a value required is absent, the default value is loaded from “/etc/defaults/rc.conf”.  The former is empty or even absent after a fresh system install.  The latter is installed and updated automatically and is very lengthy.  By the way, the lengthy file can also act as your configuration guide; more on these later.

Step 1.1: Network Configuration

FreeBSD uses ifconfig(8) to configure network interfaces.  For example, to configure network addresses of interface vtnet1 (the second virtual network interface), the default gateway and the hostname, one can use:

# sysrc vtnet1_ifconfig="inet 10.65.0.11 netmask 255.255.255.0"
vtnet1_ifconfig:  -> inet 10.65.0.11 netmask 255.255.255.0
# sysrc defaultrouter="10.65.0.1"
defaultrouter: NO -> 10.65.0.1
# sysrc hostname="myhost"
hostname:  -> myhost

In the example above, vtnet1 device exists because it exists in the hardware layer.  Sometimes, the interfaces are purely software, like the gif(4) interface we mentioned in building virtual network.  They can be generated in boot time with the cloned interface.  Note there is a plus sign before the equal.  This appends new values to the existing values.  Once the interfaces are created, they can be configured with the typical “ifconfig” above.

# sysrc cloned_interfaces+="gif0"
cloned_interfaces:  -> gif0
# sysrc cloned_interfaces+="gif1"
cloned_interfaces: gif0 -> gif0 gif1

Step 1.2: Service Configuration

The run command file allows defining what services to be switched on at boot.  These services will be switched off gracefully at shutdown as well.  For example, to enable the sshd(8) daemon, one will write this in “/etc/rc.conf”.

sshd_enable="YES"

As an unofficial but nevertheless useful way, one can search for “_enabled” in the “/etc/defaults/rc.conf” to see what can be enabled or disabled:

# grep _enabled /etc/defaults/rc.conf
apm_enable="NO" # Set to YES to enable APM BIOS functions (or NO).
apmd_enable="NO" # Run apmd to handle APM event from userland.
ddb_enable="NO" # Set to YES to load ddb scripts at boot.
devd_enable="YES" # Run devd, to trigger programs on device tree changes.
kldxref_enable="NO" # Build linker.hints files with kldxref(8).
powerd_enable="NO" # Run powerd to lower our power usage.
...

In short, some interesting services are:

  • ntpd(8): network time daemon, keep system time synchronised
  • pf(4): packet filter (or, firewall), useful for protecting your system
  • sendmail(1): mail server, in the previous page I recommend disabling it
  • sshd(8): secure shell server, essential for you to login remotely

Step 1.3: Startup Script

One more place to configure run command is to directly type them into “/etc/rc.local”.  Indeed, this was how FreeBSD 4.x or before worked.  Every time a service was installed, the administrator opened an editor and input the required startup scripts there.  It is still the preferred way for some other BSD family operating systems.

Step 2: Host Tables and Resolvers

When you have multiple machines connected in a network, you will want alias to them.  FreeBSD provides a hosts(5) table “/etc/hosts”.  As long as you can handle and synchronise the files on the different hosts, this is the most reliable and straight-forward method.  (If not, you will need a centralised place, like a name server, for this purpose, and it is out of my scope today.)

One more network configuration is the domain name service, transforming domain names to IP addresses which are understandable to the network.  It is configured with the resolv.conf(5) in “/etc/resolv.conf”.  If you are using a cloud, it is usually automatically configured with DHCP.

Step 3: Periodic Jobs

There are quite a few ways to let jobs run periodically.  I cover the maintenance and cron jobs here.  The former is more common to execute some system default cleanup activities.  The latter is more common for administrators’ customisations.  In the previous article, I changed some maintenance job settings and used a cron job to periodically clean the network offenders (in case those are false positives).

Step 3.1: Maintenance Jobs

FreeBSD has periodic(8) for running periodic maintenance jobs.  The settings are in “/etc/periodic.conf” and the default settings are in “/etc/defaults/periodic.conf”.

The file is read whenever the periodic job is run.  After updating the periodic configuration, you can just let the next periodic job to run.  Nothing special is needed to reload the configuration.

By default, the periodic jobs output are sent to the local mail server.  The step 2 of the customisation script disables these mails and direct the output to the file.  This saves you a few daily emails per server and provides one less attack vector.

Step 3.2: Cron Jobs

FreeBSD has cron(8) for running arbitrary commands on given time.  There is a master cron job file available as plain crontab(5) table “/etc/crontab”, and a crontab(1) database for each user.  Readers may feel strange the two items are both called crontab, with different numbers in the suffix.  In short, the (5) is a file, and (1) is a command.

When editing the crontab(5), the format is as follows:

minute hour day month weekday user command args...

For example, the default FreeBSD comes with cron jobs that run the periodic jobs mentioned in the previous subsection.  This means at every 03:01, command “periodic daily” is executed as the root user; at every 4:15 on Saturday, command “periodic weekly” is executed as the root user, etc.

 1 3 * * *  root  periodic daily
15 4 * * 6  root  periodic weekly
30 5 1 * *  root  periodic monthly

When editing with crontab(1), one uses “crontab -e” to edit his own list.  This gives the user advantage of defining his own jobs without modifying the master table.  The format is as follows, which is similar, yet the username is skipped for the obvious reason.

minute hour day month weekday command args...

Please note in the crontabs, it sometimes lacks the conventional environment variables.  In particular, you may need to be more specific in pathnames, such as calling “/sbin/pfctl” instead of plainly “pfctl”.

Step 4: Kernel System Settings

FreeBSD provides sysctl(8) utility for configuring kernel and kernel module settings, and reading some system status as well.

Kernel settings can be configured in “/etc/sysctl.conf”, with a default file in “/etc/defaults/sysctl.conf”.  The files are read on boot time.  After adding new system configurations, you can either reboot to make it in effect, or run this command to reload immediately: “sysctl -f /etc/sysctl.conf”

These variables are useful when a user wants to have more control on the kernel behaviour.  More on these can be found on the manual page tuning(7).  You can list them by calling “sysctl -a”.  The output is long, prepare your terminal to scroll back.

To a cloud server, most of the activities are network transfer; some interesting configurations are:

  • net.inet.tcp.sendspace: bytes of initial space for sending for each TCP session
  • net.inet.tcp.sendbuf_inc: bytes of sending space increment per session
  • net.inet.tcp.sendbuf_max: bytes of maximum space for receiving per session
  • net.inet.tcp.recvspace: bytes of initial space for receiving for each TCP session
  • net.inet.tcp.recvbuf_inc: bytes of receiving space increment for session
  • net.inet.tcp.recvbuf_max: bytes of maximum space for receiving per session
  • kern.ipc.nmbclusters: total amount of space for network memory (in 2 KiB blocks)
  • kern.ipc.somaxconn: maximum pending connections

By default, the network space values make sense.  The sending space and receiving space are 32 KiB and 64 KiB respectively.  This incurs 96 KiB when a connection is made.  These can go up to 2 MiB for sending and another 2 MiB for receiving.  The system reserves around 100 MiB network memory by default, which is enough for even for gigabit network.

If you find a real need, you can consider adjusting these values depending on the nature of the server.  These values can be lowered if the server has a lot of connections serving small files and messages.  They can be raised if the server has only a few connections and each serving large files and messages.  If the server has a lot of connections each serving large files, the total amount of space for network memory has to be increased.  You can check the buffer usage with command “netstat -m”.

The maximum pending connections, is set to be 128 as default value.  That means, if there are 129 incoming connections together and the server software is not yet capable of completing any of the handshakes, the 129th will be lost.  It is suggested to be set to 1024 or even higher.  This will prevent the system being jammed easily by denial-of-service attack.  If you have applied the customisation script, a client will be blocked if it tries to make too many connections in a short time.

Step 5: File System Table

FreeBSD uses file system table fstab(5) to define the file systems to be mounted.  The table is read by the loader (below) when the system boots.  (A file is read from the volume before the volume is officially mounted.  This is quite counter-intuitive if you think again.  But it make things much simpler.)  If there are errors, one may end up locking the system from booting.

The file format is as follows:

block mount fstype options dump pass

For example, one of my virtual machine says:

/dev/ufs/rootfs  /  ufs  rw  1  1

This means the UFS volume labeled “rootfs” to be mounted at the root directory /, as an UFS file system, read and write enabled, dump enabled, and checked for consistency first after rebooting from system crash.

Normally, this file is generated when you have a virtual machine ready.  It is useful to modify it later when you insert disks to a virtual (or physical) machine.

Step 6: Loader Settings

Eventually, a user may want to configure how a kernel is loaded, and what kernel modules to be loaded together.  FreeBSD comes with a simple yet efficient loader(8) for the purpose.  The configuration values are in “/boot/loader.conf” and defaults in “/boot/defaults/loader.conf”.  I recommend against changing these files randomly because they really affect how the kernel is loaded.  Some settings I ever changed are:

  • kern.maxproc: maximum processes in a system
  • kern.maxfiles: maximum open file handles (including sockets) in a system
  • geom_mirror_load: load the software RAID module (for booting the kernel)
  • coretemp_load: load the module to detect Intel Core™ processor temperature
  • amdtemp_load: load the module to detect AMD processor temperature

The maximum processes, and maximum open file handles are set according to the memory available in the machine.  They are suggested to be set to a predefined value if you have a lot of open files or network sockets, or when the machine is to be shared by a lot of users.  The process table and file table are initialised once and only once when the kernel loads, thus they are to be set in here instead of sysctl.

 

Step 7: Skeleton Files

Few accounts use only the default “root” user account.  To have consistent personalisation across various created users, administrators often prepare skeleton files.  The skeleton files are located at “/usr/share/skel”.  For example, “/usr/share/skel/dot.cshrc” will be copied to “$HOME/.cshrc” of the newly created user.

Once the account is created, the file is owned by the created user.  There are not automatic ways to update across multiple users.  It is therefore important to have the customisations right before creating the users.

Conclusion

We have gone through various parts in FreeBSD that can be configured, especially in context to a new comer.  We discussed how to configure the rc.conf, the host table, the resolver configuration, placing periodic jobs, adjusting kernel settings, setting file system mount points, kernel loading options, and finally skeleton files.

Virtual Private Network with FreeBSD (Part 2)

Standard

This is the second and the final part on setting up a private virtual network.  The part 1 has been uploaded about one week ago.

If you are following the guide in FreeBSD handbook, you must be frustrated because of the complicated configurations.  Those configurations are good in the sense it restricts the IPsec to particular IP pairs but they are also too tough for purpose of connecting just two routers.  In this example, I break these assumptions and go as minimal as possible so the readers can have a smoother learning curve.  I protect the private ports from unsolicited connections with the help of PF firewall instead of the IPsec configuration.

Step 7: Install Packages

Install “ipsec-tools” package on the routers.

pkg install ipsec-tools

Step 8: Configure IPsec Rules

Set the rules in IPsec in japao-roteador.  These two lines say:

  1. IP packets, in any protocols, from the Japan network (10.81.0.0) to the Singapore network (10.65.0.0) is sent out encapsulated in tunnel mode, from the japao-roteador (45.76.207.156) to cingapura-roteador (47.76.133.70), with the encryption mandatory.
  2. IP packets, in any protocols, from the Singapore network to the Japan network is accepted in encapsulated in tunnel mode, from cingapura-roteador to japao-roteador, with the encryption mandatory.
    # touch /usr/local/etc/racoon/setkey.conf
    # cat >> /usr/local/etc/racoon/setkey.conf << EOF
    spdadd 10.81.0.0/24 10.65.0.0/24 any -P out ipsec esp/tunnel/45.76.207.156-45.76.153.70/require;
    spdadd 10.65.0.0/24 10.81.0.0/24 any -P in ipsec esp/tunnel/45.76.153.70-45.76.207.156/require;
    EOF

On another router cingapura-roteador, the in and out are reversed for the obvious reason:

  1. Incoming: the Japan network to the Singapore network
  2. Outgoing: the Singapore network to the Japan network
  3. # touch /usr/local/etc/racoon/setkey.conf
    # cat >> /usr/local/etc/racoon/setkey.conf << EOF
    spdadd 10.81.0.0/24 10.65.0.0/24 any -P in ipsec esp/tunnel/45.76.207.156-45.76.153.70/require;
    spdadd 10.65.0.0/24 10.81.0.0/24 any -P out ipsec esp/tunnel/45.76.153.70-45.76.207.156/require;
    EOF

Please note I used the word “require” instead of “use” as written by some other documentations.  It means the message must be in the expected form to be accepted.  If the encryption is turned off accidentally, it should be disregarded rather than passing through.

Step 9: Configure Racoon

Racoon, as installed with the “ipsec-tools” package, is going to help us the IPsec negotiation phase.  Setting up the pre-shared keys is as easy as updating a file, with each line of the IP address, and then a secret string.  The file will be referenced by the Racoon script.  Setting up the Racoon main configuration can be much more straight forward than the handbook.  I copied an example in “/usr/local/share/ipsec-tools” and customised it.  The two routers will have very similar configuration except the listening IP.

  1. On japao-roteador:
    # touch /usr/local/etc/racoon/psk.txt
    # chmod 0600 /usr/local/etc/racoon/psk.txt
    # cat >> /usr/local/etc/racoon/psk.txt << EOF
    45.76.207.156 pleasedonotusethis
    EOF
    
    # cat > /usr/local/etc/racoon/racoon.conf << EOF
    path pre_shared_key "/usr/local/etc/racoon/psk.txt";
    log debug;
    
    listen
    {
      isakmp          45.76.153.70;
    }
    
    remote anonymous
    {
      exchange_mode     main,aggressive;
      lifetime          time 8 hour;
      passive           off;
      proposal_check    obey;
      nat_traversal     off;
      generate_policy   off;
      proposal {
        encryption_algorithm   3des;
        hash_algorithm         sha1;
        authentication_method  pre_shared_key;
        dh_group               1;
      }
    }
    sainfo anonymous
    {
      pfs_group                 1;
      lifetime                  time 12 hour;
      encryption_algorithm      3des;
      authentication_algorithm  hmac_sha1;
      compression_algorithm     deflate;
    }
    EOF
  2. On cingapura-roteador:
    # touch /usr/local/etc/racoon/psk.txt
    # chmod 0600 /usr/local/etc/racoon/psk.txt
    # cat > /usr/local/etc/racoon/psk.txt << EOF
    45.76.153.70 pleasedonotusethis
    EOF
    
    # cat > /usr/local/etc/racoon/racoon.conf << EOF
    path pre_shared_key "/usr/local/etc/racoon/psk.txt";
    log debug;
    
    listen
    {
      isakmp          45.76.207.156;
    }
    
    remote anonymous
    {
      exchange_mode     main,aggressive;
      lifetime          time 8 hour;
      passive           off;
      proposal_check    obey;
      nat_traversal     off;
      generate_policy   off;
      proposal {
        encryption_algorithm   3des;
        hash_algorithm         sha1;
        authentication_method  pre_shared_key;
        dh_group               1;
      }
    }
    sainfo anonymous
    {
      pfs_group                 1;
      lifetime                  time 12 hour;
      encryption_algorithm      3des;
      authentication_algorithm  hmac_sha1;
      compression_algorithm     deflate;
    }
    EOF

Step 10: Enable Service

Almost finish.  We enable the services and start them as soon as possible.

# cat >> /etc/rc.conf << EOF
racoon_enable="YES"
ipsec_enable="YES"
ipsec_program="/usr/local/sbin/setkey"
ipsec_file="/usr/local/etc/racoon/setkey.conf"
EOF
# service racoon start
# service ipsec start

Step 11: Update Firewall Rules

We have been using firewall.  In the step 3 of part 1, we allowed peers to pass through with encapsulated messages.  Now, we let a few more items to go through: the authentication AH packets, the encapsulated ESP messages.

# cat >> /etc/rc.conf << EOF
pass in quick inet proto {ah,esp,ipencap} from $encappeers to any
pass in quick inet proto udp from $encappeers port = 500 to any port = 500
EOF

Step 12: Try to Break Something

Hopefully, things should go well when you ping the two hosts.  If not, you can watch the debug log “/var/log/debug.log” for a bit more insights.  The next step is to break the tunnel.  Here are some examples.

  1. Try stopping Racoon on one of the routers
  2. Try stopping IPsec on one of the routers
  3. Try using different pre-shared keys on the two routers
  4. Repeat step 1, 2, 3 with “use” rather than “require” in the IPsec configuration
  5. Deleting the route on one of the routers

Virtual Private Network with FreeBSD (Part 1)

Standard

With inexpensive and agile cloud services, it is not unusual for a service to have multiple points of presence around the globe.  In each point of presence, there is usually a per-tenant private network for internal (and confidential) system communications.  One can go further and combine these internal networks together with virtual links.   Here I explain the steps how this can be achieved with FreeBSD without relying extra networking services from the cloud vendors.

The article is split into two parts due to the length.  The first part, this, is about creating a tunnel with ip-in-ip encapsulation.  The second part is about encrypting the communications between the two hosts.

Concepts

Let’s say we have two private networks, network 1 (10.81.x.x) in Japan, and network 2 (10.65.x.x) in Singapore.  The two networks are connected through routers in the public internet.  However, these routers are not acknowledged about our own private network addresses, so we cannot send our messages directly between the two sites.  To enable private communication between the two sites, we will need network tunnel technique and network encryption.

A tunnel can be created by establishing one host on each private network as a router.  Each of these routers have a public routable network address.  Whenever communications between the two private networks have to be done, the network packets are sent through their respective routers.  The routers encapsulate the packets in new packets with “proper” addresses, so that the public routers understand how to route.  Once the encapsulated packets arrive the destination router, it is decapsulated for internal forwarding.  We deploy the FreeBSD generic tunnel interfaces for this part.

The messages between the two private networks are usually secret and thus need to be encrypted.  We can configure the routers so that whenever they communicate each other, the network packets have to be encrypted.  In the second half of this topic, we will employ IPSec (alternative link) for this purpose.

Notations

In this article, the commands are prepared in preformatted text, with pound (#) sign in front of each.  There are two types of commands, one that configures the system settings permanently and one that configures the current prevalent configurations.  The former are usually in sysrc(8) and cat(1) commands.  The latter are usually ifconfig(8) and sysctl(8).

Step 0: Environment

In this setup, we will prepare two private networks, each with a end client and a router.  I use the most inexpensive plans as possible.  As of today (Feb 2017), it is common to find virtual machines around 5 US dollars per month.  I used Vultr for the demonstration and they provide virtual machines at 768 MB for 5 dollars a month.  I assume you apply my customisation script for a minimal system and firewall configuration.

  1. Host 1: japao-roteador
    • Site: Tokyo
    • Plan: anything with 512 MB memory
    • Options: enable external and internal network
    • External interface: vtnet0 (DHCP assigned: 45.76.207.156)
    • Internal interface: vtnet1 (inet 10.81.0.1  netmask 255.255.255.0)
      # sysrc ifconfig_vtnet1="inet 10.81.0.1 netmask 255.255.255.0"
      # ifconfig vtnet1 inet 10.81.0.1 netmask 255.255.255.0
  2. Host 2: japao-host
    • Site: Tokyo
    • Plan: anything with 512 MB memory
    • Options: enable internal network
    • External interface: vtnet0 (DHCP assigned: 45.32.11.250)
    • Internal interface: vtnet1 (inet 10.81.0.11  netmask 255.255.255.0)
      # sysrc ifconfig_vtnet1="inet 10.81.0.11 netmask 255.255.255.0"
      # ifconfig vtnet1 inet 10.81.0.11 netmask 255.255.255.0
  3. Host 3: cingapura-roteador
    • Site: Singapore
    • Plan: anything with 512 MB memory
    • Options: enable external and internal network
    • External interface: vtnet0 (DHCP assigned: 45.76.153.70)
    • Internal interface: vtnet1 (inet 10.65.0.1  netmask 255.255.255.0)
      # sysrc ifconfig_vtnet1="inet 10.65.0.1 netmask 255.255.255.0"
      # ifconfig vtnet1 inet 10.65.0.1 netmask 255.255.255.0
  4. Host 4: cingapura-host
    • Site: Singapore
    • Plan: anything with 512 MB memory
    • Options: enable internal network
    • External interface: vtnet0 (DHCP assigned: 45.76.145.49)
    • Internal interface vtnet1 (inet 10.65.0.11  netmask 255.255.255.0)
      # sysrc ifconfig_vtnet1="inet 10.65.0.11 netmask 255.255.255.0"
      # ifconfig vtnet1 inet 10.65.0.11 netmask 255.255.255.0

Step 1: Tunnel and Route between the Routers

Next step, we will need to turn the designated hosts as routers, create generic tunnel network interface (gif) each of the routers, and set the route accordingly.

  1. Host 1: japao-roteador
    1. Internal: 10.81.0.1 (local) to 10.65.0.1 (counterpart)
    2. External: 45.76.207.156 (local) to 45.76.153.70 (counterpart)
    3. Route: 10.65.0.0/24 (network in Singapore) to 10.65.0.1 (router in Singapore)
      # sysrc gateway_enable="YES"
      # sysrc cloned_interfaces+="gif0"
      # sysrc ifconfig_gif0="10.81.0.1 10.65.0.1 netmask 255.255.255.0"
      # sysrc ifconfig_gif0+="tunnel 45.76.207.156 45.76.153.70"
      # sysrc static_routes+="cingapura"
      # sysrc route_cingapura="10.65.0.0/24 10.65.0.1"
      
      
      # sysctl net.inet.ip.forwarding=1
      # ifconfig gif0 create
      # ifconfig gif0 10.81.0.1 10.65.0.1 netmask 255.255.255.0
      # ifconfig gif0 tunnel 45.76.207.156 45.76.153.70
      # route add 10.65.0.1/24 10.65.0.1
  2. Host 3: cingapura-roteador
    1. Internal: 10.65.0.1 (local) to 10.81.0.1 (counterpart)
    2. External: 45.76.153.70 (local) to 45.76.207.156 (counterpart)
    3. Route: 10.81.0.0/24 (network in Japan) to 10.81.0.1 (router in Japan)
      # sysrc gateway_enable="YES"
      # sysrc cloned_interfaces+="gif0"
      # sysrc ifconfig_gif0="10.65.0.1 10.81.0.1 netmask 255.255.255.0"
      # sysrc ifconfig_gif0+="tunnel 45.76.153.70 45.76.207.156"
      # sysrc static_routes+="japao"
      # sysrc route_japao="10.81.0.0/24 10.81.0.1"
      
      # sysctl net.inet.ip.forwarding=1
      # ifconfig gif0 create
      # ifconfig gif0 10.65.0.1 10.81.0.1 netmask 255.255.255.0
      # ifconfig gif0 tunnel 45.76.153.70 45.76.207.156
      # route add 10.81.0.1/24 10.81.0.1

Step 2: Update Firewall Rules of the Routers

You will notice that after setting the items above, the router in Singapore still cannot obtain ping reply from the internal network address of the router in Japan (10.81.0.1), and vice versa.  If the pf firewall on one side is disabled, it works.  This is because the computers are having a firewall enabled (per our standard customisation script).  Let us relax the rules to let these through.

  1. Host 1: japao-roteador
    1. Counterpart peer: cingapura-roteador (45.76.153.70)
    2. Protocol to allow: ipencap
      # cat >> /etc/pf.conf << EOF
      encappeers="{45.76.153.70}"
      pass in quick inet proto ipencap from $encappeers to any
      EOF
      # service pf reload
  2. Host 2: cingapura-roteador
    1. Counterpart peer: japao-roteador (45.76.207.156)
    2. Protocol to allow: ipencap
      # cat >> /etc/pf.conf << EOF
      encappeers="{45.76.207.156}"
      pass in quick inet proto ipencap from $encappeers to any
      EOF
      # service pf reload

 

Step 3: Configure Routing on the Clients

Similarly, we add static routes to the client hosts.  Please note they are subtlety different.  For example:  The router in Japan is directing Singapore traffic to the router in Singapore.  The host in Japan is directing Singapore traffic to the router in Japan instead.

  1. Host 2: japao-host
    1. Route: 10.65.0.0/24 (network in Singapore) to 10.81.0.1 (router in Japan)
      # sysrc static_routes+="cingapura"
      # sysrc route_cingapura="10.65.0.0/24 10.81.0.1"
      # route add 10.65.0.0/24 10.81.0.1
  2. Host 4: cingapura-host
    1. Route: 10.81.0.0/24 (network in Japan) to 10.81.0.1 (router in Singapore)
      # sysrc static_routes+="japao"
      # sysrc route_cingapura="10.81.0.0/24 10.65.0.1"
      # route add 10.81.0.0/24 10.65.0.1

Step 4: Test

  1. To test the routers, use command ping from japao-reteador to 10.65.0.1 (Singapore), and from cingapura-roteador to 10.81.0.1 (Japan).  Nice.  The two sites are 76 milliseconds apart.
    root@japao-roteador ~# ping 10.65.0.1
    PING 10.65.0.1 (10.65.0.1): 56 data bytes
    64 bytes from 10.65.0.1: icmp_seq=0 ttl=64 time=76.978 ms
    64 bytes from 10.65.0.1: icmp_seq=1 ttl=64 time=76.898 ms
    64 bytes from 10.65.0.1: icmp_seq=2 ttl=64 time=76.859 ms
    64 bytes from 10.65.0.1: icmp_seq=3 ttl=64 time=76.903 ms
    64 bytes from 10.65.0.1: icmp_seq=4 ttl=64 time=76.758 ms
    64 bytes from 10.65.0.1: icmp_seq=5 ttl=64 time=77.120 ms
    ^C
    --- 10.65.0.1 ping statistics ---
    6 packets transmitted, 6 packets received, 0.0% packet loss
    round-trip min/avg/max/stddev = 76.758/76.919/77.120/0.111 ms
  2. To test the hosts, use command ping from japao-host to 10.65.0.11 (Singapore host), and from cingapura-host to 10.81.0.11 (Japan host).  There is slightly one more millisecond in the round trip time.
    root@japao-host ~# ping 10.65.0.11
    PING 10.65.0.11 (10.65.0.11): 56 data bytes
    64 bytes from 10.65.0.11: icmp_seq=0 ttl=62 time=77.892 ms
    64 bytes from 10.65.0.11: icmp_seq=1 ttl=62 time=77.817 ms
    64 bytes from 10.65.0.11: icmp_seq=2 ttl=62 time=78.710 ms
    64 bytes from 10.65.0.11: icmp_seq=3 ttl=62 time=78.227 ms
    64 bytes from 10.65.0.11: icmp_seq=4 ttl=62 time=78.444 ms
    ^C
    --- 10.65.0.11 ping statistics ---
    5 packets transmitted, 5 packets received, 0.0% packet loss
    round-trip min/avg/max/stddev = 77.817/78.218/78.710/0.335 ms

Step 5: Troubleshoot

I hope you do not need this step.  Anyway…

When you are unable to receive a ping reply, there are mostly two reasons.  Either the ping request is unable to reach the destination, or the ping reply could not transverse back to the requestor.  Seeing the packets on both the hosts simultaneously gives you insight which case it is.  To see if there are any traffic in the tunnel, issue on the routers:

# tcpdump -i gif0

Why is a packet unable to appear in the network?  There are mostly two reasons.  Either the network firewall blocks it (unlikely if you follow my instructions) or the route is set incorrectly.  To see if the firewall state table and the route table:

# pfctl -s states
# netstat -rn

Step 6: To be Continued

At this stage, when you use “tcpdump” on the interface, you get messages like:

# tcpdump host 45.76.153.70
16:09:26.759030 IP 45.76.207.156.vultr.com > 45.76.153.70.vultr.com: IP 10.81.0.1 > 10.65.0.1: ICMP echo reply, id 53509, seq 9, length 64 (ipip-proto-4)

And we want it to be encrypted, like:

# tcpdump host 45.76.153.70
16:09:32.314383 IP 45.76.207.156.vultr.com > 45.76.153.70.vultr.com: ESP(spi=0x004a1fe7,seq=0x1c), length 116

In the next part, I will go through the steps to encrypt the tunnel.

Minecraft with Java and Tmux on FreeBSD

Standard

A virtual world cannot be complete without a virtual reality environment like Minecraft.  In this article, I quickly go through the steps setting a Minecraft server with FreeBSD.   Specifically, I will be installing a Spigot Minecraft Server.  I like it very much because it comes with lots of performance optimisations.  I assume you prepared your environment with my customisation script or something similar.  The whole process will take less than one hour if you have a good internet connection.

Step 1: Installing Java, Tmux, Bash, and Friends

As usual, installing packages in FreeBSD is easy.  It is simply “pkg install”.  Yet, Java and Bash requires special file systems at “/dev/fd” and “/proc”.  The file “/etc/fstab” is therefore appended and two more file systems are defined.  The file systems are mounted before we proceed on the next step.

pkg install tmux bash git openjdk8
cat >> /etc/fstab << EOF
fdesc /dev/fd fdescfs rw 0 0
proc /proc procfs rw 0 0
EOF
mount /dev/fd
mount /proc

Step 2: Trying Tmux

To try tmux, one can simply issue the command

tmux

Inside the tmux session, one can:

  • Start a new window with keystrokes Ctrl-B, C
  • Switch to the previous window with keystrokes Ctrl-B, P
  • Switch to the next window with keystrokes Ctrl-B, N
  • Switch to a specific window with keystroke Ctrl-B, then the window number
  • Detach from the session with keystrokes Ctrl-B, D

For more, you can easily find information with a search engine.  The last feature, detachment, is very useful.  One can leave a program running inside a tmux session, logout, login, and reattach to the same session.  This feature is particularly useful since a minecraft server is nothing more than a long-running Java application.

Step 3: Execute the Automated Build

In your favourite working directory, download the builder Java archive (JAR) file:

curl "https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar" -o BuildTools.jar

Then you can execute the JAR file:

java -jar BuildTools.jar

Step 4: Accept the EULA

After about half an hour of compilation, read the “eula.txt” and execute the following if you agree.

sed -ibak s/false/true/ eula.txt

Step 5: Tmux on Boot

Like last time with the firewall table flush, we can append a line to the “/etc/crontab” for a command to automatically start.  Yet, this time we are executing the command once only, we use the “@reboot” magic word.  In the second field, the “root” account is taken for running the program.  You have to stick with the user account you have chosen.  From the third field onward, with the “tmux new-session” command, we generate a new session.

The Java was executed with initial heap size to be 1024 MB, and maximum heap size to be 1024 MB as well.  This should be good enough unless you have a lot of friends.  In that case, you will experience some “OutOfMemoryError” and have to expand the memory accordingly.  Make sure your virtual machine is large enough to handle it.  In the folklores, it is said that one can only have heap size 60% of the total system memory.  If one has 8 GB main memory, at most the Java heap size is 4096 MB or 5120 MB.

cat >> /etc/crontab << EOF
@reboot root /usr/local/bin/tmux new-session -s spigot -d /usr/local/bin/java -Xmx1024M -Xms1024M -jar /root/spigot*.jar
EOF

Step 6: Start for the First Time

Starting it the first time is nothing much different from the command in the crontab.

tmux new-session -s spigot -d java -Xmx1024M -Xms1024M -jar spigot*.jar

Step 7: Firewall Configuration

Add port 25565 to the list of allowed ports.  In our context, we will update the line with “tcpports” in “/etc/pf.conf”:

tcpports="{22,80,443,25565}"

After that, restart the firewall with command:

service pf reload

Step 8: Connect to the Server

Open your Minecraft client, select “Multiplayer”, then “Direct Connect”.  You can then put in your server address.  If you just realise it is a commercial software, sorry, you got to pay.  Some say, one can use unauthorised Minecraft client for playing in his own server with the offline mode.  But the procedures above already assumes you run the server in online mode.

Step 9: Finding Plugins and Writing Startup Scripts

Once you get comfortable starting and stopping the servers, you can find plugins and put them to “plugins” directory.

Also, instead of calling the java command directly, you can write a shell script to encapsulate these complexities.  Sometimes server crash and you prefer it to automatically restart.  You can then add a automatic restart procedure inside the script.

#!/bin/sh
while true
do
  java -Xmx1024M -Xms1024M -jar spigot*.jar
  echo Press Ctrl-C now if you mean to stop instead of restart
  sleep 5
done

The actual procedures are left for you due to my laziness.

Customising FreeBSD

Standard

In this article, I share my my usual customisation steps to a fresh FreeBSD installation.  FreeBSD is very minimal, but one can definitely even go further.  These steps are similar to Charray’s approach to FreeBSD 8, and they are updated for FreeBSD 11 with the software RAID skipped.

Major Edited on 2 Feb 2017: Fixing the WordPress Auto-corrption.

Major Edited on 17 Feb 2017: Updating periodic configuration and firewall rules.

Step 1: Disabling Sendmail

FreeBSD has minimal set of services enabled.  However, there is one more service I want to disable—sendmail.  It is a really traditional mail server.  If you ask me, I would say there is nothing wrong with it.  I just do not want a mail server running on every server.

Simply, add this line in “/etc/rc.conf”:

sendmail_enable="NONE"

Usually, to disable a service, one use the word “NO”.  But sendmail is an exception, one has to use “NONE” to disable everything.  (You can refer to “/etc/rc.d/sendmail” if you understand the scripting language.)  To stop the sendmail, either stop the service gracefully or in brute force.  “pkill” means kill processes with the given name;  “-9” means the most forceful way:

pkill -9 sendmail

If you want to see what other services can be enabled or disabled, check “/etc/defaults/rc.conf”, just make sure not to change the default file.

Step 2: Disabling Periodic Mails

What are the consequences disabling the local mail server?  By default, FreeBSD performs some periodic checks and sends the results to the mail server, and also does some mail server housekeeping.  We can disable the mails and redirect them to the “/var/log” directory, and then also disable the mail server housekeeping.  Add these lines to a new “/etc/periodic.conf”:

daily_output="/var/log/daily.log"
weekly_output="/var/log/weekly.log"
monthly_output="/var/log/monthly.log"
daily_status_security_output="/var/log/daily.log"
weekly_status_security_output="/var/log/weekly.log"
monthly_status_security_output="/var/log/monthly.log"
daily_clean_hoststat_enable="NO"
daily_backup_aliases_enable="NO"
daily_status_mailq_enable="NO"
daily_status_include_submit_mailq="NO"
daily_status_mail_rejects_enable="NO"
daily_queuerun_enable="NO"

Since periodic mails are not long-running services (they are started indirectly by another service), the changes are taken effetely on the next run.

Step 3: Disabling Terminals

FreeBSD comes with seven virtual text terminals so one can switch between while working with it.  To my taste, I do not use these terminals, especially when it is on the cloud.  These configuration are in “/etc/ttys”.  One can change “on” to “off” to switch off the terminals “ttyv2” to “ttyv7”.  Let me be lazy and tell you the script for so.

sed -ibak '/ttyv2/s/on /off/; /ttyv3/s/on /off/; /ttyv4/s/on /off/; /ttyv5/s/on /off/; /ttyv6/s/on /off/; /ttyv7/s/on /off/' /etc/ttys

Then, to make it effective, send a hangup signal to the “init” process.  It is the very first process started directly by the kernel so it is having process number 1 every single time.

kill -HUP 1

Step 4: Enabling Time Services

Computers are usually keeping the time in inaccurate manners even if you have them constantly powered.  It is nice to have the time synchronised to somewhere better prepared.

ntpd_enable="YES"

By default, the system will point to places predefined by the FreeBSD distributions which can be changed in “/etc/ntpd.conf”.   For purpose of a single FreeBSD server, it is already good enough.  Finally, to start the service:

service ntpd start

The “ntpd” service will synchronise and drift the system clock accordingly.

Step 5: Enabling Firewall

Edit the file “/etc/pf.conf”.  This is usually the template I start from.  In short, it does the following: 1) set up a spammer table; 2) allow local network; 3) drop the spammers; 4) do not allow intranet addresses on the external interfaces; 5) allow connections to particular ports; 6) treat a user as spammer if there are more than 100 existing connections; 7) treat a user as spammer if there are more than 100 connection attempts per second.

extif="vtnet0"
tcpports="{22,80,443}"
martians="{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}"
table <spammers> persist
set skip on lo

block all
block drop in quick from <spammers> to any
block drop in quick on $extif from $martians to any
pass out quick inet proto udp from any to 255.255.255.255 port {67,68}
block drop out quick on $extif from any to $martians

pass out quick
pass in quick inet proto icmp from any to any
pass in quick inet proto tcp from any to any port $tcpports keep state \
  (max-src-conn 100, max-src-conn-rate 100/1 \
   overload <spammers> flush global)

Then, we add a line in “/etc/crontab” to clear the spammers after 1 day (86400 seconds).  The check is taken once every 5 minutes.  Sometimes legitimate users are blocked due to network resends.  It is therefore important to unblock them before they raise a complaint.

*/5 * * * * root /sbin/pfctl -t spammers -T expire 86400 > /dev/null 2>&1

To enable the firewall, find a physical connection (or the cloud remote management console) and issue the command:

service pf start

Your network connections will be dropped.  It is not disastrous if you can reconnect.  But it definitely is, if something is wrong with your script.  You have been warned.

Step 6: Personalisation

Personally, I like “tcsh” with autocomplete and the current directory hint in the shell.  Also, I prefer being prompted when I am going to overwrite a file.  Here is what I do to the “.cshrc” file:

alias h history 25
alias j jobs -l
alias la ls -aF
alias lf ls -FA
alias ll ls -lAF
umask 22
set path = (/sbin /bin /usr/sbin /usr/bin /usr/games /usr/local/sbin /usr/local/bin $HOME/bin)
setenv EDITOR vi
setenv PAGER more
setenv BLOCKSIZE K
if ($?prompt) then
  alias ls ls -G
  alias cp cp -i
  alias mv mv -i
  alias rm rm -i
  alias ln ln -i
  alias link link -i
  if ($uid == 0) then
    set user = root
  endif
  set prompt="%B%n%b@%B%m%b %B%~%b%# "
  set noclobber
  set rmstar
  set autolist
  set filec
  set history = 1000
  set savehist = (1000 merge)
  set autolist = ambiguous
  set autoexpand
  set autorehash
  set mail = (/var/mail/$USER)
  if ($?tcsh) then
     bindkey "^W" backward-delete-word
     bindkey -k up history-search-backward
     bindkey -k down history-search-forward
  endif
endif

And I want to make sure “tcsh” is my shell:

chpass -s /bin/tcsh

And finally, if I want to share this with upcoming new users, I will put it to the skeleton directory:

cp -a /root/.cshrc /usr/share/skel/dot.cshrc

And another thing I like to customise is “vim”.  I edit the “.vimrc” file as follows.  Interestingly, while some would argue it is not comprehensive enough, I really made my research-related programming on such a simple environment.

set nomodeline
set copyindent
set autoindent
set nowrap
set cc=80
syntax on

Then share it in the skeleton directory:

cp -a /root/.vimrc /usr/share/skel/dot.vimrc

Step 7: Initialisation Scripts

Finally, in Vultr, I have the initialisation scripts as follows.  This way, I can get the operating system customised to my flavour when it finishes booting.  I will skip my explanation for laziness sake.  Até a proxima semana.

#!/bin/sh -x

#
# Disable Sendmail
#
logger Disabling Sendmail
sysrc sendmail_enable="NONE"

#
# Disable Periodic Email
#
logger Disabling Periodic Emails
pfile="/etc/periodic.conf"
sysrc -f $pfile daily_output="/var/log/daily.log"
sysrc -f $pfile daily_output="/var/log/daily.log"
sysrc -f $pfile weekly_output="/var/log/weekly.log"
sysrc -f $pfile monthly_output="/var/log/monthly.log"
sysrc -f $pfile daily_status_security_output="/var/log/daily.log"
sysrc -f $pfile weekly_status_security_output="/var/log/weekly.log"
sysrc -f $pfile monthly_status_security_output="/var/log/monthly.log"
sysrc -f $pfile daily_clean_hoststat_enable="NO"
sysrc -f $pfile daily_backup_aliases_enable="NO"
sysrc -f $pfile daily_status_mailq_enable="NO"
sysrc -f $pfile daily_status_include_submit_mailq="NO"
sysrc -f $pfile daily_status_mail_rejects_enable="NO"
sysrc -f $pfile daily_queuerun_enable="NO"

#
# Disable TTYs
#
logger Disabling Virtual Terminals
sed -ibak '/ttyv2/s/on /off/; /ttyv3/s/on /off/; /ttyv4/s/on /off/; /ttyv5/s/on /off/; /ttyv6/s/on /off/; /ttyv7/s/on /off/' /etc/ttys

#
# NTP service
#
logger Configuring NTP
sysrc ntpd_enable="YES"

#
# PF service
#
logger Configuring PF
cat > /etc/pf.conf << EOF
extif="vtnet0"
tcpports="{22,80,443}"
martians="{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}"
table <spammers> persist
set skip on lo

block all
block drop in quick from <spammers> to any
block drop in quick on \$extif from \$martians to any
pass out quick inet proto udp from any to 255.255.255.255 port {67,68}
block drop out quick on \$extif from any to \$martians

pass out quick
pass in quick inet proto icmp from any to any
pass in quick inet proto tcp from any to any port \$tcpports keep state \
  (max-src-conn 100, max-src-conn-rate 100/1 \
   overload <spammers> flush global)
EOF
cat >> /etc/crontab << EOF
*/5 * * * * root /sbin/pfctl -t spammers -T expire 86400 > /dev/null 2>&1
EOF
sysrc pf_enable="YES"

#
# Shell environment
#
logger Configuring TCSH environment
cat > /root/.cshrc << EOF
alias h history 25
alias j jobs -l
alias la ls -aF
alias lf ls -FA
alias ll ls -lAF

umask 22

set path = (/sbin /bin /usr/sbin /usr/bin /usr/games /usr/local/sbin /usr/local/bin \$HOME/bin)

setenv EDITOR vi
setenv PAGER more
setenv BLOCKSIZE K

if (\$?prompt) then
  alias ls ls -G
  alias cp cp -i
  alias mv mv -i
  alias rm rm -i
  alias ln ln -i
  alias link link -i

   if (\$uid == 0) then
     set user = root
   endif

   set prompt="%B%n%b@%B%m%b %B%~%b%# "
   set noclobber
   set rmstar
   set autolist
   set filec
   set history = 1000
   set savehist = (1000 merge)
   set autolist = ambiguous
   set autoexpand
   set autorehash
   set mail = (/var/mail/\$USER)
   if (\$?tcsh) then
     bindkey "^W" backward-delete-word
     bindkey -k up history-search-backward
     bindkey -k down history-search-forward
   endif
endif
EOF
cp -a /root/.cshrc /usr/share/skel/dot.cshrc
chpass -s /bin/tcsh root #

# VIM environment
logger VIM environments
cat > /root/.vimrc << EOF
set nomodeline
set copyindent
set autoindent
set nowrap
set cc=80
syntax on
EOF
cp -a /root/.vimrc /usr/share/skel/dot.vimrc

#
# Refresh the pkg and install packages
#
logger Configuring Packages 
export ASSUME_ALWAYS_YES=yes
/usr/sbin/pkg bootstrap -f
/usr/local/sbin/pkg-static delete \*
/usr/local/sbin/pkg-static update
/usr/local/sbin/pkg-static upgrade
/usr/local/sbin/pkg-static install vim-lite tmux

#
# Restart the TTYs
# Send ALARM signal to reload rc.conf
#
kill -HUP 1
kill -SIGALRM $RC_PID
sysctl -f /etc/sysctl.conf