-
Notifications
You must be signed in to change notification settings - Fork 66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
despf does not consolidate cidrs #126
Comments
Have you considered using iprange in your script? |
@bakerjalexander Thanks for recommendation, I did not know about it before you mentioned it. Do you use it? How? |
@bakerjalexander Have a look at #127 please. |
I'm working towards the same ends as you. I've got a client that's using
Hover for their DNS and they have a 255 character limitation on their TXT
entries and they also have four other companies sending email on their
behalf so I'm trying to flatten the SPF records in order to maintain the 10
DNS lookup SPF limitation. I'll be glad to share my code with you when I'm
done, however I'm doing it all in perl.
If I recall correctly, I stumbled onto iprange when I was looking for a
solution for maintaining CIDR lists for firewalling countries using ipset.
When I investigate firehol's site on github, I shifted from maintaining my
own ipset lists to using his.
I appreciate the work you've done. It has been very helpful.
…On Fri, Jan 20, 2017 at 2:21 AM, Ján Sáreník ***@***.***> wrote:
@bakerjalexander <https://github.com/bakerjalexander> Thanks for
recommendation, I did not know about it before you mentioned it. Do you use
it? How?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#126 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AS3q00lYmg8AgtfJboFY0h8mG6hQonzDks5rUG6MgaJpZM4LotPr>
.
|
@bakerjalexander Thank you! I really appreciate your words and am looking forward to your Perl version! All the best to you! |
@bakerjalexander, can this issue be closed now? #127 was merged already into master. Thanks. |
I closed this. Am attaching my attempt at a cloudflare, perl based
solution. Please feel free to test.
Thanks!
On Mon, Jan 23, 2017 at 2:37 AM, Ján Sáreník ***@***.***> wrote:
@bakerjalexander <https://github.com/bakerjalexander>, can this issue be
closed now? #127 <#127> was
merged already into master. Thanks.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#126 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AS3q06OmLjTOiKWMaUA3Mc-jPnFGhNQ-ks5rVGa3gaJpZM4LotPr>
.
#!/usr/bin/perl
use Date::Manip;
use English qw( -no_match_vars );
use Algorithm::Bucketizer;
use IPC::Open2;
use Furl;
use JSON qw( encode_json decode_json );
use Data::Dumper;
# This program will update your Cloudflare SPF records and optionally make tinydns records
# stored in /tmp/tinydns. There will be a master record, consisting of your own mailservers
# and up to 10 (SPF lookup maximum) include records in the range of (q..z).yourdomain.tld.
#
# The subdomain entries are also added to Cloudflare and if there are less than 10,
# the unused ones will be removed.
#
# IMPORTANT: As of this writing, if you already have non-SPF DNS entries as specified above,
# (Or your master zone doesn't currently have and SPF record, this program will fail.
# The program can either add non-existent SPF entries or remove unused ones.
#
# The records are flattened: the includes have only ip4 and ip6 addresses and CIDRs
# The program uses iprange, available from https://github.com/firehol/iprange to
# consolidate all ip addresses into CIDRs, if possible.
#
# The program also makes use of Algorithm::Bucketizer, which tries to put the maximum possible
# addresses in each entry.
#
# To use, change the variables below to your liking and run from the command line.
#
# $api - this is your Cloudflare api
# $myzone - domain for which you need SPF records
# $auth_email - your email address you use to log into Cloudflare
#
# $masterspf - your published spf record which has - possibly - the a and mx mechanisms and all
# your includes like: v=spf1 mx include:ticketmaster.com include:constantcontact.com -all
#
# $TXTsize - this is your size for each entry, excluding the master, 500 max
# in order to keep the complete entry from exceeding 512 bytes. I suggest 450.
#
# $logfile - the program logs here
# $ignore_servers - any server(s) you wish to exclude, FQDN or ip addresses allowed
# $iprange - full path to your iprange program
# $debug_prog - if non-zero, turns on Data::Dumper on responses from Cloudflare
# $tinydns - if non-zero, writes tinydns entries to /tmp/tinydns for further use
#
####################################################################################################
$api = '99999999999999999999999999999999999';
$myzone = 'yourdomain.com';
$auth_email = 'auth_user@yourdomain.com';
$masterspf = 'spfmaster.yourdomain.com';
$TXTsize = 400;
$logfile = '/var/log/spfgen.log';
$ignore_servers = 'someexcluded.domains.com 1.2.3.4';
$iprange = '/usr/bin/iprange';
$debug_prog = 0;
$tinydns = 0;
my $furl = Furl->new(
capture_request => ':Bool = false',
agent => 'MyGreatUA/2.0',
timeout => 10,
);
$basecloud = 'https://api.cloudflare.com/client/v4/zones';
$digmasterspf = `dig TXT $masterspf +short`;
$digmasterspf =~ /v=spf1/i or die "$masterspf is not a valid SPF record";
log_it("Fetching my mail servers and removing servers to ignore");
log_it( "Looking at record " . "$masterspf" );
get_my_servers( $digmasterspf, $myzone );
log_it("My mail servers are:");
log_it("$_") for ( keys %myservers );
log_it("Excluding:");
log_it("$_") for ( keys %myignores );
$initrecord = "v=spf1";
foreach $server ( keys %myservers ) {
$initrecord = $initrecord . " ip4:" . $myservers{"$server"}
if valid_ip4( $myservers{"$server"} );
$initrecord = $initrecord . " ip6:" . $myservers{"$server"}
if valid_ip6( $myservers{"$server"} );
}
log_it("Fetching all includes");
$raw_ips = getit($masterspf);
log_it("Validating IP addresses and making master list");
$pretty_ips = make_pretty($raw_ips);
log_it("Making array of DNS entries");
$dnsentries = entries( $TXTsize, $pretty_ips );
$totallookups = scalar @$dnsentries;
$totallookups <= 10
or die "Only 10 lookups allowed! Try increasing \$TXTsize variable";
log_it( "Retrieving master zone id for " . "$myzone" );
$zone_id = get_zone_id( "$auth_email", "$api", "$myzone" );
$lookups = 0;
log_it( "Total DNS lookup entries is " . $totallookups );
log_it( "Starting CloudFlare update for " . "$myzone" );
for $includectr ( "q" .. "z" ) {
$subdomainentry = $includectr . '.' . "$myzone";
log_it( "Working on " . "$subdomainentry" );
$subdrecord = "v=spf1 " . @$dnsentries[$lookups] . " -all";
$lookups++;
log_it( "Retrieving subdomain zone id for " . "$subdomainentry" );
$subdomain_zone_id =
get_subdomain_id( "$auth_email", "$api", "$subdomainentry", "$zone_id" );
if ( "$lookups" <= "$totallookups" ) {
if ($tinydns) {
$tinydnsrecord = $subdrecord;
$tinydnsrecord =~ s/:/\\072/g;
$tinydnsrecord = "\'" . $subdomainentry . ":" . $tinydnsrecord;
push @tinydnsentries, $tinydnsrecord;
}
log_it( "Working on subdomain " . "$subdomainentry" );
log_it( "Record for "
. "$subdomainentry"
. " has length "
. length($subdrecord) );
$initrecord = $initrecord . " include:" . $subdomainentry;
if ( $subdomain_zone_id eq "nonexistent" ) {
log_it( "Couldn\'t find zone id for " . "$subdomainentry" );
log_it( "Making new DNS record for " . "$subdomainentry" );
$subdomain_change = make_new_dns_record(
"$auth_email", "$api",
"$zone_id", "$subdomainentry",
"$subdrecord"
);
}
else {
log_it( "Changing DNS record for " . $subdomainentry );
$subdomain_change = put_dns_change(
"$auth_email", "$api",
"$zone_id", "$subdomain_zone_id",
"$subdomainentry", "$subdrecord"
);
}
}
else {
log_it( "No record needed for " . $subdomainentry );
log_it( "Deleting DNS record for " . $subdomainentry );
$subdomain_delete = delete_dns_record(
"$auth_email", "$api",
"$zone_id", "$subdomain_zone_id",
"$subdomainentry"
);
}
}
$initrecord = $initrecord . " -all";
if ($tinydns) {
$tinydnsrecord = $initrecord;
$tinydnsrecord =~ s/:/\\072/g;
$tinydnsrecord = "\'" . $myzone . ":" . $tinydnsrecord;
push @tinydnsentries, $tinydnsrecord;
open( my $tinyh, '>', '/tmp/tinydns' );
print $tinyh "$_", "\n" for (@tinydnsentries);
close $tinyh;
log_it("Printed tinydns entries to /tmp/tinydns");
}
log_it( "Processing Master DNS record for " . "$myzone" );
$subdomain_zone_id =
get_subdomain_id( "$auth_email", "$api", "$myzone", "$zone_id" );
if ( $subdomain_zone_id eq "nonexistent" ) {
log_it( "No Master DNS record found for " . "$myzone" );
log_it( "Creating Master DNS record for " . "$myzone" );
$subdomain_change =
make_new_dns_record( "$auth_email", "$api", "$zone_id", "$myzone",
"$initrecord" );
}
else {
log_it( "Updating Master DNS record for " . "$myzone" );
$subdomain_change = put_dns_change(
"$auth_email", "$api",
"$zone_id", "$subdomain_zone_id",
"$myzone", "$initrecord"
);
}
log_it("Finished.");
log_it("");
sub get_my_servers {
( my $myownspfline, my $myownroot ) = @_;
@myignores = "$_" for split /\s+/, $ignore_servers;
foreach my $ban (@myignores) {
if ( valid_ip4($ban) || valid_ip6($ban) ) {
$myignores{"$ban"} = "$ban";
}
else {
my @dig_ignores = `dig $ban +short`;
chomp @dig_ignores;
$myignores{"$_"} = "$_" for @dig_ignores;
}
}
my @spflineitems = split /\s+/, $myownspfline;
foreach my $lineitem (@spflineitems) {
my $listedserver = lc( substr( $lineitem, 4 ) )
if $lineitem =~ /^ip[4,6]:.*?$/i;
next if exists $myignores{"$listedserver"};
$myservers{"$listedserver"} = "$listedserver"
if ( valid_ip4($my_ip_record) || valid_ip6($my_ip_record) );
}
if ( $myownspfline =~ /\bmx\b/i ) {
@my_mx = `dig mx $myownroot +short`;
s/(^.*?)\s+(.*?)/$2/g for @my_mx;
foreach $my_mxrecord (@my_mx) {
@my_mx_ip = ();
@my_mx_ip = `dig +short $my_mxrecord`;
chomp @my_mx_ip;
foreach $my_ip_record (@my_mx_ip) {
$my_ip_record = lc($my_ip_record);
next if exists $myignores{"$my_ip_record"};
$myservers{"$my_ip_record"} = "$my_ip_record"
if ( valid_ip4($my_ip_record) || valid_ip6($my_ip_record) );
}
}
}
if ( $myownspfline =~ /\ba\b/i ) {
@my_A = `dig A $myzone +short`;
chomp @my_A;
foreach $my_Arecord (@my_A) {
$my_Arecord = lc($my_Arecord);
next if exists $myignores{"$my_Arecord"};
$myservers{"$my_Arecord"} = "$my_Arecord"
if ( valid_ip4($my_Arecord) || valid_ip6($my_Arecord) );
}
}
}
sub entries {
( my $size, my $ips ) = @_;
@ips = @$ips;
$size = 500 if $size > 500;
my $algorithm = 'retry';
my $bucketizer = Algorithm::Bucketizer->new(
bucketsize => $size,
algorithm => $algorithm
);
foreach my $ip (@ips) {
$spf{"$ip"} = length("$ip");
$bucketizer->add_item( $ip, length("$ip") + 1 );
}
my @buckets = $bucketizer->buckets();
my @Items = $bucketizer->items();
$bucketizer->optimize( algorithm => "random", maxrounds => 1000 );
for $href (@buckets) {
for $role ( keys %$href ) {
next unless $role eq "items";
my $ipbucks = $href->{$role} if $role eq "items";
open my $fh, '>', \$dnsline or die "Can't open variable: $!";
print $fh "@$ipbucks", "\n" if $role eq "items";
push @dnsentries, $dnsline;
}
}
chomp @dnsentries;
$dnsentries = \@dnsentries;
return $dnsentries;
}
sub valid_ip4 {
my $input = shift;
return 1
if $input =~ /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}
([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/x;
return 1
if $input =~ /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}
([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$/x;
return 0;
}
sub valid_ip6 {
my $input = shift;
return 1
if $input =~
/^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:)
{6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)
(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}
(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)
(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}
(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:
((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|
:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|
((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)
(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}
(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:
((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|
(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|
((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)
(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|
((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)
(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*/x;
return 1
if $input =~
/^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}
(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|
[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:
((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|
(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:
((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|
(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:
((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|
(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:
((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|
(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:
((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|
(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d
|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*
(\/(d|dd|1[0-1]d|12[0-8]))$/x;
return 0;
}
sub getit {
my $domain = shift;
my @foo = `dig TXT $domain`;
my @results = ();
foreach (@foo) {
next if not /$domain.*TXT/;
s/$domain.*TXT.*"v=spf1/i/;
@results = split /\s+/;
my @mx = ();
if ( grep( /^MX$/i, @results ) ) {
@mx = `dig mx $domain +short`;
s/(^.*?)\s+(.*?)/$2/g for @mx;
foreach $mxrecord (@mx) {
my @mx_ip = ();
@mx_ip = `dig +short $mxrecord`;
chomp @mx_ip;
foreach $ip_record (@mx_ip) {
push @digs, $ip_record
if ( valid_ip4($ip_record) || valid_ip6($ip_record) );
}
}
}
@A = ();
if ( grep( /^A$/i, @results ) ) {
@A = `dig A $domain +short`;
foreach $Arecord (@A) {
$Arecord =~ s/\n//g;
push @digs, $Arecord
if ( valid_ip4($Arecord) || valid_ip6($Arecord) );
}
}
foreach (@results) {
next if /-all/;
push @digs, "$_";
if (/include:/) {
s/include://;
getit($_);
}
}
}
chomp @digs;
$digs = \@digs;
return $digs;
}
sub make_pretty {
my $raw_array = shift;
my @raw = @$raw_array;
for my $i ( 0 .. $#raw ) {
if ( $raw[$i] =~ m/^ip[4,6]:.*?$\"/i && $raw[ $i + 1 ] =~ /^\"/i ) {
$raw[$i] = $raw[$i] . $raw[ $i + 1 ];
$raw[$i] =~ s/\"//g;
}
$raw[$i] =~ s/(^ip[4,6]:)(.*?)/$2/gi;
$raw[$i] = undef
unless ( valid_ip4( $raw[$i] ) || valid_ip6( $raw[$i] ) );
}
@raw = grep defined, @raw;
$pid = open2( \*Reader, \*Writer, "$iprange" );
foreach $k (@raw) { print Writer $k, "\n" if valid_ip4($k); }
close Writer;
@ip4 = <Reader>;
close Reader;
chomp @ip4;
foreach $k (@raw) { push @raw_ip6, lc($k) if valid_ip6($k); }
my %hash = map { $_, 1 } @raw_ip6;
my @ip6 = keys %hash;
foreach $ip4 (@ip4) {
next if exists $myignores{"$ip4"};
next if exists $myservers{"$ip4"};
push @return_ips, 'ip4:' . $ip4;
}
foreach $ip6 (@ip6) {
next if exists $myignores{"$ip6"};
next if exists $myservers{"$ip6"};
push @return_ips, 'ip6:' . $ip6;
}
$iplist = \@return_ips;
return $iplist;
}
sub get_zone_id {
( my $email, my $key, my $zone ) = @_;
my $json_return = $furl->get(
"$basecloud\?name=$zone",
[
'X-Auth-Email' => "$email",
'X-Auth-Key' => "$key",
'Content-Type' => "application\/json"
],
);
my %json_hash = %$json_return;
my $decoded = decode_json( $json_hash{"content"} );
print Dumper $decoded if $debug_prog;
%$decoded{"success"} or die "Couldn't get id for $zone_id !";
foreach my $result ( @{ $decoded->{"result"} } ) {
foreach my $resultkey ( keys %$result ) {
return %$result{"$resultkey"} if $resultkey eq "id";
}
}
}
sub get_subdomain_id {
( my $email, my $key, my $zone, my $local_zone_id ) = @_;
my $json_return = $furl->get(
"$basecloud\/$local_zone_id\/dns_records\?name=$zone\&type=TXT",
[
'X-Auth-Email' => "$email",
'X-Auth-Key' => "$key",
'Content-Type' => "application\/json"
],
);
my %json_hash = %$json_return;
my $decoded = decode_json( $json_hash{"content"} );
my $has_spf_record = 0;
print Dumper $decoded if $debug_prog;
%$decoded{"success"}
or die "Couldn't get subdomain id for $zone !";
return "nonexistent" unless scalar @{ $decoded->{"result"} };
foreach my $result ( @{ $decoded->{"result"} } ) {
if ( defined %$result{"content"} && %$result{"content"} =~ /v=spf/ ) {
return %$result{"id"}
if defined %$result{"id"}
or die "Trouble returning subdomain id for $zone !";
$has_spf_record = 1;
}
else { next; }
}
return "nonexistent" unless $has_spf_record;
}
sub put_dns_change {
(
my $email, my $key, my $zone,
my $sub_zone_id,
my $record_name,
my $recordcontent
) = @_;
my $json_data = {
'id' => "$zone",
'type' => "TXT",
'name' => "$record_name",
'content' => "$recordcontent"
};
my $json_form_data = encode_json($json_data);
my $json_return = $furl->request(
method => "PUT",
url => "$basecloud\/$zone\/dns_records\/$sub_zone_id",
headers => [
'X-Auth-Email' => "$email",
'X-Auth-Key' => "$key",
'Content-Type' => "application\/json"
],
content => "$json_form_data"
);
my %json_hash = %$json_return;
my $decoded = decode_json( $json_hash{"content"} );
print Dumper $decoded if $debug_prog;
%$decoded{"success"} or die "Couldn't change TXT record for $record_name !";
return $record_name;
}
sub make_new_dns_record {
( my $email, my $key, my $zone, my $record_name, my $recordcontent ) = @_;
my $json_data = {
'id' => "$zone",
'type' => "TXT",
'name' => "$record_name",
'content' => "$recordcontent"
};
my $json_form_data = encode_json($json_data);
my $json_return = $furl->request(
method => "POST",
url => "$basecloud\/$zone\/dns_records",
headers => [
'X-Auth-Email' => "$email",
'X-Auth-Key' => "$key",
'Content-Type' => "application\/json"
],
content => "$json_form_data"
);
my %json_hash = %$json_return;
my $decoded = decode_json( $json_hash{"content"} );
print Dumper $decoded if $debug_prog;
%$decoded{"success"} or die "Couldn't add TXT record for $record_name !";
return $record_name;
}
sub delete_dns_record {
( my $email, my $key, my $zone, my $sub_zone_id, my $record_name ) = @_;
my $json_return = $furl->request(
method => "DELETE",
url => "$basecloud\/$zone\/dns_records\/$sub_zone_id",
headers => [
'X-Auth-Email' => "$email",
'X-Auth-Key' => "$key",
'Content-Type' => "application\/json"
]
);
my %json_hash = %$json_return;
my $decoded = decode_json( $json_hash{"content"} );
print Dumper $decoded if $debug_prog;
return $record_name if %$decoded{"success"};
return "nonexistent" unless scalar @{ $decoded->{"result"} };
}
sub log_it {
open LOG, ">>$logfile";
$logtime = localtime;
if ( @{ $_[1] } ) {
for $loglines ( @{ $_[1] } ) {
$printline = $loglines;
chomp $printline;
print LOG $logtime . " " . $printline . "\n";
}
}
print LOG $logtime . " " . $_[0] . "\n";
close LOG;
}
|
./despf.sh et._spf.pardot.com | ./normalize.sh | ./simplify.sh gives
ip4:13.111.0.0/24
ip4:13.111.1.0/24
ip4:13.111.2.0/24
ip4:13.111.3.0/24
ip4:136.147.135.0/24
ip4:136.147.176.0/24
ip4:136.147.182.0/24
ip4:198.245.81.0/24
ip4:199.122.123.188/30
ip4:199.122.123.192
This correct but not consolidated. It should be merged properly as follows:
13.111.0.0/22
136.147.135.0/24
136.147.176.0/24
136.147.182.0/24
198.245.81.0/24
199.122.123.188/30
199.122.123.192
The text was updated successfully, but these errors were encountered: