GUI CSS: Removed snapin styles from py modules and added a _snapins.scss for the...
[check_mk.git] / active_checks / check_traceroute
blobaa055683c33729830d368396f6c300047436380f
1 #!/usr/bin/env python
2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
9 # | |
10 # | Copyright Mathias Kettner 2014 mk@mathias-kettner.de |
11 # +------------------------------------------------------------------+
13 # This file is part of Check_MK.
14 # The official homepage is at http://mathias-kettner.de/check_mk.
16 # check_mk is free software; you can redistribute it and/or modify it
17 # under the terms of the GNU General Public License as published by
18 # the Free Software Foundation in version 2. check_mk is distributed
19 # in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
20 # out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
21 # PARTICULAR PURPOSE. See the GNU General Public License for more de-
22 # tails. You should have received a copy of the GNU General Public
23 # License along with GNU Make; see the file COPYING. If not, write
24 # to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 # Boston, MA 02110-1301 USA.
27 # This check does a traceroute to the specified target host
28 # (usually $HOSTADDRESS$ itself) and checks which route(s) are
29 # being taken. That way you can check if your preferred or
30 # some alternative route in in place.
31 # traceroute is expected to be in the search path and installed
32 # with SUID root bit.
34 # Example output from traceroute -n
35 # traceroute to www.google.de (173.194.44.55), 30 hops max, 60 byte packets
36 # 1 10.10.11.4 0.419 ms 0.444 ms 0.518 ms
37 # 2 33.117.16.28 14.359 ms 14.371 ms 14.434 ms
38 # 3 112.18.7.119 14.750 ms 14.765 ms 19.530 ms
39 # 4 184.50.190.61 17.844 ms 17.865 ms 17.862 ms
40 # 5 67.249.94.88 24.285 ms 78.527 ms 26.834 ms
41 # 6 209.85.240.99 27.910 ms 27.420 ms 27.442 ms
42 # 7 173.194.44.55 26.583 ms 20.410 ms 23.142 ms
44 # Output without -n option:
45 # traceroute to www.google.de (173.194.44.56), 30 hops max, 60 byte packets
46 # 1 fritz.box (10.10.11.4) 0.570 ms 0.606 ms 0.677 ms
47 # 2 foo-bar.x-online.net (33.117.16.28) 14.566 ms 14.580 ms 14.658 ms
48 # 3 xu-2-3-0.rt-inxs-1.x-online.net (112.13.6.109) 18.214 ms 18.228 ms 18.221 ms
49 # 4 * * *
50 # 5 66.249.94.88 (66.249.94.88) 24.481 ms 24.498 ms 24.271 ms
51 # 6 209.85.240.99 (209.85.240.99) 27.628 ms 21.605 ms 21.943 ms
52 # 7 muc03s08-in-f24.1e100.net (173.194.44.56) 21.277 ms 22.236 ms 22.192 ms
54 # It is also possible that for one hop several different answers appear:
55 # 11 xe-0-0-1-0.co2-96c-1b.ntwk.msn.net (204.152.141.11) 174.185 ms xe-10-0-2-0.co1-96c-1a.ntwk.msn.net (207.46.40.94) 174.279 ms xe-0-0-1-0.co2-96c-1b.ntwk.msn.net (204.152.141.11) 174.444 ms
57 # if DNS fails then it looks like this:
58 # 5 66.249.94.88 (66.249.94.88) 24.481 ms 24.498 ms 24.271 ms
59 # 6 209.85.240.99 (209.85.240.99) 27.628 ms 21.605 ms 21.943 ms
61 import getopt
62 import os
63 import subprocess
64 import sys
67 def option_to_state(c):
68 return {"w": 1, "c": 2}[c.lower()]
71 def check_traceroute(target, routes, nodns, method):
72 cmd = ["traceroute"]
73 if nodns:
74 cmd.append("-n")
75 if method:
76 cmd.append(method)
77 cmd.append(target)
78 p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
79 sto, ste = p.communicate()
80 if p.returncode:
81 return 3, "UNKNOWN - " + ste.replace("\n", " "), ""
83 # find all visited routers
84 routers = set([])
85 for line in sto.split("\n")[1:]:
86 parts = line.strip().split()
87 for part in parts:
88 if part.count(".") == 3 or (not part[0].isdigit() and part not in ["ms", "*"]):
89 part = part.lstrip("(").rstrip(",").rstrip(")")
90 routers.add(part)
92 state = 0
93 bad_routers = []
94 missing_routers = []
95 for option, route in routes:
96 s = option_to_state(option)
97 if option.islower() and route in routers:
98 state = max(state, s)
99 bad_routers.append("%s(%s)" % (route, "!" * s))
100 elif option.isupper() and route not in routers:
101 state = max(state, s)
102 missing_routers.append("%s(%s)" % (route, "!" * s))
104 info = "%s - %d hops, missing routers: %s, bad routers: %s" % (
106 0: "OK",
107 1: "WARN",
108 2: "CRIT"
109 }[state],
110 len(sto.split("\n")[1:]),
111 missing_routers and ", ".join(missing_routers) or "none",
112 bad_routers and ", ".join(bad_routers) or "none",
115 return state, info, sto
118 def bail_out(reason):
119 sys.stderr.write("FATAL ERROR: %s\n" % reason)
120 sys.exit(3)
123 def usage():
124 sys.stdout.write("""check_traceroute -{c|w|C|W} ROUTE [-{o|c|w|O|C|W} ROUTE...] TARGET
126 Check by which routes TARGET is being reached. Each possible route is being
127 prefixed with a state option:
129 -w Make outcome WARN if that route is present
130 -W Make outcome WARN if that route is missing
131 -c Make outcome CRIT if that route is present
132 -C Make outcome CRIT if that route is missing
134 Other options:
136 -h, --help show this help and exit
137 --debug show Python exceptions verbosely
138 -n disable reverse DNS lookups
139 -I Use ICMP ECHO for probes
140 -T Use TCP SYN for probes
142 """)
145 os.unsetenv("LANG")
147 opt_verbose = 0
148 opt_debug = False
149 opt_nodns = False
150 opt_method = None
152 short_options = "hw:W:c:C:nTI"
153 long_options = [
154 "verbose",
155 "help",
156 "debug",
159 route_params = []
161 try:
162 opts, args = getopt.getopt(sys.argv[1:], short_options, long_options)
164 # first parse modifers
165 for o, a in opts:
166 if o in ['-v', '--verbose']:
167 opt_verbose += 1
168 elif o in ['-d', '--debug']:
169 opt_debug = True
170 elif o in ['-w', '-W', '-c', '-C']:
171 route_params.append((o[1], a))
172 elif o == '-n':
173 opt_nodns = True
174 elif o in ['-T', '-I']:
175 opt_method = o
177 # now handle action options
178 for o, a in opts:
179 if o in ['-h', '--help']:
180 usage()
181 sys.exit(0)
183 if len(args) < 1:
184 bail_out("Please specify the target destination.")
186 target_address = args[0]
188 status, output, long_output = check_traceroute(target_address, route_params, opt_nodns,
189 opt_method)
190 sys.stdout.write(output.strip() + "\n" + long_output)
191 sys.exit(status)
193 except Exception, e:
194 if opt_debug:
195 raise
196 bail_out(e)