-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathprocessor.py
1628 lines (1538 loc) · 91.1 KB
/
processor.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# imports
######
from time import gmtime, strftime, sleep, time
from helper_functions import find_2nd, print_info_layer, print_geolocations
import socket
import requests
from ip2geotools.databases.noncommercial import DbIpCity
import gmplot
from playsound import playsound
import configuration
import math
import json
from node import NodeDataClass, DbIpCityResponse
import pycountry
import configparser
import threading
from threading import Lock
import pingResolver
import hostResolver
import badConnectionKiller
import firewallManager
from copy import deepcopy
import uuid
from getmac import get_mac_address
import ctypes
import re # for regular expressions
from random import randint
#####################
class ProcessorClass(object):
########################
# TODO: check this workaround
sanitized_ip = []
# variable used by pingRandom() and PingRandom2()
randomIPList = []
########################
packetQueueA = 0 # will be a reference to pysharkSniffer's variable
packetQueueB = 0 # will be a reference to pysharkSniffer's variable
currentCallbackQueueIsA = [True] # will be a reference to pysharkSniffer's variable
locationsRead = [False] # will be a reference to pysharkSniffer's variable
processedPacketsCount = 0
##########################
node_dict = {}
location_dict = {}
node_dict_gui = {} # current dict of new/modified nodes to be shown/updated in GUI
__mutex = Lock() # for processing or accessing node_dict_gui[]
##########################
local = "local IP address"
public = "public IP address"
localHost = "local host"
publicHost = "public host"
response_public = "will be an object obtained by calling DbIpCity()"
locationsResolved = []
hostsResolved = {}
hostsResolutionRequested = []
connected_ip_list = []
pingAuto = True
pingResolverObject = pingResolver.PingResolverClass()
threadForPingProcessing = None
hostResolverObject = hostResolver.HostResolverClass()
badConnectionKillerObject = badConnectionKiller.BadConnectionKillerClass()
firewallManagerObject = firewallManager.FirewallManagerClass()
threadForHostProcessing = None
threadForBadConnectionKilling = None
threadForFirewallManagement = None
needUpdate = False
tx_kilo_bytes = 0.0
rx_kilo_bytes = 0.0
tx_kilo_bytes_alarm = 0.0
currentNodeNumber = 0
#######################################################
def getNumberOfConnections(self):
return self.badConnectionKillerObject.getNumberOfConnections()
#######################################################
def getNumberOfNodes(self):
return len(self.node_dict)
#######################################################
def getNumberOfBadNodes(self):
return self.badConnectionKillerObject.getNumberOfBadIPs()
#######################################################
def getNumberOfKilledNodes(self):
return self.badConnectionKillerObject.getNumberOfIPsKilled()
#######################################################
def getListOfKilledNodes(self):
return self.badConnectionKillerObject.getListOfKilledNodes()
#######################################################
def getNumberOfTxKiloBytes(self):
return int(self.tx_kilo_bytes)
#######################################################
def getNumberOfRxKiloBytes(self):
return int(self.rx_kilo_bytes)
#######################################################
def getHostsResolvedPast(self):
return len(self.hostsResolved)
#######################################################
def getHostsFailedPast(self):
return self.hostResolverObject.getHostsFailedPast()
#######################################################
def getNumberOfHostsRequested(self):
return self.hostResolverObject.getNumberOfHostsRequested()
#######################################################
def getNumberOfHostsSolved(self):
return self.hostResolverObject.getNumberOfHostsSolved()
#######################################################
def getNumberOfHostsFailed(self):
return self.hostResolverObject.getNumberOfHostsFailed()
##############
def killIPs(self):
if self.badConnectionKillerObject != None:
self.badConnectionKillerObject.killIPs()
##############
def killNone(self):
if self.badConnectionKillerObject != None:
self.badConnectionKillerObject.killNone()
##############
def killAll(self):
if self.badConnectionKillerObject != None:
self.badConnectionKillerObject.killAll()
###################################
# command to kill connections to bad IPs right now (only once)
def killIPsNow(self):
if self.badConnectionKillerObject != None:
self.badConnectionKillerObject.killIPsNow()
########################################
# command to kill active connections to known IPs right now (only once)
def killAllNow(self):
if self.badConnectionKillerObject != None:
self.badConnectionKillerObject.killAllNow()
########################################
# command to kill active connection to specified IP right now (only once)
def killIP(self, ip):
if self.badConnectionKillerObject != None:
self.badConnectionKillerObject.killIP(ip)
##############
# TODO: why cant we just pass bool as argument and set flag with a single method pingAuto(self, set) ?
def pingAutoOn(self): #, set):
self.pingAuto = True
'''
if set:
self.pingAuto = True
else:
self.pingAuto = False
'''
##############
def pingAutoOff(self):
self.pingAuto = False
##############
def pingAll(self):
if self.pingResolverObject != None:
self.__mutex.acquire()
# set ping to False and make a request to update
# NOTE: we also ping ourselves..but the check to avoid this is not worth the time..
for key, value in self.node_dict.items():
value.ping = False
# add/modify updated IP to GUI-List
self.node_dict_gui[key] = value
# send request
self.pingResolverObject.putHostToPing(key)
self.__mutex.release()
# set flag
self.needUpdate = True
################
# we first send UDP-packets
# after that we wait enough time so they've been received and processed
# then we request the ping resolution if still required
def pingRandom(self):
if self.pingResolverObject != None:
self.randomIPList = []
byte_message = bytes("Hi!", "utf-8")
# generate NR_OF_RANDOM_IPS_TO_PING random IPs to ping by sending UPD-packets
###################################################
for count in range (1, configuration.NR_OF_RANDOM_IPS_TO_PING):
randomIP = str(randint(0, 255))+ "."+str(randint(0, 255))+ "."+str(randint(0, 255))+ "."+str(randint(0, 255))
# append to list, we may need it later to send pings
self.randomIPList.append(randomIP)
# send UDP packet
try:
opened_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# NOTE: port 5005 is RTP (Real-time Transport Protocol - RFC 3551, RFC 4571)
opened_socket.sendto(byte_message, (randomIP, 5005))
print("UDP packet sent to random IP = ", randomIP)
except Exception as e:
self.randomIPList.remove(randomIP)
print("Exception: processor.pingRandom(): Exception = ", e)
print("Exception: processor.pingRandom(): socket Exception with IP = ", randomIP)
# wait some time for the UDP packets to be processed and IPs added in node_dict{}
###############################################
# 10 seconds seems enough (alternatively, we could use a temporary list containing all IPs which need ping and service that in background..)
sleep(10)
# no ping really:
#########
self.pingRandom2()
#################
def pingRandom2(self):
# if pingAuto == True, then all previous UDP packets will produce also a ping to the corresponding IPs
# otherwise we do it here:
#########################################################
if self.pingAuto == False:
if self.pingResolverObject != None:
self.__mutex.acquire()
# set ping to False and make a request to update
# NOTE: we also ping ourselves..but the check to avoid this is not worth the time..
for key in self.randomIPList:
if key in self.node_dict:
self.node_dict[key].ping = False
# add/modify updated IP to GUI-List
self.node_dict_gui[key] = self.node_dict[key]
# send request
self.pingResolverObject.putHostToPing(key)
print("Ping to random IP = ", key)
else:
print("Cause not yet in node_dict, do NOT ping to random IP = ", key)
self.__mutex.release()
# set flag
self.needUpdate = True
###########################
# ping a specific host (only known hosts allowed)
###########################
def pingIP(self, host):
if self.pingResolverObject != None:
if (host.find(".") == -1) or (host not in self.node_dict):
ip = socket.gethostbyname(host)
else:
ip = host
# set ping to False and make a request to update
###########################
if ip in self.node_dict:
self.node_dict[ip].ping = False
# add/modify updated IP to GUI-List
self.__mutex.acquire()
self.node_dict_gui[ip] = self.node_dict[ip]
self.__mutex.release()
# send request
self.pingResolverObject.putHostToPing(ip)
# set flag
self.needUpdate = True
##############
# TODO: improvement: avoid all these loops by handling dicts objects instead - in mainWindow.py directly is better.
def updateShowNotShowOwners(self, listOwnersToShow, listOwnersToHide):
# owners to show:
for show in listOwnersToShow:
for ip in self.node_dict:
if show in self.node_dict[ip].whosip:
if self.node_dict[ip].show_host == False:
self.node_dict[ip].show_host = True
# add/modify updated IP to GUI-List
self.__mutex.acquire()
self.node_dict_gui[ip] = self.node_dict[ip]
self.__mutex.release()
# set flag
self.needUpdate = True
# owners to hide:
for hide in listOwnersToHide:
for ip in self.node_dict:
if hide in self.node_dict[ip].whosip:
if self.node_dict[ip].show_host == True:
self.node_dict[ip].show_host = False
# add/modify updated IP to GUI-List
self.__mutex.acquire()
self.node_dict_gui[ip] = self.node_dict[ip]
self.__mutex.release()
# set flag
self.needUpdate = True
# start()
# create and START processing threads
#######################
def start(self):
print("processor.start(): start threads")
# create ping processor
##############
# first create ping processing thread
self.threadForPingProcessing = threading.Thread(name="pingProcessingThread", target=self.pingResolverObject.processingThread)
self.threadForPingProcessing.start()
# create host processor and bad connection killer threads
################################
# first create host processing thread (threadForPacketProcessing needs it)
self.threadForHostProcessing = threading.Thread(name="hostProcessingThread", target=self.hostResolverObject.processingThread)
self.threadForHostProcessing.start()
# then create bad connection killer thread (threadForPacketProcessing needs it)
self.threadForBadConnectionKilling = threading.Thread(name="badConnectionKillerThread", target=self.badConnectionKillerObject.processingThread)
self.threadForBadConnectionKilling.start()
# then create firewall management thread (threadForFirewallManagement needs it)
self.threadForFirewallManagement = threading.Thread(name="firewallManagementThread", target=self.firewallManagerObject.processingThread)
self.threadForFirewallManagement.start()
# __init__()
# initialize known locations from file
# initialize known hosts from file
# resolve local and public hosts
######################
def __init__(self): # (self):
print("processor.__init__(): load cfg file, etc.")
# Load the configuration file
################
print("Reading config.ini")
config = configparser.ConfigParser(allow_no_value=True)
config.read("config.ini")
print("sections: ", config.sections())
if "myConfig" in config:
print("keys in section myConfig:")
if "INTERFACE" in config["myConfig"]:
configuration.INTERFACE = config['myConfig']['INTERFACE']
# TODO: improvement: print configuration.VAR instead of accessing againt the .ini file... TODO: for all variables
# print("INTERFACE = ", configuration.INTERFACE)
print("INTERFACE = ", config['myConfig']['INTERFACE'])
if "FONT_SIZE" in config["myConfig"]:
configuration.FONT_SIZE = int(config['myConfig']['FONT_SIZE'])
print("FONT_SIZE = ", int(config['myConfig']['FONT_SIZE']))
if "MAX_TX_KILOBYTES" in config["myConfig"]:
configuration.MAX_TX_KILOBYTES = int(config['myConfig']['MAX_TX_KILOBYTES'])
print("MAX_TX_KILOBYTES = ", int(config['myConfig']['MAX_TX_KILOBYTES']))
if "NR_OF_RANDOM_IPS_TO_PING" in config["myConfig"]:
configuration.NR_OF_RANDOM_IPS_TO_PING = int(config['myConfig']['NR_OF_RANDOM_IPS_TO_PING'])
print("NR_OF_RANDOM_IPS_TO_PING = ", int(config['myConfig']['NR_OF_RANDOM_IPS_TO_PING']))
if "CHECK_PERIOD_IN_SEC" in config["myConfig"]:
configuration.CHECK_PERIOD_IN_SEC = float(config['myConfig']['CHECK_PERIOD_IN_SEC'])
print("CHECK_PERIOD_IN_SEC = ", float(config['myConfig']['CHECK_PERIOD_IN_SEC']))
if "RUN_AS_ADMIN" in config["myConfig"]:
configuration.RUN_AS_ADMIN = int(config['myConfig']['RUN_AS_ADMIN'])
print("RUN_AS_ADMIN = ", int(config['myConfig']['RUN_AS_ADMIN']))
###########################################
if "ADD_FIREWALL_RULE_BLOCK_BAD_IP" in config["myConfig"]:
configuration.ADD_FIREWALL_RULE_BLOCK_BAD_IP = int(config['myConfig']['ADD_FIREWALL_RULE_BLOCK_BAD_IP'])
print("ADD_FIREWALL_RULE_BLOCK_BAD_IP = ", int(config['myConfig']['ADD_FIREWALL_RULE_BLOCK_BAD_IP']))
# show message by inconsistent configuration
if configuration.ADD_FIREWALL_RULE_BLOCK_BAD_IP:
if configuration.RUN_AS_ADMIN == False:
print("CONFIGURATION ERROR: ADD_FIREWALL_RULE_BLOCK_BAD_IP is True but RUN_AS_ADMIN is False, so NO rules will be added to the Firewall as requested!")
ctypes.windll.user32.MessageBoxW(0, "No Admin rights, so NO rules will be added to the Firewall as configured. Set both ADD_FIREWALL_RULE_BLOCK_BAD_IP and RUN_AS_ADMIN to True.", "Warning: configuration error!", 0)
###########################################
if "SHELL_TO_FILE" in config["myConfig"]:
configuration.SHELL_TO_FILE = int(config['myConfig']['SHELL_TO_FILE'])
print("SHELL_TO_FILE = ", int(config['myConfig']['SHELL_TO_FILE']))
if "PACKED_OUTPUT" in config["myConfig"]:
configuration.PACKED_OUTPUT = int(config['myConfig']['PACKED_OUTPUT'])
print("PACKED_OUTPUT = ", int(config['myConfig']['PACKED_OUTPUT']))
if "ROUTER_IP" in config["myConfig"]:
configuration.ROUTER_IP = config['myConfig']['ROUTER_IP']
print("ROUTER_IP = ", config['myConfig']['ROUTER_IP'])
if "RULE_NAME_STR" in config["myConfig"]:
configuration.RULE_NAME_STR = config['myConfig']['RULE_NAME_STR']
print("RULE_NAME_STR = ", config['myConfig']['RULE_NAME_STR'])
if "CONN_ESTABLISHED_STR" in config["myConfig"]:
configuration.CONN_ESTABLISHED_STR = config['myConfig']['CONN_ESTABLISHED_STR']
print("CONN_ESTABLISHED_STR = ", config['myConfig']['CONN_ESTABLISHED_STR'])
if "PUBLIC_IP" in config["myConfig"]:
configuration.PUBLIC_IP = config['myConfig']['PUBLIC_IP']
print("PUBLIC_IP = ", config['myConfig']['PUBLIC_IP'])
if "MY_CITY" in config["myConfig"]:
configuration.MY_CITY = config['myConfig']['MY_CITY']
print("MY_CITY = ", config['myConfig']['MY_CITY'])
if "MY_COUNTRY" in config["myConfig"]:
configuration.MY_COUNTRY = config['myConfig']['MY_COUNTRY']
print("MY_COUNTRY = ", config['myConfig']['MY_COUNTRY'])
if "MY_IP_ADDRESS" in config["myConfig"]:
configuration.MY_IP_ADDRESS = config['myConfig']['MY_IP_ADDRESS']
print("MY_IP_ADDRESS = ", config['myConfig']['MY_IP_ADDRESS'])
if "MY_LATITUDE" in config["myConfig"]:
configuration.MY_LATITUDE = float(config['myConfig']['MY_LATITUDE'])
print("MY_LATITUDE = ", float(config['myConfig']['MY_LATITUDE']))
if "MY_LONGITUDE" in config["myConfig"]:
configuration.MY_LONGITUDE = float(config['myConfig']['MY_LONGITUDE'])
print("MY_LONGITUDE = ", float(config['myConfig']['MY_LONGITUDE']))
if "MY_REGION" in config["myConfig"]:
configuration.MY_REGION = config['myConfig']['MY_REGION']
print("MY_REGION = ", config['myConfig']['MY_REGION'])
if "MAP_CENTER_LAT" in config["myConfig"]:
configuration.MAP_CENTER_LAT = float(config['myConfig']['MAP_CENTER_LAT'])
print("MAP_CENTER_LAT = ", float(config['myConfig']['MAP_CENTER_LAT']))
if "MAP_CENTER_LON" in config["myConfig"]:
configuration.MAP_CENTER_LON = float(config['myConfig']['MAP_CENTER_LON'])
print("MAP_CENTER_LON = ", float(config['myConfig']['MAP_CENTER_LON']))
if "MAP_INFO_LAT" in config["myConfig"]:
configuration.MAP_INFO_LAT = float(config['myConfig']['MAP_INFO_LAT'])
print("MAP_INFO_LAT = ", float(config['myConfig']['MAP_INFO_LAT']))
if "MAP_INFO_LON" in config["myConfig"]:
configuration.MAP_INFO_LON = float(config['myConfig']['MAP_INFO_LON'])
print("MAP_INFO_LON = ", float(config['myConfig']['MAP_INFO_LON']))
if "MAP_ZOOM" in config["myConfig"]:
configuration.MAP_ZOOM = int(config['myConfig']['MAP_ZOOM'])
print("MAP_ZOOM = ", int(config['myConfig']['MAP_ZOOM']))
if "USE_WHITE_LIST" in config["myConfig"]:
configuration.USE_WHITE_LIST = int(config['myConfig']['USE_WHITE_LIST'])
print("USE_WHITE_LIST = ", configuration.USE_WHITE_LIST)
if "BlackList" in config["myConfig"]:
configuration.BlackList = config['myConfig']['BlackList']
print("BlackList = ", configuration.BlackList)
if "WhiteList" in config["myConfig"]:
configuration.WhiteList = config['myConfig']['WhiteList']
print("WhiteList = ", configuration.WhiteList)
if "WhiteListNotKill" in config["myConfig"]:
configuration.WhiteListNotKill = json.loads(config['myConfig']['WhiteListNotKill'])
print("WhiteListNotKill = ", configuration.WhiteListNotKill)
if "BlackListOwner" in config["myConfig"]:
configuration.BlackListOwner = json.loads(config['myConfig']['BlackListOwner'])
print("BlackListOwner = ", configuration.BlackListOwner)
if "WhiteListOwner" in config["myConfig"]:
configuration.WhiteListOwner = json.loads(config['myConfig']['WhiteListOwner'])
print("WhiteListOwner = ", configuration.WhiteListOwner)
if "BlackListCity" in config["myConfig"]:
configuration.BlackListCity = json.loads(config['myConfig']['BlackListCity'])
print("BlackListCity = ", configuration.BlackListCity)
if "WhiteListCity" in config["myConfig"]:
configuration.WhiteListCity = json.loads(config['myConfig']['WhiteListCity'])
print("WhiteListCity = ", configuration.WhiteListCity)
###########################
# initialize list with known locations from file
##########################
locationsFile = open("locationsResolved.json", "r", encoding="utf-8")
self.locationsResolved = list(locationsFile) # list of geo-locations, each in json format (same in .json file)
locationsFile.close()
i = 0
# covert json "string" to dictionary format - index exception only works with "dictionary" format!
for location in self.locationsResolved:
if location != "":
self.locationsResolved[i] = json.loads(location)
i = i +1
# MAC address of device
##############
print("MAC address (hex) = ", hex(uuid.getnode()))
print("MAC address (fmt) = ", end="")
print(':'.join(['{:02x}'.format((uuid.getnode() >> ele) & 0xff)
for ele in range(0,8*6,8)][::-1]))
# MAC address of router
print("MAC of router = ", get_mac_address(ip=configuration.ROUTER_IP))
# resolve local and public host
#################
self.localHost = socket.gethostname()
self.local = socket.gethostbyname(self.localHost)
self.badConnectionKillerObject.setLocalIP(self.local)
print("Local IP address = ", self.local)
netlocalendpos = find_2nd(self.local, ".")
self.netlocal = self.local[:netlocalendpos+1]
#################
if configuration.PUBLIC_IP == "":
try:
self.public = requests.get('http://ip.42.pl/raw').text
except Exception as e:
self.public = ""
print("processor.__init__(): Exception when calling requests.get('http://ip.42.pl/raw'): ", e)
ctypes.windll.user32.MessageBoxW(0, "Could not retrieve the public IP. Please check your network connection!", "Warning! No public IP.", 0)
else:
self.public = configuration.PUBLIC_IP
#################
print("Public IP address = ", self.public)
try:
self.publicHost = socket.gethostbyaddr(self.public)
self.publicHost = self.publicHost[0]
except Exception as e:
self.publicHost = "(not found)"
print("processor.__init__(): Exception when calling gethostbyaddr(): ", e)
print("Host name of Local IP address = ", self.localHost)
print("Host name of Public IP address = ", self.publicHost)
# Note: we dont get location with DbIpCity.get() because we may appear e.g. in "another" city near us.
# Instead, we use configuration:
self.response_public = DbIpCityResponse(
configuration.MY_CITY, configuration.MY_COUNTRY, configuration.MY_IP_ADDRESS, configuration.MY_LATITUDE,
configuration.MY_LONGITUDE, configuration.MY_REGION)
self.response_public.ip_address = self.public # overwrite IP, even if it is actually somewhere else
print("Location:\n", self.response_public)
######################
# end of __init__()
######################
# helper function used in plotMap()
# converts input float argument rx
# to an integer in the range MIN_MARKER_SIZE to MAX_MARKER_SIZE
# considering saturation defined by MAX_RX_BYTES, where we return MAX_MARKER_SIZE
def getRxInt(self, rx):
# set rx_int
if rx < configuration.MAX_RX_BYTES:
# linear growth between zero and max. traffic
# moving between 30 and 130
rx_int = (rx*100.0)/configuration.MAX_RX_BYTES + configuration.MIN_MARKER_SIZE
else:
# saturation
rx_int = configuration.MAX_MARKER_SIZE
# return value
return rx_int
######################
# end of getRxInt()
#-------------------------------------------------------------------------------------------------------------------
######################
# plot the map
# Each time plotMap() is called we create NEW structures (latitude_local[]..) to draw.
# This could be improved by storing and extending these structures instead, but we dont do that
# in order to be more flexible and e.g. apply filters based directly on the original data.
######################
def plotMap(self):
# firs clear update flag
self.needUpdate = False
# Local variables
latitude_local_list = []
longitude_local_list = []
latitude_bad_local_list = []
longitude_bad_local_list = []
# copy values to avoid inconsistencies if configuration is changed
MIN_MARKER_SIZE = configuration.MIN_MARKER_SIZE
BOUNCE = configuration.BOUNCE
HEATMAP = configuration.HEATMAP
HEATMAP_SRC = configuration.HEATMAP_SRC
HEATMAP_DST = configuration.HEATMAP_DST
SHOW_NODES = configuration.SHOW_NODES
SHOW_CONNECTIONS = configuration.SHOW_CONNECTIONS
SHOW_INFO = configuration.SHOW_INFO
SHOW_HOST_GOOD = configuration.SHOW_HOST_GOOD
SHOW_HOST_UNKNOWN = configuration.SHOW_HOST_UNKNOWN
SHOW_HOST_BAD = configuration.SHOW_HOST_BAD
SHOW_HOST_KILLED = configuration.SHOW_HOST_KILLED
SHOW_HOST_ACTIVE = configuration.SHOW_HOST_ACTIVE
SHOW_HOST_PING = configuration.SHOW_HOST_PING
SHOW_CONNECTION_GOOD = configuration.SHOW_CONNECTION_GOOD
SHOW_CONNECTION_UNKNOWN = configuration.SHOW_CONNECTION_UNKNOWN
SHOW_CONNECTION_BAD = configuration.SHOW_CONNECTION_BAD
SHOW_CONNECTION_KILLED = configuration.SHOW_CONNECTION_KILLED
SHOW_CONNECTIONS_ACTIVE = configuration.SHOW_CONNECTIONS_ACTIVE
# create map object
############
gmap = gmplot.GoogleMapPlotter(configuration.MAP_CENTER_LAT, configuration.MAP_CENTER_LON, configuration.MAP_ZOOM, configuration.currentmaptype, showHeatmap=HEATMAP)
gmap.grids = True
# API key
# TODO: enter key here (from a file)
##############
# gmap.apikey = "AIzaKyOeLFMnA__VmQDiZRiuz4kKjF_c9r1kWe8"
# gmap.apikey = "free"
# Grid
##############
# gmap.grid(-67.42, 67.42, 10.0, -122.15, 42.15, 10.0) # eh?
# Rings (distance rings)
# TODO: new feature: to make it look more like a radar ;-)
# same geo-locations are spread in a CIRCLE
#########################
for srcNode in self.node_dict.values():
# first calculate size of node depending on RX traffic
##############################
tx_int = MIN_MARKER_SIZE
# only External Nodes for now..
if srcNode.local == True:
rx_int = MIN_MARKER_SIZE
else:
rx_int = self.getRxInt(float(srcNode.rx))
##############################
# show srcNode with that owner ?
if srcNode.show_host == True:
if srcNode.bad:
latitude_bad_local = []
longitude_bad_local = []
# add all connections to communication partners as RED lines
for dstNode in srcNode.comm_partner_list:
# show dstNode with that owner ?
if self.node_dict[dstNode].show_host == True:
activeConnection = srcNode.conn_established==True or self.node_dict[dstNode].conn_established==True
killedConnection = dstNode in srcNode.comm_partner_list_killed or srcNode.ip in self.node_dict[dstNode].comm_partner_list_killed
# plot RED line
if (SHOW_CONNECTIONS and (SHOW_CONNECTION_BAD or (killedConnection and SHOW_CONNECTION_KILLED) or (activeConnection and SHOW_CONNECTIONS_ACTIVE))):
latitude_bad_local.append(srcNode.lat_plot)
longitude_bad_local.append(srcNode.lon_plot)
latitude_bad_local.append(self.node_dict[dstNode].lat_plot)
longitude_bad_local.append(self.node_dict[dstNode].lon_plot)
#############
# killed connections override other colors
if killedConnection:
connection_color = configuration.CON_KILLED_COLOR
else:
connection_color = configuration.CON_BAD_COLOR
#############
if activeConnection:
gmap.plot(latitude_bad_local, longitude_bad_local, connection_color, edge_width=4.0)
else:
gmap.plot(latitude_bad_local, longitude_bad_local, connection_color, edge_width=2.0)
# needed for heatmap
if HEATMAP:
if HEATMAP_SRC == True:
latitude_bad_local_list.append(srcNode.lat_plot)
longitude_bad_local_list.append(srcNode.lon_plot)
if HEATMAP_DST == True:
latitude_bad_local_list.append(self.node_dict[dstNode].lat_plot)
longitude_bad_local_list.append(self.node_dict[dstNode].lon_plot)
# add marker RED of source
if SHOW_NODES and (SHOW_HOST_BAD or (SHOW_HOST_ACTIVE and srcNode.conn_established==True) or (SHOW_HOST_KILLED and srcNode.killed==True) or (SHOW_HOST_PING and srcNode.ping==False)):
#############
# killed nodes override other colors
if srcNode.killed:
node_color = configuration.NODE_KILLED_COLOR
else:
node_color = configuration.NODE_BAD_COLOR
gmap.marker(srcNode.lat_plot, srcNode.lon_plot, node_color, title=srcNode.host, bounce=BOUNCE, dot=srcNode.ping, tx=tx_int, rx=rx_int)
else: # this is a good guy
# add connections to communication partners
# bad destinations will be added to bad path - RED lines
for dstNode in srcNode.comm_partner_list:
# show dstNode with that owner ?
if self.node_dict[dstNode].show_host == True:
latitude_local = []
longitude_local = []
latitude_bad_local = []
longitude_bad_local = []
if self.node_dict[dstNode].bad: # destination is bad
activeConnection = srcNode.conn_established==True or self.node_dict[dstNode].conn_established==True
killedConnection = dstNode in srcNode.comm_partner_list_killed or srcNode.ip in self.node_dict[dstNode].comm_partner_list_killed
# plot RED line
if (SHOW_CONNECTIONS and (SHOW_CONNECTION_BAD or (killedConnection and SHOW_CONNECTION_KILLED) or (activeConnection and SHOW_CONNECTIONS_ACTIVE))):
latitude_bad_local.append(srcNode.lat_plot)
longitude_bad_local.append(srcNode.lon_plot)
latitude_bad_local.append(self.node_dict[dstNode].lat_plot)
longitude_bad_local.append(self.node_dict[dstNode].lon_plot)
#############
# killed connections override other colors
if killedConnection:
connection_color = configuration.CON_KILLED_COLOR
else:
connection_color = configuration.CON_BAD_COLOR
#############
if activeConnection:
gmap.plot(latitude_bad_local, longitude_bad_local, connection_color, edge_width=4.0)
else:
gmap.plot(latitude_bad_local, longitude_bad_local, connection_color, edge_width=2.0)
# needed for heatmap
if HEATMAP:
if HEATMAP_SRC == True:
latitude_bad_local_list.append(srcNode.lat_plot)
longitude_bad_local_list.append(srcNode.lon_plot)
if HEATMAP_DST == True:
latitude_bad_local_list.append(self.node_dict[dstNode].lat_plot)
longitude_bad_local_list.append(self.node_dict[dstNode].lon_plot)
else: # both hosts are good
activeConnection = srcNode.conn_established==True or self.node_dict[dstNode].conn_established==True
killedConnection = dstNode in srcNode.comm_partner_list_killed or srcNode.ip in self.node_dict[dstNode].comm_partner_list_killed
# plot line
if SHOW_CONNECTIONS:
latitude_local.append(srcNode.lat_plot)
longitude_local.append(srcNode.lon_plot)
latitude_local.append(self.node_dict[dstNode].lat_plot)
longitude_local.append(self.node_dict[dstNode].lon_plot)
if srcNode.host_resolved == False or self.node_dict[dstNode].host_resolved == False:
if (SHOW_CONNECTION_UNKNOWN or (killedConnection and SHOW_CONNECTION_KILLED) or (activeConnection and SHOW_CONNECTIONS_ACTIVE)):
#############
# killed connections override other colors
if killedConnection:
connection_color = configuration.CON_KILLED_COLOR
else:
connection_color = configuration.CON_UNKNOWN_COLOR
#############
if activeConnection:
gmap.plot(latitude_local, longitude_local, connection_color, edge_width=4.0)
else:
gmap.plot(latitude_local, longitude_local, connection_color, edge_width=2.0)
else:
if (SHOW_CONNECTION_GOOD or (killedConnection and SHOW_CONNECTION_KILLED) or (activeConnection and SHOW_CONNECTIONS_ACTIVE)):
#############
# killed connections override other colors
if killedConnection:
connection_color = configuration.CON_KILLED_COLOR
else:
connection_color = configuration.CON_GOOD_COLOR
#############
if activeConnection:
gmap.plot(latitude_local, longitude_local, connection_color, edge_width=4.0)
else:
gmap.plot(latitude_local, longitude_local, connection_color, edge_width=2.0)
# needed for heatmap
if HEATMAP:
if HEATMAP_SRC == True:
latitude_local_list.append(srcNode.lat_plot)
longitude_local_list.append(srcNode.lon_plot)
if HEATMAP_DST == True:
latitude_local_list.append(self.node_dict[dstNode].lat_plot)
longitude_local_list.append(self.node_dict[dstNode].lon_plot)
# add marker UNKNOWN source
if srcNode.host_resolved == False:
if SHOW_NODES and (SHOW_HOST_UNKNOWN or (SHOW_HOST_ACTIVE and srcNode.conn_established==True) or (SHOW_HOST_KILLED and srcNode.killed==True) or (SHOW_HOST_PING and srcNode.ping==False)):
if "(unknown)" in srcNode.host:
#############
# killed nodes override other colors
if srcNode.killed:
node_color = configuration.NODE_KILLED_COLOR
else:
node_color = configuration.NODE_UNKNOWN_OLD_COLOR
#############
gmap.marker(srcNode.lat_plot, srcNode.lon_plot, node_color, title=srcNode.host, bounce=BOUNCE, dot=srcNode.ping, tx=tx_int, rx=rx_int)
else:
#############
# killed nodes override other colors
if srcNode.killed:
node_color = configuration.NODE_KILLED_COLOR
else:
node_color = configuration.NODE_UNKNOWN_COLOR
#############
gmap.marker(srcNode.lat_plot, srcNode.lon_plot, node_color, title=srcNode.host, bounce=BOUNCE, dot=srcNode.ping, tx=tx_int, rx=rx_int)
else:
# add marker GOOD source
if SHOW_NODES and (SHOW_HOST_GOOD or (SHOW_HOST_ACTIVE and srcNode.conn_established==True) or (SHOW_HOST_KILLED and srcNode.killed==True) or (SHOW_HOST_PING and srcNode.ping==False)):
markerColor = configuration.NODE_GOOD_COLOR
# we assume internal NW sources are always good (yes, even your wife! :-)
if srcNode.ip.startswith(self.netlocal):
if srcNode.ip == configuration.ROUTER_IP:
markerColor = configuration.NODE_ROUTER_COLOR
# TODO: distinguish local PCs, broadcast and multicast
elif srcNode.ip == self.local:
markerColor = configuration.NODE_MY_DEVICE_COLOR
else:
markerColor = configuration.NODE_DEFAULT_COLOR
#############
# killed nodes override other colors
if srcNode.killed:
node_color = configuration.NODE_KILLED_COLOR
else:
node_color = markerColor
#############
gmap.marker(srcNode.lat_plot, srcNode.lon_plot, node_color, title=srcNode.host, bounce=BOUNCE, dot=srcNode.ping, tx=tx_int, rx=rx_int)
###########################
# heatmap
if HEATMAP:
gmap.heatmap(latitude_local_list, longitude_local_list, threshold=10, radius=40)
gmap.heatmap(latitude_bad_local_list, longitude_bad_local_list, threshold=10, radius=40)
############################
# marker with last update-time
############################
if SHOW_INFO:
info = strftime("%Y.%m.%d %H:%M:%S", gmtime()) + " marks = " + str(len(self.node_dict))
gmap.marker(configuration.MAP_INFO_LAT, configuration.MAP_INFO_LON, configuration.NODE_DEFAULT_COLOR, title=info, bounce=BOUNCE, dot=False, tx=MIN_MARKER_SIZE, rx=MIN_MARKER_SIZE)
# WORKAROUND
# TODO: find actual problem!
#################
# check also
tempDoDraw = True
for point in gmap.points:
if point[0] == None or point[1] == None:
# tuples cannot be changed!
# point[0] = 0.1
# point[1] = 0.1
tempDoDraw = False
print("************* ERR: point with None value!!!")
for ip in self.node_dict:
if self.node_dict[ip].lat == None or self.node_dict[ip].lon == None:
self.node_dict[ip].lat = 0.1
self.node_dict[ip].lon = 0.1
print("************* corrected lat, lon of IP ", ip)
#################
# draw map
#######
if tempDoDraw:
try:
gmap.draw("Output/map_"+configuration.START_TIME+".html")
except Exception as e:
print("plotMap()->gmap.draw() throwed exception = ", e)
##########
# end of plotMap()
#-------------------------------------------------------------------------------------------------------------------
#-------------------------------------------------------------------------------------------------------------------
#########################
# check if new hosts have been pinged positively
def checkForHostsPinged(self):
pinged_host_list = self.pingResolverObject.getPingedHosts()
if pinged_host_list:
# loop list of already resolved hosts
for ipAddress in pinged_host_list:
# check because if it is a "random" IP it will not yet be in node_dict
if ipAddress in self.node_dict:
self.node_dict[ipAddress].ping = True
# add/modify updated IP to GUI-List
self.__mutex.acquire()
self.node_dict_gui[ipAddress] = self.node_dict[ipAddress]
self.__mutex.release()
else:
print("Error: ping result of host which is not yet in node_dict! IP = ", ipAddress)
# set flag
self.needUpdate = True
#########################
# end of checkForHostsPinged()
#-------------------------------------------------------------------------------------------------------------------
#-------------------------------------------------------------------------------------------------------------------
######################
# check if new hosts have been resolved
def checkForHostsResolution(self):
resolved_host_list = self.hostResolverObject.getResolvedHosts()
if resolved_host_list:
# loop list of already resolved hosts
for host in resolved_host_list:
ipAddress = host["ip"]
self.node_dict[ipAddress].host = str(self.node_dict[ipAddress].pos) + ": " + host["host"]
self.node_dict[ipAddress].whosip = host["whosip"]
self.node_dict[ipAddress].host_resolved = True
if ipAddress not in self.hostsResolved:
# is this (unknown)?
# add only if really resolved..
if "(unknown)" not in host["host"]:
# add to dict of resolved hosts
self.hostsResolved[ipAddress] = host["host"]
print("resolved host = " + host["host"] + " for IP = " + host["ip"] + " in position " + str(self.node_dict[ipAddress].pos))
# if BAD: it may be a "white-listed" owner -> make it GOOD again
# note: when we marked host as BAD, we didn't yet know the owner and could not check if it was white-listed
#############################################################
if self.node_dict[ipAddress].bad:
for owner in configuration.WhiteListOwner:
# check if owner in whosip (ignore upper/lower case)
# TODO: improvement: store all individual fields of whosip in separate fieds in node so we can use them directly
if re.search("Owner Name: "+owner, self.node_dict[ipAddress].whosip, re.IGNORECASE) != None:
# mark as good again
self.node_dict[ipAddress].bad = False
print("\n\"WARNING! previously detected illegal IP {0} in country {1} is set back to GOOD cause whilte-list owner = {2}\"".format(ipAddress, self.node_dict[ipAddress].country_iso, owner))
self.sanitized_ip.append(ipAddress)
break
# if we are still BAD it means bad IP has no white-listed owner
if self.node_dict[ipAddress].bad == True:
print("\n\"ALARM CONFIRMATION! the detected illegal IP {0} in country {1} is indeed a BAD guy.\"".format(ipAddress, self.node_dict[ipAddress].country_iso))
# else if not yet BAD: it may be an illegal OWNER -> make it BAD and add it to firewall rule
####################################################
else:
# owner empty?
#########
if re.search("Owner Name: ,", self.node_dict[ipAddress].whosip) != None:
print("Owner is empty so we assume it is BAD!")
self.node_dict[ipAddress].bad = True
print("\n\"ALARM! detected illegal owner {0} with IP {1} in country {2}\"".format("", ipAddress, self.node_dict[ipAddress].country_iso))
# otherwise check black list of owners
######################
else:
for badOwner in configuration.BlackListOwner:
# black-listed owner?
if re.search("Owner Name: "+badOwner, self.node_dict[ipAddress].whosip, re.IGNORECASE) != None:
reallyBad = True
# got black-listed owner string but - just to be 100% sure - we check that owner does NOT contain string in white-list
for goodOwner in configuration.WhiteListOwner:
if re.search("Owner Name: "+goodOwner, self.node_dict[ipAddress].whosip, re.IGNORECASE) != None:
# got white-listed owner string, although we had black-listed owner string
print("What? got good owner string {0}, although we had bad owner string {1}. Just to be sure we leave it as GOOD!".format(goodOwner, badOwner))
reallyBad = False
break
# owner in black-list and NOT in white-list
if reallyBad:
self.node_dict[ipAddress].bad = True
print("\n\"ALARM! detected illegal owner {0} with IP {1} in country {2}\"".format(badOwner, ipAddress, self.node_dict[ipAddress].country_iso))
break
# handle BAD host as it corresponds
#####################
if self.node_dict[ipAddress].bad == True:
print("\n\"Processing bad IP = {0} \"".format(ipAddress))
# add bad IP to bad connection killer
self.badConnectionKillerObject.putIPToKill(ipAddress)
# add rule to Firewall?
#############
if configuration.ADD_FIREWALL_RULE_BLOCK_BAD_IP:
if configuration.RUN_AS_ADMIN:
response_src_temp = self.node_dict[ipAddress].country_iso+","+self.node_dict[ipAddress].city
response_src_temp = response_src_temp+","+str(self.node_dict[ipAddress].whosip).replace("'", "")
##################
# and now remove all spaces
# firewall does not like spaces
response_src_temp = response_src_temp.replace(" ", "")
self.firewallManagerObject.putHostToRule(ipAddress, response_src_temp)
else:
msg = "ERROR: shall add rule to firewall to block IP " + ipAddress + " but have no Admin rights!"
print(msg)
# play alarm?
########
if configuration.SOUND:
playsound('Sounds/Alarm/salamisound-8723691-alarm-sirene-auto.mp3', block=False)
# add/modify updated IP to GUI-List
#####################
self.__mutex.acquire()
self.node_dict_gui[ipAddress] = self.node_dict[ipAddress]
self.__mutex.release()
###################
# set flag
self.needUpdate = True
#########################
# end of checkForHostsResolution()
#-------------------------------------------------------------------------------------------------------------------
#-------------------------------------------------------------------------------------------------------------------
#########################
# check if new processes have been killed in order to stop the connection to a BAD IP
def checkKilledConnections(self):
killed_ip_dict = self.badConnectionKillerObject.getKilledIPs()
if killed_ip_dict:
# loop dict of killed connections
for killed_ip, killed_process in killed_ip_dict.items():
# mark node as killed (if available in node dict)
if killed_ip in self.node_dict:
self.node_dict[killed_ip].killed = True
self.node_dict[killed_ip].killed_process = killed_process
# add/modify updated IP to GUI-List
self.__mutex.acquire()
self.node_dict_gui[killed_ip] = self.node_dict[killed_ip]
self.__mutex.release()
# loop all nodes
for ip in self.node_dict:
if killed_ip in self.node_dict[ip].comm_partner_list:
self.node_dict[ip].comm_partner_list_killed.append(killed_ip)
self.node_dict[ip].comm_partner_list.remove(killed_ip)
print("Killed connection "+ip+" to "+killed_ip)
# add/modify updated IP to GUI-List
self.__mutex.acquire()
self.node_dict_gui[ip] = self.node_dict[ip]
self.__mutex.release()
# set flag
self.needUpdate = True
#########################
# end of checkKilledConnections()
#-------------------------------------------------------------------------------------------------------------------
#-------------------------------------------------------------------------------------------------------------------
#########################
# check current active connections (=estalished)
def checkActiveConnections(self):
oldNrOfConnections = len(self.connected_ip_list)
connected_ip_list_temp = self.badConnectionKillerObject.getConnectedIPs()
# need copy so we can remove unknown IPs later
connected_ip_list_local = deepcopy(connected_ip_list_temp)
if connected_ip_list_local:
# first clear all connection flags which dont exist anymore
for oldConnectedIP in self.connected_ip_list:
if oldConnectedIP not in connected_ip_list_local:
# change from True to False
self.node_dict[oldConnectedIP].conn_established = False
# loop list of active connections and set flag to True in node_dict
for connected_ip in connected_ip_list_local:
if connected_ip in self.node_dict: # need check in case we detect a conneciton of an IP which is not yet registered..
self.node_dict[connected_ip].conn_established = True
else:
# we make sure only known IPs are kept in the list
connected_ip_list_temp.remove(connected_ip)
###########################
# cross check to detect changes and inform GUI
###########################
for ip in self.connected_ip_list:
if ip not in connected_ip_list_temp:
# add/modify updated IP to GUI-List
if ip in self.node_dict: # may be connection of IP whic is not (yet) registered
self.__mutex.acquire()
self.node_dict_gui[ip] = self.node_dict[ip]
self.__mutex.release()
for ip in connected_ip_list_temp:
if ip not in self.connected_ip_list:
# add/modify updated IP to GUI-List
if ip in self.node_dict: # may be connection of IP whic is not (yet) registered
self.__mutex.acquire()
self.node_dict_gui[ip] = self.node_dict[ip]
self.__mutex.release()
####################################
# update list of connected IPs
self.connected_ip_list = connected_ip_list_temp
else:
# clear flags, reset list and also local handling...
if self.connected_ip_list: # need this?
# NOTE: getConnectedIPs() returns constantly empty list
# so we need to check if there are really zero connections by checking nr. of connections
if self.badConnectionKillerObject.getNumberOfConnections() == 0:
for oldConnectedIP in self.connected_ip_list:
# for some reason we need this check.
# TODO: how is it possible that the oldConnectedIP is NOT in the node_dict?
# we checked before and we copied from connected_ip_list_temp only IPs that exist in node_dict..
#######################################################
if oldConnectedIP in self.node_dict: