Saturday, 18 April 2015

Multicast IPsec protected OSPFv2/OSPFv3 areas


1. Short introduction.

The presumption that your backbone area is the safest segment of your corporate network is untenable, especially when your backbone is based on MAN service. Usually the MAN operators are used to provide to the clients virtual networks (logical layer of Layer 2 frames transport) based on 802.1q VLAN or VPLS. It is a shared service because the clients' networks are logically defined transport of frames across the operator's physical network. Therefore any successful attack on the operator's active equipment creates is direct risk of compromising the clients' networks.

OSPF is still the most used protocol for intra-AS routing. Usually the routers connected to the corporate backbone networks are configured as OSPF speakers (they speak either OSPFv2 and OSPFv3, or both). The OSPFv2 protocol provides both simple and cryptographic authentication, and the cryprographic ones is based on the MD5 hash function. In contrast the authetication in OSPFv3 is moved out of the protocol. One very serious reason the authentication is moved is because the OSPF applications are critical, they are part of the user space, and process multicast messages. The operating system kernel escalates the multicast messages received for the OSPF group address to the OSPF application regardless they are properly autheticated or not. Therefore if an intruder gain an access to an OSPF area it may send a lot of packets to the OSPF listeners and rise the load of their protocol processing applications. Given that the OSPF algorithm strongly depends on the ability of processing as fast as possible the incomming update messages, any intentionally caused high load may affect the dynamic routing over the whole OSPF area.

One possible way to prevent the unautheticated OSPF messages from reaching the OSPF application and affect its performance is to employ the kernel to perform the packet authentication. In other words the kernel should filter the unauthenticated OSPF messages. That can be achieved by implementing an IPsec transport protocol so the kernel should escalate to the OSPF application only the packets passed a successful ESP/AH authentication. Such an idea sounds very reasonable but it should solve somehow an importent principle problem - IKE cannot exchange (yet) keys over multicast. Hence if IPsec is going to be implemented to secure OSPF a static keys must be configured on all OSPF listeners in the area.

Below it is decribed how to use IPsec to protect and authenticate the communication between OSPF speakers running quagga daemons ospfd and ospf6d.


2. Generating the keys.

Two keys for each direction of the communication should be generated - one for the encryption algorithm and one for the message digest algorithm. Bellow are presented command lines that can be used to generated that keys:

  • 128-bits key (AES, SHA1):

    $ echo -n "0x" && dd if=/dev/urandom count=16 bs=1 2> /dev/null | xxd -ps -c 16

  • 160-bits key (RIPEMD):

    $ echo -n "0x" && dd if=/dev/urandom count=20 bs=1 2> /dev/null | xxd -ps -c 20

  • 256-bits key (AES, SHA256):

    $ echo -n "0x" && dd if=/dev/urandom count=32 bs=1 2> /dev/null | xxd -ps -c 32

  • 448-bits key (Blowfish):

    $ echo -n "0x" && dd if=/dev/urandom count=56 bs=1 2> /dev/null | xxd -ps -c 56

  • 512-bits key (AES, SHA512):

    $ echo -n "0x" && dd if=/dev/urandom count=64 bs=1 2> /dev/null | xxd -ps -c 64


3. Loading the keys and configuring the IPsec policy.

The most convenient way of configuring IPsec for multicast with pre-shared keys on Linux is to use the package ipsec-tools. It provides the IKEv2 daemon racoon and the policy manager setkey. Since only pre-shared keys will be configured and used there is no need to run the racoon. Only setkey should be run once when both keys and policies need to be loaded into the memory. On the hard disk they should be kept in the file setkey.conf, by following the example bellow:


# OSPFv2

spdadd[0][0] any -P out ipsec esp/transport//require ;
spdadd[0][0] any -P out ipsec esp/transport//require ;
add esp 0x10003 -m transport -E blowfish-cbc 0xd7e13bc95b0d7a40b4591e06a22bdd40c7dd0632b1cff938b9bc947d03a6dc14091e69de309b3c9d6627ee871317a39cd85d65402b674e2e -A hmac-sha256 0x2ff9702ace1e5986135074bb4be183537f85d255a250dfa46d01edfa625038ca ;
add esp 0x10005 -m transport -E blowfish-cbc 0xd5c69b9088ec8054724cdd84e5fb82ca39f5ff5979e6f33ebf453d568320c7df19a39c771397143cd54d55b858c5ca27e17fb01105da183f -A hmac-sha256 0x46693831b5c989b186fd7ba884d8bcea503a9ea4fc835958c3166051604eb3ab ;

# OSPFv3
spdadd ::/0 ff02::5 any -P out ipsec esp/transport//require ;
spdadd ::/0 ff02::6 any -P out ipsec esp/transport//require ;
add :: ff02::5 esp 0x10003 -m transport -E blowfish-cbc 0x8f46177b518ad6f43e519ac1bc63657bef66390e013bad95b835536e3eb7f509a867f203a21a70ddd32f92d8fd1a7dd71c1fc5f083c44f9e -A hmac-sha256 0x70249c37454edf0a5696a4f9f487604cf6a9ef06580a18bd2baa380b35b622ec ;
add :: ff02::6 esp 0x10005 -m transport -E blowfish-cbc 0xd555e5ec47dcc407c3650efdda92210e24de57ce96a0305c251881f606adcb7d38b7d03d5e06fac45cbdbf5572fc948d733957852931c2f9 -A hmac-sha256 0x1e8ec58b12aa6a5ac51f80af34ffc6082f2cc8f1efaac49f480e9e413cc0f424 ;

Note that there is only "out" direction policy and we do not have one matches "in". It is because the policy is established to control multicast communication.

In RHEL and CentOS the file setkey.conf is usually located in the directory /etc/racoon, if the package ipsec-tools is installed from RPM packages. To load the keys and the policy setkey should be run like this:

# setkey -f setkey.conf

To check if they are successfully loaded into the memory and configured in the kernel, run:

# ip xfrm state

It is good idea to create a service (RHEL/CentOS <=6) or systemd configuration (RHEL/CentOS >=7) for loading the policy at a boot time or reload it later. Note that it is vital to load the policy simultaneous on all OSPF speakers to prevent OSPF area splitting.


4. Debugging.

If ospf6d is properly started and the IPsec policy is correctly loaded, the router should join the OSPF area and start exchange routing information. The received routes can be listed by executing:

# vtysh -c "sh ipv6 ospf6 route"

An example output is provided bellow:

*N E1 2001:67c:20d0:20::/64 fe80::16da:e9ff:fef1:195a eth0 33d03:07:59
*N E1 2001:67c:20d0:22::/64 fe80::201:3ff:fed8:8b39 eth0 33d03:09:44
*N E1 2001:67c:20d0:23::/64 fe80::210:5aff:fef2:8484 eth0 33d03:09:44
*N E1 2001:67c:20d0:24::/64 fe80::16da:e9ff:fef1:195a eth0 33d03:07:59
*N E1 2001:67c:20d0:25::/64 fe80::16da:e9ff:fef1:195a eth0 33d03:07:59
*N IA 2001:67c:20d0:2f::ffff:0/112   :: eth0 33d03:09:44

If no routes appear for a long time in the list there might be a problem with the IPsec configuration. So check the content of setkey.conf, correct and reload the policies, and restart the ospf6d daemon.

To check if there is an IPsec communication on ff02::5 tcpdump should be run in order to capture and analyze the packets arriving on the ethernet interface the router is connected to the OSPF area (eth0 for instance):

# tcpdump -n -i eth0 host ff02::5

and if there is IPsec multicast communication exchange it will be diplayed as:

17:45:41.770145 IP6 fe80::20e:cff:fe84:945b > ff02::5: ESP(spi=0x00010003,seq=0x6df6a), length 84
17:45:41.770498 IP6 fe80::16da:e9ff:fef1:195a > ff02::5: ESP(spi=0x00010003,seq=0x702e0), length 84
17:45:41.770647 IP6 fe80::210:5aff:fef2:8484 > ff02::5: ESP(spi=0x00010003,seq=0x5fafa), length 84
17:45:41.771146 IP6 fe80::201:3ff:fed8:8b39 > ff02::5: ESP(spi=0x00010003,seq=0x75ca0), length 84
17:45:51.770765 IP6 fe80::20e:cff:fe84:945b > ff02::5: ESP(spi=0x00010003,seq=0x6df6b), length 84
17:45:51.771100 IP6 fe80::16da:e9ff:fef1:195a > ff02::5: ESP(spi=0x00010003,seq=0x702e1), length 84
17:45:51.771297 IP6 fe80::210:5aff:fef2:8484 > ff02::5: ESP(spi=0x00010003,seq=0x5fafb), length 84
17:45:51.771749 IP6 fe80::201:3ff:fed8:8b39 > ff02::5: ESP(spi=0x00010003,seq=0x75ca1), length 84

Note that the source of the packets is always the link-local address of the router interface attached to the OSPF area. So by checking the output of tcpdump to estimate which router participate in the IPsec multicast communication.

IPv6 Deployment in Sofia University Network (2007-2013)

IPv6 Deployment in Sofia University Network (2007-2013)

The slides were presented at the Third South East Europe (SEE 3)/RIPE NCC Regional Meeting (14-15 April 2014, Sofia, Bulgaria). You can download the presentation on PDF here:

Monday, 6 April 2015

