Showing posts with label networking. Show all posts
Showing posts with label networking. Show all posts

Wednesday, April 6, 2016

Sniff traffic in a remote node

Sniffing traffic in an interface is an excellent tool for a network manager. Linux based routers like openWRT or Linux servers can use tools like tcpdump or wireshark to capture the traffic in their interfaces. Mikrotik has its own tool too, “/tool/sniffer”. The problems start when you need to capture the traffic in a device that doesn't have a facility for this purpose, and it grows when the device is placed in a remote node.

Fortunately, there is a solution for each problem. In this post I will explain how to capture traffic in any interface of any device placed in any remote node of your network and how to send this capture to your computer in real time for viewing it with a graphical application like Wireshark. All you need is a little device with RouterOS and two network interfaces connected in the switch of the remote node.

See the scheme below to illustrate the example.


In the picture we can see a server. We want to sniff the interface of this server. We can see a Mikrotik router too. The router has two interfaces connected to the switch; one of them will be used for managing the device and the other one will be the sniffer interface.

Ok. Let's do magic:
The first thing you must do is to configure a mirror port in the switch. A mirror port will send all packet received in a source interface to a destination interface. Obviously we want to configure the port connected to the server as source port of the mirror and the port connected to the sniffer router (Mikrotik router) as destination interface.

The way to configure a couple of ports as mirror ports can differ between manufacturers. In a RouterOS switch the command is:


/interface ethernet switch
  set switch1 mirror-source=ether3-slave-local mirror-target=ether4-slave-local

In a Cisco IOS the command is:

monitor session 1 source interface gigabitEthernet 1/1 both
monitor session 1 destination interface gigabitEthernet 1/2

With this first step the RouterOS router see all the server´s traffic. Now we need to send this traffic to our computer. RouterOS has a useful tool (/tool/sniffer) that can do it. This is the configuration:

/tool sniffer
  set filter-interface=ether4-slave-local streaming-enabled=yes streaming-server=192.168.2.5

Ok. Now all the traffic of the server is sent to our computer, but RouerOS sends the traffic using TZSP protocol, so you must configure a Wireshark filter for viewing only this type of packet.
Here is an example:


Now you can filter the packets of the server you want to view:


Note that the traffic sended to our computer comes from the IP 192.168.0.1 (the sniffer router), but the source shown in Wireshark is 192.168.150.226 (the Server). You must to see the packet encapsulated in the TZSP header.

Sunday, March 13, 2016

Ansible and cisco

I pushed a collection of Ansible modules for cisco IOS routers on my Github .
There are two modules with an example for using them: one of the modules gather some usefull facts from cisco IOS routers and the other module execute in a cisco IOS router a list of commands from a file.
The cisco_exec_commands module doesn't replace the ansible core module that do the same (http://docs.ansible.com/ansible/list_of_network_modules.html#ios), it's only another usefull module that can be run in version 1.7.0.

The facts gathered by cisco_gather_facts can be used as inputs to other modules or can be used in templates to create documentation used for inventorying, assessments, etc.

The playbook example adds a VRF and some interfaces in the VRF. In order to do that, the playbook has the following tasks:

  Search in BGP Reflector routers of de network if the RD you want to configure already exists.
  Search in BRAS if a VRF with the same name exists.
  Adds the new VRF, some interfaces, and place the interfaces in the VRF.

And here is de link: https://github.com/AntonioArriaga/ansible-cisco


NOTE: I used netlib python module from https://github.com/jtdub/netlib

UPDATE (04/04/2016): I added a module that connects to cisco via serial console port and an example of use of this module.

Wednesday, February 17, 2016

Are you ready for disaster prevent and recovery?

Things that a good network administrator must do.


If you manage a medium or wide network you probably know what this post is talking about. To be a network manager is funny and gratifying… if there are not problems. Unfortunately, SHIT HAPPENS. You can have the best devices of the market, and the best topology and network strategy, but anybody have a bad day. Are you prepared for network troubleshooting?

Here are some tips that can help you to make your job easier when troubles appear.

clusterize all your services.

In other words: make your services independent of the devices that run it. Make sure that the shutdown of a single device will not affect the running services.
  • Some services can run in different devices at the same time: pppoe servers, RADIUS servers...
  • Use dynamic routing instead of static routing anytime you can. It will be your network auto-adaptable in case of device or link fail.
  • If you cannot avoid using static routing, use first hop redundancy protocols (VRRP, HSRP, GLBP)
  • Replicate critical resources (databases, file systems)
  • Use a dual stack in layer 2 and 3 for critical devices: more than one switch with more than one IP network.
Combine this methods in order to avoid any single point of failure. For example, if you have a critical application that attack a database, this database must be replicated in more than one server. Each server must be connected to more than one switch. The communication between database motors must be done via loopback interfaces routed by a routing protocol that runs in each interface (in each IP network and in each switch). Then, the IP that serves the database connection to the application must have a failover method like VRRP in the servers.
The goal is that a single device shutdown could not affect any network service.

Backup all configurations.

The most frequent trouble in a wide network is broken hardware. Replacing it can be as easy as prepared you are. Many devices has CLI interfaces that can be easily backed with an appropriate software. I use rancid. Rancid connect via SSH, telnet or any other protocol that you enable. It collects configuration and other useful information (firmware version, hardware properties, etc) and stores all this data in a file.
When it detects any change in the device, it will inform you via email. All changes in devices will be registered with a CSV repository, so you can trace changes made in any device.
If rancid can't connect to a device in more than 24 hours, it will warn you.
Running rancid once a day you have the security that you can configure a replacement device in a short time.


