From 4d87f4fcb59ac6ccaf16abf406dca9984ef25347 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Tue, 24 Feb 2015 13:20:56 +0100 Subject: [PATCH] Add python client API --- .gitignore | 4 ++++ client/LICENSE | 27 ++++++++++++++++++++++ client/README.md | 11 +++++++++ client/pypssl/__init__.py | 1 + client/pypssl/api.py | 47 +++++++++++++++++++++++++++++++++++++++ client/setup.py | 26 ++++++++++++++++++++++ 6 files changed, 116 insertions(+) create mode 100644 .gitignore create mode 100644 client/LICENSE create mode 100644 client/README.md create mode 100644 client/pypssl/__init__.py create mode 100644 client/pypssl/api.py create mode 100644 client/setup.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8f1becb --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +build/ +dist/ +*.egg-info/ + diff --git a/client/LICENSE b/client/LICENSE new file mode 100644 index 0000000..fb253a8 --- /dev/null +++ b/client/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2013, 2014 Raphaël Vinot +Copyright (c) 2013, 2014 Alexandre Dulaunoy +Copyright (c) 2013, 2014 CIRCL - Computer Incident Response Center Luxembourg + (c/o smile, security made in Lëtzebuerg, Groupement + d'Intérêt Economique) + +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 HOLDER 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. diff --git a/client/README.md b/client/README.md new file mode 100644 index 0000000..276c917 --- /dev/null +++ b/client/README.md @@ -0,0 +1,11 @@ +Client API for PSSL +=================== + +Client API to query the Passive SSL implementation provided by CIRCL. + +Passive DNS Services +==================== + +* (default) [CIRCL Passive SSL](http://circl.lu/services/passive-ssl/) + + diff --git a/client/pypssl/__init__.py b/client/pypssl/__init__.py new file mode 100644 index 0000000..474fdd2 --- /dev/null +++ b/client/pypssl/__init__.py @@ -0,0 +1 @@ +from api import PyPSSL diff --git a/client/pypssl/api.py b/client/pypssl/api.py new file mode 100644 index 0000000..818a980 --- /dev/null +++ b/client/pypssl/api.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import requests +import socket + + +class PyPSSL(object): + + def __init__(self, url='https://www.circl.lu/pssl/query', basic_auth=None, + auth_token=None): + self.url = url + + self.session = requests.Session() + if basic_auth is not None: + # basic_auth has do be a tuple ('user_name', 'password') + self.session.auth = basic_auth + elif auth_token is not None: + self.session.headers.update({'Authorization': auth_token}) + else: + # No authentication defined. + pass + + def _check_IP(self, ip): + if ':' in ip: + return {'error': 'IPv6 is not (yet) supported'} + splitted = ip.split('/') + try: + if len(splitted) == 2: + ip, block = splitted + if int(block) < 23: + return {'error': 'Maximum CIDR block size reached >/23'} + socket.inet_aton(ip) + except: + return {'error': 'Incorrect format'} + return None + + def query(self, q): + check = self._check_IP(q) + if check is not None: + return check + response = self.session.get('{}/{}' .format(self.url, q)) + try: + return response.json() + except: + raise Exception('Unable to decode JSON object: ' + response.text) + return {} diff --git a/client/setup.py b/client/setup.py new file mode 100644 index 0000000..48eb112 --- /dev/null +++ b/client/setup.py @@ -0,0 +1,26 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +from setuptools import setup + +setup( + name='pypssl', + version='1.0', + author='Raphaël Vinot', + author_email='raphael.vinot@circl.lu', + maintainer='Raphaël Vinot', + url='https://github.com/CIRCL/PyPSSL', + description='Python API for PSSL.', + long_description=open('README.md').read(), + packages=['pypssl'], + classifiers=[ + 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', + 'Development Status :: 3 - Alpha', + 'Environment :: Console', + 'Intended Audience :: Science/Research', + 'Intended Audience :: Telecommunications Industry', + 'Programming Language :: Python', + 'Topic :: Security', + 'Topic :: Internet', + ], + install_requires=['requests'], +)