OpenLI Tutorial 09: Collector Configuration - OpenLI-NZ/openli GitHub Wiki

OpenLI Tutorial 09: Collector Configuration

OpenLI Tutorial 09

You may either watch the tutorial lesson on YouTube by clicking on the image above, or you can download the slides and read them alongside the transcript provided below.


Welcome back -- this is the ninth chapter in a series of OpenLI training lessons, where you will learn how to configure your OpenLI collector component. After the previous two lessons, you should have a working provisioner and mediator, so now we just need a collector to complete the full set!

Most of what we’re covering in this lesson should feel quite familiar by now, but bear with me as there are a few new concepts for you to discover here as well.


As you hopefully remember, the collector is responsible for examining the packet traffic on your network, determining which packets should be intercepted and then encoding those intercepted packets into ETSI-compliant records. Intercept targets are announced by the provisioner in the form of usernames or phone numbers, and the collector must look for those identities in the session management protocols that traverse the monitored network. The session details can then be used to recognise the IP traffic and multimedia calls that need to be intercepted for each target.

Once a packet is intercepted, the collector must also label, sequence and encode the packet to conform to the relevant ETSI standards, and then the resulting record can be forwarded to a mediator which will place it on the correct LEA handover.

So there’s a lot of work that needs to be done by the collector, but fortunately the amount of required configuration is relatively small.


As with the other components, our configuration process begins by getting a shell on the collector container. This is the exact same process as before, with the obvious substitution of “collector” for the other component names you might have used previously.


The collector configuration file resides in /etc/openli and you’ll once again need to open it up in your preferred text editor.

The first few lines of the config file should look a lot like what you’re seeing on the slide right now -- you’ll notice that there are only a very small number of tokens that need to be replaced this time around, and you can probably already guess what needs to go in the place of those tokens already.


But, for the sake of completeness, let’s walk through it quickly anyway.

The first replacement is to set the “provisioneraddr” option to be the IP address of your provisioner on the openli-lab network. This should be the same address that your provisioner is listening on for collector connections.


Based on the examples in previous lessons, this is going to be 172.19.0.3 in my case. Your provisioner address may be slightly different.


Next, we need to set the “provisionerport” option to match the port that our provisioner is listening on for collector connections.


You may remember that I had set this to 9001 when I configured my provisioner, so that’s what I have to set it to here.


Finally, we need to set the operator ID option again, just like we did with our mediator. This should take the same value that you used when you configured the mediator.


In my case, I had set my operator ID to “WAND”, but yours is going to be something that better describes your network or organization.


All of the other options have been set to sensible values for you, but I’m going to take this time to explain them in a bit more detail so you will be able to choose suitable values for them once you try to deploy collectors on your own network.

We’re going to begin by describing the network element ID option. This is a required value in the ETSI intercept record header that is intended to describe the location of the collector in your network. In a multi-collector deployment, this allows the LEAs to determine where in your network a particular intercept took place.

For instance, you might want to name this after the POP where your collector is located, or the device that is the source of the traffic you are mirroring into the collector. You are limited to 16 characters for this field though, so don’t try to get too descriptive here.


In the rare case where you happen to have multiple collectors at the same location within your network, you can use the interception point ID field to further distinguish between them. You are given a maximum of eight more characters to uniquely identify this particular collector, which will be included in the ETSI record header if specified in the configuration file.

The interception point ID is only strictly required in situations where both the operator ID and network element ID are the same for two or more collectors. In all other cases, it is an optional field and you can ignore it if you prefer -- but since there is no harm in having one, it is usually safest to just include the extra identifier in case you do end up needing it in the future.


The last section of the configuration that I want to talk about here is the “inputs” section. This is where you specify the interfaces or devices that you want OpenLI to capture packets on. You can have multiple capture interfaces listed here if you want, and you express each interface as a YAML list item led by the hyphen character.

Each capture interface has several additional configuration options that can be specified for it. The first is the “uri”, which is a required field. The URI describes the capture method to use and which interface or device to perform the capture on, using the URI format defined by libtrace. Hopefully, you will remember our discussions on capture methods back in lesson 3 as these will help you understand the different possible URI values.

In the example shown here, I’ve configured the capture to take place using the AF_PACKET method to capture all packets observed on the eth2 interface. In our lab topology, you may remember that eth2 on the collector container was on the “openli-lab-replay” network, which is where we are going to be intercepting traffic from eventually.