Monitor everything.

Troubleshooting a problem without information is a hard work. It’s a very hard work. Troubleshooting a sporadic problem that appears in shorts time ranges without information is impossible. So, you must be prepared. Any network device can give you a lot of information that can be collected and stored for real-time analysis or later analysis.
Well, at this point I’d like to make a distinction between two types of data:
  • Data that can be graphed: Interfaces traffic or errors, temperature, CPU usage, amount of BGP routes, etc.
    This information can be stored in a graph application like cacti, MRTG, Munin… It's very easy to analyze graphs to find information about a problem.
  • Data that cannot be graphed: syslog events, interfaces states, or any abnormal state in general. This data can be collected in two ways:
    • Data that devices report. i.e: syslog events. It is important to organize this data at the moment of collecting it.
      Specifically, syslog is a good example of this: If you divide the information in files with the name of the device that come from, searching information about a single host will be easier.
    • Data that we collect from devices with external system like Nagios or Icinga.
I have a law: every data that can be monitored must be monitored. Some of this data can be used to warn you about an abnormal state, other can be used only for informational purposes, but all of them can be useful in a future time. There is a lot of software that collect all data automatically, process it and report you alerts if something goes wrong.

A little example:
It can appears that collects temperature from devices is irrelevant, but I worked with a SHDSL modem that self reboots when its temperature reaches 70ºC. This trouble could be easily discovered because I had a graph with the device temperature.

Stay prepared for dumping network traffic.

Sometimes it is very useful to sniff a specifical interface of a device. A lot of troubles can be detected by sniffing traffic. The problem is that not all devices had this feature. Mikrotik or Linux hosts can sniff traffic with tools like “/tool sniffer” or “tcpdump”, but Cisco or Ubiquiti has not a useful tool for this.
It's a good idea to have an ace up your sleeve in remote network nodes where you don't have devices that can sniff traffic. A simple and very useful method is to prepare a small sniffer device with more than one interface connected to the switch (or switches): one of them for managing the router and other for sniffing traffic. To sniff a specific device interface is as easy as configure the switch interface that is connected to the sniffer as “mirroring port” of the device interface you want to monitor.
In a future post I will explain better how to do this with a cheap Mikrotik router.

Alert of network changes

Like I said before, there is a lot of software that collects, analyze and report abnormal states of your network. Use them. At first it's hard to configure, but it will be one of the best ways to make your network safe.

Be careful and search any abnormal state. Some of them are very obvious: shutdown devices, down links… other can be less obvious, but these are going to alert you about an abnormal situation before it becomes a problem: exceed of traffic, fan that doesn’t work, a short number of OSPF neighbors, a big number of errors in an interface…
Correct the little thing before it becomes a big problem is the best way for making your network stable.

New services or topology changes must also be alerted. You must decide if each new situation is under control and meets your quality standards.

Automate and centralize management.

How many problems are caused because of an error while configuring a new service or making a change in network topology?
Use tools to automate all tasks you do frequently. Humans make errors, but a well designed and configured tool for doing changes never mistakes. My prefered software for this is Ansible. With a single playbook you can make a wide range of changes remotely without syntax error or forgotten parameters.

keep informed of news about your equipment and services.

Companies updates their equipment or software because something can be improved. Bug fixes, security fixes, new features... A new that you have read six months ago can give you a track of a current problem.

Wednesday, January 13, 2016

Ansible and Mikrotik

Overview.

If you are a network administrator you probably have dozens of devices to manage. Usually, each device is built by a manufacturer and although its administration may seem similar, it uses to be different.
For some tasks you will need to do several configurations in a group of devices that have different administration interfaces. This is a lot of work with a lot of possibilities of error.
Some manufacturers can provide a centralized platform to configure their equipment, but there is no one platform that could manage different devices for a single task that configure them all.
In this way, you have two alternatives:
  • Do yourself. Develop your own platform that connect to your devices, update their configurations and report the result.
  • Adapt an existing platform. There are some free software, but obviously you must configure and adapt them. We will take this way in this post.

What is Ansible.

Ansible’s web site describes itself like: “a radically simple IT automation platform that makes your applications and systems easier to deploy”.
Ansible is a software that has a collection of well described hosts, scripts, templates and variables, uses them for managing groups of hosts in a simple and automatic way and report the result of changes made in the hosts.

One of most common examples is update a config file of a web server farm and reload the web server daemon in all hosts of the farm. Ansible will connect to each host, change the config file, reload the daemon and report the result to the system administrator.

It's a powerful software, but not everything that shines is gold.

The problem.

Unfortunately, Ansible is oriented to manage Linux hosts. More exactly, Ansible expects that remote hosts runs python. Fortunately, you are a good network administrator that read good blogs and you can adapt Ansible to work with almost any device that can be administered by SSH, telnet or API.

Scenario.

The goal is to show how ansible can be configured for managing almost any network device. To do this we will need to build a module and use it. This module must connect to the network device in the way that you chose, and must report if the configurations had changed something in the remote device, if a problem had occurred, or if everything was fine.

For the example we will create a complete set of queues in a Mikrotik router. We will build a module that read a YAML file with the queues description, it connects to Mikrotik via API and adds all the queues to the router. This module will use API for configuring the Mikrotik in order to expose that any managing protocol supported by network devices can be used, but I have modules that manages routers and switches by SSH and Telnet.

