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: Testing

  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: Troubleshooting

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

Starting with FreeBSD on the Cloud

Standard

This article describes how one can get some FreeBSD virtual instances on the Internet quick.  For cost-saving, Vultr, which charges hourly, is used.  The exercise will finish within an hour or two.

Objectives

  1. Start some FreeBSD instances
  2. Experiment some configurations
  3. Setup password-less logins

Step 0: Why (and why not) FreeBSD

FreeBSD is an operating system.  If you are reading this article online, I am almost certain you know one particular operating system.  There are various operating systems for daily computing activities—Windows, [M]acOS, iOS, Solaris, etc.  (In case you want to say an L-word, click here.)  In addition to one’s personal taste.  The official website gives a perfect explanation.

FreeBSD is an advanced computer operating system used to power modern servers, desktops, and embedded platforms.  A large community has continually developed it for more than thirty years.  Its advanced networking, security, and storage features have made FreeBSD the platform of choice for many of the busiest web sites and most pervasive embedded networking and storage devices.

What would be valid reasons not to use FreeBSD?  Indeed, there are also a lot but I like to put only one here.  FreeBSD is best operated in commands, not mouse clicks.  If you insist using only mouse clicks for your tasks, you are likely to try Microsoft Windows.

(As a side note, some would say FreeBSD is only a server operating system.  You can watch some counter-examples in Charray’s YouTube channel or Riba’s channel.  Once it is set up, the mental workload to use it is minimal.  I had been using it for most of my research career and at least the mascot had not killed me!)

Step 1: Get an Online Account and Deposit

I feel like scamming telling you to prepaid for a service, but please trust me.  There are of course postpaid services, but they are usually more expensive and less controllable.  Think what happens in event of a bill shock.  If you feel really uncertain, you can deposit as little as a few dollars.  Best of all, the provider Vultr we use today accepts other payment methods like Paypal and Bitcoin, which helps you to reduce chance of having the credit card number stolen.

To register, fill in the “Create Account” form and answer the questions.  You are reminded to use a valid email address since it is critical for creating virtual machines.  The so-called “Password” field here does not refer to the password of your email account, but a new password for this new service.  Never use your existing email password when applying other services.

screen-shot-2017-01-17-at-10-46-38-pm

After the first login, you will be guided to deposit some money to the account.  Please check your email box and reply to the email verification as well.

screen-shot-2017-01-17-at-10-44-34-pm

Step 2: Submit a Form for Virtual Machines

Once you have deposited money, you can direct to the “Server” page.  The plus sign on the far-right is the one for submitting for virtual machines.

screen-shot-2017-01-17-at-10-56-20-pm

In the form, you can first select the region closest to you, select “FreeBSD 11 x64”, “20 GB SSD” plan, and the “Enable Private Network” option.  Leave the “Startup Scripts” and “SSH Keys” unselected.  Your new account is not supposed to have any yet.

screen-shot-2017-01-17-at-11-21-29-pm

screen-shot-2017-01-17-at-11-16-04-pm

screen-shot-2017-01-17-at-11-16-18-pm

Once you are comfortable with the choice, click “Deploy Now”.  No, soon you will discover, you are not getting charged 10 dollars immediately.  Be brave.

Step 3: Wait

You can refresh faster by clicking the “Server” pane.  The instance will go through several stages when it is in preparation—installing, resizing, starting, etc.  But there is a catch.  Once it is started, it is not necessary really started.  In context of cloud provider, a machine is considered started even when it is booting through the firmware and startup scripts!  By the way, you are being charged for one hour of usage—2 cents.

screen-shot-2017-01-20-at-8-57-22-pm

screen-shot-2017-01-20-at-8-57-56-pm

screen-shot-2017-01-20-at-8-58-10-pm

You can reveal a new page by clicking the machine name.  Inside you can have options such as viewing the console, switching off the machine, reinstalling, etc.  The password can also be revealed in an extra click.

screen-shot-2017-01-20-at-8-58-15-pm

Step 4: Login and some Configurations

With the given IP address, the username, and the password, you can login through the secured shell.  For Unix-like operating systems, there is usually a tool “Terminal” where you can use the command “ssh” directly.  (For Windows, you can consider using putty.  It starts with a point-and-click interface for making the connection.)  The basic command for the “ssh” is:

ssh <username>@<host>

And the dialog will be like:

Last login: Fri Jan 20 20:52:50 on ttys001

kinsonchan@almond ~% ssh root@45.76.147.176
The authenticity of host '45.76.147.176 (45.76.147.176)' can't be established.
RSA key fingerprint is 9c:1e:0e:9c:f0:ba:38:56:5a:9a:90:54:68:aa:aa:07.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '45.76.147.176' (RSA) to the list of known hosts.
Password for root@vultr.guest:
Last login: Fri Jan 20 12:59:05 2017
FreeBSD 11.0-RELEASE-p2 (GENERIC) #0: Mon Oct 24 06:55:27 UTC 2016

Welcome to FreeBSD!

Release Notes, Errata: https://www.FreeBSD.org/releases/
Security Advisories:   https://www.FreeBSD.org/security/
FreeBSD Handbook:      https://www.FreeBSD.org/handbook/
FreeBSD FAQ:           https://www.FreeBSD.org/faq/
Questions List: https://lists.FreeBSD.org/mailman/listinfo/freebsd-questions/
FreeBSD Forums:        https://forums.FreeBSD.org/

