Skip to content

Instantly share code, notes, and snippets.

@mgax
Created May 7, 2009 19:35
Show Gist options
  • Save mgax/108306 to your computer and use it in GitHub Desktop.
Save mgax/108306 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
#
# $Id: czoink.py 11 2008-06-18 23:44:45Z respawned $
#
# Copyright (c) 2008 Respwaned Fluff <[email protected]>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation
# files (the "Software"), to deal in the Software without
# restriction, including without limitation the rights to use,
# copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following
# conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
# OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
# Simplified by Alex Morega; original source available
# from http://code.google.com/p/czoink/
import os, re, sys, urllib, logging, logging.handlers, getopt, base64, time
# import mcrypt # mcrypt usually needs to be installed.
import ConfigParser, signal, socket
CZ_VER = "1.0.1.3" # This is the version we're compatible with.
CZ_KEY = "f52412c4ff1dacd2111f4951f3db1260"
CZ_IV = "0e32f4c96203f892"
def read_config():
global USER, PASSWD
config = ConfigParser.ConfigParser()
config.read("/home/alexm/czone/czoink.ini")
USER = config.get("login", "user")
PASSWD = config.get("login", "pass")
def daemon_me():
return len(sys.argv) > 1 and sys.argv[1] == "-d"
LOG_FORMAT = "%(asctime)s: %(name)s[%(levelname)s]: %(message)s"
if daemon_me():
LOG_LEVEL = logging.INFO
else:
LOG_LEVEL = logging.DEBUG
def setup_log():
log = logging.getLogger("czoink")
if daemon_me():
hand = logging.FileHandler('/home/alexm/czone/czoink.log')
else:
hand = logging.StreamHandler()
fmt = logging.Formatter(LOG_FORMAT)
hand.setFormatter(fmt)
log.addHandler(hand)
log.setLevel(LOG_LEVEL) # log filter
hand.setLevel(LOG_LEVEL) # handler filter
return log
def beh64(data):
return base64.encodestring(data).strip().replace("\n", "")
def setup_aes():
try:
from mcrypt import MCRYPT
aes = MCRYPT("rijndael-128", "cbc")
aes.init(CZ_KEY, CZ_IV)
def cz_fun(strn):
aes.reinit()
return beh64(beh64(aes.encrypt(strn)))
cry_prov = "mcrypt"
except:
from Crypto.Cipher import AES
def cz_fun(strn):
aes = AES.new(CZ_KEY, AES.MODE_CBC, CZ_IV) # no reinit
pad = len(strn) % 16
if pad != 0:
strn = strn + ('\x00' * (16 - pad))
return beh64(beh64(aes.encrypt(strn)))
cry_prov = "pycrypto"
global cz_arg
cz_arg = cz_fun
return cry_prov
def check_ver():
try:
fil = urllib.urlopen("https://acces.czone.ro/czone/versionlinux.txt")
remote_ver = fil.readline()
fil.close()
if remote_ver != CZ_VER:
log.warning("I may be too old. Seek newer version.")
else:
log.info("Version check passes.")
except:
log.error("Could not determine latest czone app version.")
junkre = re.compile("<b.+?\x0a")
def skip_warns(strn):
# Ignore line that starts with "<b" (i.e. "<br />" or "<b>Warning...")
while junkre.match(strn):
strn = strn[strn.find("\x0a")+1:]
return strn
class CzRPCError(Exception):
def __init__(self, url):
self.url = url
def __str__(self):
return repr(self.url)
def cz_rpc(cmd):
url = "https://acces.czone.ro/czone/c-zone.php?Data=" + cz_arg(cmd)
try:
log.debug(url)
fil = urllib.urlopen(url)
res = fil.read()
fil.close()
equs = skip_warns(res.strip("\x09\x0a\x0d\x20")).split("\x0d")
log.debug(equs)
return dict([elm.split("=", 1) for elm in equs if elm])
except:
log.error("RPC failed: " + url)
raise CzRPCError(url)
iline = re.compile(r'\d+: (\w+):')
nline = re.compile(r'\s+inet ([0-9.]+)')
sanre = re.compile(r'[0-9.]+')
def sanit(strn):
return sanre.match(strn).group()
def do_sys(cmd):
log.info("Executing: %s", cmd)
status = os.system(cmd)
if status:
log.error("Command %s failed.", cmd) # TBD: error string
return False
return True
must_die = False
def death_handler(signum, frame):
global must_die
log.info('Terminating on signal %s.', signum)
must_die = True
def refresh_handler(signum, frame):
log.info('Refreshing on signal %s.', signum)
def setup_signals():
signal.signal(signal.SIGTERM, death_handler)
signal.signal(signal.SIGINT, death_handler)
signal.signal(signal.SIGUSR1, refresh_handler)
signal.signal(signal.SIGALRM, refresh_handler)
def cz_login():
nonce = cz_rpc("IP=unknown&COMMAND=NONCE&USERNAME=" + USER)
login = cz_rpc(("IP=unknown&COMMAND=LOGIN&USERNAME=%s" +
"&PASSWORD=%s&NONCE=%s") %
(USER, PASSWD, nonce["NONCE"]))
if login["MESSAGE"] == "INSTALL":
log.error('IP setup functionality removed.')
global must_die
must_die = True
return False
elif login["MESSAGE"] == "CONNECTED":
log.info("Connected.")
huh = cz_rpc("IP=unknown&COMMAND=LINUX&USERNAME=" + USER +
"&FORWARD=0&SNAT=0&TTL=0&MASQ=0")
log.debug(huh)
return True
log.error("Oopsie: " + login)
return False
def reindent(s, numSpaces):
leading_space = numSpaces * ' '
lines = [ leading_space + line.strip( )
for line in s.splitlines( ) ]
return '\n'.join(lines)
def daemon():
try:
pid = os.fork()
if pid > 0:
# exit first parent
sys.exit(0)
except OSError, e:
print >>sys.stderr, "fork #1 failed: %d (%s)" % (e.errno, e.strerror)
sys.exit(1)
# decouple from parent environment
os.chdir("/") #don't prevent unmounting....
os.setsid()
os.umask(0)
# do second fork
try:
pid = os.fork()
if pid > 0:
# exit from second parent, print eventual PID before
#print "Daemon PID %d" % pid
open("/home/alexm/czone/czoink.pid", 'w').write("%d\n" % pid)
sys.exit(0)
except OSError, e:
print >>sys.stderr, "fork #2 failed: %d (%s)" % (e.errno, e.strerror)
sys.exit(1)
if __name__ == "__main__":
log = setup_log()
aes = setup_aes()
setup_signals()
read_config()
if daemon_me():
daemon()
log.info("Startup using %s AES provider.", aes)
verchk = True
while not must_die:
if verchk:
check_ver()
verchk = False
if cz_login():
time.sleep(600)
else:
raise ValueError
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment