Commit 5d0e6c21 authored by Simon Redman's avatar Simon Redman

Configure border routers to collect and spew netflow v9

parent 8f00440f
#!/usr/bin/env python3
# Copyright (C) 2019 Simon Redman <>
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import ssh_helper
import argparse
import networkx
from typing import List
Remove the ipt_NETFLOW module if it exists and then insert it with the new parameters
MODPROBE_TEMPLATE = "sudo modprobe -rq ipt_NETFLOW; sudo modprobe ipt_NETFLOW destination={collector_ip}:{port} protocol=9"
IPTABLES_LINE_TEMPLATE = "sudo ip6tables -D {table} -j NETFLOW 2>/dev/null; sudo ip6tables -I {table} -j NETFLOW"
def _write_iptables_commands(router_sessions, iptables_commands: List[str]) -> None:
ssh_helper.run_commands_on_many_hosts(router_sessions, iptables_commands)
def _write_modprobe_commands(router_sessions, modprobe_commands: List[str]) -> None:
ssh_helper.run_commands_on_many_hosts(router_sessions, modprobe_commands)
def _build_iptables_lines(number: int) -> List[str]:
Build the iptables to collect all netflow traffic
:param number: Build this many copies. There is nothing node-unique about the iptables command.
line = " && ".join([IPTABLES_LINE_TEMPLATE.format(
) for table in ["INPUT", "OUTPUT", "FORWARD"]])
return [line] * number
def _build_modprobe_lines(netgraph: networkx.Graph, port_nums: List[int], collector_node: str) -> List[str]:
Construct a command line to load ipt_NETFLOW for each border router with the port number it
should send data to
collector_ip = netgraph._node[collector_node]['management-ip']
lines: List[str] = [MODPROBE_TEMPLATE.format(
) for port in port_nums]
return lines
def _get_port_nums(netgraph: networkx.Graph, border_routers: List[str]) -> List[int]:
Read the 'sensor_port' property for each border_router in the netgraph
port_nums: List[int] = [netgraph._node[router]['sensor_port'] for router in border_routers]
return port_nums
def configure(netgraph: networkx.Graph, collector_node: str, border_routers: List[str]) -> None:
Configure the controller node to be a SiLK NetFlow v9 collector
MODIFIES netgraph to have the listening port information needed by ipt_NETFLOW_configurator
:param netgraph: networkx graph object representing the network
:param collector_node: Node which is running the SiLK collector as represented in the graph
:param border_routers: List of nodes to whom we are listening
:return: Output from the SSH commands
router_sessions = [netgraph._node[node]['session'] for node in border_routers]
port_nums: List[int] = _get_port_nums(netgraph, border_routers)
modprobe_lines: List[str] = _build_modprobe_lines(netgraph, port_nums, collector_node)
iptables_lines: List[str] = _build_iptables_lines(len(border_routers))
_write_modprobe_commands(router_sessions, modprobe_lines)
_write_iptables_commands(router_sessions, iptables_lines)
if __name__ == "__main__":
parser = argparse.ArgumentParser("Configure the ipt_NETFLOW on border routers to send data to the central collector")
args = parser.parse_args()
print("This library is not currently executable")
......@@ -19,7 +19,7 @@
import add_routable_ipv6_addrs
import frr_configurator
import json
import ipt_NETFLOW_configurator
import ospf_sniffer_configurator
import silk_configurator
import ssh_helper
......@@ -28,6 +28,7 @@ import topomap_parser
import argparse
import getpass
import json
from netdiff import NetJsonParser
import re
......@@ -105,6 +106,11 @@ if __name__ == "__main__":
if args.netgraph_write:
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment