:::: MENU ::::

Posts Categorized / Linux

  • Feb 27 / 2015
  • 0
Linux

How to setup an IPSec tunnel with Strongswan with high-availability on Linux

It is possible to secure your communication between several sites (datacenters for example) by using an open-source VPN IPSec on your Linux System. We will see here how to:

  1. Set-up a VPN IPSec on Linux with Strongswan (https://www.strongswan.org)
  2. Set-up a high availability mechanism on top of this VPN connection to ensure the link will always be up with KeepAlived (http://www.keepalived.org/)

Architecture

Here is the architecture example I will use in this post.

  • – – – represents a local link
  • === represents a VPN link
192.168.50.0/24 - - - 192.168.100.1 === 192.168.100.2 - - - 10.0.0.0/16

VPN Installation

First of all, install the package strongswan using the package manager you used to, or by compiling it from sources. In the same time, install the keepalived package to be able to set it highly available at the end of this post.

$apt-get install strongswan keepalived

This will install the packages and the libraries needed to make them work.

Certificates

First thing to do will be to generate certificates used for the encryption of communication within the VPN. This can be done in two ways:

CA Certificate

Once the packages are properly installed, we will have to create the different certificates that we will use to encrypt our connection between peers. For the example we will be using self-signed certificate here. The first certificate to generate wil be the CA certificate with which one we will sign any certificate we want to use in the VPN network.

Generate a 2048 bit RSA private key (caKey.der) for the CA certificate (caCert.der) and self-sign it with this key:

$ipsec pki --gen > caKey.der
$ipsec pki --self --in caKey.der --dn "C=FR, O=myCompany, CN=myCompany CA" --ca > caCert.der

End Entity Certificate

For each peer (i.e. each gateway), a private key (peerKey.der) and a certificate (peerCert.der) will have to be generated using the CA previously created:

$ipsec pki --gen > peerKey.der
$ipsec pki --pub --in peerKey.der | ipsec pki --issue --cacert caCert.der --cakey caKey.der --dn "C=FR, O=myCompany, CN=vpn-peer1" > peerCert.der

Install certificates

On each peer, store the following certficates and private keys in /etc/ipsec.d/ subdirectory as:

  • /etc/ipsec.d/private/peerKey.der for the private key of the peer
  • /etc/ipsec.d/certs/peerCert.der for the certificate of the peer
  • /etc/ipsec.d/cacerts/caCert.der for the CA certificate that signed the certificates

The CA private key (caKey.der) should never be stored on a server directly reachable from the Internet and be kept safe.

IPSec configuration

To configure IPSec, you will have to configure two files:

  • /etc/ipsec.conf for the configuration of your tunnels
  • /etc/ipsec.secrets for the configuration of your keys and/or PSK (pre-shared keys)

If you use certificate for your connection, here is what your configuration should look like:

#/etc/ipsec.conf
# ipsec.conf - strongSwan IPsec configuration file

config setup

conn %default
  ikelifetime=60m
  keylife=20m
  rekeymargin=3m
  keyingtries=1
  keyexchange=ikev2
  mobike=no

conn peer1-peer2
  left=192.168.100.1
  leftcert=peerCert.der
  leftid="C=FR O=myOrganisation, CN=vpn-peer1"
  leftsubnet=192.168.50.0/24
  leftfirewall=yes
  right=192.168.100.2
  rightid="C=FR, O=myOrganisation, CN=vpn-peer2"
  rightsubnet=10.0.0.0/16
  auto=start
  closeaction=restart
#/etc/ipsec.secrets
# This file holds shared secrets or RSA private keys for authentication.

: RSA peerKey.der

If instead of using certificates you prefered to use Pre-Shared Key (as you will have to if you want to connect to AWS VPN Services), here are how should be configured both files:

#/etc/ipsec.conf
# ipsec.conf - strongSwan IPsec configuration file

config setup

conn %default
  ikelifetime=60m
  keylife=20m
  rekeymargin=3m
  keyingtries=1
  authby=secret
  keyexchange=ikev2
  mobike=no

conn peer1-peer2
  left=192.168.100.1
  [email protected]
  leftsubnet=192.168.50.0/24
  leftfirewall=yes
  right=192.168.100.2
  rightsubnet=10.0.0.0/16
  auto=start
#/etc/ipsec.secrets
# This file holds shared secrets or RSA private keys for authentication.

@vpn-peer-1 @vpn-peer-2 : PSK "poiuYTREzaQSdfGhJKlmNbvCxw"

IPsec commands and monitoring

First of all, each time you are changing part of the configuration, it’s strongly advised to reload configuration by doing:

$ipsec restart

Once this done, you can easily up/down a configuration by using:

$ipsec up peer1-peer2
$ipsec down peer1-peer2

A last command very useful is “statusall” that allows you to check and monitor VPN links:

$ipsec statusall
Status of IKE charon daemon (strongSwan 5.1.2, Linux 3.13.0-45-generic, x86_64):
  uptime: 7 hours, since Feb 15 23:25:20 2015
  malloc: sbrk 1486848, mmap 0, used 407360, free 1079488
  worker threads: 11 of 16 idle, 5/0/0/0 working, job queue: 0/0/0/0, scheduled: 6
  loaded plugins: charon test-vectors aes rc2 sha1 sha2 md4 md5 random nonce x509 revocation constraints pkcs1 pkcs7 pkcs8 pkcs12 pem openssl xcbc cmac hmac ctr ccm gcm attr kernel-netlink resolve socket-default stroke updown eap-identity addrblock
Listening IP addresses:
  192.168.100.1
Connections:
  peer1-peer2: 192.168.100.1...192.168.100.2 IKEv2
  peer1-peer2: local: [C=FR, O=myOrganisation, CN=vpn-peer1] uses public key authentication
  peer1-peer2: cert: "C=FR, O=myOrganisation, CN=vpn-peer1"
  peer1-peer2: remote: [C=FR, O=myOrganisation, CN=vpn-peer2] uses public key authentication
  peer1-peer2: child: 192.168.50.0/24 === 10.0.0.0/16 TUNNEL
Security Associations (1 up, 0 connecting):
  peer1-peer2[25]: ESTABLISHED 2 minutes ago, 192.168.100.1[C=FR, O=myOrganisation, CN=vpn-peer1]...192.168.100.2[C=FR, O=myOrganisation, CN=vpn-peer2]
  peer1-peer2[25]: IKEv2 SPIs: 9f7e598d22e98081_i 003d60cae30e9548_r*, public key reauthentication in 52 minutes
  peer1-peer2[25]: IKE proposal: AES_CBC_128/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_2048
  peer1-peer2{23}: INSTALLED, TUNNEL, ESP SPIs: cc8513e9_i c729b4f7_o
  peer1-peer2{23}: AES_CBC_128/HMAC_SHA1_96, 0 bytes_i, 0 bytes_o, rekeying in 12 minutes
  peer1-peer2{23}: 192.168.50.0/24 === 10.0.0.0/16

High availability configuration

So that your VPN can be highly available, you will need to configure keepalived that you just installed at the beginning. You will have to configure it on both sides by using a virtual IP and a script to automate the restart on both nodes depending on the state of the cluster (option “notify”).

Here is the configuration for the master server:

! Configuration File for keepalived

vrrp_instance VI_1 {
  state MASTER
  interface eth0
  virtual_router_id 51
  priority 150
  advert_int 1
  authentication {
    auth_type PASS
    auth_pass $ place secure password here.
  }
  virtual_ipaddress {
    192.168.100.1
  }
  notify /opt/notifyipsec.sh
}

The configuration for the slave (backup) server is almost similar but state and priority are changing:

! Configuration File for keepalived

vrrp_instance VI_1 {
  state BACKUP
  interface eth0
  virtual_router_id 51
  priority 100
  advert_int 1
  authentication {
    auth_type PASS
    auth_pass $ place secure password here.
  }
  virtual_ipaddress {
   192.168.100.1
  }
  notify /opt/notifyipsec.sh
}

And here is the script notifyipsec.sh for the “notify” option:

#!/bin/bash

TYPE=$1
NAME=$2
STATE=$3

case $STATE in
    "MASTER") ipsec restart
              exit 0
              ;;
    "BACKUP") ipsec stop
              exit 0
              ;;
    "FAULT")  ipsec stop
              exit 0
              ;;
    *)        echo "unknown state"
              exit 1
              ;;
esac

Now you can restart both services and your IPSec VPN inter-site is ready with a high-availability mechanism enabled!!

Obviously, you will have to do the same on the other node if you want your VPN to work properly, by reversing configuration.

  • Feb 19 / 2015
  • 0
Linux

How to capture results of a watch in a file

For debugging purposes, it can sometimes be useful to write the results of a command executed at a given time lapse. You can easily monitor a command by using the watch command.

By default a watch command is only displaying result, and you have to be in front of to see the results. If you want to write them in a file with a timestamp, you can easily do it by using this command that combines  a watch command with tee:

# watch -t -n 1 "(date '+TIME:%H:%M:%S' ; netstat -np | egrep -i *:443) | tee -a /tmp/logfilewatch"

You can now open your file /tmp/logfilewatch and see the results you just got!
For example, here is what you could get with my previous command, checking all the connections on port TCP 443:

TIME:22:24:22
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      1722/apache2
TIME:22:24:23
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      1722/apache2
TIME:22:24:35
tcp        0      0 192.168.100.250:443       12.34.56.78:27911     TIME_WAIT   -
TIME:22:24:36
tcp        0      0 192.168.100.250:443       12.34.56.78:27911     TIME_WAIT   -
TIME:22:24:37
tcp        0      0 192.168.100.250:443       12.34.56.78:27911     TIME_WAIT   -
TIME:22:24:38
tcp        0      0 192.168.100.250:443       12.34.56.78:27911     TIME_WAIT   -
TIME:22:24:39
tcp        0      0 192.168.100.250:443       12.34.56.78:27916     SYN_RECV    -
tcp        0      0 192.168.100.250:443       12.34.56.78:27911     TIME_WAIT   -
TIME:22:24:41
tcp        0      0 192.168.100.250:443       12.34.56.78:27916     ESTABLISHED 16810/apache2
tcp        0      0 192.168.100.250:443       12.34.56.78:27911     TIME_WAIT   -
TIME:22:24:42
tcp        0      0 192.168.100.250:443       12.34.56.78:27916     ESTABLISHED 16810/apache2
tcp        0      0 192.168.100.250:443       12.34.56.78:27911     TIME_WAIT   -

  • Feb 11 / 2015
  • 0
