dmarc_report 1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '008d36fdf239257774fba2efbb5a49503b7057bc728f247f16e3dbf0c4e3ce8e'
4
+ data.tar.gz: 8933c858c7fa067c9dfef91223f5bc6c01cb8bc59b7f30ea5f0d02ee78a4b09d
5
+ SHA512:
6
+ metadata.gz: e82ae67b93a3e13e1e7d093f4ad3fdf5b9b3fc4cde861213aab513fae979246231799c1db7648d4d347cf8d83e8961db3928becba5c57b5eefe5b6ae3a05f59f
7
+ data.tar.gz: 9ab1f2409872e52297959960b0c48f429079a9a46729f9c30cfe893d83f0312e13ac96dafc3a50dc3e5ed71ec2ffe0bccd5b0df6fd081baf6010009cc22147f7
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ .rubocop_todo.yml
2
+ DMARC
3
+ HISTORY
4
+ Makefile
5
+ crontab.new
6
+ run-dmarc.sh
7
+ dmarc-profile.sh
8
+ /config
9
+ /doc
10
+ /log
11
+ /rules
12
+ *.json
13
+ *.csv
14
+ *.gem
data/.rubocop.yml ADDED
@@ -0,0 +1,44 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ # rubocop configuration
4
+
5
+ AllCops:
6
+ NewCops: enable
7
+
8
+ Layout/SpaceInsideArrayLiteralBrackets:
9
+ EnforcedStyle: space
10
+ Exclude:
11
+ - 'blocklistshow.gemspec'
12
+
13
+ Layout/SpaceInsideParens:
14
+ EnforcedStyle: space
15
+ Exclude:
16
+ - 'blocklistshow.gemspec'
17
+
18
+ Layout/SpaceInsideRangeLiteral:
19
+ #EnforcedStyle: space
20
+ Enabled: false
21
+
22
+ Layout/SpaceInsideReferenceBrackets:
23
+ EnforcedStyle: space
24
+ Exclude:
25
+ - 'blocklistshow.gemspec'
26
+
27
+ Metrics/MethodLength:
28
+ Max: 20
29
+
30
+ Style/FrozenStringLiteralComment:
31
+ Enabled: false
32
+
33
+ Style/RegexpLiteral:
34
+ Enabled: false
35
+
36
+ Style/SpecialGlobalVars:
37
+ EnforcedStyle: use_perl_names
38
+
39
+ Style/SymbolArray:
40
+ EnforcedStyle: brackets
41
+
42
+ Style/WordArray:
43
+ EnforcedStyle: brackets
44
+
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ ## 1.0 (2023-12-23)
2
+
3
+ - Initial Release.
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2020-2023 Dirk Meyer
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,84 @@
1
+ # dmarc_report
2
+ This is the backend for parsing DMARC reports
3
+
4
+ Backend and frontend should run on diffrent machines.
5
+ This avoids to have you IMAP credentials on the public webserver.
6
+ The cron-job push the results via rsync to the webserver.
7
+
8
+ ## Requirements:
9
+ * Install cron
10
+ * Install ruby
11
+ * Install ruby-rubygems
12
+ * Install ripmime
13
+ * Install gzip (gunzip)
14
+ * Install unzip
15
+ * Install rsync
16
+ * IMAP Account where DMARC reports are comming in
17
+ * Configuration in YAML
18
+
19
+ ## Installation:
20
+
21
+ gem install --user-install dmarc_report
22
+
23
+ for Diagnostics, add the rubygem dir to your search path
24
+
25
+ FreeBSD:
26
+
27
+ vim .profile
28
+ PATH="$PATH:$HOME/.gem/ruby/3.1/bin"
29
+
30
+ Debian:
31
+
32
+ vim .profile
33
+ PATH="$PATH:$HOME/.local/share/gem/ruby/3.1.0/bin"
34
+
35
+ Create the working directory:
36
+
37
+ cd
38
+ mkdir -p dmarc
39
+ cd dmarc
40
+ install-dmarc_report.rb
41
+
42
+ Edit your IMAP account data:
43
+
44
+ vim config/dmarc.yml
45
+
46
+ Check your rulesets:
47
+
48
+ vim rules/dmarc.yml
49
+
50
+ Edit the target directory for your webserver:
51
+
52
+ vim dmarc_profile.sh
53
+
54
+ Check the script for your cron:
55
+
56
+ vim run-dmarc.sh
57
+
58
+ Check the function
59
+
60
+ ./run-dmarc.sh
61
+
62
+ Edit your crontab:
63
+
64
+ crontab -e
65
+ # crontab for dmarc_report
66
+ #minute hour mday month wday command
67
+ 13 8,12,18 * * * /home/user/dmarc/run-dmarc.sh
68
+ #
69
+
70
+ # Processing:
71
+
72
+ ```mermaid
73
+ sequenceDiagram
74
+ IMAP ->> File: dmarc_imap.rb
75
+ File ->> Attachment: dmarc_ripmime.rb
76
+ Attachment ->> XML: dmarc_ripmime.rb
77
+ XML ->> CSV: dmarc_report.rbS
78
+ CSV ->> HTML: dmarc.rhtml
79
+ ```
80
+
81
+ # Frontend:
82
+
83
+ See: https://github.com/dinoex/dmarc_view
84
+
data/bin/dmarc_dns.rb ADDED
@@ -0,0 +1,109 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # = dmarc_dns.rb
4
+ #
5
+ # Author:: Dirk Meyer
6
+ # Copyright:: Copyright (c) 2020 - 2023 Dirk Meyer
7
+ # License:: Distributes under the same terms as Ruby
8
+ # SPDX-FileCopyrightText: 2020-2023 Dirk Meyer
9
+ # SPDX-License-Identifier: Ruby
10
+ #
11
+ # Maintain a DNS cache for IPs of Mail-servers
12
+ # Input: dmarc-report.csv
13
+ # Output: dmarc-dns.json
14
+ #
15
+
16
+ require 'resolv'
17
+ require 'ipaddr'
18
+ require 'json'
19
+ require 'csv'
20
+
21
+ # input file in CSV format
22
+ INPUT_FILE = 'dmarc-report.csv'.freeze
23
+ # output file in JSON format
24
+ DNS_CACHE_FILE = 'dmarc-dns.json'.freeze
25
+
26
+ # get ptr from host command (bind9)
27
+ def get_dns_host( ip )
28
+ result = nil
29
+ `host '#{ip}'`.split( "\n" ).each do |line|
30
+ return 'not found' if line =~ /not found/
31
+ return line.split( /\s/ ).last if line =~ /domain name pointer/
32
+
33
+ result = line
34
+ end
35
+ result
36
+ end
37
+
38
+ # get ptr from DNS resolver
39
+ def getname_save( ip )
40
+ Resolv.getname( ip ).to_s
41
+ rescue Resolv::ResolvError
42
+ 'not found'
43
+ end
44
+
45
+ # get ptr for IP
46
+ def get_dns( ip )
47
+ return 'not found' if ip == ''
48
+ return 'not found' if ip.nil?
49
+
50
+ # return get_dns_host( ip )
51
+ getname_save( ip )
52
+ end
53
+
54
+ # get ptr from cache
55
+ def get_cached_dns( ip )
56
+ return @dns_cache[ ip ] if @dns_cache.key?( ip )
57
+
58
+ @dns_cache[ ip ] = get_dns( ip )
59
+ end
60
+
61
+ # load json file
62
+ def load_json( filename )
63
+ return {} unless File.exist?( filename )
64
+
65
+ JSON.parse( File.read( filename ) )
66
+ end
67
+
68
+ # load cache file
69
+ def load_cache
70
+ @dns_cache = load_json( DNS_CACHE_FILE )
71
+ end
72
+
73
+ # save cache file
74
+ def save_cache
75
+ File.write( DNS_CACHE_FILE, "#{JSON.dump( @dns_cache )}\n" )
76
+ end
77
+
78
+ # parse CSV for source ips
79
+ def run_csv
80
+ return unless File.exist?( INPUT_FILE )
81
+
82
+ CSV.foreach( INPUT_FILE, encoding: 'UTF-8', col_sep: ';' ) do |row|
83
+ ip = row[ 2 ]
84
+ next if ip == 'source_ip'
85
+
86
+ get_cached_dns( ip )
87
+ end
88
+ end
89
+
90
+ # check arguments
91
+ ARGV.each do |option|
92
+ case option
93
+ when 'test' # diagnostics
94
+ ARGV.shift
95
+ ip = ARGV.shift
96
+ p get_dns( ip )
97
+ exit 0
98
+ else
99
+ warn "Fehler #{option}"
100
+ exit 65
101
+ end
102
+ end
103
+
104
+ load_cache
105
+ run_csv
106
+ save_cache
107
+
108
+ exit 0
109
+ # eof
data/bin/dmarc_dump.rb ADDED
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # = dmarc_dump.rb
4
+ #
5
+ # Author:: Dirk Meyer
6
+ # Copyright:: Copyright (c) 2023 Dirk Meyer
7
+ # License:: Distributes under the same terms as Ruby
8
+ # SPDX-FileCopyrightText: 2023 Dirk Meyer
9
+ # SPDX-License-Identifier: Ruby
10
+ #
11
+ # Parse an DMARC report XML file and print it in JSON
12
+ # Input: xmlfile with DMARC report
13
+ # Output: formatted JSON text
14
+ #
15
+
16
+ require 'nokogiri'
17
+ require 'csv'
18
+
19
+ $: << 'lib'
20
+
21
+ require 'xmltohash'
22
+
23
+ # read and print xml file
24
+ def run_xml( fullname )
25
+ p fullname
26
+ raw = File.read( fullname )
27
+ return if raw.empty?
28
+ return if raw == 'unused'
29
+
30
+ begin
31
+ h = Hash.from_xml( raw )
32
+ rescue NoMethodError
33
+ warn "Bad XML in #{fullname}"
34
+ pp 'raw'
35
+ return
36
+ end
37
+ pp h
38
+ # AOL can send empty XML files
39
+ nil if h.nil?
40
+ end
41
+
42
+ ARGV.each do |arg|
43
+ run_xml( arg )
44
+ end
45
+
46
+ exit 0
47
+ # eof