#!/usr/bin/env python
"""	Copyright (C) 2005 Luke Kenneth Casson Leighton <lkcl@lkcl.net>

	This program takes firewall builder .fwb scripts, chews the
	XML and spits forth HTML.  It was written because there is
	a curious lack of reporting and print options in fwbuilder,
	which, in my mind, makes an extremely good program completely
	useless: no program as otherwise-comprehensive and important
	as fwbuilder should be without a damn print option!

	If this program breaks things for you: tough.  If it doesn't
	provide all the information you wanted: tough.  If you make
	mistakes in your firewall because you relied on this program
	instead of doing your job: tough.  If you cannot accept
	responsibility for these things, DON'T use this program,
	and certainly keep away from me: I don't like people who can't
	accept responsibility for their lives, decisions or lack of.

	Warnings having been said: those people who find this program
	to be useful: if you can think of ways to improve it, if
	you like it, want it to do something better, or _have_
	improved it, I would love to hear from you.

	P.S. you might have noticed i have a strange taste in colours,
	which is why i added a css/text section.  feel free to burn
	your eyes out with your own evil colour schemes.
"""

# yes you will need python-xml libraries...
from xml.dom.minidom import parseString, parse


class fw:

	def __init__(self):
		
		self.hosts = {}
		self.descriptions = {}

	def print_comment(self, c):
		print '<pre>'
		for l in c.split("\\n"):
			while l:
				bp = l.find(' ', 50)
				if bp < 50: bp = 50
				if len(l) >= 50:
					end = l.rfind(' ')
					if end <= 50:
						bp = end
				print "%s" % l[:bp]
				l = l[bp:]
		print '</pre>'

		
	def decode_address_ranges(self, i):
		adrs = []
		print '<table class="tabledataindent">'
		for a in i:
			print '<tr class="tablerow" valign="top">'
			self.descriptions[a.getAttribute('id')] = a.getAttribute('name')
			print """
				<td> %s: </td>
				<td> %s </td>
				<td> %s </td>
				""" % \
				(a.getAttribute('name'),
				 a.getAttribute('start_address'),
				 a.getAttribute('end_address'))

			comment = a.getAttribute('comment')
			if comment:
				print '</tr>'
				print '<tr class="tablerow" valign="top">'
				print '<td> </td>'
				print '<td colspan="2">'
				self.print_comment(comment)
				print '</td>'
			print '</tr>'
		print '</table>'

	def decode_ipv4(self, i):
		adrs = []
		print '<table class="tabledataindent">'
		for a in i:
			self.descriptions[a.getAttribute('id')] = a.getAttribute('name')
			print '<tr class="tablerow" valign="top">'
			print "<td>%s: </td> <td>%s/%s</td>" % \
				(a.getAttribute('name'), a.getAttribute('address'), a.getAttribute('netmask'))
			print "</tr>"
			comment = a.getAttribute('comment')
			if comment:
				print '</tr>'
				print '<tr class="tablerow" valign="top">'
				print '<td> </td>'
				print '<td colspan="2">'
				self.print_comment(comment)
				print '</td>'
			print '</tr>'
		print '</table>'

	def decode_interface(self, i):
		self.descriptions[i.getAttribute('id')] = i.getAttribute('name')
		
		print '<tr class="tablerow" valign="top">'
		print "<td>Interface: %-8s </td> <td> %s </td>" % \
			(i.getAttribute('name'), i.getAttribute('label'))
		print "<td>"
		self.decode_ipv4(i.getElementsByTagName('IPv4'))
		print "</td>"
		print "</tr>"
		
	def get_desc(self, id):
		if type(id) is not list:
			id = [id]
		l = []
		for i in id:
			l.append(self.descriptions.get(i, "<unknown: %s>" % str(i)))
		return '<br />'.join(l)

	def decode_host(self, h):
		self.descriptions[h.getAttribute('id')] = h.getAttribute('name')

		print "<td>"

		print '<table class="tabledata">'
		print '<tr class="tablerow" valign="top"><td>'
		print "Hostname: <br /> %s" % h.getAttribute('name')
		print "</td></tr>"
		print '</table>'

		print "</td>"

		print "<td>"

		print '<table class="tabledata">'
		for i in h.getElementsByTagName('Interface'):
			self.decode_interface(i)
		print '</table>'

		print "</td>"
		
	def decode_hosts(self, o):

		print '<table class="tabledataindent">'
		hl = o.getElementsByTagName('Host')
		for h in hl:
			print '<tr class="tablerow" valign="top">'
			self.decode_host(h)
			print '</tr>'
		print '</table>'

	def decode_svc_icmp(self, t):

		self.descriptions[t.getAttribute('id')] = t.getAttribute('name')
		print """
			<tr class="section">

				<td class="name">	Name: %-10s </td>
				<td class="item">	Code: %s </td>
				<td class="item">	Type: %s </td>
			</tr>
			""" % \
			(t.getAttribute('name'),
			t.getAttribute('code'),
			t.getAttribute('type'))

	def decode_svc_tcp(self, t):

		self.descriptions[t.getAttribute('id')] = t.getAttribute('name')

		start = int(t.getAttribute('dst_range_start'))
		end = int(t.getAttribute('dst_range_end'))

		if start == end:
			dest = '%d' % start
		else:
			dest = '%d-%d' % (start, end)

		print """
			<tr class="section">

				<td class="name">	Name: %-10s </td>
				<td class="item">	Dest: %s </td>
			</tr>
			""" % \
			(t.getAttribute('name'), dest)

	def print_heading(self, sh):

		print '<table class="heading">'
		print '<tr><td>'
		print sh
		print '</td></tr>'
		print '</table>'

	def print_subheading(self, sh, comment=''):

		print '<table>'
		print '<tr><td>'

		print '<table class="subheading">'
		print '<tr><td>'
		print sh
		print '</td></tr>'
		print '</table>'

		print '</td></tr>'

		print '<tr>'
		print '<td>'
		print '<div class="subindented">' 
		self.print_comment(comment)
		print '</div>'
		print '</td>'
		print '</tr>'

		print '</table>'


	def decode_svc_group_members(self, i):

		print '<table class="tabledataindent">'
		for a in i:
			print '<tr class="tablerow" valign="top">'
			print """
				<td> %s </td>
				""" % self.descriptions[a] 
			print '</tr>'
		print '</table>'

	def decode_svc_grp(self, h):
		self.descriptions[h.getAttribute('id')] = h.getAttribute('name')
		self.print_subheading("Service Group: %s" % h.getAttribute('name'),
		                      h.getAttribute('comment'))
		print '<div class="indented">'
		l = []
		for n in h.getElementsByTagName('ServiceRef'):
			l.append(n.getAttribute('ref'))
		self.decode_svc_group_members(l)
		print '</div>'
		
	def decode_service_groups(self, o):

		ts = o.getElementsByTagName('ServiceGroup')
		self.print_subheading("Service Groups")
		print '<div class="subindented">'
		for t in ts:
			n = t.getAttribute('name')
			if n == 'Groups':
				for g in t.getElementsByTagName('ServiceGroup'):
					self.decode_svc_grp(g)
		print '</div>'

	def decode_services(self, o):

		ts = o.getElementsByTagName('UDPService')
		self.print_subheading("UDP Services")
		print '<table class="tabledataindent">'
		for t in ts:
			self.decode_svc_tcp(t)
		print '</table>'

		ts = o.getElementsByTagName('TCPService')
		self.print_subheading("TCP Services")
		print '<table class="tabledataindent">'
		for t in ts:
			self.decode_svc_tcp(t)
		print '</table>'

		ts = o.getElementsByTagName('ICMPService')
		self.print_subheading("ICMP Services")
		print '<table class="tabledataindent">'
		for t in ts:
			self.decode_svc_icmp(t)
		print '</table>'

	def get_srvref(self, c, ref):
		r = c.getElementsByTagName(ref)
		ans = []
		for n in r[0].getElementsByTagName('ServiceRef'):
			ans.append(n.getAttribute('ref'))
		return ans

	def get_ref(self, c, ref):
		r = c.getElementsByTagName(ref)
		ans = []
		for n in r[0].getElementsByTagName('ObjectRef'):
			ans.append(n.getAttribute('ref'))
		return ans

	def decode_policyrule(self, nr):

		print '<tr class="tablerow" valign="top">'

		print '<td> %s </td>' % nr.getAttribute('action')

		comment = nr.getAttribute('comment')
		print '<td>'
		self.print_comment(comment)
		print '</td>'

		src = self.get_ref(nr, 'Src')
		dst = self.get_ref(nr, 'Dst')
		srv = self.get_srvref(nr, 'Srv')

		print """<td>
			
			    <table class="tabledata">
				<tr class="tablerow" valign="top"> <td> Src: </td> <td> %s  </td> </tr>
				<tr class="tablerow" valign="top"> <td> Dest: </td> <td> %s  </td> </tr>
				<tr class="tablerow" valign="top"> <td> Service: </td> <td> %s </td> </tr>
			    </table>
			</td>
			""" % \
			(self.get_desc(src),
			 self.get_desc(dst),
			 self.get_desc(srv))
	
		print '</tr>'

	def decode_natrule(self, nr):

		print '<tr class="tablerow" valign="top">'

		comment = nr.getAttribute('comment')
		print '<td>'
		self.print_comment(comment)
		print '</td>'

		osrc = self.get_ref(nr, 'OSrc')
		odst = self.get_ref(nr, 'ODst')
		osrv = self.get_srvref(nr, 'OSrv')
		tsrc = self.get_ref(nr, 'TSrc')
		tdst = self.get_ref(nr, 'TDst')
		tsrv = self.get_srvref(nr, 'TSrv')

		print """
		<td>
		    <table class="tabledata">
			<tr class="tablerow" valign="top"> <td> Original Src: </td> <td> %s  </td> </tr>
			<tr class="tablerow" valign="top"> <td> Original Dest: </td> <td> %s  </td> </tr>
			<tr class="tablerow" valign="top"> <td> Original Service: </td> <td> %s </td> </tr>
		    </table>
		</td>
			""" % \
			(self.get_desc(osrc),
			 self.get_desc(odst),
			 self.get_desc(osrv))

		print """
		<td>
			
		    <table class="tabledata">
			<tr class="tablerow" valign="top"> <td> Target Src: </td> <td> %s  </td> </tr>
			<tr class="tablerow" valign="top"> <td> Target Dest: </td> <td> %s  </td> </tr>
			<tr class="tablerow" valign="top"> <td> Target Service: </td> <td> %s </td> </tr>
		    </table>
		</td>
			""" % \
			(self.get_desc(tsrc),
			 self.get_desc(tdst),
			 self.get_desc(tsrv))

		print '</tr>'

	def decode_fw_interface(self, n):
		self.print_subheading("Interface: %s" % n.getAttribute('name'),
		                      n.getAttribute('comment'))

		print '<table class="tabledataindent">'
		for pr in n.getElementsByTagName('PolicyRule'):
			self.decode_policyrule(pr)
		print '</table>'

	def decode_policy(self, n):
		self.print_subheading("Policy:")
		print '<table class="tabledataindent">'
		for nr in n.getElementsByTagName('PolicyRule'):
			self.decode_policyrule(nr)
		print '</table>'

	def decode_nat(self, n):
		self.print_subheading("NAT:")
		print '<table class="tabledataindent">'
		for nr in n.getElementsByTagName('NATRule'):
			self.decode_natrule(nr)
		print '</table>'

	def decode_group_members(self, i):

		print '<table class="tabledataindent">'
		for a in i:
			print '<tr class="tablerow" valign="top">'
			print """
				<td> %s </td>
				""" % self.descriptions[a] 
			print '</tr>'
		print '</table>'

	def decode_group(self, h):
		self.descriptions[h.getAttribute('id')] = h.getAttribute('name')
		self.print_subheading("Group: %s" % h.getAttribute('name'),
		                      h.getAttribute('comment'))
		print '<div class="indented">'
		l = []
		for n in h.getElementsByTagName('ObjectRef'):
			l.append(n.getAttribute('ref'))
		self.decode_group_members(l)
		print '</div>'
		
	def decode_groups(self, h):
		print '<div class="indented">'
		for n in h.getElementsByTagName('ObjectGroup'):
			self.decode_group(n)
		print '</div>'
		
	def decode_firewall(self, h):
		self.print_subheading("Firewall: %s" % h.getAttribute('name'))
		print '<div class="indented">'
		for n in h.getElementsByTagName('Interface'):
			self.decode_interface(n)
		for n in h.getElementsByTagName('Policy'):
			self.decode_policy(n)
		for n in h.getElementsByTagName('NAT'):
			self.decode_nat(n)
		for n in h.getElementsByTagName('Interface'):
			self.decode_fw_interface(n)
		print '</div>'
		
	def decode_firewalls(self, o):

		hl = o.getElementsByTagName('Firewall')
		for fw in hl:
			self.decode_firewall(fw)

if __name__ == '__main__':

	from sys import argv

	fd = open(argv[1], "r")
	doc = parse(fd)

	f = fw()

	print "<html>"
	print """
<style type="text/css">
.tabledataindent
{
        color: #000000;
	background: #aaffaa;
	border-color: #000000 #999999 #999999 #000000;
	border-style: solid;
	border-top-width: 1px;
	border-right-width: 1px;
	border-bottom-width: 1px;
	border-left-width: 1px;
	margin-left: 40px;
}
.tablerow
{
        color: #000000;
	background: #ccffcc;
	border-color: #000000 #999999 #999999 #000000;
	border-style: solid;
	border-top-width: 1px;
	border-right-width: 1px;
	border-bottom-width: 1px;
	border-left-width: 1px;
}
.tabledata
{
        color: #000000;
	background: #ccffcc;
}
.heading
{
	font-size: 20;
	font-family: Verdana, Arial, Helvetica, sans-serif;
	color: #000000;
	background: #aaaaff;
	margin-top: 40px;
	margin-bottom: 10px;
	border-style: solid;
	border-top-width: 1px;
	border-right-width: 1px;
	border-bottom-width: 1px;
	border-left-width: 1px;
}
.subheading
{
	font-size: 15;
	font-family: Verdana, Arial, Helvetica, sans-serif;
	color: #000000;
	background: #ccccff;
	margin-top: 15px;
	margin-left: 20px;
	margin-right: 20px;
	border-style: solid;
	border-top-width: 1px;
	border-right-width: 1px;
	border-bottom-width: 1px;
	border-left-width: 1px;
}
.indented
{
	margin-left: 40px;
}
.subindented
{
	margin-left: 20px;
	margin-bottom: 10px;
}
</style>
	"""
	print "<body>"

	lib = doc.getElementsByTagName('Library')
	f.descriptions['sysid0'] = 'Any Network'
	f.descriptions['sysid1'] = 'Any IP Service'

	svcs = doc.getElementsByTagName('ServiceGroup')

	for o in svcs:
		n = o.getAttribute('name')
		if n == 'Services':
			f.print_heading(n)
			f.decode_services(o)

	for o in svcs:
		n = o.getAttribute('name')
		if n == 'Services':
			f.decode_service_groups(o)

	objs = doc.getElementsByTagName('ObjectGroup')

	for o in objs:
		n = o.getAttribute('name')

		if n == 'Hosts':
			f.print_heading(n)
			f.decode_hosts(o)

		if n == 'Address Ranges':
			f.print_heading(n)
			f.decode_address_ranges(o.getElementsByTagName('AddressRange'))

		if n == 'Addresses':
			f.print_heading(n)
			f.decode_ipv4(o.getElementsByTagName('IPv4'))
			print

	for o in objs:
		n = o.getAttribute('name')
		if n == 'Groups':
			f.print_heading(n)
			f.decode_groups(o)
			print

	for o in objs:
		n = o.getAttribute('name')
		if n == 'Firewalls':
			f.print_heading(n)
			f.decode_firewalls(o)
			print

	print "</body>"
	print "</html>"