Linux

Find which process is using a specific port

If you need to know/find which process is using a specific port on your system, you can use some default tools for troubleshooting:

  • netstat
  • lsof

WARNING: For the use of these tools, you will need root rights (or sudo rights will be efficient)

First, with netstat you can use options tnlpu to display much informations on connections:

$ sudo netstat -tlnpu
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.1:9000          0.0.0.0:*               LISTEN      5786/php-fpm: pool
tcp        0      0 127.0.0.1:27017         0.0.0.0:*               LISTEN      18591/mongod
tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      15481/python
tcp        0      0 0.0.0.0:8081            0.0.0.0:*               LISTEN      19238/nginx
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      1105/sshd
tcp        0      0 127.0.0.1:5432          0.0.0.0:*               LISTEN      15098/postgres
tcp6       0      0 :::22                   :::*                    LISTEN      1105/sshd

Then, with lsof you can easily find which connections are opened on a specified port with the option -i on your command-line:

$ sudo lsof -i tcp:22
COMMAND  PID       USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
sshd    1054       root    3u  IPv4   9672      0t0  TCP *:ssh (LISTEN)
sshd    1054       root    4u  IPv6   9674      0t0  TCP *:ssh (LISTEN)
sshd    1146       root    3u  IPv4   9794      0t0  TCP 192.168.56.101:ssh->192.168.56.1:49931 (ESTABLISHED)
sshd    1150       root    3u  IPv4   9876      0t0  TCP 192.168.56.101:ssh->192.168.56.1:49933 (ESTABLISHED)
sshd    1254       admin   3u  IPv4   9794      0t0  TCP 192.168.56.101:ssh->192.168.56.1:49931 (ESTABLISHED)
sshd    1265       admin   3u  IPv4   9876      0t0  TCP 192.168.56.101:ssh->192.168.56.1:49933 (ESTABLISHED)

  • Jan 22 / 2015
  • 0