Basic configurations.

As I comment before, this is not a manual about Ansible's installation. I guess that you can read Ansible documentation by yourself and you can install it without my help.
The first thing we need to do is to declare a host in Ansible's host file. We need to provide a user/password for API access (Only for this example that uses API, the best way is do this with a SSH key pair with no user/password).

[mikrotik]
192.168.150.1 username=ansible password=s0mEStr0ngP4ssw0rd

And a basic YAML playbook for testing the connection. We will use Roles. They aren't needed for this basic example, but it’s a good habit to order the information from the first steps.

# cat mktQueue.yml
---
- name: Test connection
  hosts: 192.168.150.1
  gather_facts: no

  roles:
  - mikrotik

By default Ansible will try to gather a lot of information from remote hosts, but it will use python for this. With “gather_facts: no” we ensure that Ansible will not recover this information.

# cat roles/mikrotik/tasks/main.yml
- name: Test connection
  addqueues.py:
    hostname: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
  delegate_to: 127.0.0.1

The line “delegate_to: 127.0.0.1” says to Ansible that module “addqueues.py” must be run locally (in the same host where Ansible is running) and not in remote devices.

# cat roles/mikrotik/library/addqueues.py
#! /usr/bin/python

import rosapi
import socket

from ansible.module_utils.basic import *

def main():

  module = AnsibleModule(
    argument_spec=dict(
      hostname=dict(required=True),
      username=dict(required=True),
      password=dict(required=True),
      )
    )

  hostname = module.params['hostname']
  username = module.params['username']
  password = module.params['password']
  changed = False
  msg = ""

  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  s.connect((hostname, 8728))
  apiros = rosapi.RosAPI(s)
  apiros.login(username, password)

  module.exit_json(changed=False, msg=msg, username=username, password=password)

if __name__ == '__main__':
  main()

I have used this python module: https://pypi.python.org/pypi/rosapi to connect via API.
With this basic configuration we can test

Build your own module.

Now the more interesting part of the post: build an Ansible module. This python module will read a YAML file placed in “files” directory of the role, it will build a Mikrotik queue tree configuration, it will connect to the Mikrotik router Via API and it will apply the configuration.

# cat roles/mikrotik/library/addqueues.py      
#! /usr/bin/python

import sys
import string
import rosapi
import socket

from yaml import load, dump
try:
    from yaml import CLoader as Loader, CDumper as Dumper
except ImportError:
    from yaml import Loader, Dumper

from ansible.module_utils.basic import *

#
# Function ApplyQueue
# Connect to Mikrotik via API and apply all queues previously treated by processQueues
#

def applyQueue (hostname, username, password, queues):

  returnValue ={'changed': False, 'error': ""}
  error=None
  s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  s.connect((hostname, 8728))
  apiros = rosapi.RosAPI(s)
  apiros.login(username, password)

  for singleQueue in queues:
    newQueue=[]
    newQueue.append("/queue/tree/add")
    for (param, value) in singleQueue.iteritems():
        newQueue.append("=" + str(param) + "=" + str(value))

    apiros.write_sentence(newQueue)
    output=apiros.read_sentence()

    if output[0] != "!done":
        returnValue['error']=str(output[0]) + ": " + str(output[1] + " in \"" + singleQueue['name'] + "\"")
    else:
        returnValue['changed']=True

  return returnValue

#
# function processQueues
# For a well formated dictionary of properties/values return an ordered array of dictionaries with
# a description of a queue and its children.
#


def processQueues( queues ):
  newQueue={}
  orderedQueues=[]

#
# In a first round search all properties/values of the queue.
#
  for param, value in queues.iteritems():
    if not isinstance(value, list):
#
# for property "comment", add a couple of colons
#
      if param=="comment":
        newQueue[param]="\""+value+"\""
      else:
       newQueue[param]=value

  orderedQueues.append(newQueue)

#
# In second round search its children. Each child is treated as a new queue (recursive call)
#
  for param, value in queues.iteritems():
    if isinstance(value, list):
      for subQueue in value:
        subQueue['parent']=newQueue['name']
        orderedQueues = orderedQueues + processQueues(subQueue)

  return orderedQueues



def main():

  module = AnsibleModule(
    argument_spec=dict(
      hostname=dict(required=True),
      username=dict(required=True),
      password=dict(required=True),
      queuesFile=dict(required=True)
      )
    )

  hostname = module.params['hostname']
  username = module.params['username']
  password = module.params['password']
  queuesFile = module.params['queuesFile']
  changed = False
  queuesToApply = []

#
#  Open the YAML file with queues configuration
#
  yamlFile=open(queuesFile, 'r')
  queues = load(yamlFile, Loader=Loader)

#
# for each queue in the YAML file process the queue (build it and its children, grandsons, etc.
# After all queues are processed, apply them.
#

  for queue in queues:
    queue['parent']="global"
    queuesToApply = queuesToApply + processQueues(queue)

  result=applyQueue (hostname, username, password, queuesToApply)

#
# return the result of the operation.
#

  changed=result['changed']

  if result['error']:
     module.fail_json(changed=changed, msg=result['error'])
  else :
    module.exit_json(changed=changed, result=result['error'], username=username, password=password)


if __name__ == '__main__':
    main()

For doing a tree example I will use the tree configuration of Greg Sowell's blog. But I want to show a three-level tree structure, so I have configured two extra queues called “high-priority-in” and “high-priority-out” and I have put the queues VoIP and admin like children of the queues high-priority:

