MISP-Taxii-Server/scripts/run-taxii-poll.py

184 lines
6.7 KiB
Python

#!/usr/bin/env python3
from cabby import create_client
from pyaml import yaml
from yaml import Loader
import pytz
import argparse
import os
import logging
import sys
from datetime import datetime
# Create an argument parser for our program
# Will just take in a config file and logging options
parser = argparse.ArgumentParser(description='Run MISP taxii pull.')
parser.add_argument('-c', "--configdir", default="~/.misptaxii",
help='Config directory')
parser.add_argument("-v", "--verbose", action="store_true",
help="More verbose logging")
parser.add_argument("-s", "--stdout", action="store_true",
help="Log to STDOUT")
parser.add_argument("--start",
help="Date to poll from (YYYY-MM-DDTHH:MM:SS), Exclusive")
parser.add_argument("--end",
help="Date to poll to (YYYY-MM-DDTHH:MM:SS), Inclusive")
parser.add_argument("--subscription_id", help="The ID of the subscription",
default=None)
parser.add_argument("--tz",
help="Your timezone, e.g Europe/London. Default utc",
default="utc")
args = parser.parse_args()
# Set up a logger for logging's sake
log = logging.getLogger(__name__)
logging.basicConfig(
filename="poll.log",
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
log.setLevel(logging.DEBUG if args.verbose else logging.INFO)
# If we want, print the output to stdout
if args.stdout:
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s")
ch = logging.StreamHandler(sys.stdout)
ch.setFormatter(formatter)
log.addHandler(ch)
# Read in the remote server configurations
config_file = "{}/remote-servers.yml".format(
os.path.expanduser(args.configdir))
log.debug("Opening config file %s", config_file)
with open(config_file, "r") as f:
config = yaml.load(f.read(), Loader=Loader)
log.debug("Config read %s", config)
# Read in the local server configuration
local_config = "{}/local-server.yml".format(os.path.expanduser(args.configdir))
log.debug("Reading local server config")
with open(local_config, "r") as f:
local_config = yaml.load(f.read(), Loader=Loader)
# Attempt to make contact with the local server
log.info("Connecting to local server...")
local_client = create_client(host=local_config["host"],
port=local_config["port"],
discovery_path=local_config["discovery_path"],
use_https=local_config["use_https"],
version=local_config["taxii_version"],
headers=local_config["headers"])
local_client.username = local_config["auth"]["username"]
local_client.password = local_config["auth"]["password"]
local_inbox = "{}://{}:{}{}".format(
"https" if local_config["use_https"] else "http",
local_config["host"], local_config["port"],
local_config["inbox_path"])
# Check that we're all good and authenticated
try:
list(local_client.discover_services())
except Exception as ex:
log.fatal("Could not connect to local server")
log.fatal(ex)
sys.exit(1)
log.info("Connected")
subscription_id = args.subscription_id
poll_from = datetime.strptime(args.start, "%Y-%m-%dT%H:%M:%S") if args.start else None
poll_to = datetime.strptime(args.end, "%Y-%m-%dT%H:%M:%S") if args.end else datetime.now()
timezone = args.tz
# Try to cast to pytz
try:
timezone = pytz.timezone(timezone)
except pytz.exceptions.UnknownTimeZoneError:
log.fatal("Timezone %s unknown", timezone)
log.fatal("Please select one of %s", ", ".join(pytz.all_timezones))
log.fatal("That's case sensitive!")
sys.exit(1)
# Add timezone info
if poll_from:
# (may not exist)
poll_from = poll_from.replace(tzinfo=pytz.timezone(args.tz))
poll_to = poll_to.replace(tzinfo=pytz.timezone(args.tz))
log.info("Set poll time to %s - %s", poll_from, poll_to)
for server in config:
log.info("== %s ==", server["name"])
log.debug("Creating client")
log.debug("HOST:PORT : %s:%s", server["host"], server["port"])
log.debug("DISCPATH: %s", server["discovery_path"])
# Standard autodiscovery
client_args = {
"host": server["host"],
"port": server["port"],
"discovery_path": server["discovery_path"],
"use_https": server["use_https"],
"version": server["taxii_version"],
"headers": server["headers"]
}
cli = create_client(**client_args)
log.debug("Setting client log level")
cli.log.setLevel(logging.DEBUG if args.verbose else logging.INFO)
log.debug("Setting authentication...")
cli.set_auth(username=server["auth"]["username"],
password=server["auth"]["password"],
ca_cert=server["auth"].get("ca_cert"),
cert_file=server["auth"].get("cert_file"),
key_file=server["auth"].get("key_file"),
key_password=server["auth"].get("key_password"),
jwt_auth_url=server["auth"].get("jwt_auth_url"),
verify_ssl=server["auth"].get("verify_ssl"))
log.debug("Discovering services...")
services = cli.discover_services()
log.debug(services)
log.debug("Auth set.")
for collection in server["collections"]:
log.debug("Polling %s", collection)
server_uri_override = server.get("uri", "")
if not server_uri_override.startswith("http"):
server_uri_override = None
if server_uri_override:
log.debug("Poll URL override set to %s", server_uri_override)
log.debug("Within date range %s - %s",
poll_from or "Beginning of time", poll_to)
try:
for content_block in cli.poll(collection_name=collection,
subscription_id=subscription_id,
begin_date=poll_from,
end_date=poll_to,
uri=server.get("uri", None)):
try:
log.debug("Pushing block %s", content_block)
local_client.push(
content_block.content.decode("utf-8"),
collection_names=local_config["collections"],
content_binding=content_block.binding,
uri=local_inbox)
except Exception as ex:
log.error("FAILED TO PUSH BLOCK!")
log.error("%s", content_block)
log.exception(ex, exc_info=True)
except Exception as ex:
log.error("FAILED TO POLL %s", collection)
log.exception(ex, exc_info=True)
log.info("Finished!")