Compare commits

...

10 Commits

6 changed files with 118 additions and 135 deletions

5
.gitignore vendored
View File

@ -1,2 +1,5 @@
conf.json conf.json
.vscode .vscode
# Ignore anything in the payload, this is downloaded from a url internally on a timely basis.
payload/

View File

@ -1,8 +1,11 @@
{ {
"loglevel": "",
"chkinterval": "",
"filepath": "",
"srcurl": "",
"os": "",
"server": "", "server": "",
"port": "", "port": "",
"payload": "payload/payload.sh",
"ssh-user": "", "ssh-user": "",
"ssh-password": "", "ssh-pw": ""
"ssh-key": ""
} }

128
deploy.py
View File

@ -1,52 +1,110 @@
import paramiko import paramiko # this sounds like an anime
import json import json
import os import os
import time # i need time to get this done import time # i need time to get this done
import requests # for getting the commands to run on client
import logging
# import modules # Open the config file and make it accessible via "cfg"
with open("conf.json", "r") as file: with open("conf.json", "r") as file:
cfg = json.load(file) cfg = json.load(file)
# open the config file and make it accessible via "cfg"
# set our variables
sshc = paramiko.client.SSHClient() sshc = paramiko.client.SSHClient()
healthstatus = "" # possible values: "ok", "err" healthstatus = "" # possible values: "ok", "err"
healthpassing = True healthpassing = True
# set our variables shcommands = []
def healthcheck(): # Configure logging
logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s')
log = logging.getLogger()
try:
if cfg["loglevel"] == "debug":
log.setLevel(logging.DEBUG)
else:
log.setLevel(logging.INFO)
except KeyError:
log.setLevel(logging.INFO)
log.debug("Logger was initialized")
def healthcheck(): # Uses os.system to ping the ONT to check for responses/status.
global healthstatus global healthstatus
response = os.system("ping -c 2 " + cfg["server"] + ">> /dev/null") response = ""
if cfg["os"] == "win":
response = os.system("ping -n 2 " + cfg["server"]+ "> nul")
else:
response = os.system("ping -c 2 " + cfg["server"] + ">> /dev/null")
if response != 0: if response != 0:
log.debug("healthstatus set to err!")
healthstatus = "err" healthstatus = "err"
else: else:
log.debug("healthstatus set to ok!")
healthstatus = "ok" healthstatus = "ok"
def deploy(): def downloadLatestCommands(): # If the "srcurl" attribute in the configuration is set, downloads the latest iptables commands to be run on the ONT from another server using HTTP.
sshc.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # so we don't get whined at and crash over a unrecognized host-key try:
sshc.connect(cfg["server"],port=cfg["port"],key_filename=cfg["ssh-key"]) r = requests.get(cfg['srcurl'])
open(cfg["filepath"], 'wb').write(r.content)
sftp = sshc.open_sftp() # after opening the ssh connection, we'll open a sftp connection. commandList() # Run this here instead of seperately if this method is used.
sftp.put("./payload/payload.sh", "/payload.sh") # upload the payload via SFTP. except:
if os.path.exists(cfg["filepath"]):
sshc.exec_command("chmod +x $HOME/payload.sh") # make it executable log.warning("The latest commands could not be retrieved, however a copy of the commands was saved previously, which will be used.")
sshc.exec_command("./payload.sh") # and finally, run the payload. else:
sshc.close # close the connection. log.error("The latest commands could not be retrieved, and no previous copy is saved on the system.")
while True: log.debug("The commandList method will also fail!")
healthcheck()
if healthstatus != "ok": def commandList(): # Opens the file defined by the configuration's "filepath" variable and splits the commands into a parseable list with every new line (\n).
print("ONT is not responding!! Did we lose network connection, or is the ONT rebooting? waiting for ONT to respond, then deploying payload!") global shcommands
healthpassing = False if os.path.exists(cfg["filepath"]):
while healthpassing == False: cmdtxt = open(cfg["filepath"], "r")
print("Checking for a response...") cmddata = cmdtxt.read()
healthcheck() shcommands = cmddata.split("\n")
cmdtxt.close()
if healthstatus == "ok":
print("ONT responded, deploying payload!")
healthpassing == True;
deploy()
break
else: else:
print("Got a response! health status is ok.") log.error("The commands to be run on the ONT could not be split into a list, as no previous copy is saved on the system.")
time.sleep(30) # we will run this loop every 30 seconds so we don't pelt the poor thing in pings.
def deploy():
downloadLatestCommands()
sshc.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # so we don't get whined at and crash over a unrecognized host-key
sshc.connect(cfg["server"],port=cfg["port"],username=cfg["ssh-user"],password=cfg["ssh-pw"])
time.sleep(3) # Sleep 3 seconds, because the ONT's sshd takes forever to start a shell.
for command in shcommands:
sshc.exec_command(command)
log.info(f'{command} was executed on the ONT')
log.info("All commands were executed, now disconnecting...")
sshc.close # close the connection.
def firstRun(): # Methods to run when starting the script initially.
log.debug("firstRun method started")
log.info("--iptables-deploy for Brazos WiFi ONTs--")
log.info("Co-authored by iRaven and IDeletedSystem64.")
downloadLatestCommands() # Do this at first run
commandList() # Break all the commands into a list
healthcheck() # Run the health check for the first time
main() # Start the loop.
def main(): # Main method to be looped.
while True:
healthcheck() # Run the health check
if healthstatus != "ok":
log.info("ONT is not responding- Waiting for a response, then deploying iptables commands!")
healthpassing = False
while healthpassing == False:
log.info("Checking for a response (pinging "+cfg["server"]+")...")
healthcheck()
if healthstatus == "ok":
log.warning("ONT responded after a fail, deploying payload!")
healthpassing == True
time.sleep(10) # Wait 10 seconds for the ONT to fully boot up and start sshd.
deploy()
log.info("ONT payload was deployed, resuming normal operations.")
break
else:
log.info("Got a response, the ONT is running and healthy.")
log.info("Trying again in " + cfg["chkinterval"] + " seconds.")
time.sleep(int(cfg["chkinterval"])) # we will run this loop every X seconds, defined by checkinterval
firstRun()