# cat roles/mikrotik/files/queuesDefinition.yml    
- max-limit: 10M
  name: in
  parent: global
  queue: default
  children:
  - limit-at: 3M
    max-limit: 10M
    name: http-in
    packet-mark: http-in
    priority: 4
    queue: default
  - limit-at: 4M
    max-limit: 10M
    name: streaming-video-in
    packet-mark: streaming-video-in
    priority: 3
    queue: default
  - limit-at: 500k
    max-limit: 10M
    name: gaming-in
    packet-mark: games-in
    priority: 2
    queue: default
  - max-limit: 10M
    name: download-in
    packet-mark: in
    queue: default
  - limit-at: 1M
    max-limit: 10M
    name: customer-servers-in
    packet-mark: customer-servers-in
    priority: 1
    queue: default
  - limit-at: 500k
    max-limit: 10M
    name: vpn-in
    packet-mark: vpn-in
    priority: 2
    queue: default
  - name: high-priority-in
    priority: 1
    queue: default
    children:
    - limit-at: 500k
      max-limit: 10M
      name: voip-in
      packet-mark: voip-in
      priority: 1
      queue: default
    - limit-at: 500k
      max-limit: 10M
      name: admin-in
      packet-mark: admin-in
      priority: 5
      queue: default
- max-limit: 10M
  name: out
  parent: global
  queue: default
  children:
  - max-limit: 10M
    name: upload-out
    packet-mark: out
    queue: default
  - name: high-priority-out
    priority: 1
    queue: default
    children:
    - limit-at: 1M
      max-limit: 10M
      name: customer-servers-out
      packet-mark: customer-servers-out
      priority: 6
      queue: default
    - limit-at: 500k
      max-limit: 10M
      name: voip-out
      packet-mark: voip-out
      priority: 1
      queue: default
    - limit-at: 500k
      max-limit: 10M
      name: admin-out
      packet-mark: admin-out
      priority: 3
      queue: default
  - limit-at: 500k
    max-limit: 10M
    name: gaming-out
    packet-mark: games-out
    priority: 2
    queue: default
  - limit-at: 3M
    max-limit: 10M
    name: http-out
    packet-mark: http-out
    priority: 4
    queue: default
  - limit-at: 4M
    max-limit: 10M
    name: streaming-video-out
    packet-mark: streaming-video-out
    priority: 3
    queue: default
  - limit-at: 500k
    max-limit: 10M
    name: vpn-out
    packet-mark: vpn-out
    priority: 2
    queue: default

With this extra configurations we must update the “tasks” file:

# cat roles/mikrotik/tasks/main.yml
- name: Test"
  addqueues.py:
    hostname: "{{ inventory_hostname }}"
    username: "{{ username }}"
    password: "{{ password }}"
    queuesFile: "{{ playbook_dir }}/roles/mikrotik/files/queuesDefinition.yml"
  delegate_to: 127.0.0.1

And finally, we can run it:


An error will show something like this:
Final notes and conclusions

Obviously, nobody needs an Ansible configuration to apply a dozen of queues. It has no sense doing so much work for a task that probably you don't need to repeat anymore. But this is only an example of how Ansible can manage network devices in a centralized way.
Some more interesting cases can be:

  • A module that connect to Mikrotik, create a Mikrotik script from a template placed in the host that runs Ansible, run it on Mikrotik devices and return the result. This module can be a good method to update any general configuration in any number of Mikrotik devices in your network (for example, update your syslog server). If you build this module, the next time that you need to do a task in all your Mikrotik devices the only thing you must do is the Mikrotik script. Applying it in all network will be easy.
  • A group of roles with its own modules that connect to groups Mikrotik, cisco and switches and configure some specific services that needs changes in these devices.

Wednesday, December 16, 2015

OpenWRT: one device, multiple routers.

Overview.

Commonly companies has many departments or sections that needs isolated networks, differents types of Internet access and internal routing protocols.
In this way, sometimes each department do its own war whitout a common solution that integrates all company services. The result of this lack of planification is a lot of under-exploited resources: duplicated switches, routers and a lot of wireless access points for each department.
This is, of course, the worst way to build and maintain an company network. A better way is to use the same devices for all services and isolate services in such devices. Isolate a LAN is as easy as to use VLAN in switches, but… What about isolate route tables, NAT or routing protocols? This post will try to give you a resource to do it this using OpenWRT on a single device.

Why OpenWRT.

There are thousands of routers with NAT and routing protocols. But, how many of them can isolate L3 or L4 IP services? not them all, anyway.
Cisco, Juniper, Fortigate, Mikrotik and most of other can do it, but generally they are expensive or don’t collects all requirements. OpenWRT can be a good alternative. Some of its advantages are:
  • built-in package manager that allows you to install packages from a software repository
  • In two years, you may need a new functionality that you have not thought about today. In other devices you must change the software version or buy a new device (some functionalities may be incompatibles).
    OpenWRT repository has thousands of available software packages you can install, try, and discard.
  • Hard development.
  • OpenWRT community is high active. Its software is constantly developing and updating packages.
  • Embedded.
  • OpenWRT needs less than 50Mb to be installed and once it’s running only the access to hard drive for writing configuration changes. It can be installed on a Compact Flash, a SD card or any plugable device such a USB. It doesn't need hard drive maintenance.
  • Customizable (scripting capable).
  • Like all other Linux based systems, almost its processes can be managed by using scripts. You can schedule or automate any job.
  • Runnable on any x86 hardware.

