diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2014-08-12 22:19:21 -0400 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2014-08-12 22:19:21 -0400 |
commit | 3a037c0254ef50f5b0d33995b1ea5ff3d1b95af3 (patch) | |
tree | 8af8f52ad8ce23efd7a7401ac366c9654d6a55f1 | |
download | cidrchk-3a037c0254ef50f5b0d33995b1ea5ff3d1b95af3.tar.gz |
Initial commit
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | README.md | 103 | ||||
-rwxr-xr-x | cidrchk | 125 | ||||
-rw-r--r-- | setup.py | 26 | ||||
-rwxr-xr-x | test_cidrchk.sh | 29 |
5 files changed, 287 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..de8b3f4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +build +*.egg-info +dist +*project diff --git a/README.md b/README.md new file mode 100644 index 0000000..7ab2b1e --- /dev/null +++ b/README.md @@ -0,0 +1,103 @@ +# Installation + +* Clone the `cidrchk` git repository +* `sudo python setup.py install` + +If you are unable to install `cidrchk` as root, please use the following notation instead: + +* `python setup.py install --user` + +# What is cidrchk? + +`cidrchk` is a simple Python script with only one purpose: To inform a user whether or not their computer is connected to a particular network. For example, on your "work" laptop, you depend on autofs to automatically mount NFS directories. However, when you are off-site or not connected to your institution's VPN, you quickly realize attempting to access these data areas will cause significantly long delays (i.e. the *five minute* default timeout period) + +# Options + +``` +usage: cidrchk [-h] [--ignore IGNORE] [--debug] [--verbose] cidr [cidr ...] + +Detects whether or not any ethernet devices match to a defined CIDR range. + +positional arguments: + cidr IP range(s) to detect + +optional arguments: + -h, --help show this help message and exit + --ignore IGNORE, -i IGNORE + IP range(s) to ignore (Default: link-local and + localhost) + --debug, -d + --verbose, -v +``` + +# How do I use it? + +Consider the following **.cshrc** example: + +``` +setenv PATH $HOME/bin:${PATH} +setenv MYDATA /remote/data1 +alias badidea "cd ${MYDATA}" +``` + +What happens if you, out of habit, attempt to execute your favorite alias? + +``` +$ badidea +[ no output, waiting for autofs to timeout ] +``` + +Whoops! Things didn't go as planned, so let's take a look at the same **.cshrc** example using `cidrchk`: + +``` +setenv PATH $HOME/bin:${PATH} +setenv MYDATA /remote/data1 + +set _OFFSITE = `cidrchk 10.0.0.0/20 66.55.32.0/20 >/dev/null` +setenv OFFSITE $status +unset _OFFSITE + +alias badidea "cd ${MYDATA}" + +if ( ${OFFSITE} ) then + unalias badidea +endif +``` + +In the above example the following is *true*: + +If 10.0.0.0/20 represents your institution's VPN address space and 66.55.32.0/20 represents your company's local intranet, and your home IP was 192.168.1.101, `cidrchk` returned a non-zero value indicating your computer was "off-site". + +Inversely, if your computer's IP address was 66.55.45.10 (i.e. you are in your cubicle), `cidrchk` would return zero indicating your computer was "on-site". + +## Other Possiblities + +Issuing `-v` to `cidrchk` will echo the return value to the console, resulting in slightly more cleaner code: + +``` +setenv OFFSITE `cidrchk -v 10.0.0.0/24 66.55.32.0/20` + +if ( ${OFFSITE} ) then + # do something clever to prevent personal hardship +endif +``` + +## How do I use BASH with cidrchk? + +The notation required for `cidrchk` to use BASH is nearly identical to TCSH: + +``` +_OFFSITE=$(cidrchk 10.0.0.0/24 66.55.32.0/20 >/dev/null) +export OFFSITE=$? + +if (( ${OFFSITE} )); then + #do something clever to prevent personal hardship +fi +``` + +# Bug Reporting + +Submit bug reports via this project's issue tracker: https://bitbucket.org/jhunkeler/cidrchk/issues + +Please remember to include your computer's operating system, the name of the shell you executed `cidrchk` from, the output of `cidrchk -d`, and any relevant code snippets you may have. + @@ -0,0 +1,125 @@ +#!/usr/bin/env python +# Copyright (c) 2014, Joseph Hunkeler <jhunkeler at gmail.com> +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +class ExitCode(object): + SUCCESS, FAIL, NO_MODULE, NO_INTERFACE = range(4) + +try: + import argparse +except ImportError: + print('argparse module required.') + exit(ExitCode.NO_MODULE) + +try: + import netifaces +except ImportError: + print('netifaces module required.') + exit(ExitCode.NO_MODULE) + +try: + from netaddr import IPNetwork +except ImportError: + print('netaddr module required.') + exit(ExitCode.NO_MODULE) + + +DEBUG = False +VERBOSE = False + +def info(ignore, accept): + status = {'IGNORED':[], 'DETECTED':[], 'OTHER':[]} + for interface in netifaces.interfaces(): + ignored = False + detected = False + + try: + addr = netifaces.ifaddresses(interface) + if not netifaces.AF_INET in addr: + continue + except: + return None + + for iface in addr[netifaces.AF_INET]: + if not 'addr' in iface: + continue + + address = iface['addr'] + for ip_range in ignore: + if address in ip_range: + ignored = True + + for ip_range in accept: + if address in ip_range: + detected = True + + if ignored: + if DEBUG: + print('Ignored: {0} on {1}'.format(address, interface)) + status['IGNORED'].append(address) + continue + + if detected: + if DEBUG: + print('Detected: {0} on {1}'.format(address, interface)) + status['DETECTED'].append(address) + continue + + if DEBUG: + print('Detected (non-match): {0} on {1}'.format(address, interface)) + status['OTHER'].append(address) + return status + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Detects whether or not any ethernet devices match to a defined CIDR range.') + parser.add_argument('--ignore', '-i', action='append', default=[ IPNetwork('127.0.0.0/8'), IPNetwork('169.254.0.0/16') ], type=IPNetwork, help='IP range(s) to ignore (Default: link-local and localhost)') + parser.add_argument('--debug', '-d', action='store_true', default=False) + parser.add_argument('--verbose', '-v', action='store_true', default=False) + parser.add_argument('cidr', nargs="+", type=IPNetwork, help='IP range(s) to detect') + args = parser.parse_args() + + DEBUG = args.debug + VERBOSE = args.verbose + + status = info(args.ignore, args.cidr) + + if status is None: + if DEBUG: + print("No ethernet interface detected") + if VERBOSE: + print(ExitCode.NO_INTERFACE) + exit(ExitCode.NO_INTERFACE) + + if not status['DETECTED']: + if DEBUG: + print("No ethernet interface is operating at the defined range") + if VERBOSE: + print(ExitCode.FAIL) + exit(ExitCode.FAIL) + + if DEBUG: + print("A network interface matched defined range") + if VERBOSE: + print(ExitCode.SUCCESS) + + exit(ExitCode.SUCCESS) diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..f98a98d --- /dev/null +++ b/setup.py @@ -0,0 +1,26 @@ +import os +from setuptools import setup + +setup( + name = 'cidrchk', + version = '1.0.0', + author = 'Joseph Hunkeler', + author_email = 'jhunkeler@gmail.com', + description = ('A simple "Is my computer on this subnet?" detection script.'), + license = 'BSD', + keywords = 'cidrchk detect network interface ethernet', + zip_safe = True, + scripts = [ + 'cidrchk', + ], + install_requires = [ + 'netaddr', + 'netifaces', + 'argparse', + ], + classifiers = [ + 'Development Status :: 5 - Production/Stable', + 'Topic :: Utilities', + 'License :: OSI Approved :: BSD License', + ] +) diff --git a/test_cidrchk.sh b/test_cidrchk.sh new file mode 100755 index 0000000..cc3fe4b --- /dev/null +++ b/test_cidrchk.sh @@ -0,0 +1,29 @@ +#!/bin/bash +program=./cidrchk +args="$@" + +if [ -z "$args" ]; then + echo "No CIDR range(s) defined" + exit 1 +fi + +$program $args +retval=$? + +case "$retval" in + 0) + echo "On net" + ;; + 1) + echo "Off net" + ;; + 2) + echo "Module import failure detected" + ;; + 3) + echo "No network interfaces detected" + ;; + *) + echo "Unknown failure" + ;; +esac |