Documents installed with the system are in the /usr/local/share/doc/freebsd/
directory, or can be installed later with:  pkg install en-freebsd-doc
For other languages, replace "en" with a language code like de or fr.

Show the version of FreeBSD installed:  freebsd-version ; uname -a
Please include that output and any error messages when posting questions.
Introduction to manual pages:  man man
FreeBSD directory layout:      man hier

Edit /etc/motd to change this login announcement.
#

You can then edit the main configuration file.  Unlike most operating systems, the configuration of FreeBSD is quite centralised to several files, mostly “/etc/rc.conf”.  You can use “vi” if you like.  But since you are reading this article, you are likely to use “ee” instead.  As I will show in upcoming articles, I have some preferences in what services to enable and disable.  I will edit the file with command:

ee /etc/rc.conf

And update the screen content as follows.  Use arrow keys to navigate.

^[ (escape) menu ^y search prompt ^k delete line ^p prev li ^g prev page
^o ascii code    ^x search     ^l undelete line  ^n next li ^v next page
^u end of file   ^a begin of line ^w delete word   ^b back 1 char
^t top of text   ^e end of line   ^r restore word  ^f forward 1 char
^c command       ^d delete char   ^j undelete char ^z next word
=====line 6 col 17 lines from top 6 =====================================
hostname="vultr.guest"
sshd_enable="YES"
static_routes="linklocal"
ifconfig_vtnet0="DHCP"
sendmail_enable="NONE"
ntpd_enable="YES"

After that, press the “Esc” button for a menu, then “a” twice to save and exit.  By the way, if you are experienced, the meaning of the file is literally setting the hostname and services.  Unlike some other operating systems, in FreeBSD it is done all in one place.  Neat.

Step 5: Password-less Login

Inside the same prompt, you can issue the command “ssh” to itself.  Strangely, it asks you for a password.

# ssh localhost

The authenticity of host 'localhost (127.0.0.1)' can't be established.
ECDSA key fingerprint is SHA256:+.......
No matching host key fingerprint found in DNS.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'localhost' (ECDSA) to the list of known hosts
Password for root@vultr.guest:

This is no good if you are asked the password for every login.  Let us solve it with “ssh-keygen” and put it as a default login.   For demonstration purpose, let us execute this on the same machine.

# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:Er4yNuYmjvbmTOlJP6sNFCV6QuD++45MeFBv5A6QFmg root@vultr.guest
The key's randomart image is:
+---[RSA 2048]----+
|+o . .           |
|+E+ o            |
|.B + ..          |
|o = =. .         |
| o o +o S        |
|  = =  o         |
| . O*..          |
| oX=O=           |
|o.=&=*o          |
+----[SHA256]-----+

After the dialogue and the messy picture, what else do you get?  Some files in the “.ssh” folder.  You can list them with the “ls” command.

# ls .ssh
id_rsa  id_rsa.pub  known_hosts

The “id_rsa” is your private file.  It should be kept within your own computers only, not those owned by anyone else.  The “id_rsa.pub” is your public key.  You can install it to the machines where you need the password-less login.  The file content can be listed with “cat” command.

# cat .ssh/id_rsa.pub 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD93syOQa78tYAysC52H/gUNIMQRjJpu/zKIbc0qFsGFouv9OtnehFix/EIeIBQmYIVv0gRmfI9qiFx2TQpkk0AHvmDew5VfWFeszfGOQnI3xU8hSeG7kKENMozGT+yh5RbjL6ZGRu/cWX5+K9M96kuNbI7CFU0p/muzqeQgOtYsGx+G1qnrW6K6EDFD8guNPF5JXBb88x8WaL7ooqNUZhTbLVIxHtycMqArka84Wvmvi3lJvVQGygid9qLO9WL8NaQ3KaithAR05sNoLw2y+AoXHfRLWoWRMrXvaVE3PrkntnLIi6Cvn/+HsuBdF71/cDu6TCLfU/SlTxdpYY/omez root@vultr.guest

This piece of string (from “ssh-rsa” to the end) can be put into the SSH key place of the cloud.  Then, when you start a new machine next time (left as your exercise… do you have two more cents to try?), you can login without the password.  What about the machines that are already provisioned, like the one we already have?  Put them in “.ssh/authorized_keys”.

Screen Shot 2017-01-20 at 9.52.28 pm.png

# mkdir -p .ssh
# chmod 0700 .ssh
# touch .ssh/authorized_keys
# chmod 0600 .ssh/authorized_keys
# cat .ssh/id_rsa.pub >> .ssh/authorized_keys

You can see the commands are all executed without a line of output.  This is the philosophy of Unix—return nothing on success.  After this, you will find the file “.ssh/authorized_keys” contains the line of the “.ssh/id_rsa.pub”.  (You can verify this with the “ee” command.)  If things are going well, “ssh localhost” this time should be connected without password.

Step 6: Clean up

When you are finished, go to the cloud provider page, select the machine, activate the pop-up menu and select “Server Destroy”.  Hopefully, we finish this exercise before being charged too much.

screen-shot-2017-01-20-at-10-04-12-pm

In my case here, I have spent only three cents for demonstration on this blog.  Three cents are way cheaper than my own manpower to find a computer and install FreeBSD thereon.  This is why some people are so attracted to public cloud services.

In this article, we have went through starting FreeBSD instances, some basic configuration exercise, and finally experimented one of the ways for password-less login.  Next week, we will likely continue with my preferred customisations and installing an example server application.