Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
epsylon
GitHub Repository: epsylon/ufonet
Path: blob/master/core/ajaxmap.py
1205 views
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-"
3
"""
4
This file is part of the UFONet project, https://ufonet.03c8.net
5
6
Copyright (c) 2013/2020 | psy <[email protected]>
7
8
You should have received a copy of the GNU General Public License along
9
with UFONet; if not, write to the Free Software Foundation, Inc., 51
10
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
11
"""
12
import socket, threading, re, os, time, base64, traceback
13
import webbrowser, subprocess, json, sys, shlex
14
import urllib.request, urllib.error
15
from urllib.parse import urlparse as urlparse
16
from .main import UFONet
17
try:
18
import pygeoip
19
except:
20
print("\n[Error] [AI] Cannot import lib: pygeoip. \n\n To install it try:\n\n $ 'sudo apt-get install python3-geoip libgeoip-dev libgeoip1'\n")
21
sys.exit(2)
22
23
class AjaxMap(object):
24
def __init__(self):
25
self.geo_db_mirror1 = 'https://turina.space/bordercheck/maps.tar.gz' # Turina Server
26
self._geoip=None
27
self._geoasn=None
28
self._geoipstatus='nomap'
29
self._err=''
30
ufonet = UFONet()
31
ufonet.create_options()
32
try:
33
self.zombies = ufonet.extract_zombies()
34
aliens_army = ufonet.extract_aliens()
35
droids_army = ufonet.extract_droids()
36
ucavs_army = ufonet.extract_ucavs()
37
rpcs_army = ufonet.extract_rpcs()
38
self.zombies.extend(aliens_army)
39
self.zombies.extend(droids_army)
40
self.zombies.extend(ucavs_army)
41
self.zombies.extend(rpcs_army)
42
except:
43
return
44
45
def get_err(self):
46
return self._err
47
48
# check for geoip data status
49
# basic lock file mechanism to avoid multiple downloads
50
def get_status(self):
51
if os.path.exists('maps.downloading'):
52
if not os.path.exists('maps.downloadmsg'):
53
f=open("maps.downloadmsg","wb")
54
f.write("".encode('utf-8'))
55
f.close()
56
print("[Info] [AI] [Control] GeoIP data download started! -> [OK!]\n")
57
self._geoipstatus='downloading'
58
elif os.path.isdir('maps'):
59
if self._geoip == None :
60
self._geoip = pygeoip.GeoIP('maps/GeoLiteCity.dat')
61
if self._geoasn == None :
62
self._geoasn = pygeoip.GeoIP('maps/GeoIPASNum.dat')
63
if os.path.exists("maps.downloadmsg") :
64
os.remove("maps.downloadmsg")
65
self._geoipstatus='ok'
66
return self._geoipstatus
67
68
def retrieve(self,url,name):
69
try:
70
handle = urllib.request.urlopen(url)
71
CHUNK = 16384
72
with open(name,'wb') as fp:
73
while True:
74
chunk = handle.read(CHUNK)
75
if not chunk:
76
break
77
fp.write(chunk)
78
except:
79
traceback.print_exc()
80
81
def download_maps(self):
82
# generate geolocation values on a map
83
if self.get_status() != 'nomap':
84
return self._geoipstatus == 'ok'
85
if os.path.exists("maps.downloadmsg"):
86
os.remove("maps.downloadmsg")
87
f=open("maps.downloading",'w')
88
f.write("download started<script>$'('#ufomsg').load('/js/ajax.js?fetchmap=')")
89
f.close()
90
self._geoipstatus="downloading"
91
try: # mirror 1
92
print("\n[Info] [AI] Fetching maps from 'Turina Server':", self.geo_db_mirror1 + "\n")
93
response = self.retrieve(self.geo_db_mirror1, 'maps.tar.gz')
94
except:
95
print(("[Error] [AI] Something wrong fetching maps from remote servers! -> [Aborting!]"), "\n")
96
traceback.print_exc()
97
return False #sys.exit(2)
98
subprocess.call(shlex.split('tar zxfv maps.tar.gz'))
99
print("\n[Info] [AI] [Control] GeoIP maps and databases -> [OK!]\n")
100
# set pygeoip data sources
101
self._geoip = pygeoip.GeoIP('maps/GeoLiteCity.dat')
102
self._geoasn = pygeoip.GeoIP('maps/GeoIPASNum.dat')
103
self._geoipstatus='ok'
104
os.remove('maps.tar.gz')
105
os.remove('maps.downloading')
106
return True
107
108
# fetches geoip data for specified zombie
109
def geo_ip(self, zombie):
110
# check for status, downloading is done by ajax() method
111
if self.get_status() != 'ok':
112
if self._geoipstatus =='downloading':
113
print("\n[Info] [AI] [Control] GeoIP maps and databases -> [Downloading!]\n")
114
self._err= "ufomsg('[Info] [AI] Downloading maps... -> [Waiting!]')"
115
elif not os.path.exists('maps/GeoIPASNum.dat') or not os.path.exists('maps/GeoLiteCity.dat'):
116
print("\n[Info] [AI] GeoIP maps and databases -> [Starting!]\n")
117
self._err= "ufomsg('[Info] [AI] Map download starting')\n$('#ufomsg').load('/js/ajax.js?fetchgeoip=')"
118
else:
119
print("\n[Error] [AI] GeoIP maps and databases: FAILED! -> [Discarding!]\n")
120
self._err= "ufomsg('<font color='red'>[Info] [AI]</font> Maps: unknown error -> [Discarding!]')"
121
return None
122
if re.match(r'^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$', zombie) or re.match(r'^10\.\d{1,3}\.\d{1,3}\.\d{1,3}$', zombie) or re.match(r'^192.168\.\d{1,3}\.\d{1,3}$', zombie) or re.match(r'^172.(1[6-9]|2[0-9]|3[0-1]).[0-9]{1,3}.[0-9]{1,3}$', zombie) or re.match('localhost', zombie):
123
self._err= "ufomsg('<font color='red'>[Info] [AI] [Control]</font> Maps: invalid ip data -> [Discarding!]')"
124
return None
125
# create geoip data skeleton
126
geo_zombie={}
127
geo_zombie['qq']=zombie
128
url = urlparse(zombie)
129
geo_zombie['city'] = '-'
130
geo_zombie['country'] = '-'
131
geo_zombie['country_code'] = '-'
132
geo_zombie['longitude'] = '-'
133
geo_zombie['latitude'] = '-'
134
geo_zombie['ip'] = '-'
135
geo_zombie['host_name'] = '-'
136
geo_zombie['asn'] = '-'
137
geo_zombie['latitude'] = '-'
138
# retrieve and allocate geoip data
139
try:
140
ip = socket.gethostbyname(url.netloc)
141
except:
142
try:
143
import dns.resolver
144
r = dns.resolver.Resolver()
145
r.nameservers = ['8.8.8.8', '8.8.4.4'] # google DNS resolvers
146
a = r.query(url.netloc, "A") # A record
147
for rd in a:
148
ip = str(rd)
149
except:
150
self._err= "ufomsg('<font color='yellow'>[Error] [AI]</font> GeoIP: hostbyname failed for "+str(url.netloc)+"...')"
151
return None
152
if ip:
153
if re.match(r"^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$",ip):
154
geo_zombie['ip'] = ip
155
try:
156
record = self._geoip.record_by_addr(ip)
157
except:
158
self._err= "ufomsg('<font color='yellow'>[Error] [AI] </font> GeoIP: lookup failed for "+ip+", page reload required...')"
159
return None
160
try:
161
asn = self._geoasn.org_by_addr(ip)
162
if asn is not None:
163
geo_zombie['asn'] = asn
164
except:
165
geo_zombie['asn'] = 'No ASN provided'
166
try:
167
geo_zombie['host_name'] = socket.gethostbyaddr(ip)[0]
168
except:
169
geo_zombie['host_name'] = 'No hostname'
170
try:
171
longitude = str(float(record['longitude']))
172
geo_zombie['longitude'] = longitude
173
latitude = str(float(record['latitude']))
174
geo_zombie['latitude'] = latitude
175
except:
176
pass
177
try:
178
geo_zombie['country'] = record["country_name"]
179
geo_zombie['country_code'] = record["country_code"].lower()
180
if record['city'] is not None:
181
geo_zombie['city'] = record["city"]
182
except:
183
pass
184
else:
185
geo_zombie = None
186
return geo_zombie
187
188
# generates javascript for adding a new zombie with geoip data
189
def get_js(self,z):
190
ret = ""
191
gz = self.geo_ip(z)
192
if gz is not None and gz['latitude']!= '-':
193
ret = "Zombies.add('"+str(z)+"',Array(new L.LatLng("+str(gz['latitude'])+","+str(gz['longitude'])+"),'"+str(gz['city'])+"','"+str(gz['country'])+"','"+str(gz['country_code'])+"','"+str(gz['asn'])+"','"+str(gz['ip'])+"','"+str(gz['host_name'])+"'))\n"
194
else:
195
ret += "dead_zombies.push('"+z+"')\n"
196
ret += "last_zombie = '"+z+"'\n"
197
return ret
198
199
# fetches next zombie from list (using all types of zombies)
200
def get_next_zombie(self,name):
201
if name in self.zombies:
202
for z in self.zombies:
203
if name == None:
204
return z
205
if z == name:
206
name = None
207
return None
208
else:
209
return self.zombies[0]
210
211
# ajax controller
212
def ajax(self,pGet={}):
213
if 'fetchgeoip' in list(pGet.keys()):
214
if self.get_status() == "nomap":
215
self.download_maps()
216
return "[Info] [AI] [Control] Geoip data download! -> [OK!]<br/>"
217
if 'stats' in list(pGet.keys()):
218
stat='<script>$(".ufo_stat_div").show()</script>'
219
if os.path.exists('/tmp/ufonet.html'):
220
for x in open(r'/tmp/ufonet.html').readlines():
221
stat = stat + x
222
else:
223
stat="<i>[Info] [AI] [Control] Generating statistics... -> [Waiting!]</i>"
224
return stat+"</div>"
225
if self.get_status() != "ok":
226
dljs=""
227
if self.get_status() == "nomap":
228
dljs+="$('#ufomsg').load('/js/ajax.js?fetchgeoip=')\n"
229
if 'doll' in list(pGet.keys()):
230
dljs+="$('#ufomsg').load('/js/ajax.js?fetchdoll="+pGet['doll']+"')\n"
231
dljs+="doll=new Doll('"+pGet["doll"]+"')\n"
232
return "[Info] [AI] GeoIP data download in progress...<br><i>See console for errors</i>+<script>"+dljs+"</script>"
233
if 'zombie' in list(pGet.keys()):
234
zn=base64.b64decode(pGet['zombie']).decode('utf-8')
235
nzn=self.get_next_zombie(zn)
236
if nzn is not None:
237
zombie=self.get_js(nzn)
238
return """ <script>
239
"""+str(zombie)+"""
240
ufomsg('[Info] [AI] [Control] Adding zombie: """+str(nzn)+"""...')
241
</script>"""
242
else:
243
return "<script>zdone=true\nufomsg('[Info] [AI] [Control] All zombies deployed! -> [OK!]')\n </script>\n"
244
if 'fetchdoll' in list(pGet.keys()):
245
tn=pGet['fetchdoll']
246
target = self.geo_ip(tn)
247
if target is None:
248
return "doll waiting for geoip data !"
249
return """ doll up !<script>
250
doll.setData(Array(new L.LatLng("""+str(target['latitude'])+","+str(target['longitude'])+"),'"+target['city']+"','"+target['country']+"','"+target['country_code']+"','"+target['asn']+"','"+target['ip']+"','"+target['host_name']+"'))\nufomsg('[Info] Adding target: """+tn+"""...')\ndoll.show() </script>"""
251
if 'doll' in list(pGet.keys()):
252
tn=pGet['doll']
253
return """<script>
254
doll=new Doll('"""+tn+"""')\n</script>"""
255
return "\n"
256
257