#!/bin/bash

# IPFire network object creator for IPv4 addresses based on ASN information
# Creates 'customnetworks' objects in /var/ipfire/fwhosts/customnetworks
# Creates 'customgroups' objects in /var/ipfire/fwhosts/customgroups

# Version: 0.3.2
# Last updated: May 5 2017
# Author: Mike Kuketz, maloe (Function: consolidateNetblocks)
# Visit: www.kuketz-blog.de

##############
# Edit here  #
##############
# Define companys
# For example: company_array=(Google Facebook COMPANY)
company_array=(Google Facebook)

# Path to IPFire customnetworks|customgroups 
customnetworks=/var/ipfire/fwhosts/customnetworks
customgroups=/var/ipfire/fwhosts/customgroups

##############
# Functions  #
##############
# Convert CIDR notation (eg. 192.168.0.0/24) of a subnetmask to dotted decimal form (255.255.255.0)
cdr2mask ()
{
	# Number of args to shift, 255..255, first non-255 byte, zeroes
	set -- $(( 5 - ($1 / 8) )) 255 255 255 255 $(( (255 << (8 - ($1 % 8))) & 255 )) 0 0 0
	[ $1 -gt 1 ] && shift $1 || shift
	echo ${1-0}.${2-0}.${3-0}.${4-0}
}
# Read the file in parameter and fill the array named "array"
getArray() {
	array=() # Create array
	while IFS= read -r line # Read a line
	do
		array+=("$line") # Append line to the array
	done < "$1"
}

# Consolidate adjacent and overlapping netblocks
consolidateNetblocks() {
	infile=$1
	if [ -f $infile ]
	then
		# Create temporary file
		tempfile=temp_consolidateNetblocks.tmp
		touch $tempfile > $tempfile
				
		maxline=`cat $infile | wc -l`

		if [ $maxline -gt 1 ]
		then
			# Format: firstIP suffix lastIP CIDR  # Sorted by firstIP, suffix
			cat $infile | sed -e 's/\//\./' | awk -F"." '{ printf "%d %d %d %d.%d.%d.%d/%d\n", $1 * 2^24 + $2 * 2^16 + $3 * 2^8 + $4, $5, $1 * 2^24 + $2 * 2^16 + $3 * 2^8 + $4 + 2^(32 - $5), $1, $2, $3, $4, $5 }' | sort -n -k1,1 -k2,2 > $tempfile

			# Find redundant netblocks
			n=1
			lastIP=`awk 'NR == '$n' { printf "%d\n", $3 }' $tempfile` 
			n=$[$n+1]

			maxline=`cat $tempfile | wc -l`

			# Loop through file
			while [ $n -le $maxline ]
			do
				act_lastIP=`awk 'NR == '$n' {printf "%d\n", $3 }' $tempfile`

				# If lastIP is smaller than lastIP of previous line then this IPrange is already covered 
				if [ $act_lastIP -gt $lastIP ]
				then
					# Next highest lastIP
					lastIP=$act_lastIP
				else
					# Mark lines as redundant
					sed -i "$n s/$/ #redundant/" $tempfile
				fi
				n=$[$n+1] 
			done

			# Write changes
			# Remove lines marked as #redundant
			sed -i '/#redundant/d' $tempfile
			# CIDR format only
			sed -i 's/^.* \([0-9].*[0-9]\).*$/\1/' $tempfile
			# Return result
			cat $tempfile > $infile

			# Count redundants
			newmaxline=`cat $tempfile | wc -l`
			echo "---[$[$maxline - $newmaxline] from $maxline networks removed]---"
		else
			# None or only 1 netblock 
			echo "---[Nothing to do (none or only 1 network)]---"
		fi
				
	# Clean up
	rm $tempfile	
	
	fi
}
##################
# Prepare files  #
##################
# Cleanup all existing objects
for company in "${company_array[@]}"
do
	sed -i "/$company-Network/d" $customnetworks
	sed -i "/$company-Network/d" $customgroups
done

# Get highest number from existing objects in [customnetworks|customgroups]
network_object_number=$(cat $customnetworks | cut -f1 -d',' | awk '{for(i=1;i<=NF;i++) 
if($i>maxval) maxval=$i;}; END { print maxval;}')
group_object_number=$(cat $customgroups | cut -f1 -d',' | awk '{for(i=1;i<=NF;i++) 
if($i>maxval) maxval=$i;}; END { print maxval;}')
# Increase counter
network_object_number=$[$network_object_number +1]
group_object_number=$[$group_object_number +1]

################
# Do the magic #
################
# Loop through 'company_array'
for company in "${company_array[@]}"
do
	# Get all company ASNs
	echo "---[Get all $company ASNs]---"
	curl --silent "https://www.ultratools.com/tools/asnInfoResult?domainName=${company}" | grep -Eo 'AS[0-9]+' > asn.txt

	# Create 'asn_array'
	getArray "asn.txt"
	asn_array=("${array[@]}")   
	counter=1

	touch nets.txt > nets.txt

	# Loop through 'asn_array' 
	for asn in "${asn_array[@]}"
	do
		# Store networks from ASN in file
		echo "---[Get $company networks for $asn]---"
		curl --silent "https://stat.ripe.net/data/announced-prefixes/data.json?preferred_version=1.1&resource=${asn}" | grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}' | uniq >> nets.txt
	done
        
	# Consolidate adjacent and overlapping netblocks
	echo "---[Remove adjacent and overlapping netblocks]---"
	consolidateNetblocks "nets.txt"

	# Create NETWORK array
	getArray "nets.txt"
	echo "---[Creating IPFire objects for $company networks]---"

	# Loop through NETWORK array
	for net in "${array[@]}"
	do
		# Seperate IP and netmask
		ip=${net%/*}
		netmask=${net#*/}
		# Write new objects to files [customnetworks|customgroups]                
		printf "$network_object_number,$company-Network Nr.$counter,$ip,$(cdr2mask $netmask),\n" >> $customnetworks
		printf "$group_object_number,$company,,$company-Network Nr.$counter,Custom Network,\n" >> $customgroups
		# Increase counter
		network_object_number=$[$network_object_number +1]
		group_object_number=$[$group_object_number +1]
		counter=$[$counter +1]
	done
done

####################
# Still work to do #
####################

# Restart firewall
/etc/init.d/firewall restart

# Clean up
echo "---[Doing cleanup]---"
rm asn.txt
rm nets.txt

# Ready
echo "---[All done!]---"