For other capture methods, the URI is structured slightly differently. First, the URI must explicitly state the capture method name, be it “dpdk”, “xdp” or “pfring”, followed by a colon, and then either the interface name or the PCI address of the interface (depending on the method). An interface name alone will always use AF_PACKET, so make sure you are explicit if you want to use one of the other methods.


You can use the “threads” configuration option to set the number of packet processing threads that should be used by a particular input.

The higher your anticipated packet rate on the capture interface, the more threads you should dedicate to the corresponding input. Each thread will potentially consume a CPU core on your collector host.

A couple of things to bear in mind, though. Firstly, you’ll still need to make sure that you have CPU cores available for the other tasks that the collector will be performing, such as encoding, forwarding and so on. The other thing is that creating too many packet capture threads will actually decrease the performance of your collector, as threading overhead and scheduling contention costs will start to outweigh any performance gains from the additional parallelisation.

For smaller traffic volumes, I’d suggest sticking to 1 or 2 capture threads. Multi gigabit captures will want to start out with 4 threads and anything close to 10 gigabit should consider scaling up to 8 threads.


The hasher configuration option tells the collector which algorithm you would like OpenLI to use to distribute captured packets among the processing threads.

Any capture input that is going to be seeing RADIUS traffic should always use the “radius” hasher option -- this will ensure that all messages for a particular RADIUS session will arrive on a consistent thread, and therefore always be processed in the correct order. For non-RADIUS traffic, the radius hasher will distribute packets as per the bidirectional algorithm.

Inputs that never see RADIUS traffic have a couple of other possible options that they can choose from. “Bidirectional” will ensure that all packets for the same bidirectional traffic flow (as defined by the classic 5-tuple) will be designated to the same processing thread. “Balanced”, on the other hand, is a simple round robin approach that will try to ensure even workloads on each thread, regardless of traffic mix.

The last config option, which is disabled by default in your container configuration, is the “filter” option, which allows you to specify a BPF filter string to apply to all captured traffic. Any packets that do not match the filter will be immediately discarded.


And that is all you need to know right now about the collector configuration file. Go ahead and save your changes and exit the text editor. We’re now ready to get the collector running.


As before, we will want to reconfigure rsyslog to write the collector’s log messages into /var/log/openli beforehand.

The process is a repeat of what you’ve already done for the provisioner and mediator, just with a slightly different file name, so you should have no trouble doing this once more for the collector.


The steps for starting the collector service should also look very familiar to you by now. I don’t think I really need to explain this in any more detail than what we’ve already done for the other components.


This is what the collector log messages should look like if you managed to configure and start the component successfully.


Here, you can see the collector describing the input that we told it to capture packets on -- note that the interface name, thread count and hasher method all match what we had in our config file.


And further down, we can see that the collector has been told about our mediator and has been able to successfully connect to the mediator on its listening socket.


There are a few things that can go wrong with the basic collector configuration. In the case shown here, I’ve tried to configure an input that uses an interface that doesn’t actually exist, which obviously is not going to be very conducive to intercepting network traffic.


Another possible mistake is that we got our input configuration right, but we couldn’t connect to the provisioner for some reason. In this case, I accidentally put the mediator’s IP address in my collector config rather than the provisioner’s, so the connection attempt failed.

Because the connection failure might be due to the provisioner being temporarily down, the collector will continue to retry the connection periodically just in case the provisioner comes back up. All OpenLI components will attempt continuous reconnection attempts if a particular communication channel fails, so for the most part the system will easily recover from temporary failures.

In this case, of course, we’ve screwed up our configuration and there’s never going to be a provisioner on that IP address. We’ll need to infer that from the error message and fix our config before the collector will work properly.


We will also be able to see evidence of our collector being functional in the logs for the other components.

For instance, here we can see a message announcing that the provisioner has accepted a connection from our new collector.


And here is a similar announcement that we can find in the mediator logs.


As with the other components, we provide you with a stop script to halt the collector service. For the last time, I will remind you that this is a peculiarity of our containerized lab environment, and that conventional systemd halt commands should work just fine when you deploy your container for real.


So there you have it, you should now have a complete OpenLI deployment running in your training lab environment: collector, provisioner and mediator all running side by side and able to communicate with one another.

But before we try to conduct any actual intercepts, we’re going to need a place for the intercepted traffic to go to. This will be the subject of our next lesson, where we will use one more container to act as a pretend LEA for testing purposes and I’ll show you some handy tools that you can use to sink intercept records and validate their correctness.

For now though, well done on making it this far -- you’re doing a great job. I’ll see you again soon for another lesson.