Link-state BGP prefix announcements with quagga

Link-state BGP prefix announcements with quagga

The border routers should be excluded from the process of route origination in BGP unless they are configured to do a route aggregation. In all other cases they should only redistribute as BGP prefixes the routes created (originated) by the access routers inside the autonomous system. Most often the access routers run OSPF software and therefore the routes they originate are send to the borders through OSPF areas. It is a common practice to originate routes for the connected to the router networks based on the link-state of the interfaces. In that case if the interface of interest is up and if an IP address is configured on it, the network the configured IP address belongs to may become originated (if the configuration of the access router allows that). This post is intended to show how to do such kind of orignation by using quagga and BGP (not OSPF).

Lets describe the schema employed for the origination of connected routes. When an IP address is configured on a network interface (and the link state of that interface is "up") the operating system kernel marks the network the IP belongs to, as a connected (directly accessible) and creates the correponsing route in the routing table. That route represents the network as directly accessed through some interface name (without next-hop IP address). Routes directed by an network interface instead of next-hop IP address are connected routes. Accroding to both linux kernel and quagga specifications thay appear as supplied to the routing table by the routing protocol "connected". Because each connected route is related ony to a network interface it will be part of the kernel routing table as long as the link state of the interface is "up". When the interface is going down the kernel should delete from the routing table all routes (not only the connected ones) connected through it. The kernel should do the same if the IP address used for connecting the network is delted from the interface configuration.

The configuration bellow gives an idea how to configure bgpd to redistribute the connected routes into iBGP as prefixes. Both IPv4 and IPv6 route origination are described.

hostname bgpd
password zebra
log file /var/log/quagga/bgpd.log
router bgp 5421
 bgp router-id
 redistribute connected route-map REDISTRIBUTE_CONNECTED_IPV4
 neighbor BORDER_ROUTERS_V4 peer-group
 neighbor BORDER_ROUTERS_V4 remote-as 5421
 neighbor BORDER_ROUTERS_V4 next-hop-self
 neighbor BORDER_ROUTERS_V4 soft-reconfiguration inbound
 neighbor BORDER_ROUTERS_V6 peer-group
 neighbor BORDER_ROUTERS_V6 remote-as 5421
 neighbor peer-group BORDER_ROUTERS_V4
 neighbor peer-group BORDER_ROUTERS_V4
 address-family ipv6
 redistribute connected route-map REDISTRIBUTE_CONNECTED_IPV6
 neighbor BORDER_ROUTERS_V6 activate
 neighbor BORDER_ROUTERS_V6 next-hop-self
 neighbor 2001:67c:20d0:0:62:44:127:17 peer-group BORDER_ROUTERS_V6
 neighbor 2001:67c:20d0:0:62:44:127:18 peer-group BORDER_ROUTERS_V6
ip prefix list REDISTRIBUTE_IPV4 seq 5 permit
ipv6 prefix list REDISTRIBUTE_IPV6 permit 2001:67c:20d0:20::/64
route-map OUTGOING_IPV6_PREFIXES permit 20
 match ipv6 address prefix-list REDISTRIBUTE_CONNECTED_IPV6
 set community 5421:19
route-map INCOMMING_IPV4_PREFIXES accept 10
route-map INCOMMING_IPV6_PREFIXES accept 10
 match ip address prefix list REDISTRIBUTE_IPV4
 set origin igp
 match ipv6 address prefix list REDISTRIBUTE_IPV6
 set origin igp
line vty

How it works? When quagga is installed and configured as a routing protocol its zebra daemon takes in account the content on the kernel routing table and the changes happening there. For instancee if the IP addresses and 2001:67c:20d0:29::/64 are configured on the interface enp3s0 the networks and 2001:67c:20d0:20::/64 will appear as connected routes in the routing kernel table. That information becomes available to zebra (through NETLINK) and it forwards it to the other routing protocol daemons (such as ospfd, ospf6d, ripd, ripngd, bgpd, isisd). When bgpd receives updates from zebra it classify them by protocol (the one the kernel set as an atribute to the respective routes). Then it checks if the configuration (as the one given above) requires route redistribution. Because "redistribute connected" appears as a part of the bgp router configuration, those routes that matching the protocol "connected" will be processed. But only those of them that can successfully pass through the prefix lists (REDISTRIBUTE_IPV4 or REDISTRIBUTE_IPV6) will appear as BGP routes and will be eventyally announced to the border routers.

Note that the good practise in using quagga instists that the IP addresses should be configured on the respective interfaces by using the zebra configuration. For instance:

zebra@lcpe-gw(config)# interface enp3s0
zebra@lcpe-gw(config-if)# ipv6 address
zebra@lcpe-gw(config-if)# ipv6 address 2001:67c:20d0:29::/64