Scenario.

Like I had explain in the overview our scenario will be an enterprise with three departments: Red, Blue and Green. Each department have its own network with different offices in the same building, and each office has a different subnet. Each department has its own Internet provider and all of them use routing protocols for manage its subnets.

Software and hardware.

Obviously, we will use OpenWRT to do this, otherwise the title of this post would be a big mistake. There are more than one package we can use to solve each need, I had choose this ones:

For isolating departments lans: Vlan.

For isolating departments networks: namespaces. All process running within a namespace have their own work environment and are isolated and invisible for the others. Namespaces can contain interfaces. When an interface is linked to a namespace it’s invisible for other namespaces.

For routing protocols: BIRD daemon. BIRD is a powerful routing daemon. I had used Quagga for many years, but in the last few years I had needed to migrate to BIRD because it can do more things in an easier way. Run several instances of Quagga is a bit more difficult than running several instances of BIRD. All you need to run a second instance of BIRD is a second configure file and a second PID file.

OpenWRT can run in a wide range of commercial routers and in lot of X86 based hardware (PC, PCengines, Raspberry Pi, etc) as well. I will use a VirtualBox virtual machine.


Configuration.

It isn't necessary to explain how to download, compile and install OpenWRT, because it is widely explained in its web page and in many other blogs. I want to bore you with configurations and scripts, but not with installations. The only thing you must know is to enable namespaces in the kernel before compile:

CONFIG_KERNEL_NET_NS=yes

Namespaces, vlans, IP address.
Let's start working!
First of all we want to create vlan. If you had managed a Linux system before, you probably know how to do it. We will assign vlan 100 for Red department, vlan 150 for Blue department and vlan 200 for Green department:

vconfig add eth1 100
vconfig add eth1 150
vconfig add eth1 200


Now we want to create the namespaces.

ip netns add red
ip netns add blue
ip netns add green

Link the vlan to its namespace:

ip link set eth1.100 netns red
ip link set eth1.150 netns blue
ip link set eth1.200 netns green

For viewing a list of namespaces running in the system simply run:

ip netns

To execute a command inside the namespace:

ip netns exec red ip addr


And configure IP address for each interface:

ip netns exec red ifconfig eth1.100 192.168.100.1 netmask 255.255.255.0
ip netns exec blue ifconfig eth1.150 192.168.150.1 netmask 255.255.255.0
ip netns exec green ifconfig eth1.200 192.168.200.1 netmask 255.255.255.0

You can try to ping from a namespace to others, but you will see you cannot:

Init script.
To make our life easier, we can use OpenWRT UCI configuration format and a script that loads it to make all configurations.

The configuration file can be something like this:

config namespace 'red_namespace'
        option name 'red’
        option vlan '100'
        option ip '192.168.100.1/24’

config namespace 'blue_namespace'
        option name 'blue’
        option vlan '150'
        option ip '192.168.150.1/24’

config namespace 'green_namespace'
        option name 'green’
        option vlan '200'
        option ip '192.168.100.1/24’

And the script:

config_namespaces(){
        config_get name "$1" name
       config_get ip "$1" ip
        config_get vlan "$1" vlan

        logger "loaded configurtion for namespace "$name

        if [ ! -f /var/run/netns/$name ]; then
                ip netns add $name
                logger "adding namespace "$name
        else
                logger "namespace "$name" alredy exists"
        fi


        logger "new vlan eth0."$vlan."
        vconfig add eth0 $vlan

        logger "link vlan eth0."$vlan " to namespace "$name
        ip link set eth0.$vlan netns $name

       logger "setting IP to vlan eth0."$vlan
        ip netns exec $name ip addr add $ip dev eth0.$vlan
        ip netns exec $name ifconfig eth0.$vlan up


}

start() {
 
        config_load namespaces
        config_foreach config_namespaces namespace
}

Obviously, we must assign execution permissions and enable the script to run at boot time:

chmod ug+x
/etc/init.d/namespaces enable

BIRD4 daemon.

BIRD4 daemon is in OpenWRT repositories, so install it is as simple as use opkg package manager:


opkg install bird4 birdc4

Default install will create a script in /etc/init.d for run the daemon at boot time. If we don't want to use it we must disable

/etc/init.d/bird4 disable

if we want to run three instances of BIRD4 daemon, one per namespace. We will place de configuration files in /etc/bird4.d/namespace.bird4.conf and PID file in /var/run/namespace.bird4.pid. Also BIRD4 client (bird4c) needs a socket file for communicate with the daemon, so we will place this file in /var/run/namespace.bird4.ctl

ip netns exec red bird4 -c /etc/bird4.d/red.bird4.conf -P /var/run/red.bird4.pid -s /var/run/red.bird4.ctl

We can update the init script to run BIRD4 if the configuration file has the line “option bird ‘yes’” adding these lines to function config_namespaces():

        config_get_bool bird "$1" bird


        if [ $bird ]; then
        logger “Running BIRD4 in namespace “$name
                ip netns exec $name bird4 -c /etc/bird4.d/$name.bird4.conf -P /var/run/$name.bird4.pid -s /var/run/$name.bird4.ctl
        fi

if you want to connect bird4 client to a daemon, you must use the CTL socket placed in /var/run. For example:

birdc4 -s /var/run/green.bird4.ctl

IPTables.

Now probably you want to add an external interface, and you may want to use NAT and firewall between external and internal networks. We can use the same method: add a Vlan to external interface, configure external IP and run a script that configure IPTables rules.

