63 lines
1.2 KiB
Ruby
63 lines
1.2 KiB
Ruby
|
#!/usr/bin/env ruby
|
||
|
require 'shellwords'
|
||
|
require 'ipaddress'
|
||
|
require 'resolv'
|
||
|
|
||
|
class R
|
||
|
def initialize opts=nil
|
||
|
@resolv = Resolv::DNS.new opts
|
||
|
end
|
||
|
IN = Resolv::DNS::Resource::IN
|
||
|
|
||
|
def a( q) @resolv.getresources( q, IN::A) end
|
||
|
def aaaa( q) @resolv.getresources( q, IN::AAAA) end
|
||
|
def txt( q) @resolv.getresources( q, IN::TXT) end
|
||
|
def mx( q) @resolv.getresources( q, IN::MX) end
|
||
|
|
||
|
def ip q
|
||
|
a(q) + aaaa(q)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
$resolv = R.new
|
||
|
|
||
|
def bb d
|
||
|
$resolv.txt( d).map do |l|
|
||
|
v, *as = l.data.split( ' ')
|
||
|
if "v=spf1" == v
|
||
|
as.map do |a|
|
||
|
case a
|
||
|
when /\Aa:(.*)\z/
|
||
|
$resolv.ip( $1).map( &:address)
|
||
|
when "mx"
|
||
|
$resolv.mx( d).map do |l|
|
||
|
$resolv.ip( l.exchange.to_s).map( &:address)
|
||
|
end
|
||
|
when /\Aip[46]:(.*)\z/ then $1
|
||
|
when /\A(?:redirect=|include:)(.*)\z/ then bb $1
|
||
|
when /\A[-~+]all/ then nil
|
||
|
else nil
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
ARGV.
|
||
|
flat_map do |d|
|
||
|
bb( d).
|
||
|
flatten.
|
||
|
compact.
|
||
|
uniq.
|
||
|
map {|x| IPAddress.parse( x).first.to_string rescue ArgumentError }.
|
||
|
select {|x| String === x }.
|
||
|
uniq.
|
||
|
map {|x| [x, d]}
|
||
|
end.
|
||
|
group_by {|(x,d)| x }.
|
||
|
each {|x,xs| xs.map! &:last }.
|
||
|
sort_by {|x,ds| x = IPAddress.parse x; [x.class.name, x] }.
|
||
|
each do |(x,ds)|
|
||
|
puts "#{x} permit # #{ds.uniq.sort.join ' '}"
|
||
|
end
|