13
ontdeploy.service Normal file
View File

@ -0,0 +1,13 @@
[Unit]
Description=ONT Deploy Script
After=network.target
[Service]
Type=idle
Restart=on-failure
User=root
WorkingDirectory=/opt/iptables-deploy
ExecStart=/usr/bin/python3 deploy.py
[Install]
WantedBy=multi-user.target

View File

@ -1,3 +0,0 @@
#!/bin/bash
wall "it works!!"

View File

@ -1,93 +1,2 @@
appdirs==1.4.4 paramiko
argcomplete==2.0.0 requests
bcrypt==4.1.2
beautifulsoup4==4.12.2
blivet==3.7.1
blivet-gui==2.4.2
Brlapi==0.8.4
Brotli==1.0.9
certifi==2022.9.24
cffi==1.15.1
chardet==5.2.0
charset-normalizer==3.1.0
click==8.1.3
cryptography==41.0.7
cssselect==1.1.0
cupshelpers==1.0
dasbus==1.7
dbus-python==1.3.2
decorator==5.1.1
Deprecated==1.2.14
distro==1.8.0
dnf==4.18.2
docopt==0.6.2
evdev==1.6.1
fedora-third-party==0.10
file-magic==0.4.0
gpg==1.17.1
humanize==3.13.1
idna==3.4
initial-setup==0.3.97
invoke==2.2.0
Jinja2==3.0.3
langtable==0.0.64
libcomps==0.1.20
libdnf==0.72.0
libvirt-python==9.0.0
lxml==4.9.2
MarkupSafe==2.1.2
mutagen==1.46.0
nftables==0.1
numpy==1.24.4
olefile==0.46
packaging==23.0
paramiko==3.4.0
pexpect==4.8.0
pid==2.2.3
Pillow==9.5.0
ply==3.11
productmd==1.37
protonvpn-cli==2.2.11
ptyprocess==0.7.0
pwquality==1.4.5
pycairo==1.23.0
pycparser==2.20
pycryptodomex==3.19.0
pycups==2.0.1
pycurl==7.45.2
pyenchant==3.2.2
PyGObject==3.44.2
pykickstart==3.47
PyNaCl==1.5.0
pyparted==3.12.0
PyQt5==5.15.9
PyQt5-sip==12.11.1
PySocks==1.7.1
python-augeas==1.1.0
python-dateutil==2.8.2
python-gettext==4.0
python-manatools==0.0.4
python-meh==0.51
pythondialog==3.5.3
pyudev==0.24.0
pyxdg==0.27
PyYAML==6.0
regex==2023.10.3
requests==2.28.2
requests-file==1.5.1
requests-ftp==0.3.1
rpm==4.18.2
scour==0.38.2
selinux==3.5
sepolicy==3.5
setools==4.4.3
simpleaudio==1.0.4
simpleline==1.9.0
six==1.16.0
sos==4.5.1
soupsieve==2.4.1
systemd-python==235
urllib3==1.26.18
websockets==10.4
wrapt==1.16.0
yt-dlp==2023.10.7