As it is the same procedure, I will summarize the steps and show the full script code in the next section

Final config file and script.

The final config file can be someting like this:

config namespace 'red_namespace'
        option name 'red'
        option internalVlan '100'
        option internalIP '192.168.100.1/24'
        option bird 'true'
        option externalVlan '1100'
        option externalIP '10.0.0.2/30'
        option defaultGW '10.0.0.1'
        option iptables 'true'


config namespace 'blue_namespace'
        option name 'blue'
        option internalVlan '150'
        option internalIP '192.168.150.1/24'
        option bird 'true'
        option externalVlan '1150'
        option externalIP '10.20.0.2/30'
        option defaultGW '10.20.0.1'
        option iptables 'true'


config namespace 'green_namespace'
        option name 'green'
        option internalVlan '200'
        option internalIP '192.168.100.1/24'
        option bird 'true'
        option externalVlan '1200'
        option externalIP '10.50.0.2/30'
        option defaultGW '10.50.0.1'
        option iptables 'true'


And the final script:

#!/bin/sh /etc/rc.common


START=70
STOP=15


config_namespaces(){

        config_get name "$1" name
        config_get internalIP "$1" internalIP
        config_get internalVlan "$1" internalVlan
        config_get externalIP "$1" externalIP
        config_get externalVlan "$1" externalVlan
        config_get defaultGW "$1" defaultGW
        config_get_bool bird "$1" bird
        config_get_bool iptables "$1" iptables

        logger -t "Namespaces Configuration" "loaded configurtion for namespace "$name


        #
        # If namespace already exists do not add it.
        #


        if [ ! -f /var/run/netns/$name ]; then
                ip netns add $name
                logger -t "Namespaces Configuration" "adding namespace "$name
        else
                logger -t "Namespaces Configuration" "namespace "$name" alredy exists"
        fi

        #
        # Add Vlan for LAN access (internal Vlan).
        #

        logger -t "Namespaces Configuration" "new vlan eth0."$internalVlan
        vconfig add eth0 $internalVlan

        #
        # Link internal Vlan to namespace
        #

        logger -t "Namespaces Configuration" "link vlan eth0."$internalVlan " to namespace "$name
        ip link set eth0.$internalVlan netns $name

        #
        # Add IP address to internal Vlan. After this, up it.
        #

        logger -t "Namespaces Configuration" "setting IP to vlan eth0."$internalVlan
        ip netns exec $name ip addr add $internalIP dev eth0.$internalVlan
        ip netns exec $name ifconfig eth0.$internalVlan up

        #
        # If option "bird" is enabled in configuration file, run BIRD4.
        #

        if [ $bird ]; then
                logger -t "Namespaces Configuration" "Running BIRD4 in namespace "$name
                ip netns exec $name bird4 -c /etc/bird4.d/$name.bird4.conf -P /var/run/$name.bird4.pid -s /var/run/$name.bird4.ctl
        fi

        #
        # If externalVlan is enabled in configuration file, add WAN vlan (external access).
        # Then link it to namespace and configure its IP address.
        # Then add a default route.
        #

        if [ externalVlan ]; then
                logger -t "Namespaces Configuration" "new vlan eth1."$externalVlan
                vconfig add eth1 $externalVlan

                logger -t "Namespaces Configuration" "link vlan eth1."$externalVlan " to namespace "$name
                ip link set eth1.$externalVlan netns $name

                logger -t "Namespaces Configuration" "setting IP to vlan eth1."$externalVlan
                ip netns exec $name ip addr add $externalIP dev eth1.$externalVlan
                ip netns exec $name ifconfig eth1.$externalVlan up

                ip netns exec $name ip route add default via $defaultGW
        fi

        #
        # If iptables is enabled in configuration file, run a script that has iptables rules.
        #

        if [ $iptables ]; then
                logger -t "Namespaces Configuration" "Running IPTables rules in namespace "$name
                ip netns exec $name /etc/iptables.d/$name.iptables.sh
        fi

}

start() {

        config_load namespaces
        config_foreach config_namespaces namespace
}

I hope you fun with this post as I had fun.
SEE US IN NEXT POST!

Monday, November 9, 2015

Securing your Mikrotik access

My first entry in the blog will explain how to secure access to a Mikrotik device. In order to do this we will use three methods:
  • Disable unnecessary protocols.
  • Firewall filters:
    • Port knocking technique.
    • Detection and filter of force brute attacks technique.
We are going to use the following scenario:

The Mikrotik device have three hypothetical interfaces:
  • ether1: WAN interface. It has a public IP address and, of course, it has Internet access.
  • ether2: LAN interface dedicated to user network. In this interface we want to allow manager access, but we want to make the access safe anyway.
Note: Make this changes can be dangerous and you can loose the access to the device, so you probably want to make it in Mikrotik safe mode.


First method: Make Mikrotik listen only for needed services.
Mikrotik can disable the protocols that you don’t need in ip service menu, so the first step is configure them. In this example we want to disable all manage protocols but SSH (the device will only listen for SSH and drops any other request).

/ip service
set telnet disabled=yes
set ftp disabled=yes
set www disabled=yes
set ssh address=10.0.0.0/24
set api disabled=yes
set winbox disabled=yes
set api-ssl disabled=yes



And this is all about this method.