Linux

Add a function in shell on Linux (make dmesg timestamps human readable)

You want to add a specific function on your shell which is not available in standard functions and you would like to be able to call it anywhere you want without the need to specify the script location? That’s quite easy to do, with some simple tricks 😉 !

We will here work with a simple example of a useful function:

When you are calling the dmesg command, you got a timestamp which is not human readable and it can be hard to align these logs with the logs of another application running on the server for example. We will create a function called dmesghr (for dmesg human readable) that will allow us to call exactly the same than the dmesg command but with a timestamp human readable.

First of all, we will create our function under our profile at the end of file ~/.bashrc after all the already existing declarations:

[...]
# Function translating dmesg timestamp into a timestamp human readable
function dmesghr {
    # Define date format (similar to syslog)
    date_format="%b %d %T %Y"

    # Get the uptime in seconds from /proc/uptime
    uptime=$(cut -d " " -f 1 /proc/uptime)

    # Read dmesg and convert date with date_format defined above
    dmesg | sed "s/^\[[ ]*\?\([0-9.]*\)\] \(.*\)/\\1 \\2/" | while read timestamp message; do
        printf "[%s] %s\n" "$(date --date "now - $uptime seconds + $timestamp seconds" +"${date_format}")" "$message"
    done
}

Once this done, we will reload the profile file and export our new function so we can use it anywhere:

~$source ~/.bashrc
~$export -f dmesghr

Right now, we can call it directly from our shell and use it as a standard function:

~$dmesghr
[...]
[jan. 21 09:34:00 2015] Initializing cgroup subsys cpuset
[jan. 21 09:34:00 2015] Initializing cgroup subsys cpu
[jan. 21 09:34:00 2015] Initializing cgroup subsys cpuacct
[jan. 21 09:34:00 2015] Linux version 3.13.0-39-generic ([email protected]) (gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1) ) #66-Ubuntu SMP Tue Oct 28 13:30:27 UTC 2014 (Ubuntu 3.13.0-39.66-generic 3.13.11.8)
[jan. 21 09:34:00 2015] Command line: BOOT_IMAGE=/boot/vmlinuz-3.13.0-39-generic root=UUID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx ro quiet splash vt.handoff=7
[jan. 21 09:34:00 2015] KERNEL supported cpus:
[jan. 21 09:34:00 2015] Intel GenuineIntel
[...]

  • Jan 12 / 2015
  • 0
Linux, Python

Create an interactive command-line menu using Python

It can be necessary to create a simple interactive menu on CLI (Command-Line Interface) using Python to allow users to make some choices while executing a script/program. As there is no standard library for this in Python, you will have to adapt it by yourself.

Here is a very simple example of how to do this. Feel free to modify, update and improve it as depending on your needs and your expectations 😉 !

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#title           :menu.py
#description     :This program displays an interactive menu on CLI
#author          :
#date            :
#version         :0.1
#usage           :python menu.py
#notes           :
#python_version  :2.7.6  
#=======================================================================

# Import the modules needed to run the script.
import sys, os

# Main definition - constants
menu_actions  = {}  

# =======================
#     MENUS FUNCTIONS
# =======================

# Main menu
def main_menu():
    os.system('clear')
    
    print "Welcome,\n"
    print "Please choose the menu you want to start:"
    print "1. Menu 1"
    print "2. Menu 2"
    print "\n0. Quit"
    choice = raw_input(" >>  ")
    exec_menu(choice)

    return

