Repository: elastic/ecs

Issue:
DNS model
Added DNS model based on [Packetbeat DNS fields](
https://www.elastic.co/guide/en/beats/packetbeat/current/exported-fields-dns.html)  + one extra field — `dns.question.size`, which represents a size of name being queried (in bytes). 

We calculate it using the next Logstash config:

```ruby
ruby {
      code => 'event.set("dns.question.size", event.get("dns.question.name").length)'
}
```

I've presented one of our alerts based on this field ("Exfiltration over DNS, Large Domain Name Request") on the next conferences:

- CONFidence 2018, Krakow: [Practical intelligence-driven defense](https://www.youtube.com/watch?v=VJRGZLNtEg4)
- EU ATT&CK Workshop 2018, Luxembourg: [Use Case Framework, MITM tactic](https://drive.google.com/drive/folders/1UG0uRbselLshlclt6Ah5L9eegqKL3e-9)

Resolve (?) issue #10 


Discussion:

Resolving patch:
diff --git a/scripts/generators/es_template.py b/scripts/generators/es_template.py
--- a/scripts/generators/es_template.py
+++ b/scripts/generators/es_template.py
@@ -26,11 +26,18 @@ def dict_add_nested(dict, nestings, value):
     if len(rest_nestings) > 0:
         if current_nesting not in dict:
             dict[current_nesting] = {'properties': {}}
-        dict_add_nested(
-            dict[current_nesting]['properties'],
-            rest_nestings,
-            value)
+        elif 'type' in dict[current_nesting] and 'object' == dict[current_nesting]['type']:
+            dict[current_nesting] = {'type': dict[current_nesting]['type'], 'properties': {}}
+
+        if 'properties' in dict[current_nesting]:
+            dict_add_nested(
+                dict[current_nesting]['properties'],
+                rest_nestings,
+                value)
+
     else:
+        if current_nesting in dict and 'type' in value and 'object' == value['type']:
+            return
         dict[current_nesting] = value
 
 


Test patch:
diff --git a/scripts/tests/test_es_template.py b/scripts/tests/test_es_template.py
--- a/scripts/tests/test_es_template.py
+++ b/scripts/tests/test_es_template.py
@@ -12,24 +12,38 @@ class TestGeneratorsEsTemplate(unittest.TestCase):
 
     def test_add_not_nested(self):
         dict = {}
-        es_template.dict_add_nested(dict, ['level1'], 'value')
-        self.assertEqual(dict, {'level1': 'value'})
+        es_template.dict_add_nested(dict, ['field1'], {'field': 'details'})
+        self.assertEqual(dict, {'field1': {'field': 'details'}})
 
     def test_dict_add_nested(self):
         dict = {}
-        es_template.dict_add_nested(dict, ['level1', 'level2'], 'value')
-        self.assertEqual(dict, {'level1': {'properties': {'level2': 'value'}}})
+        es_template.dict_add_nested(dict, ['parent_field', 'leaf_field'], {'field': 'details'})
+        self.assertEqual(dict, {'parent_field': {'properties': {'leaf_field': {'field': 'details'}}}})
 
     def test_add_siblings(self):
-        dict = {'key1': 'value1', 'key2': {'properties': {'nested1': 'value12'}}}
-        es_template.dict_add_nested(dict, ['key3'], 'value3')
-        es_template.dict_add_nested(dict, ['key2', 'nested2'], 'value22')
+        dict = {'field1': {'field': 'details 1'},
+                'field2': {'properties': {'leaf1': {'field': 'details 2-1'}}}}
+        es_template.dict_add_nested(dict, ['field3'], {'field': 'details 3'})
+        es_template.dict_add_nested(dict, ['field2', 'leaf2'], {'field': 'details 2-2'})
         self.assertEqual(dict, {
-            'key1': 'value1',
-            'key2': {'properties': {'nested1': 'value12', 'nested2': 'value22'}},
-            'key3': 'value3'
+            'field1': {'field': 'details 1'},
+            'field2': {'properties': {
+                'leaf1': {'field': 'details 2-1'},
+                'leaf2': {'field': 'details 2-2'}
+            }},
+            'field3': {'field': 'details 3'}
         })
 
+    def test_dict_add_nested_to_explicit_object(self):
+        dict = {'answers': {'type': 'object'}}
+        es_template.dict_add_nested(dict, ['answers', 'ttl'], {'type': 'long'})
+        self.assertEqual(dict, {'answers': {'type': 'object', 'properties': {'ttl': {'type': 'long'}}}})
+
+    def test_dict_add_nested_shouldnt_clobber_with_objects(self):
+        dict = {'answers': {'properties': {'ttl': {'type': 'long'}}}}
+        es_template.dict_add_nested(dict, ['answers'], {'type': 'object'})
+        self.assertEqual(dict, {'answers': {'properties': {'ttl': {'type': 'long'}}}})
+
 
 if __name__ == '__main__':
     unittest.main()