def mass_contact(ip_address=None, category=None, campaign_name=None, email_subject=None, email_body=None, user_id=None): """ Try to identify customer based on `ip_address`, creates Cerberus ticket then send email to customer and finally close ticket. The use case is: a trusted provider sent you a list of vulnerable DNS servers (DrDOS amp) for example. To prevent abuse on your network, you notify customer of this vulnerability. :param str ip_address: The IP address :param str category: The category of the abuse :param str campaign_name: The name if the "mass-conctact" campaign :param str email_subject: The subject of the email to send to defendant :param str email_body: The body of the email to send to defendant :param int user_id: The id of the Cerberus `abuse.models.User` who created the campaign """ # Check params _, _, _, values = inspect.getargvalues(inspect.currentframe()) if not all(values.values()): Logger.error(unicode('invalid parameters submitted %s' % str(values))) return try: validate_ipv46_address(ip_address) except (TypeError, ValidationError): Logger.error(unicode('invalid ip addresses submitted')) return # Get Django model objects try: category = Category.objects.get(name=category) user = User.objects.get(id=user_id) except (AttributeError, ObjectDoesNotExist, TypeError): Logger.error(unicode('invalid user or category')) return # Identify service for ip_address try: services = ImplementationFactory.instance.get_singleton_of('CustomerDaoBase').get_services_from_items(ips=[ip_address]) schema.valid_adapter_response('CustomerDaoBase', 'get_services_from_items', services) except CustomerDaoException as ex: Logger.error(unicode('Exception while identifying defendants for ip %s -> %s ' % (ip_address, str(ex)))) raise CustomerDaoException(ex) # Create report/ticket if services: Logger.debug(unicode('creating report/ticket for ip address %s' % (ip_address))) with pglocks.advisory_lock('cerberus_lock'): __create_contact_tickets(services, campaign_name, ip_address, category, email_subject, email_body, user) return True else: Logger.debug(unicode('no service found for ip address %s' % (ip_address))) return False
def create_from_email(email_content=None, filename=None, lang='EN', send_ack=False): """ Create Cerberus report(s) based on email content If send_ack is True and report is attached to a ticket, then an acknowledgement is sent to the email provider. :param str email_content: The raw email content :param str filename: The name of the raw email file :param str lang: Langage to use if send_ack is True :param bool send_ack: If an acknowledgment have to be sent to provider :raises CustomerDaoException: if exception while identifying defendants from items :raises MailerServiceException: if exception while updating ticket's emails :raises StorageServiceException: if exception while accessing storage """ # This function use a lock/commit_on_succes on db when creating reports # # Huge blocks of code are under transaction because it's important to # rollback if ANYTHING goes wrong in the report creation workflow. # # Concurrent transactions (with multiple workers), on defendant/service creation # can result in unconsistent data, So a pg_lock is used. # # `abuse.models.Defendant` and `abuse.models.Service` HAVE to be unique. if not email_content: Logger.error(unicode('Missing email content')) return if not filename: # Worker have to push email to Storage Service filename = hashlib.sha256(email_content).hexdigest() __save_email(filename, email_content) # Parse email content abuse_report = Parser.parse(email_content) Logger.debug(unicode('New email from %s' % (abuse_report.provider)), extra={'from': abuse_report.provider, 'action': 'new email'}) # Check if provider is not blacklisted if abuse_report.provider in settings.PARSING['providers_to_ignore']: Logger.error(unicode('Provider %s is blacklisted, skipping ...' % (abuse_report.provider))) return # Check if it's an answer to a ticket(s) tickets = ImplementationFactory.instance.get_singleton_of('MailerServiceBase').is_email_ticket_answer(abuse_report) if tickets: for ticket, category, recipient in tickets: if all((ticket, category, recipient)) and not ticket.locked: # OK it's an anwser, updating ticket and exiting _update_ticket_if_answer(ticket, category, recipient, abuse_report, filename) return # Check if items are linked to customer and get corresponding services try: services = ImplementationFactory.instance.get_singleton_of('CustomerDaoBase').get_services_from_items( urls=abuse_report.urls, ips=abuse_report.ips, fqdn=abuse_report.fqdn ) schema.valid_adapter_response('CustomerDaoBase', 'get_services_from_items', services) except CustomerDaoException as ex: Logger.error(unicode('Exception while identifying defendants from items for mail %s -> %s ' % (filename, str(ex)))) raise CustomerDaoException(ex) # Create report(s) with identified services if not services: created_reports = [__create_without_services(abuse_report, filename)] else: with pglocks.advisory_lock('cerberus_lock'): __create_defendants_and_services(services) created_reports = __create_with_services(abuse_report, filename, services) # Upload attachments if abuse_report.attachments: _save_attachments(filename, abuse_report.attachments, reports=created_reports) # Send acknowledgement to provider (only if send_ack = True and report is attached to a ticket) for report in created_reports: if send_ack and report.ticket: try: __send_ack(report, lang=lang) except MailerServiceException as ex: raise MailerServiceException(ex) # Index to SearchService if ImplementationFactory.instance.is_implemented('SearchServiceBase'): __index_report_to_searchservice(abuse_report, filename, [rep.id for rep in created_reports]) Logger.info(unicode('All done successfully for email %s' % (filename)))