# Execute menu
def exec_menu(choice):
    os.system('clear')
    ch = choice.lower()
    if ch == '':
        menu_actions['main_menu']()
    else:
        try:
            menu_actions[ch]()
        except KeyError:
            print "Invalid selection, please try again.\n"
            menu_actions['main_menu']()
    return

# Menu 1
def menu1():
    print "Hello Menu 1 !\n"
    print "9. Back"
    print "0. Quit"
    choice = raw_input(" >>  ")
    exec_menu(choice)
    return


# Menu 2
def menu2():
    print "Hello Menu 2 !\n"
    print "9. Back"
    print "0. Quit" 
    choice = raw_input(" >>  ")
    exec_menu(choice)
    return

# Back to main menu
def back():
    menu_actions['main_menu']()

# Exit program
def exit():
    sys.exit()

# =======================
#    MENUS DEFINITIONS
# =======================

# Menu definition
menu_actions = {
    'main_menu': main_menu,
    '1': menu1,
    '2': menu2,
    '9': back,
    '0': exit,
}

# =======================
#      MAIN PROGRAM
# =======================

# Main Program
if __name__ == "__main__":
    # Launch main menu
    main_menu()

  • Dec 18 / 2014
  • 0
Linux

Testing SMTP server using telnet (whether with authentication or not)

You can need to perform testing with your SMTP server and see if you are able to send mail with it.
You have your domain name, and you want to check if mail server is answering properly?

1. Check the mail server with DNS entries

We first need to find the right DNS entry for MX record and know what is the mail server.

~$ nslookup
> server 8.8.8.8
Default server: 8.8.8.8
Address: 8.8.8.8#53
> set querytype=MX
> mydomain.com
Server:		8.8.8.8
Address:	8.8.8.8#53

Non-authoritative answer:
mydomain.com	mail exchanger = 10 mail.mydomain.com.

2. Open connection to mail server (default ports 25,587)

We will now open a telnet connection on the mail server we just found. Port to use can be different depending on the configuration of the server mail.

~$ telnet mail.mydomain.com 587
Trying www.xxx.yyy.zzz...
Connected to mydomain.com.
Escape character is '^]'.
220 mail.mydomain.com ESMTP Postfix

The answer can change depending on the mail engine used, this is just an example.

3. Send an email with or without authentication

In case of there is no authentication needs (an open smtp server), just perform:

EHLO mydomain.com 
250
MAIL FROM:<[email protected]> 
250 OK
RCPT TO:<[email protected]> 
250 OK
DATA
354 GO AHEAD
From: Me <[email protected]>
To: Him <[email protected]>
Subject: This is a testing mail
This message is only sent for testing purposes.
. 
250 OK 1413684421 qp 18534
QUIT
221

If the server requests an SSL/TLS authentication before being able to send mail, you will probably need to use openssl library as telnet does not support TLS by default (you will get an error on STARTTLS command).
You will also need to prepare the credentials by encoding them in base 64:

~$ echo -ne 'userpassword' | base64
AHVzZXIAcGFzc3dvcmQ=

Once you got this, you can open connection and request mail sending as following:

openssl s_client -starttls smtp -connect mail.mydomain.com:587
CONNECTED(00000003)
EHLO mydomain.com
250-mail.mydomain.com
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-AUTH PLAIN LOGIN
250-AUTH=PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
AUTH PLAIN AHVzZXIAcGFzc3dvcmQ=
235 2.7.0 Authentication successful
mail from: <[email protected]>
250 2.1.0 Ok
rcpt to: <[email protected]>
250 2.1.5 Ok
DATA
354 End data with .
From: Me <[email protected]>
To: Him <[email protected]>
Subject: This is a testing mail
This mail is only for testing purposes
.
250 2.0.0 Ok: queued as E65832403CF
QUIT
DONE

Notice that if the mail server doesn’t allow SMTP relay, you won’t be able to send a mail to another domain that the ones that this server is allowing. In that case, you will get an error as:

554 5.7.1 <[email protected]>: Relay access denied

That means you will only be able to send mail to an “@mydomain.com” mail address and not to any other.

Question ? Contact