Second method: Port Knocking.
This is a little more interesting section. This is the goal: SSH port is disabled by default. To enable it you must to knock two doors. Knock a door is as easy as send a well known formatted packet (in this example first door opens when the device receive a TCP packet in port 2500 and second door opens when the device receive a TCP packet in port 2600). After this you can open a SSH session.
Port knocking prevents from port scanning techniques, because SSH port is closed until somebody knocks the doors.

Make sure you read the complete section before apply any command because its order is important to ensure you don’t loose the connection to the device you are configuring.

Let's go!

In first step, we disable any kind of traffic that has not been previously stablished:

/ip firewall filter
add chain=input connection-state=established,related
add action=drop chain=input

Print command should show something like this:

0 chain=input action=accept connection-state=established,related log=no log-prefix=""
1 chain=input action=drop log=no log-prefix=""

After this, in second step, we can add a rule that implement the first knock:

add chain=input connection-state=new dst-port=2500 protocol=tcp action=add-src-to-address-list address-list=DOOR1 address-list-timeout=30s log=no log-prefix="" place-before=1

The only thing this rule do is adding the IP address source that had send a TCP packet with destination port 2500 to an address list called “DOOR1” during 30 seconds. Cause Mikrotik applies rules in order, this rule must be applied before the rule that drops all incoming traffic.

0 chain=input action=accept connection-state=established,related log=no log-prefix=""
1 chain=input action=add-src-to-address-list connection-state=new protocol=tcp address-list=DOOR1 address-list-timeout=30s dst-port=2500 log=no log-prefix=""
2 chain=input action=drop log=no log-prefix=""

The second knock only occurs after the first one. Do this is as easy as add a new condition to rule: source IP must be in address-list “DOOR1”:

add chain=input connection-state=new dst-port=2600 protocol=tcp src-address-list=DOOR1 action=add-src-to-address-list address-list=DOOR2 address-list-timeout=2m log=no log-prefix="" place-before=2

I have incremented the timeout because sometimes I mistake the device password and I need several tries.

And finally, the SSH access:

add chain=input connection-state=new dst-port=22 protocol=tcp src-address-list=DOOR2 log=no log-prefix="" place-before=3

The print command must look like this:

0 chain=input action=accept connection-state=established,related log=no log-prefix="" 1 chain=input action=add-src-to-address-list connection-state=new protocol=tcp address-list=DOOR1 address-list-timeout=30s dst-port=2500 log=no log-prefix=""
2 chain=input action=add-src-to-address-list connection-state=new protocol=tcp src-address-list=DOOR1 address-list=DOOR2 address-list-timeout=2m dst-port=2600 log=no log-prefix=""
3 chain=input action=accept connection-state=new protocol=tcp src-address-list=DOOR2 dst-port=22 log=no log-prefix=""
4 chain=input action=drop log=no log-prefix=""

Now a port scan will be useless:



You can knock with command "nmap -PN --host_timeout 201 --max-retries 0 -p 2500 10.0.0.1". I will use a simple ssh access with destination port 2500.
And this is an access example:



Ok. A bit further away. What about if you think “I only need port knocking on WAN interface, not on LAN interface"?. It's as easy as adding a rule that places in DOOR2 the access that comes from LAN interface:

add chain=input connection-state=new dst-port=22 in-interface=ether2 action=add-src-to-address-list address-list=DOOR2 address-list-timeout=1s log=no log-prefix="" protocol=tcp place-before=3

You can add a list of ACCESS_WHITELIST to this rule.

Extra security configuration: detect and filter port scanning. Port knocking can be a good way to make your device access safe, but you can go a step further away. There is another way to detect intrusions tries: filter the port scanning.
From Mikrotik wiki: port scan detection. In order to integrate this configuration with the rest of them you can place the rule before the port knocking rules.

add chain=input protocol=tcp psd=21,3s,3,1
action=add-src-to-address-list address-list=ACCESS_BLACKLIST address-list-timeout=30m log=no log-prefix="" place-before=1

And a rule that drops the traffic from hosts listed in “ACCESS_BLACKLIST”.

add chain=input action=drop port=22 protocol=tcp src-address-list=ACCESS_BLACKLIST place-before=5

The output of print command:

0 chain=input action=accept connection-state=established,related log=no log-prefix=""
1 chain=input action=add-src-to-address-list protocol=tcp psd=21,3s,3,1 address-list=ACCESS_BLACKLIST address-list-timeout=30m log=no log-prefix=""
2 chain=input action=add-src-to-address-list connection-state=new protocol=tcp address-list=DOOR1 address-list-timeout=30s dst-port=2500 log=no log-prefix=""
3 chain=input action=add-src-to-address-list connection-state=new protocol=tcp src-address-list=DOOR1 address-list=DOOR2 addresslist-timeout=2m dst-port=2600 log=no log-prefix=""
4 chain=input action=add-src-to-address-list connection-state=new protocol=tcp address-list=DOOR2 address-list-timeout=1s in-interface=ether2 dst-port=22 log=no log-prefix=""
5 chain=input action=drop protocol=tcp src-address-list=ACCESS_BLACKLIST port=22 log=no log-prefix=""
6 chain=input action=accept connection-state=new protocol=tcp src-address-list=DOOR2 dst-port=22 log=no log-prefix=""
7 chain=input action=drop log=no log-prefix=""

A port scan test on WAN interface:




The address list with the source IP address of the port scanner:




A try of access after a port scan:




And the result: SSH connection tries will be dropped




Third method: detect and filter brute force attacks.

