Projet

Général

Profil

Paste
Télécharger au format
Statistiques
| Branche: | Révision:

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)