Files
i2p.plugins.i2pcontrol/scripts/i2pcontrol.py

362 lines
12 KiB
Python
Executable File

#!/usr/bin/env python
#
# If it fails "No module named yaml"
# then sudo apt install python-yaml
#
import argparse
import json
import urllib2
import httplib
import socket
import ssl
import sys
import yaml
from urllib2 import HTTPError, URLError
from string import whitespace
# Info about requestable data can be found at https://geti2p.net/i2pcontrol.html & https://geti2p.net/ratestats.html
address = "127.0.0.1" # Default I2PControl Address
port = 7650 # Default I2PControl Port
usessl = 1 # Change to 0 for HTTP
apiPassword = "itoopie" # Default I2PControl password
## Do not edit below
apiVersion = 1 # Default API Version
msgId = 1
token = None
def checkToken():
global token
if (token == None):
token = getToken()
if (token == None):
print("Unable to login. Quitting..")
sys.exit()
def getToken():
loginStr = "{\"id\":" + str(msgId) + ", \"method\":\"Authenticate\",\"params\":{\"API\":" + str(apiVersion) + ", \"Password\":\"" + apiPassword + "\"}, \"jsonrpc\":\"2.0\"}"
try:
jsonResp = sendMsg(loginStr)
return jsonResp.get("result").get("Token")
except HTTPError, e:
print("HTTPError: %s" % e.reason)
except URLError, e:
print("URLError: %s" % e.reason)
def getRate(rateName, ratePeriod):
checkToken()
msgStr = "{\"id\":" + str(msgId) + ", \"method\":\"GetRate\",\"params\":{\"Stat\":\"" + rateName + "\", \"Period\":" + str(ratePeriod) + ", \"Token\":\"" + token +"\" }, \"jsonrpc\":\"2.0\"}"
jsonResp = sendMsg(msgStr)
return jsonResp.get("result").get("Result")
def getRouterInfo(infoName):
checkToken()
## The parameter names in 'params' defines which answers are requested
msgStr = "{\"id\":" + str(msgId) + ", \"method\":\"RouterInfo\",\"params\":{\""+infoName+"\":\"\", \"Token\":\"" + token +"\" }, \"jsonrpc\":\"2.0\"}"
jsonResp = sendMsg(msgStr)
return jsonResp.get("result").get(infoName)
def getControlInfo(infoName):
checkToken()
## The parameter names in 'params' defines which answers are requested
if ("=" in infoName):
toks = infoName.split("=", 2);
infoName = toks[0];
infoValue = toks[1];
msgStr = "{\"id\":" + str(msgId) + ", \"method\":\"I2PControl\",\"params\":{\""+infoName+"\":\""+infoValue+"\", \"Token\":\"" + token +"\" }, \"jsonrpc\":\"2.0\"}"
else:
return "Parameter value required for " + infoName
jsonResp = sendMsg(msgStr)
return "I2PControl setting " + infoName + " set to " + infoValue
def getRouterManagerInfo(infoName):
checkToken()
## The parameter names in 'params' defines which answers are requested
msgStr = "{\"id\":" + str(msgId) + ", \"method\":\"RouterManager\",\"params\":{\""+infoName+"\":\"\", \"Token\":\"" + token +"\" }, \"jsonrpc\":\"2.0\"}"
jsonResp = sendMsg(msgStr)
if (infoName == "FindUpdates" or infoName == "Update"):
return jsonResp.get("result").get(infoName)
else:
return "Sent Router Manager command: " + infoName
def getNetworkInfo(infoName):
checkToken()
isset = 0;
## The parameter names in 'params' defines which answers are requested
if ("=" in infoName):
toks = infoName.split("=", 2);
isset = 1;
infoName = toks[0];
infoValue = toks[1];
msgStr = "{\"id\":" + str(msgId) + ", \"method\":\"NetworkSetting\",\"params\":{\""+infoName+"\":\""+infoValue+"\", \"Token\":\"" + token +"\" }, \"jsonrpc\":\"2.0\"}"
else:
msgStr = "{\"id\":" + str(msgId) + ", \"method\":\"NetworkSetting\",\"params\":{\""+infoName+"\":null, \"Token\":\"" + token +"\" }, \"jsonrpc\":\"2.0\"}"
jsonResp = sendMsg(msgStr)
if (isset == 1):
return "Network setting " + infoName + " set to " + infoValue
else:
return jsonResp.get("result").get(infoName)
def getAdvancedInfo(infoName):
checkToken()
isset = 0;
## The parameter names in 'params' defines which answers are requested
if (infoName == "GetAll"):
msgStr = "{\"id\":" + str(msgId) + ", \"method\":\"AdvancedSettings\",\"params\":{\""+infoName+"\":\"\", \"Token\":\"" + token +"\" }, \"jsonrpc\":\"2.0\"}"
elif (infoName == "SetAll"):
return "SetAll unsupported"
elif ("=" in infoName):
toks = infoName.split("=", 2);
isset = 1;
infoName = toks[0];
infoValue = toks[1];
msgStr = "{\"id\":" + str(msgId) + ", \"method\":\"AdvancedSettings\",\"params\":{\"set\":{\""+infoName+"\":\""+infoValue+"\"}, \"Token\":\"" + token +"\" }, \"jsonrpc\":\"2.0\"}"
else:
msgStr = "{\"id\":" + str(msgId) + ", \"method\":\"AdvancedSettings\",\"params\":{\"get\":\""+infoName+"\", \"Token\":\"" + token +"\" }, \"jsonrpc\":\"2.0\"}"
jsonResp = sendMsg(msgStr)
if (infoName == "GetAll"):
return jsonResp.get("result").get(infoName)
elif (isset == 1):
return "Advanced configuration " + infoName + " set to " + infoValue
else:
return jsonResp.get("result").get("get").get(infoName)
def sendMsg(jsonStr):
global msgId
https_handler = UnauthenticatedHTTPSHandler()
url_opener = urllib2.build_opener(https_handler)
if (usessl != 0):
handle = url_opener.open("https://"+address+":"+ str(port) + "/jsonrpc/", jsonStr)
else:
handle = url_opener.open("http://"+address+":"+ str(port) + "/jsonrpc/", jsonStr)
response = handle.read()
handle.close()
msgId = msgId + 1;
jsonResp = json.loads(response)
if (jsonResp.has_key("error")):
print ("Remote server: I2PControl Error: " + str(jsonResp.get("error").get("code")) + ", " + jsonResp.get("error").get("message"))
sys.exit()
return jsonResp
###
# Overrides the version in httplib so that we can ignore server certificate authenticity
###
class UnauthenticatedHTTPSConnection(httplib.HTTPSConnection):
def connect(self):
#
sock = socket.create_connection((self.host, self.port), self.timeout)
if self._tunnel_host:
self.sock = sock
self._tunnel()
self.sock = ssl.wrap_socket(sock,
cert_reqs=ssl.CERT_NONE)
###
# HTTPS handler which uses SSLv3 and ignores server cert authenticity
###
class UnauthenticatedHTTPSHandler(urllib2.HTTPSHandler):
def __init__(self, connection_class = UnauthenticatedHTTPSConnection):
self.specialized_conn_class = connection_class
urllib2.HTTPSHandler.__init__(self)
def https_open(self, req):
return self.do_open(self.specialized_conn_class, req)
def zabbix_config(fileName, outfile):
yamlDict = dict()
for line in open(fileName):
li=line.strip()
if li.startswith("UserParameter"):
i2pCtrlOpt = li.strip("UserParameter=").split(",")
i2pCtrlOpt[1] = i2pCtrlOpt[1].split()
i2pCtrlOpt[1].pop(0) # Remove path of this script (i2pcontrol)
i2pCtrlParams = i2pCtrlOpt[1]
#print i2pCtrlOpt #Delete me!
result = ""
if (i2pCtrlParams[0] == "-i" or i2pCtrlParams[0] == "--router-info"):
result = getRouterInfo(i2pCtrlParams[1])
elif (i2pCtrlParams[0] == "-s" or i2pCtrlParams[0] == "--rate-stat"):
result = getRate(i2pCtrlParams[1], i2pCtrlParams[2])
else:
result = "Bad query syntax."
yamlDict[i2pCtrlParams[1]] = result
#print yaml.dump(yamlDict)
yaml.dump(yamlDict, open(outfile,'w'))
def from_file(infile, parameter):
try:
yamlDict = yaml.load(open(infile,'r'))
print yamlDict[parameter]
except IOError, e:
print "File \""+ infile +"\" couldn't be read."
def main():
global address
global port
global usessl
parser = argparse.ArgumentParser(description='Fetch I2P info via the I2PControl API.')
parser.add_argument("-l",
"--host",
nargs=1,
metavar="host",
dest="address",
action="store",
help="Listen host address of the i2pcontrol server")
parser.add_argument("-p",
"--port",
nargs=1,
metavar="port",
dest="port",
action="store",
help="Port of the i2pcontrol server")
parser.add_argument("-x",
"--no-ssl",
dest="http",
action="store_true",
help="Use HTTP instead of HTTPS")
parser.add_argument("-i",
"--router-info",
nargs=1,
metavar="info",
dest="router_info",
action="store",
help="Request info such as I2P version and uptime. Returned info can be of any type. Full list of options at https://geti2p.net/i2pcontrol.html. Usage: \"-i i2p.router.version\"")
parser.add_argument("-c",
"--i2pcontrol-info",
nargs=1,
metavar="key[=value]",
dest="i2pcontrol_info",
action="store",
help="Change settings such as password. Usage: \"-c i2pcontrol.password=foo\"")
parser.add_argument("-r",
"--routermanager-info",
nargs=1,
metavar="command",
dest="routermanager_info",
action="store",
help="Send a command to the router. Usage: \"-r FindUpdates|Reseed|Restart|RestartGraceful|Shutdown|ShutdownGraceful|Update\"")
parser.add_argument("-n",
"--network-info",
nargs=1,
metavar="key[=value]",
dest="network_info",
action="store",
help="Request info such as bandwidth. Usage: \"-n i2p.router.net.bw.in[=xxx]\"")
parser.add_argument("-a",
"--advanced-info",
nargs=1,
metavar="key[=value]",
dest="advanced_info",
action="store",
help="Request configuration info. Usage: \"-a GetAll|foo[=bar]\"")
parser.add_argument("-s",
"--rate-stat",
nargs=2,
metavar=("rateStatName", "period"),
dest="rate_stat",
action="store",
help="Request info such as bandwidth, number active peers, clock skew, etc.. The period is measured in ms and must be longer than 60s. Full list at https://geti2p.net/ratestats.html. Usage: \"-s bw.receiveBps 3600000\"")
parser.add_argument("-z",
"--zabbix",
nargs=2,
metavar=("\"path to zabbix_agent.conf\"", "\"path to output file\""),
dest="zabbix",
action="store",
help="Parse options to request, by reading a zabbix config file for \"UserParameter\"s relating to I2P. Usage: \"-z /etc/zabbix/zabbix_agent.conf\"")
parser.add_argument("-f",
"--from-file",
nargs=1,
metavar=("\"path to input file\""),
dest="from_file",
action="store",
help="Parse options to request, by reading a zabbix config file for \"UserParameter\"s relating to I2P. Usage: \"-z /etc/zabbix/zabbix_agent.conf\"")
if (len(sys.argv) == 1):
parser.parse_args(["-h"])
options = parser.parse_args()
# todo we don't check all the options
if ((options.rate_stat != None) and (options.router_info != None)):
print("Error: Choose _one_ option. \n\n")
parser.parse_args(["-h"])
# todo we don't check all the options
if ((options.zabbix != None) and ((options.rate_stat != None) or (options.router_info != None) or (options.from_file != None))):
print("Error: Don't combine option --zabbix with other options.\n")
parser.parse_args(["-h"])
# From-file can only be used when either router-info or rate-stat is enabled.
# todo we don't check all the options
if ((options.from_file != None) and (options.rate_stat == None) and (options.router_info == None)):
print("Error: --from-file must be used with either --router-info or --rate-stat.\n")
parser.parse_args(["-h"])
if (options.port != None):
port = int(options.port[0]);
if (options.address != None):
address = options.address[0];
if (options.http):
usessl = 0;
if (options.from_file != None):
if (options.router_info != None):
from_file(options.from_file[0], options.router_info[0])
if (options.rate_stat != None):
from_file(options.from_file[0], options.rate_stat[0])
sys.exit()
if (options.rate_stat != None):
try:
period = int(options.rate_stat[1])
if (period < 60000):
raise ValueError
print getRate(options.rate_stat[0], period)
except ValueError, e:
print("Error: \""+options.rate_stat[1]+"\" is not an integer > 60000 \n\n")
parser.parse_args(["-h"])
sys.exit()
if (options.router_info != None):
print getRouterInfo(options.router_info[0])
sys.exit()
if (options.i2pcontrol_info != None):
print getControlInfo(options.i2pcontrol_info[0])
sys.exit()
if (options.routermanager_info != None):
print getRouterManagerInfo(options.routermanager_info[0])
sys.exit()
if (options.network_info != None):
print getNetworkInfo(options.network_info[0])
sys.exit()
if (options.advanced_info != None):
print getAdvancedInfo(options.advanced_info[0])
sys.exit()
if (options.zabbix != None):
zabbix_config(options.zabbix[0], options.zabbix[1])
sys.exit()
if __name__ == "__main__":
main()