First version of the RPZ export

- still undocumented
- very naive policy settings
- limit per event / tags / date range
pull/567/head
iglocska 2015-05-15 14:58:53 +02:00
parent 235262fcd3
commit 99f79ec318
5 changed files with 182 additions and 0 deletions

View File

@ -1792,6 +1792,41 @@ class AttributesController extends AppController {
$this->set('attributes', $attributes);
}
public function rpz($key='download', $tags=false, $eventId=false, $from=false, $to=false, $policy='DROP') {
$simpleFalse = array('eventId', 'tags', 'from', 'to');
foreach ($simpleFalse as $sF) {
if (${$sF} === 'null' || ${$sF} == '0' || ${$sF} === false || strtolower(${$sF}) === 'false') ${$sF} = false;
}
if (!in_array($policy, array('NXDOMAIN', 'NODATA', 'DROP'))) $policy = 'DROP';
if ($from) $from = $this->Attribute->Event->dateFieldCheck($from);
if ($to) $from = $this->Attribute->Event->dateFieldCheck($to);
if ($key != 'download') {
// check if the key is valid -> search for users based on key
$user = $this->checkAuthUser($key);
if (!$user) {
throw new UnauthorizedException('This authentication key is not authorized to be used for exports. Contact your administrator.');
}
} else {
if (!$this->Auth->user('id')) {
throw new UnauthorizedException('You have to be logged in to do that.');
}
}
$values = $this->Attribute->rpz($this->_checkOrg(), $this->_isSiteAdmin(), $tags, $eventId, $from, $to);
$this->response->type('txt'); // set the content type
$file = '';
if ($tags) $file = 'filtered.';
if ($eventId) $file .= 'event-' . $eventId . '.';
if ($from) $file .= 'from-' . $from . '.';
if ($to) $file .= 'to-' . $to . '.';
if ($file == '') $file = 'all';
$this->header('Content-Disposition: download; filename="misp.rpz.' . $file . '.txt"');
$this->layout = 'text/default';
$this->loadModel('Whitelist');
$values = $this->Whitelist->removeWhitelistedValuesFromArray($values);
$this->set('values', $values);
$this->set('policy', $policy);
//debug($values);
}
public function reportValidationIssuesAttributes() {
// TODO improve performance of this function by eliminating the additional SQL query per attribute

View File

@ -0,0 +1,78 @@
<?php
class RPZExport {
public function explain($type, $policy) {
$explanations = array(
'ip' => '# The following list of IP addresses will ',
'domain' => '# The following domain names and all of their sub-domains will ',
'hostname' => '# The following hostnames will '
);
$policy_explanations = array(
'NXDOMAIN' => 'return NXDOMAIN (name does not exist) irrespective of actual result received.',
'NODATA' => 'returns NODATA (name exists but no answers returned) irrespective of actual result received.',
'DROP' => 'timeout.',
);
return $explanations[$type] . $policy_explanations[$policy] . PHP_EOL . PHP_EOL;
}
public function export($items, $policy) {
switch ($policy) {
case 'NXDOMAIN':
$action = '.';
break;
case 'NODATA':
$action = '*.';
break;
default:
$policy = 'DROP';
$action = 'rpz-drop.';
}
$result = '';
$result .= $this->explain('ip', $policy);
foreach ($items['ip'] as $item) {
$result .= $this->__convertIP($item, $action);
}
$result .= $this->explain('domain', $policy);
foreach ($items['domain'] as $item) {
$result .= $this->__convertdomain($item, $action);
}
$result .= $this->explain('hostname', $policy);
foreach ($items['hostname'] as $item) {
$result .= $this->__converthostname($item, $action);
}
return $result;
}
private function __convertdomain($input, $action) {
return $input . ' CNAME ' . $action . PHP_EOL . '*.' . $input . ' CNAME ' . $action . PHP_EOL;
}
private function __converthostname($input, $action) {
return $input . ' CNAME ' . $action . PHP_EOL;
}
private function __convertip($input, $action) {
$type = filter_var($input, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ? 'ipv6' : 'ipv4';
if ($type == 'ipv6') $prefix = '128';
else $prefix = '32';
if (strpos($input, '/')) {
list($input, $prefix) = explode('/', $input);
}
return $prefix . '.' . $this->{'__' . $type}($input) . ' CNAME ' . $action . PHP_EOL;
}
private function __ipv6($input) {
return implode('.', array_reverse(preg_split('/:/', str_replace('::', ':zz:', $input), NULL, PREG_SPLIT_NO_EMPTY)));
}
private function __ipv4($input) {
return implode('.', array_reverse(explode('.', $input)));
}
}

View File

@ -1314,6 +1314,55 @@ class Attribute extends AppModel {
return $attributes;
}
public function rpz($org, $isSiteAdmin, $tags = false, $eventId = false, $from = false, $to = false) {
// we can group hostname and domain as well as ip-src and ip-dst in this case
$conditions['AND'] = array('Attribute.to_ids' => 1, 'Event.published' => 1);
$typesToFetch = array('ip' => array('ip-src', 'ip-dst'), 'hostname' => array('hostname'), 'domain' => array('domain'));
if ($from) $conditions['AND']['Event.date >='] = $from;
if ($to) $conditions['AND']['Event.date <='] = $to;
if (!$isSiteAdmin) {
$temp = array();
$distribution = array();
array_push($temp, array('Attribute.distribution >' => 0));
array_push($temp, array('(SELECT events.org FROM events WHERE events.id = Attribute.event_id) LIKE' => $org));
$conditions['OR'] = $temp;
}
if ($eventId !== false) {
$conditions['AND'][] = array('Event.id' => $eventId);
} elseif ($tags !== false) {
// If we sent any tags along, load the associated tag names for each attribute
$tag = ClassRegistry::init('Tag');
$args = $this->dissectArgs($tags);
$tagArray = $tag->fetchEventTagIds($args[0], $args[1]);
$temp = array();
foreach ($tagArray[0] as $accepted) {
$temp['OR'][] = array('Event.id' => $accepted);
}
$conditions['AND'][] = $temp;
$temp = array();
foreach ($tagArray[1] as $rejected) {
$temp['AND'][] = array('Event.id !=' => $rejected);
}
$conditions['AND'][] = $temp;
}
foreach ($typesToFetch as $k => $v) {
$params = array(
'conditions' => array('AND' =>
$conditions,
array('type' => $v),
),
'fields' => array('Attribute.value'), //array of field names
'order' => array('Attribute.value'), //string or array defining order
'group' => array('Attribute.value'), //fields to GROUP BY
);
$temp = $this->find('all', $params);
foreach ($temp as $value) $values[$k][] = $value['Attribute']['value'];
unset($temp);
}
return $values;
}
public function generateCorrelation() {
$this->Correlation = ClassRegistry::init('Correlation');
$this->Correlation->deleteAll(array('id !=' => ''), false);

View File

@ -126,4 +126,20 @@ class Whitelist extends AppModel {
}
return $data;
}
// A simplified whitelist removal, for when we just want to throw values against the list instead of attributes / events
public function removeWhitelistedValuesFromArray($data) {
$whitelists = $this->getBlockedValues();
// if we don't have any whitelist items in the db, don't loop through each attribute
if (!empty($whitelists)) {
foreach ($data as $k => $value) {
foreach ($whitelists as $wlitem) {
if (preg_match($wlitem, $value)) {
unset($data[$k]);
}
}
}
}
return $data;
}
}

View File

@ -0,0 +1,4 @@
<?php
App::uses('RPZExport', 'Export');
$rpzExport = new RPZExport();
echo ($rpzExport->export($values, $policy));