mirror of https://github.com/fail2ban/fail2ban
- 0.7.0 soon
git-svn-id: https://fail2ban.svn.sourceforge.net/svnroot/fail2ban/trunk@251 a942ae1a-1317-0410-a47c-b1dcaea8d6050.x
parent
12c222bd1c
commit
7048e19995
|
@ -32,9 +32,10 @@ logSys = logging.getLogger("fail2ban.client.config")
|
|||
|
||||
class ActionReader(ConfigReader):
|
||||
|
||||
def __init__(self, file, name):
|
||||
def __init__(self, action, name):
|
||||
ConfigReader.__init__(self)
|
||||
self.file = file
|
||||
self.file = action[0]
|
||||
self.cInfo = action[1]
|
||||
self.name = name
|
||||
|
||||
def setFile(self, file):
|
||||
|
@ -58,7 +59,12 @@ class ActionReader(ConfigReader):
|
|||
["string", "actioncheck", ""],
|
||||
["string", "actionban", ""],
|
||||
["string", "actionunban", ""]]
|
||||
self.opts = ConfigReader.getOptions(self, "DEFAULT", opts, pOpts)
|
||||
self.opts = ConfigReader.getOptions(self, "Definition", opts, pOpts)
|
||||
|
||||
if self.has_section("Init"):
|
||||
for opt in self.options("Init"):
|
||||
if not self.cInfo.has_key(opt):
|
||||
self.cInfo[opt] = self.get("Init", opt)
|
||||
|
||||
def convert(self):
|
||||
head = ["set", self.name]
|
||||
|
@ -75,5 +81,10 @@ class ActionReader(ConfigReader):
|
|||
stream.append(head + ["actionban", self.file, self.opts[opt]])
|
||||
elif opt == "actionunban":
|
||||
stream.append(head + ["actionunban", self.file, self.opts[opt]])
|
||||
# cInfo
|
||||
if self.cInfo:
|
||||
for p in self.cInfo:
|
||||
stream.append(head + ["setcinfo", self.file, p, self.cInfo[p]])
|
||||
|
||||
return stream
|
||||
|
|
@ -40,7 +40,7 @@ class Fail2banReader(ConfigReader):
|
|||
|
||||
def getOptions(self):
|
||||
opts = [["int", "loglevel", 1]]
|
||||
self.opts = ConfigReader.getOptions(self, "DEFAULT", opts)
|
||||
self.opts = ConfigReader.getOptions(self, "Definition", opts)
|
||||
|
||||
def convert(self):
|
||||
stream = list()
|
||||
|
|
|
@ -59,7 +59,7 @@ class FilterReader(ConfigReader):
|
|||
["string", "failregex", ""],
|
||||
["int", "maxtime", 600],
|
||||
["int", "maxretry", 3]]
|
||||
self.opts = ConfigReader.getOptions(self, "DEFAULT", opts, pOpts)
|
||||
self.opts = ConfigReader.getOptions(self, "Definition", opts, pOpts)
|
||||
|
||||
def convert(self):
|
||||
stream = list()
|
||||
|
|
|
@ -24,7 +24,7 @@ __date__ = "$Date: 2005/11/20 17:07:47 $"
|
|||
__copyright__ = "Copyright (c) 2004 Cyril Jaquier"
|
||||
__license__ = "GPL"
|
||||
|
||||
import logging
|
||||
import logging, re
|
||||
from configreader import ConfigReader
|
||||
from filterreader import FilterReader
|
||||
from actionreader import ActionReader
|
||||
|
@ -68,7 +68,8 @@ class JailReader(ConfigReader):
|
|||
|
||||
# Read action
|
||||
for act in self.opts["action"].split():
|
||||
action = ActionReader(act, self.name)
|
||||
splitAct = JailReader.splitAction(act)
|
||||
action = ActionReader(splitAct, self.name)
|
||||
action.read()
|
||||
action.getOptions(self.opts)
|
||||
self.actions.append(action)
|
||||
|
@ -84,4 +85,13 @@ class JailReader(ConfigReader):
|
|||
for action in self.actions:
|
||||
stream.extend(action.convert())
|
||||
return stream
|
||||
|
||||
|
||||
@staticmethod
|
||||
def splitAction(action):
|
||||
m = re.match("^(\w+)(?:\[(.*)\])?$", action)
|
||||
d = dict()
|
||||
if m.group(2) <> None:
|
||||
for param in m.group(2).split(','):
|
||||
p = param.split('=')
|
||||
d[p[0]] = p[1]
|
||||
return [m.group(1), d]
|
||||
|
|
|
@ -42,7 +42,7 @@ class JailsReader(ConfigReader):
|
|||
|
||||
def getOptions(self):
|
||||
opts = []
|
||||
self.opts = ConfigReader.getOptions(self, "DEFAULT", opts)
|
||||
self.opts = ConfigReader.getOptions(self, "Definition", opts)
|
||||
|
||||
for sec in self.sections():
|
||||
jail = JailReader(sec)
|
||||
|
|
|
@ -1,18 +1,11 @@
|
|||
[DEFAULT]
|
||||
|
||||
name = temporary
|
||||
|
||||
# Option: protocol
|
||||
# Notes.: internally used by config reader for interpolations.
|
||||
# Values: [ tcp | udp | icmp | all ] Default: tcp
|
||||
#
|
||||
protocol = tcp
|
||||
[Definition]
|
||||
|
||||
# Option: fwstart
|
||||
# Notes.: command executed once at the start of Fail2Ban.
|
||||
# Values: CMD Default:
|
||||
#
|
||||
actionstart = touch /tmp/fail2ban.dummy
|
||||
echo "<init>" >> /tmp/fail2ban.dummy
|
||||
|
||||
# Option: fwend
|
||||
# Notes.: command executed once at the end of Fail2Ban
|
||||
|
@ -48,3 +41,7 @@ actionban = echo "+<ip>" >> /tmp/fail2ban.dummy
|
|||
# Default: iptables -D INPUT -s <ip> -j DROP
|
||||
#
|
||||
actionunban = echo "-<ip>" >> /tmp/fail2ban.dummy
|
||||
|
||||
[Init]
|
||||
|
||||
init = 123
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
[DEFAULT]
|
||||
|
||||
name = temporary
|
||||
[Definition]
|
||||
|
||||
# Option: protocol
|
||||
# Notes.: internally used by config reader for interpolations.
|
||||
|
@ -18,13 +16,13 @@ actionstart = touch /tmp/fail2ban.foo
|
|||
# Notes.: command executed once at the end of Fail2Ban
|
||||
# Values: CMD Default:
|
||||
#
|
||||
actionstop = rm /tmp/fail2ban.foo
|
||||
actionstop = rm -f /tmp/fail2ban.foo
|
||||
|
||||
# Option: fwcheck
|
||||
# Notes.: command executed once before each fwban command
|
||||
# Values: CMD Default:
|
||||
#
|
||||
actioncheck =
|
||||
actioncheck = [ -e "/tmp/fail2ban.foo" ]
|
||||
|
||||
# Option: fwban
|
||||
# Notes.: command executed when banning an IP. Take care that the
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
[Definition]
|
||||
|
||||
# Option: fwstart
|
||||
# Notes.: command executed once at the start of Fail2Ban.
|
||||
# Values: CMD Default:
|
||||
#
|
||||
actionstart = touch <tmpfile>
|
||||
|
||||
# Option: fwend
|
||||
# Notes.: command executed once at the end of Fail2Ban
|
||||
# Values: CMD Default:
|
||||
#
|
||||
actionstop = rm -f <tmpfile>
|
||||
|
||||
# Option: fwcheck
|
||||
# Notes.: command executed once before each fwban command
|
||||
# Values: CMD Default:
|
||||
#
|
||||
actioncheck =
|
||||
|
||||
# Option: fwban
|
||||
# Notes.: command executed when banning an IP. Take care that the
|
||||
# command is executed with Fail2Ban user rights.
|
||||
# Tags: <ip> IP address
|
||||
# <failures> number of failures
|
||||
# <failtime> unix timestamp of the last failure
|
||||
# <bantime> unix timestamp of the ban time
|
||||
# Values: CMD
|
||||
# Default: iptables -I INPUT 1 -s <ip> -j DROP
|
||||
#
|
||||
actionban = IP=<ip> &&
|
||||
echo "ALL: $IP" >> <file>
|
||||
|
||||
# Option: fwunban
|
||||
# Notes.: command executed when unbanning an IP. Take care that the
|
||||
# command is executed with Fail2Ban user rights.
|
||||
# Tags: <ip> IP address
|
||||
# <bantime> unix timestamp of the ban time
|
||||
# <unbantime> unix timestamp of the unban time
|
||||
# Values: CMD
|
||||
# Default: iptables -D INPUT -s <ip> -j DROP
|
||||
#
|
||||
actionunban = IP=<ip> &&
|
||||
grep -v "ALL: $IP" <file> > <tmpfile> &&
|
||||
mv <tmpfile> <file>
|
||||
|
||||
[Init]
|
||||
|
||||
# Option: file
|
||||
# Notes.: hosts.deny file path.
|
||||
# Values: STR Default: /etc/hosts.deny
|
||||
#
|
||||
file = /etc/hosts.deny
|
||||
|
||||
# Option: file
|
||||
# Notes.: hosts.deny temporary file path.
|
||||
# Values: STR Default: /etc/hostsdeny.failban
|
||||
#
|
||||
tmpfile = /tmp/hosts.deny.tmp
|
|
@ -1,35 +1,26 @@
|
|||
[DEFAULT]
|
||||
|
||||
name = temporary
|
||||
port = 22
|
||||
|
||||
# Option: protocol
|
||||
# Notes.: internally used by config reader for interpolations.
|
||||
# Values: [ tcp | udp | icmp | all ] Default: tcp
|
||||
#
|
||||
protocol = tcp
|
||||
[Definition]
|
||||
|
||||
# Option: fwstart
|
||||
# Notes.: command executed once at the start of Fail2Ban.
|
||||
# Values: CMD Default:
|
||||
#
|
||||
actionstart = iptables -N fail2ban-%(name)s
|
||||
iptables -A fail2ban-%(name)s -j RETURN
|
||||
iptables -I INPUT -p %(protocol)s --dport %(port)s -j fail2ban-%(name)s
|
||||
actionstart = iptables -N fail2ban-<name>
|
||||
iptables -A fail2ban-<name> -j RETURN
|
||||
iptables -I INPUT -p <protocol> --dport <port> -j fail2ban-<name>
|
||||
|
||||
# Option: fwend
|
||||
# Notes.: command executed once at the end of Fail2Ban
|
||||
# Values: CMD Default:
|
||||
#
|
||||
actionstop = iptables -D INPUT -p %(protocol)s --dport %(port)s -j fail2ban-%(name)s
|
||||
iptables -F fail2ban-%(name)s
|
||||
iptables -X fail2ban-%(name)s
|
||||
actionstop = iptables -D INPUT -p <protocol> --dport <port> -j fail2ban-<name>
|
||||
iptables -F fail2ban-<name>
|
||||
iptables -X fail2ban-<name>
|
||||
|
||||
# Option: fwcheck
|
||||
# Notes.: command executed once before each fwban command
|
||||
# Values: CMD Default:
|
||||
#
|
||||
actioncheck = iptables -L INPUT | grep -q fail2ban-%(name)s
|
||||
actioncheck = iptables -L INPUT | grep -q fail2ban-<name>
|
||||
|
||||
# Option: fwban
|
||||
# Notes.: command executed when banning an IP. Take care that the
|
||||
|
@ -41,7 +32,7 @@ actioncheck = iptables -L INPUT | grep -q fail2ban-%(name)s
|
|||
# Values: CMD
|
||||
# Default: iptables -I INPUT 1 -s <ip> -j DROP
|
||||
#
|
||||
actionban = iptables -I fail2ban-%(name)s 1 -s <ip> -j DROP
|
||||
actionban = iptables -I fail2ban-<name> 1 -s <ip> -j DROP
|
||||
|
||||
# Option: fwunban
|
||||
# Notes.: command executed when unbanning an IP. Take care that the
|
||||
|
@ -52,4 +43,22 @@ actionban = iptables -I fail2ban-%(name)s 1 -s <ip> -j DROP
|
|||
# Values: CMD
|
||||
# Default: iptables -D INPUT -s <ip> -j DROP
|
||||
#
|
||||
actionunban = iptables -D fail2ban-%(name)s -s <ip> -j DROP
|
||||
actionunban = iptables -D fail2ban-<name> -s <ip> -j DROP
|
||||
|
||||
[Init]
|
||||
|
||||
# Defaut name of the chain
|
||||
#
|
||||
name = default
|
||||
|
||||
# Option: port
|
||||
# Notes.: specifies port to monitor
|
||||
# Values: [ NUM | STRING ] Default:
|
||||
#
|
||||
port = ssh
|
||||
|
||||
# Option: protocol
|
||||
# Notes.: internally used by config reader for interpolations.
|
||||
# Values: [ tcp | udp | icmp | all ] Default: tcp
|
||||
#
|
||||
protocol = tcp
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
[DEFAULT]
|
||||
[Definition]
|
||||
|
||||
loglevel = 3
|
||||
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
[Definition]
|
||||
|
||||
# Option: maxretry
|
||||
# Notes.: number of failures before IP gets banned.
|
||||
# Values: NUM Default: 5
|
||||
#
|
||||
maxretry = 5
|
||||
|
||||
# Option: logfile
|
||||
# Notes.: logfile to monitor.
|
||||
# Values: FILE Default: /var/log/httpd/access_log
|
||||
#
|
||||
logfile = /var/log/httpd/access_log
|
||||
|
||||
# Option: timeregex
|
||||
# Notes.: regex to match timestamp in Apache logfile. For TAI64N format,
|
||||
# use timeregex = @[0-9a-f]{24}
|
||||
# Values: [Wed Jan 05 15:08:01 2005]
|
||||
# Default: \S{3} \S{3} \d{2} \d{2}:\d{2}:\d{2} \d{4}
|
||||
#
|
||||
timeregex = \S{3} \S{3} \d{2} \d{2}:\d{2}:\d{2} \d{4}
|
||||
|
||||
# Option: timepattern
|
||||
# Notes.: format used in "timeregex" fields definition. Note that '%' must be
|
||||
# escaped with '%' (see http://rgruet.free.fr/PQR2.3.html#timeModule).
|
||||
# For TAI64N format, use timepattern = tai64n
|
||||
# Values: TEXT Default: %%a %%b %%d %%H:%%M:%%S %%Y
|
||||
#
|
||||
timepattern = %%a %%b %%d %%H:%%M:%%S %%Y
|
||||
|
||||
# Option: failregex
|
||||
# Notes.: regex to match the password failure messages in the logfile.
|
||||
# Values: TEXT Default: authentication failure|user .* not found
|
||||
#
|
||||
failregex = authentication failure|user .* not found
|
|
@ -1,12 +1,16 @@
|
|||
[DEFAULT]
|
||||
[Definition]
|
||||
|
||||
maxretry = 22
|
||||
# Option: maxretry
|
||||
# Notes.: number of failures before IP gets banned.
|
||||
# Values: NUM Default: 5
|
||||
#
|
||||
maxretry = 5
|
||||
|
||||
# Option: logpath
|
||||
# Notes.: logfile to monitor.
|
||||
# Values: FILE Default: /var/log/secure
|
||||
#
|
||||
logpath = testcases/files/testcase01.log
|
||||
logpath = /var/log/secure
|
||||
|
||||
# Option: timeregex
|
||||
# Notes.: regex to match timestamp in SSH logfile. For TAI64N format,
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
[Definition]
|
||||
|
||||
# Option: maxretry
|
||||
# Notes.: number of failures before IP gets banned.
|
||||
# Values: NUM Default: 5
|
||||
#
|
||||
maxretry = 5
|
||||
|
||||
# Option: logfile
|
||||
# Notes.: logfile to monitor.
|
||||
# Values: FILE Default: /var/log/vsftpd.log
|
||||
#
|
||||
logfile = /var/log/vsftpd.log
|
||||
|
||||
# Option: timeregex
|
||||
# Notes.: regex to match timestamp in VSFTPD logfile.
|
||||
# Values: [Mar 7 17:53:28]
|
||||
# Default: \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}
|
||||
#
|
||||
timeregex = \S{3}\s{1,2}\d{1,2} \d{2}:\d{2}:\d{2}
|
||||
|
||||
# Option: timepattern
|
||||
# Notes.: format used in "timeregex" fields definition. Note that '%' must be
|
||||
# escaped with '%' (see http://rgruet.free.fr/PQR2.3.html#timeModule)
|
||||
# Values: TEXT Default: %%b %%d %%H:%%M:%%S
|
||||
#
|
||||
timepattern = %%b %%d %%H:%%M:%%S
|
||||
|
||||
# Option: failregex
|
||||
# Notes.: regex to match the password failures messages in the logfile.
|
||||
# Values: TEXT Default: Authentication failure|Failed password|Invalid user
|
||||
#
|
||||
failregex = FAIL LOGIN
|
|
@ -2,18 +2,18 @@
|
|||
|
||||
enabled = true
|
||||
filter = sshd
|
||||
action = dummy foo
|
||||
action = hostsdeny[file=/tmp/hosts.deny]
|
||||
maxretry = 2
|
||||
bantime = 5
|
||||
|
||||
[SSH]
|
||||
[ssh]
|
||||
|
||||
enabled = false
|
||||
filter = sshd
|
||||
action = iptables
|
||||
bantime = 10
|
||||
|
||||
[Apache-error]
|
||||
[apache-error]
|
||||
|
||||
enabled = false
|
||||
filter = apache-error
|
||||
|
|
|
@ -40,6 +40,7 @@ class Action:
|
|||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
self.cInfo = dict()
|
||||
## Command executed in order to initialize the system.
|
||||
self.actionStart = ''
|
||||
## Command executed when an IP address gets banned.
|
||||
|
@ -58,6 +59,15 @@ class Action:
|
|||
def getName(self):
|
||||
return self.name
|
||||
|
||||
def setCInfo(self, key, value):
|
||||
self.cInfo[key] = value
|
||||
|
||||
def getCInfo(self, key):
|
||||
return self.cInfo[key]
|
||||
|
||||
def delCInfo(self, key):
|
||||
del self.cInfo[key]
|
||||
|
||||
##
|
||||
# Set the "start" command.
|
||||
#
|
||||
|
@ -75,8 +85,9 @@ class Action:
|
|||
def getActionStart(self):
|
||||
return self.actionStart
|
||||
|
||||
def execActionStart(self, aInfo):
|
||||
return self.executeCmd(self.actionStart, aInfo);
|
||||
def execActionStart(self):
|
||||
startCmd = Action.replaceTag(self.actionStart, self.cInfo)
|
||||
return Action.executeCmd(startCmd)
|
||||
|
||||
##
|
||||
# Set the "ban" command.
|
||||
|
@ -96,7 +107,7 @@ class Action:
|
|||
return self.actionBan
|
||||
|
||||
def execActionBan(self, aInfo):
|
||||
return self.executeCmd(self.actionBan, aInfo);
|
||||
return self.processCmd(self.actionBan, aInfo);
|
||||
|
||||
##
|
||||
# Set the "unban" command.
|
||||
|
@ -116,7 +127,7 @@ class Action:
|
|||
return self.actionUnban
|
||||
|
||||
def execActionUnban(self, aInfo):
|
||||
return self.executeCmd(self.actionUnban, aInfo);
|
||||
return self.processCmd(self.actionUnban, aInfo);
|
||||
|
||||
##
|
||||
# Set the "check" command.
|
||||
|
@ -135,9 +146,6 @@ class Action:
|
|||
def getActionCheck(self):
|
||||
return self.actionCheck
|
||||
|
||||
def execActionCheck(self, aInfo):
|
||||
return self.executeCmd(self.actionCheck, aInfo);
|
||||
|
||||
##
|
||||
# Set the "stop" command.
|
||||
#
|
||||
|
@ -155,8 +163,9 @@ class Action:
|
|||
def getActionStop(self):
|
||||
return self.actionStop
|
||||
|
||||
def execActionStop(self, aInfo):
|
||||
return self.executeCmd(self.actionStop, aInfo);
|
||||
def execActionStop(self):
|
||||
stopCmd = Action.replaceTag(self.actionStop, self.cInfo)
|
||||
return Action.executeCmd(stopCmd)
|
||||
|
||||
@staticmethod
|
||||
def replaceTag(query, aInfo):
|
||||
|
@ -169,20 +178,38 @@ class Action:
|
|||
string = string.replace("<br>", '\n')
|
||||
return string
|
||||
|
||||
@staticmethod
|
||||
def executeCmd(cmd, aInfo = None):
|
||||
def processCmd(self, cmd, aInfo = None):
|
||||
""" Executes an OS command.
|
||||
"""
|
||||
if cmd == "":
|
||||
logSys.debug("Nothing to do")
|
||||
return True
|
||||
|
||||
checkCmd = Action.replaceTag(self.actionCheck, self.cInfo)
|
||||
if not Action.executeCmd(checkCmd):
|
||||
logSys.error("Invariant check failed. Trying to restore a sane" +
|
||||
" environment")
|
||||
stopCmd = Action.replaceTag(self.actionStop, self.cInfo)
|
||||
Action.executeCmd(stopCmd)
|
||||
startCmd = Action.replaceTag(self.actionStart, self.cInfo)
|
||||
Action.executeCmd(startCmd)
|
||||
if not Action.executeCmd(checkCmd):
|
||||
logSys.fatal("Unable to restore environment")
|
||||
return False
|
||||
|
||||
# Replace tags
|
||||
if not aInfo == None:
|
||||
realCmd = Action.replaceTag(cmd, aInfo)
|
||||
else:
|
||||
realCmd = cmd
|
||||
|
||||
# Replace static fields
|
||||
realCmd = Action.replaceTag(realCmd, self.cInfo)
|
||||
|
||||
return Action.executeCmd(realCmd)
|
||||
|
||||
@staticmethod
|
||||
def executeCmd(realCmd):
|
||||
logSys.debug(realCmd)
|
||||
retval = os.system(realCmd)
|
||||
#if not retval == 0:
|
||||
|
@ -192,4 +219,5 @@ class Action:
|
|||
return True
|
||||
else:
|
||||
logSys.error("%s returned %x" % (realCmd, retval))
|
||||
return False
|
||||
return False
|
||||
|
|
@ -103,7 +103,7 @@ class Actions(JailThread):
|
|||
|
||||
def run(self):
|
||||
for action in self.actions:
|
||||
action.execActionStart(None)
|
||||
action.execActionStart()
|
||||
self.setActive(True)
|
||||
while self.isActive():
|
||||
if not self.isIdle:
|
||||
|
@ -116,7 +116,7 @@ class Actions(JailThread):
|
|||
time.sleep(self.sleepTime)
|
||||
self.flushBan()
|
||||
for action in self.actions:
|
||||
action.execActionStop(None)
|
||||
action.execActionStop()
|
||||
logSys.debug(self.jail.getName() + ": action terminated")
|
||||
return True
|
||||
|
||||
|
|
|
@ -181,6 +181,24 @@ class Server:
|
|||
else:
|
||||
raise ServerUnknownJail(name)
|
||||
|
||||
def setCInfo(self, name, action, key, value):
|
||||
if self.jails.has_key(name):
|
||||
self.jails[name].getAction().getAction(action).setCInfo(key, value)
|
||||
else:
|
||||
raise ServerUnknownJail(name)
|
||||
|
||||
def getCInfo(self, name, action, key):
|
||||
if self.jails.has_key(name):
|
||||
return self.jails[name].getAction().getAction(action).getCInfo(key)
|
||||
else:
|
||||
raise ServerUnknownJail(name)
|
||||
|
||||
def delCInfo(self, name, action, key):
|
||||
if self.jails.has_key(name):
|
||||
self.jails[name].getAction().getAction(action).delCInfo(key)
|
||||
else:
|
||||
raise ServerUnknownJail(name)
|
||||
|
||||
def setBanTime(self, name, value):
|
||||
if self.jails.has_key(name):
|
||||
self.jails[name].getAction().setBanTime(value)
|
||||
|
|
|
@ -147,6 +147,17 @@ class Transmitter:
|
|||
elif action[1] == "delaction":
|
||||
self.server.delAction(name, value)
|
||||
return None
|
||||
elif action[1] == "setcinfo":
|
||||
act = action[2]
|
||||
key = action[3]
|
||||
value = action[4]
|
||||
self.server.setCInfo(name, act, key, value)
|
||||
return self.server.getCInfo(name, act, key)
|
||||
elif action[1] == "delcinfo":
|
||||
act = action[2]
|
||||
key = action[3]
|
||||
self.server.delCInfo(name, act, key)
|
||||
return None
|
||||
elif action[1] == "actionstart":
|
||||
act = action[2]
|
||||
value = action[3]
|
||||
|
|
Loading…
Reference in New Issue