/src/notrackd.py

https://github.com/quidsup/notrack · Python · 251 lines · 133 code · 55 blank · 63 comment · 29 complexity · 72705b43102df3f02d63507d34e49507 MD5 · raw file

  1. #!/usr/bin/env python3
  2. #Title : NoTrackD
  3. #Description : NoTrack Daemon
  4. #Author : QuidsUp
  5. #Date : 2020-07-24
  6. #Version : 2020.07
  7. #Usage :
  8. #Standard imports
  9. from datetime import datetime
  10. import os
  11. import time
  12. import signal
  13. import sys
  14. #Local imports
  15. from analytics import NoTrackAnalytics
  16. from blockparser import BlockParser
  17. from config import NoTrackConfig
  18. from logparser import NoTrackParser
  19. from ntrkfolders import FolderList
  20. from ntrkservices import Services
  21. from statusconsts import *
  22. runtime_analytics = 0.0
  23. runtime_blocklist = 0.0
  24. runtime_parser = 0.0
  25. runtime_trim = 0.0
  26. endloop = False
  27. ntrkparser = NoTrackParser()
  28. ntrkanalytics = NoTrackAnalytics()
  29. folders = FolderList()
  30. config = NoTrackConfig()
  31. def blocklist_update():
  32. """
  33. Once a day update of the NoTrack blocklists
  34. """
  35. print()
  36. print('Updating Blocklist')
  37. blockparser = BlockParser(config.dns_blockip)
  38. blockparser.load_blconfig()
  39. blockparser.create_blocklist() #Create / Update Blocklists
  40. time.sleep(6) #Prevent race condition
  41. ntrkparser.readblocklist() #Reload the blocklist on the log parser
  42. set_lastrun_times()
  43. def change_status():
  44. """
  45. """
  46. print()
  47. print('Changing status of NoTrack')
  48. blockparser = BlockParser(config.dns_blockip)
  49. if config.status & STATUS_ENABLED:
  50. blockparser.enable_blockling()
  51. else:
  52. blockparser.disable_blocking()
  53. def check_pause(current_time):
  54. """
  55. Check if pause time has been reached
  56. Function should only be called if status is STATUS_PAUSED
  57. Parameters:
  58. current_time (int): The current epoch time value
  59. """
  60. if config.unpausetime < current_time:
  61. print()
  62. print('Unpause time reached')
  63. blockparser = BlockParser(config.dns_blockip)
  64. blockparser.enable_blockling()
  65. config.status -= STATUS_PAUSED
  66. config.status += STATUS_ENABLED
  67. config.unpausetime = 0
  68. def get_status(currentstatus):
  69. """
  70. Confirm system status is as currentstatus specifies
  71. e.g. main or temp blocklist could be missing
  72. Parameters:
  73. currentstatus (int): The current belived status
  74. Returns:
  75. Actual Status
  76. """
  77. mainexists = os.path.isfile(folders.main_blocklist)
  78. tempexists = os.path.isfile(folders.temp_blocklist)
  79. if currentstatus & STATUS_ENABLED and mainexists: #Check Enabled Status
  80. return currentstatus
  81. elif currentstatus & STATUS_ENABLED:
  82. return STATUS_ERROR
  83. if currentstatus & STATUS_DISABLED and tempexists: #Check Disabled Status
  84. return currentstatus
  85. elif currentstatus & STATUS_DISABLED:
  86. return STATUS_ERROR
  87. if currentstatus & STATUS_PAUSED and tempexists: #Check Paused Status
  88. return currentstatus
  89. elif currentstatus & STATUS_PAUSED:
  90. return STATUS_ERROR
  91. return STATUS_ERROR #Shouldn't get here
  92. def exit_gracefully(signum, frame):
  93. """
  94. End the main loop when SIGINT, SIGABRT or SIGTERM is received
  95. Parameters:
  96. signum (int): Signal
  97. frame (int): Frame
  98. """
  99. global endloop
  100. #if signum == signal.SIGABRT: #Abort moves state to Disabled
  101. #self.__enable_blocking = False
  102. endloop = True #Trigger breakout of main loop
  103. def set_lastrun_times():
  104. """
  105. Ensure jobs run when ready
  106. 1. Analytics - On the hour
  107. 2. Blocklist Parser - 04:10 AM
  108. 3. Trim - 03:10 AM
  109. """
  110. global runtime_analytics, runtime_blocklist, runtime_trim
  111. dtanalytics = datetime.strptime(time.strftime("%y-%m-%d %H:00:00"), '%y-%m-%d %H:%M:%S')
  112. dtblocklist = datetime.strptime(time.strftime("%y-%m-%d 04:10:00"), '%y-%m-%d %H:%M:%S')
  113. dttrim = datetime.strptime(time.strftime("%y-%m-%d 03:10:00"), '%y-%m-%d %H:%M:%S')
  114. runtime_analytics = dtanalytics.timestamp()
  115. runtime_blocklist = dtblocklist.timestamp()
  116. runtime_trim = dttrim.timestamp()
  117. def analytics():
  118. """
  119. Run NoTrack Analytics
  120. """
  121. ntrkanalytics.checkmalware()
  122. ntrkanalytics.checktrackers()
  123. def logparser():
  124. """
  125. Run NoTrack Log Parser
  126. """
  127. if config.status & STATUS_INCOGNITO: #No parsing with incognito
  128. ntrkparser.blank_dnslog()
  129. else:
  130. ntrkparser.parsedns()
  131. def check_config_files():
  132. """
  133. Check config to see if any files have been modified
  134. Action any changes depending on which config file has been updated
  135. If statements are ordered in the most likely config to be updated
  136. """
  137. filechanged = ''
  138. filechanged = config.check_modified_times() #Check for the first file modified
  139. if filechanged == 'status.php': #Status Config
  140. print('Status config updated')
  141. if get_status(config.status) != config.status:
  142. change_status()
  143. elif filechanged == 'bl.php': #Blocklist Config
  144. print('Blocklist config updated')
  145. blocklist_update()
  146. #One of the domain list files
  147. elif filechanged == 'blacklist.txt' or filechanged == 'whitelist.txt' or filechanged == 'tldlist.txt':
  148. print('Domain lists updated')
  149. blocklist_update()
  150. elif filechanged == 'server.php': #Server Config
  151. restart_dns()
  152. def restart_dns():
  153. """
  154. Restart the DNS server
  155. """
  156. services = Services()
  157. services.restart_dnsserver()
  158. def main():
  159. global endloop
  160. global runtime_analytics, runtime_blocklist, runtime_parser, runtime_trim
  161. signal.signal(signal.SIGINT, exit_gracefully) #2 Inturrupt
  162. signal.signal(signal.SIGABRT, exit_gracefully) #6 Abort
  163. signal.signal(signal.SIGTERM, exit_gracefully) #9 Terminate
  164. current_time = 0.0
  165. current_time = time.time()
  166. print('NoTrack Daemon')
  167. if get_status(config.status) != config.status:
  168. change_status()
  169. time.sleep(5)
  170. #Initial setup
  171. ntrkparser.readblocklist()
  172. set_lastrun_times()
  173. while not endloop:
  174. current_time = time.time()
  175. check_config_files()
  176. if (config.status & STATUS_PAUSED):
  177. check_pause(current_time)
  178. if (runtime_analytics + 3600) <= current_time:
  179. runtime_analytics = current_time
  180. analytics()
  181. if (runtime_parser + 240) <= current_time:
  182. runtime_parser = current_time
  183. logparser()
  184. if (runtime_blocklist + 86400) <= current_time:
  185. blocklist_update()
  186. if (runtime_trim + 86400) <= current_time:
  187. runtime_trim = current_time #Reset runtime_trim
  188. ntrkparser.trimlogs(config.dns_logretention)
  189. time.sleep(5)
  190. if __name__ == "__main__":
  191. main()