ipt_NETFLOW_configurator.py 3.65 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
#!/usr/bin/env python3

# Copyright (C) 2019 Simon Redman <sredman@cs.utah.edu>
#
# 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
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# 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(
        table=table,
    ) 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(
        collector_ip=collector_ip,
        port=port,
    ) 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")