root / plugins / network / shorewall-accounting_ @ 942bda31
Historique | Voir | Annoter | Télécharger (6,02 ko)
| 1 | a345d90e | Chris AtLee | #!/usr/bin/python |
|---|---|---|---|
| 2 | 265e39e0 | Lars Kruse | # shorewall_accounting v1.3 |
| 3 | a345d90e | Chris AtLee | # |
| 4 | # A munin plugin for tracking traffic as recorded by shorewall accounting rules. |
||
| 5 | # See "man shorewall-accounting" for all possible accounting rules. |
||
| 6 | # Basically this plugin examines the output of "shorewall -x show accounting". |
||
| 7 | # See http://atlee.ca/blog/2006/01/20/munin-shorewall/ for a description of |
||
| 8 | # the original script by Chris AtLee. |
||
| 9 | # |
||
| 10 | 265e39e0 | Lars Kruse | # Copyright 2010-2012 Lars Kruse <devel@sumpralle.de> |
| 11 | a345d90e | Chris AtLee | # Copyright 2006 Chris AtLee <chris@atlee.ca> |
| 12 | # |
||
| 13 | # Original publication: http://atlee.ca/blog/2006/01/20/munin-shorewall/ |
||
| 14 | 265e39e0 | Lars Kruse | # Released under the GPL v3 or later |
| 15 | eb3dad43 | Lars Kruse | # |
| 16 | # You can use symlinks of this script according to the following pattern: |
||
| 17 | 265e39e0 | Lars Kruse | # shorewall-accounting_prot: use only rules with a specific protocol |
| 18 | # shorewall-accounting_in: use only rules with a specific input interface |
||
| 19 | # shorewall-accounting_out: use only rules with a specific output interface |
||
| 20 | # shorewall-accounting_source: use only rules with a specific source IP |
||
| 21 | # shorewall-accounting_destination: use only rules with a specific destination IP |
||
| 22 | # shorewall-accounting_details: use only rules with specific details (e.g. a port) |
||
| 23 | eb3dad43 | Lars Kruse | # |
| 24 | # Here "specific" means: non-default (e.g. a protocol was specified). |
||
| 25 | # Combinations are allowed: |
||
| 26 | 265e39e0 | Lars Kruse | # shorewall-accounting_prot_in_source: use only rules with a specific protocol, input interface and source IP |
| 27 | eb3dad43 | Lars Kruse | # |
| 28 | 265e39e0 | Lars Kruse | # Environment variables: |
| 29 | # SHOREWALL_BIN - defaults to /sbin/shorewall |
||
| 30 | # |
||
| 31 | # Changelog: |
||
| 32 | # v1.3 - 2012/04/02 |
||
| 33 | # * renamed plugin file from "shorewall_accounting" to "shorewall-accounting_" |
||
| 34 | # * CAUTION: rename your symlinks and plugin config section! |
||
| 35 | # * added optional SHOREWALL_BIN environment variable |
||
| 36 | # * improved labels for rules (don't mask dots) |
||
| 37 | # |
||
| 38 | #%# family=auto |
||
| 39 | #%# capabilities=autoconf |
||
| 40 | a345d90e | Chris AtLee | |
| 41 | import sys |
||
| 42 | eb3dad43 | Lars Kruse | import os |
| 43 | a345d90e | Chris AtLee | import commands |
| 44 | import re |
||
| 45 | |||
| 46 | 265e39e0 | Lars Kruse | PLUGIN_BASE_NAME = "shorewall-accounting" |
| 47 | SHOREWALL_BIN = os.environ.get("SHOREWALL_BIN", "/sbin/shorewall")
|
||
| 48 | a345d90e | Chris AtLee | ACCOUNTING_LINE_EXP = re.compile(r"^\s*\d+\s+(\d+)\s+(?P<prot>\w+)\s+(?P<opt>[\w-]+)\s+(?P<in>[\w*]+)\s+(?P<out>[\w*]+)\s+(?P<source>[\w./+-]+)\s+(?P<destination>[\w./+-]+)\s*(?P<details>.*)\s*$") |
| 49 | KEY_ORDER = ["prot", "in", "out", "source", "destination", "details"] |
||
| 50 | eb3dad43 | Lars Kruse | FILTER_PATTERNS = {
|
| 51 | "prot": r"^all$", |
||
| 52 | "in": r"^\*$", |
||
| 53 | "out": r"^\*$", |
||
| 54 | "source": r"^0\.0\.0\.0/0$", |
||
| 55 | "destination": r"^0\.0\.0\.0/0$", |
||
| 56 | "details": r"^$", |
||
| 57 | } |
||
| 58 | REPLACE_PATTERNS = {
|
||
| 59 | "prot": ("^all$", "allProt"),
|
||
| 60 | a345d90e | Chris AtLee | "in": (r"^\*$", "allIn"), |
| 61 | "out": (r"^\*$", "allOut"), |
||
| 62 | "source": (r"^0\.0\.0\.0/0", "allSrc"), |
||
| 63 | "destination": (r"^0\.0\.0\.0/0", "allDst"), |
||
| 64 | "details": (r"^multiport\s+", ""), |
||
| 65 | } |
||
| 66 | |||
| 67 | |||
| 68 | 265e39e0 | Lars Kruse | def get_accounting_rule_fieldname_and_label(regdict): |
| 69 | a345d90e | Chris AtLee | items = [] |
| 70 | # filter and clean all requested keys |
||
| 71 | for key in KEY_ORDER: |
||
| 72 | raw = regdict[key] |
||
| 73 | pattern, replacement = REPLACE_PATTERNS[key] |
||
| 74 | value = re.sub(pattern, replacement, raw).strip() |
||
| 75 | if value: |
||
| 76 | items.append(value) |
||
| 77 | result = "_".join(items) |
||
| 78 | # clean the fieldname: http://munin-monitoring.org/wiki/notes_on_datasource_names |
||
| 79 | result = re.sub(r"^[^A-Za-z_]", "_", result) |
||
| 80 | 265e39e0 | Lars Kruse | fieldname = re.sub(r"[^A-Za-z0-9_]", "_", result) |
| 81 | # keep dots (for IP addresses) |
||
| 82 | label = re.sub(r"[^A-Za-z0-9_\.]", "_", result) |
||
| 83 | return fieldname, label |
||
| 84 | a345d90e | Chris AtLee | |
| 85 | eb3dad43 | Lars Kruse | def is_wanted(regdict, filter_list): |
| 86 | for item in filter_list: |
||
| 87 | # is the item empty? |
||
| 88 | if not regdict[item]: |
||
| 89 | return False |
||
| 90 | # is the default value (unfiltered) set? |
||
| 91 | if re.search(FILTER_PATTERNS[item], regdict[item]): |
||
| 92 | return False |
||
| 93 | return True |
||
| 94 | |||
| 95 | def get_bytes_by_chain(filter_list): |
||
| 96 | 265e39e0 | Lars Kruse | status, output = commands.getstatusoutput("'%s' -x show accounting" \
|
| 97 | % SHOREWALL_BIN) |
||
| 98 | a345d90e | Chris AtLee | if status != 0: |
| 99 | 265e39e0 | Lars Kruse | raise OSError("Error running command (%s)[%i]: %s" % (SHOREWALL_BIN,
|
| 100 | status, output)) |
||
| 101 | a345d90e | Chris AtLee | chains = {}
|
| 102 | for line in output.splitlines(): |
||
| 103 | m = ACCOUNTING_LINE_EXP.match(line) |
||
| 104 | if m is not None: |
||
| 105 | eb3dad43 | Lars Kruse | # check if this line was filtered |
| 106 | if not is_wanted(m.groupdict(), filter_list): |
||
| 107 | continue |
||
| 108 | 265e39e0 | Lars Kruse | fieldname, label = get_accounting_rule_fieldname_and_label(m.groupdict()) |
| 109 | a345d90e | Chris AtLee | bytes = int(m.group(1)) |
| 110 | 265e39e0 | Lars Kruse | if fieldname in chains: |
| 111 | chains[fieldname][1] += bytes |
||
| 112 | a345d90e | Chris AtLee | else: |
| 113 | 265e39e0 | Lars Kruse | chains[fieldname] = [label, bytes] |
| 114 | a345d90e | Chris AtLee | retval = [] |
| 115 | names = chains.keys() |
||
| 116 | names.sort() |
||
| 117 | for name in names: |
||
| 118 | 265e39e0 | Lars Kruse | retval.append((name, chains[name][0], chains[name][1])) |
| 119 | a345d90e | Chris AtLee | return retval |
| 120 | |||
| 121 | eb3dad43 | Lars Kruse | |
| 122 | 265e39e0 | Lars Kruse | # extract the filters from the symlink's name |
| 123 | # (e.g. "shorewall-accounting_in_out_details" -> in, out, details) |
||
| 124 | eb3dad43 | Lars Kruse | call_name = os.path.basename(sys.argv[0]) |
| 125 | if call_name.startswith(PLUGIN_BASE_NAME): |
||
| 126 | suffix = call_name[len(PLUGIN_BASE_NAME):] |
||
| 127 | suffixes = suffix.split("_")
|
||
| 128 | # use only suffixes that are listed in FILTER_PATTERNS |
||
| 129 | filter_list = [item for item in suffixes if item in FILTER_PATTERNS] |
||
| 130 | else: |
||
| 131 | filter_list = [] |
||
| 132 | |||
| 133 | a345d90e | Chris AtLee | if len(sys.argv) > 1: |
| 134 | if sys.argv[1] == "autoconf": |
||
| 135 | 265e39e0 | Lars Kruse | status, output = commands.getstatusoutput("'%s' -x show accounting" \
|
| 136 | % SHOREWALL_BIN) |
||
| 137 | if (status != 0) or not output: |
||
| 138 | print "no" |
||
| 139 | else: |
||
| 140 | print "yes" |
||
| 141 | a345d90e | Chris AtLee | elif sys.argv[1] == "config": |
| 142 | 265e39e0 | Lars Kruse | if not filter_list: |
| 143 | title_addon = "all" |
||
| 144 | else: |
||
| 145 | title_addon = " / ".join(filter_list) |
||
| 146 | print "graph_title Shorewall accounting: %s" % title_addon |
||
| 147 | a345d90e | Chris AtLee | print "graph_category network" |
| 148 | print "graph_vlabel bits per ${graph_period}"
|
||
| 149 | 265e39e0 | Lars Kruse | for chain, label, bytes in get_bytes_by_chain(filter_list): |
| 150 | label = " ".join([item for item in label.split("_")
|
||
| 151 | if not item.lower().startswith("all")])
|
||
| 152 | if not label: |
||
| 153 | label = "all" |
||
| 154 | a345d90e | Chris AtLee | print "%s.min 0" % chain |
| 155 | print "%s.type DERIVE" % chain |
||
| 156 | 265e39e0 | Lars Kruse | print "%s.label %s" % (chain, label) |
| 157 | a345d90e | Chris AtLee | print "%s.cdef %s,8,*" % (chain, chain) |
| 158 | 265e39e0 | Lars Kruse | sys.exit(0) |
| 159 | a345d90e | Chris AtLee | |
| 160 | 265e39e0 | Lars Kruse | for chain, label, bytes in get_bytes_by_chain(filter_list): |
| 161 | a345d90e | Chris AtLee | print "%s.value %i" % (chain, bytes) |
