3 # This script will generate a formatted report based on the data
4 # produced by Passive Real-time Asset Detection System (PRADS).
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 # TODO: ARP (mac, date)
23 # TODO: SERVICE/CLIENT port/service/application
36 assetlogfile
= 'prads-asset.log'
38 def wait_channel(channel
):
40 read_fds
, write_fds
= channel
.getsock()
41 if not read_fds
and not write_fds
:
43 timeout
= channel
.timeout()
45 channel
.process_fd(pycares
.ARES_SOCKET_BAD
, pycares
.ARES_SOCKET_BAD
)
47 rlist
, wlist
, xlist
= select
.select(read_fds
, write_fds
, [], timeout
)
49 channel
.process_fd(fd
, pycares
.ARES_SOCKET_BAD
)
51 channel
.process_fd(pycares
.ARES_SOCKET_BAD
, fd
)
53 def lookup_dns(address
):
55 ai
= socket
.getaddrinfo(address
, None)
59 # print("address %s error: %s" % address, )
61 def lookup_reversedns(address
):
63 ha
= socket
.gethostbyaddr(address
)
69 def lookup_dns(channel
, address
, reverse
=False, ip6
=False):
70 def cb(results
, error
):
71 print("Should add this to queue: ")
76 channel
.gethostbyaddr6(address
, cb
)
78 channel
.gethostbyname(address
, socket
.AF_INET6
, cb
)
81 channel
.gethostbyaddr(address
, cb
)
83 channel
.gethostbyname(address
, socket
.AF_INET
, cb
)
87 def cb(result
, error
):
90 channel
= pycares
.Channel()
91 channel
.gethostbyname('google.com', socket
.AF_INET
, cb
)
92 channel
.query('google.com', pycares
.QUERY_TYPE_A
, cb
)
93 channel
.query('sip2sip.info', pycares
.QUERY_TYPE_SOA
, cb
)
97 def match_serviceline(line
):
98 m
= validpartial
.match(line
)
104 return "unknown", "unknown", 0, 0, 1
106 if __name__
== '__main__':
110 # asset,vlan,port,proto,service,[service-info],distance,discovered
111 validline
= re
.compile('^([\w\.:]+),([\d]{1,4}),([\d]{1,5}),([\d]{1,3}),(\S+?),\[(.*)\],([\d]{1,3}),(\d{10})')
112 validpartial
= re
.compile('^\[(.*)\],([\d]{1,3}),(\d{10})')
114 fpinfo
= re
.compile('^SYN')
115 #Invalid match on S20:58:1:60:M1452,S,T,N,W7:.:unknown:unknown:link:pppoe (DSL):uptime:184hrs
116 validsyn
= re
.compile(':[\d]{2,4}:\d:.*:.*:.*:(\w+):(.*):link')
118 validservice
= re
.compile('^(\w+):(.*)$')
122 # ARP => [ $mac, $discovered, $vendor ],
124 # TCP => [ $port, $service, $app, $discovered ]
128 # m = liner.match("85.105.159.158,0,33372,6,SYN,[S4:53:1:60:M1452,S,T,N,W1:.:Linux:2.6, seldom 2.4 (older, 2):link:pppoe (DSL):uptime:154hrs],11,1429563367")
133 with
open(assetlogfile
) as file:
136 ip
, vlan
, sport
, proto
, service
= l
[0:5]
137 s_info
, distance
, discovered
= '','',''
144 if fpinfo
.match(service
):
145 smatch
= match_serviceline(','.join(l
[5:]))
146 s_info
, distance
, discovered
= smatch
147 fp
= s_info
.split(':')
148 os
,details
= fp
[6], fp
[7]
149 if service
== 'SERVER' or service
== 'CLIENT':
150 ms
= validservice
.match(s_info
)
152 service_nfo
= ms
.group(1)
153 #ARP (info, discovered, vendor) ICMP,
156 if service
not in asset
[ip
]:
157 asset
[ip
][service
] = [ (proto
, sport
, service
, s_info
, discovered
, distance
, os
, details
)]
159 asset
[ip
][service
].append( (proto
, sport
, service
, s_info
, discovered
, distance
, os
, details
) )
161 # now iterate over all assets and dump them
162 for ip
in sorted(asset
.keys()):
163 host
= lookup_reversedns(ip
)
165 print("DNS: %s" % (host
))
166 fwdip
= lookup_dns(host
)
170 print(" (dnswall: no such domain)")
172 print(" (%s)" % fwdip
)
173 revhost
= lookup_reversedns(fwdip
)
175 print("[%s]" % revhost
)
177 # and now the prads data..
178 os
, desc
, confidence
, timestamp
, flux
= guess_os(asset
[ip
])
179 #print("OS: %s %s (%s%%) %s" % (os,desc,confidence,flux))