Imagine a very intelligent attacker had obtained the format of the packets for knocking the doors. He will try to probe a force brute attack in order to obtain the device user and password.
This method assumes that more than three tries of authentication in less than a minute is an attack (or a very clumsy operator that needs to be punished). For each new connection to SSH port we will add the source IP to an additional address-list (ACCESS_TRY_1, ACCESS_TRY_2 and ACCESS_TRY_3). After this, the next try will be considered as an attack and will be dropped.

After you have knocked two doors, your IP must be in address-list “DOOR2”, so we must change the rule 6 to something like this:


set 6 connection-state=new port=22 protocol=tcp src-address-list=DOOR2 action=add-src-to-address-list address-list=ACCESS_TRY_1 address-list-timeout=20s place-before=5
OK. The second try will be similar to the first, but it will check the address-list ACCESS_TRY_1. Must be placed before the rule that register the first try, because if not, this rule will be executed immediately after and will register the first try as a new second try (Remember: Mikrotik matches the rules in order). We will use the same procedure with third try, but the address list that we will add the source IP will be ACCESS_BLACKLIST.

The result must be like this:

0 chain=input action=accept connection-state=established,related log=no log-prefix=""
1 chain=input action=add-src-to-address-list protocol=tcp psd=21,3s,3,1 address-list=ACCESS_BLACKLIST address-list-timeout=30m log=no log-prefix=""
2 chain=input action=add-src-to-address-list connection-state=new protocol=tcp address-list=DOOR1 address-list-timeout=30s dst-port=2500 log=no log-prefix=""
3 chain=input action=add-src-to-address-list connection-state=new protocol=tcp src-address-list=DOOR1 address-list=DOOR2 address-list-timeout=2m dst-port=2600 log=no log-prefix=""
4 chain=input action=add-src-to-address-list connection-state=new protocol=tcp address-list=DOOR2 address-list-timeout=1s in-interface=ether2 dst-port=22 log=no log-prefix=""
5 chain=input action=add-src-to-address-list connection-state=new protocol=tcp src-address-list=ACCESS_TRY_3 address-list=ACCESS_BLACKLIST address-list-timeout=20s port=22 log=no log-prefix=""
6 chain=input action=add-src-to-address-list connection-state=new protocol=tcp src-address-list=ACCESS_TRY_2 address-list=ACCESS_TRY_3 address-list-timeout=20s port=22 log=no log-prefix=""
7 chain=input action=add-src-to-address-list connection-state=new protocol=tcp src-address-list=ACCESS_TRY_1 address-list=ACCESS_TRY_2 ddress-list-timeout=20s port=22 log=no log-prefix=""
8 chain=input action=add-src-to-address-list connection-state=new protocol=tcp src-address-list=DOOR2 address-list=ACCESS_TRY_1 address list-timeout=20s port=22 log=no log-prefix=""
9 chain=input action=drop protocol=tcp src-address-list=ACCESS_BLACKLIST port=22 log=no log-prefix=""
10 chain=input action=accept connection-state=new protocol=tcp src-address-list=DOOR2 dst-port=22 log=no log-prefix=""
11 chain=input action=drop log=no log-prefix=""


an example of a brute force attack:



And a bit further again: email when your router detect and filter an attack. You need only two configurations: “/tool e-mail” and “system loggin”. In addition you can add a prefix to log line.

/ip firewall filter
set 5 log=yes log-prefix="IP BACKLISTED"
/system logging action
add email-to=somebody@example.com name=mail target=email
/system logging
add action=mail prefix=**IP-BANNED** topics=firewall

Finally, the complete script that resume all the post is the following:

/ip firewall filter
add chain=input connection-state=established,related
add chain=input protocol=tcp psd=21,3s,3,1 \
action=add-src-to-address-list address-list=ACCESS_BLACKLIST address-list-timeout=30m
add chain=input connection-state=new dst-port=2500 protocol=tcp \
action=add-src-to-address-list address-list=DOOR1 address-list-timeout=30s
add chain=input connection-state=new dst-port=2600 protocol=tcp src-address-list=DOOR1 \
action=add-src-to-address-list address-list=DOOR2 address-list-timeout=2m
add chain=input connection-state=new dst-port=22 in-interface=ether2 protocol=tcp \
action=add-src-to-address-list address-list=DOOR2 address-list-timeout=1s
add chain=input connection-state=new dst-port=22 protocol=tcp src-address-list=ACCESS_TRY_3 \
action=add-src-to-address-list address-list=ACCESS_BLACKLIST address-list-timeout=20s \
log=yes log-prefix="IP BACKLISTED"
add chain=input connection-state=new dst-port=22 protocol=tcp src-address-list=ACCESS_TRY_2 \
action=add-src-to-address-list address-list=ACCESS_TRY_3 address-list-timeout=20s
add chain=input connection-state=new dst-port=22 protocol=tcp src-address-list=ACCESS_TRY_1 \
action=add-src-to-address-list address-list=ACCESS_TRY_2 address-list-timeout=20s
add chain=input connection-state=new dst-port=22 protocol=tcp src-address-list=DOOR2 \
action=add-src-to-address-list address-list=ACCESS_TRY_1 address-list-timeout=20s
add action=drop chain=input port=22 protocol=tcp src-address-list=ACCESS_BLACKLIST
add chain=input connection-state=new dst-port=22 protocol=tcp src-address-list=DOOR2
add action=drop chain=input

/system logging action
add email-to=somebody@example.com name=mail target=emai

/system logging
add action=mail prefix=**IP-BAN** topics=firewall
I hope you enjoy it!