Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #torqux.py:
- import Queue
- import re
- import sys
- import threading
- import time
- import uuid
- import random
- import Queue
- import socket
- import select
- import threading
- import time
- import uuid
- import os
- from socket import AF_INET, AF_INET6, ntohs, ntohl, inet_ntop
- from ctypes import Structure, Union, POINTER, pointer, get_errno, cast, c_ushort, c_char, c_byte, c_void_p, c_char_p, c_uint, c_int, c_uint16, c_uint32
- import collections
- import ctypes.util
- import ctypes
- IFF_LOOPBACK = 8
- sa_family_t = c_ushort
- class struct_sockaddr(Structure):
- _fields_ = [('sa_family', c_ushort), ('sa_data', c_byte * 14)]
- struct_in_addr = c_byte * 4
- class struct_sockaddr_in(Structure):
- _fields_ = [('sin_family', sa_family_t), ('sin_port', c_uint16), ('sin_addr', struct_in_addr)]
- struct_in6_addr = c_byte * 16
- class struct_sockaddr_in6(Structure):
- _fields_ = [('sin6_family', c_ushort),
- ('sin6_port', c_uint16),
- ('sin6_flowinfo', c_uint32),
- ('sin6_addr', struct_in6_addr),
- ('sin6_scope_id', c_uint32)]
- class union_ifa_ifu(Union):
- _fields_ = [('ifu_broadaddr', POINTER(struct_sockaddr)), ('ifu_dstaddr', POINTER(struct_sockaddr))]
- class struct_ifaddrs(Structure):
- pass
- struct_ifaddrs._fields_ = [('ifa_next', POINTER(struct_ifaddrs)),
- ('ifa_name', c_char_p),
- ('ifa_flags', c_uint),
- ('ifa_addr', POINTER(struct_sockaddr)),
- ('ifa_netmask', POINTER(struct_sockaddr)),
- ('ifa_ifu', union_ifa_ifu),
- ('ifa_data', c_void_p)]
- class py_ifaddrs():
- __slots__ = ('name', 'flags', 'family', 'addr', 'netmask')
- def __init__(self, **kwds):
- for (key, value,) in kwds.items():
- setattr(self, key, value)
- def __repr__(self):
- s = self.__class__.__name__ + '('
- kwargs = {slot:getattr(self, slot) for slot in self.__slots__}
- kwargs['flags'] = hex(kwargs['flags'])
- s += ', '.join(('{}={}'.format(k, v) for (k, v,) in kwargs.items()))
- return s + ')'
- class struct_in_pktinfo(Structure):
- _fields_ = [('ipi_ifindex', ctypes.c_uint), ('ipi_spec_dst', struct_in_addr), ('ipi_addr', struct_in_addr)]
- libc = ctypes.CDLL(ctypes.util.find_library('c'))
- _getifaddrs = libc.getifaddrs
- _getifaddrs.restype = c_int
- _getifaddrs.argtypes = [POINTER(POINTER(struct_ifaddrs))]
- _freeifaddrs = libc.freeifaddrs
- _freeifaddrs.restype = None
- _freeifaddrs.argtypes = [POINTER(struct_ifaddrs)]
- def ifap_iter(ifap):
- """Iterate over linked list of ifaddrs"""
- ifa = ifap.contents
- while True:
- yield ifa
- if not ifa.ifa_next:
- break
- ifa = ifa.ifa_next.contents
- class uniquedict(dict):
- def __setitem__(self, key, value):
- if key in self:
- raise KeyError('Key {!r} already set'.format(key))
- else:
- super().__setitem__(key, value)
- def pythonize_sockaddr(sa):
- """Convert ctypes Structure of sockaddr into the Python tuple used in the socket module"""
- family = sa.sa_family
- if family == 528:
- family = AF_INET
- if family == 7196:
- family = AF_INET6
- if family == AF_INET:
- sa = cast(pointer(sa), POINTER(struct_sockaddr_in)).contents
- addr = (inet_ntop(AF_INET, sa.sin_addr), ntohs(sa.sin_port))
- elif family == AF_INET6:
- sa = cast(pointer(sa), POINTER(struct_sockaddr_in6)).contents
- addr = (inet_ntop(AF_INET6, sa.sin6_addr),
- ntohs(sa.sin6_port),
- ntohl(sa.sin6_flowinfo),
- sa.sin6_scope_id)
- else:
- addr = None
- return (family, addr)
- def getifaddrs():
- """Wraps the C getifaddrs call, returns a list of pythonic ifaddrs"""
- ifap = POINTER(struct_ifaddrs)()
- result = _getifaddrs(pointer(ifap))
- if result == -1:
- raise OSError(get_errno())
- elif result == 0:
- pass
- else:
- assert False, result
- del result
- try:
- retval = []
- for ifa in ifap_iter(ifap):
- (family, addr,) = pythonize_sockaddr(ifa.ifa_addr.contents)
- retval.append(py_ifaddrs(name=ifa.ifa_name, family=family, flags=ifa.ifa_flags, addr=addr, netmask=ifa.ifa_netmask))
- return retval
- finally:
- _freeifaddrs(ifap)
- def get_ip(interface, ip_class):
- for i in getifaddrs():
- if i.name == interface and i.family == ip_class:
- return i.addr[0]
- def get_server():
- ip = get_ip('em1', AF_INET6)
- good = ':'.join(ip.split(':')[:-1] + ['7'])
- return good
- class SocketHandler(threading.Thread):
- _sendBuffer = {}
- _masterDict = {}
- def _addClient(self, name, data):
- (host, port, recvSize,) = data
- sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
- sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- sock.connect((host, port))
- sock.setblocking(0)
- self._masterDict.update({name: ('CLIENT', (sock, recvSize))})
- def _addServer(self, name, data):
- (host, port, recvSize, timeOut, backlog,) = data
- server = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
- server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- server.bind((host, port))
- server.listen(backlog)
- self._masterDict.update({name: ('SERVER', (server,
- recvSize,
- timeOut,
- []))})
- def _close(self, name):
- (itemType, data,) = self._masterDict[name]
- if itemType == 'SERVCLIENT':
- parent = data[2]
- self._masterDict[parent][1][3].remove(name)
- sock = data[0]
- sock.shutdown(1)
- sock.close()
- del self._masterDict[name]
- if self._sendBuffer.has_key(name):
- del self._sendBuffer[name]
- def _rwConnections(self):
- names = self._masterDict.keys()
- for name in names:
- if not self._masterDict.has_key(name):
- continue
- (itemType, data,) = self._masterDict[name]
- if itemType == 'SERVER':
- (server, recvSize, timeOut, connectionNames,) = data
- (r2r, r2w, error,) = select.select([server], [], [server], 0)
- if r2r:
- (client, address,) = server.accept()
- cName = uuid.uuid4().hex
- self._masterDict.update({cName: ('SERVCLIENT', (client,
- recvSize,
- name,
- time.time()))})
- self._masterDict[name][1][3].append(cName)
- self._outQueue.put(('SERV_NEW_CLIENT', (name, cName, address)))
- elif itemType == 'SERVCLIENT':
- (sock, recvSize, parent, timeOut,) = data
- toTimeOut = self._masterDict[parent][1][2]
- if timeOut <= time.time() - toTimeOut:
- self._close(name)
- continue
- (r2r, r2w, error,) = select.select([sock], [sock], [sock], 0)
- if r2w:
- if self._sendBuffer.has_key(name):
- line = self._sendBuffer[name]
- sock.send(line)
- del self._sendBuffer[name]
- else:
- self._close(name)
- self._outQueue.put(('SERVCLIENT_DISCON', name))
- if r2r:
- data = sock.recv(recvSize)
- if data:
- (junk, (client, recvSize, parent, junk,),) = self._masterDict[name]
- self._masterDict[name] = ('SERVCLIENT', (client,
- recvSize,
- parent,
- time.time()))
- self._outQueue.put(('SERVCLIENT_RECV', (parent, name, data)))
- elif itemType == 'CLIENT':
- (sock, recvSize,) = data
- (r2r, r2w, error,) = select.select([sock], [sock], [sock], 0)
- if r2w:
- if self._sendBuffer.has_key(name):
- line = self._sendBuffer[name]
- sock.send(line)
- del self._sendBuffer[name]
- if r2r:
- data = sock.recv(recvSize)
- if data:
- self._outQueue.put(('CLIENT_RECV', (name, data)))
- def _sendData(self, name, data):
- if type(data) is tuple:
- (name, data,) = data
- self._sendBuffer.update({name: data})
- def _stop(self):
- names = self._masterDict.keys()
- for name in names:
- (itemType, data,) = self._masterDict[name]
- if itemType == 'SERVER':
- continue
- self._close(name)
- names = self._masterDict.keys()
- for name in names:
- (itemType, data,) = self._masterDict[name]
- socket = data[0]
- socket.close(name, '')
- self._outQueue.put('THREAD_STOPPED')
- def _stopServ(self, name):
- (type, (server, recvSize, timeOut, connectionNames,),) = self._masterDict[name]
- del self._masterDict[name]
- for name in connectionNames:
- self._close(name)
- server.shutdown(1)
- server.close()
- self._outQueue.put(('CLOSE', (name, '')))
- def run(self):
- while True:
- (command, name, data,) = self._getQueue()
- if command == 'ADDCLIENT':
- self._addClient(name, data)
- elif command == 'ADDSERVER':
- self._addServer(name, data)
- elif command == 'CLOSE' or command == 'DISCON':
- self._close(name)
- elif command == 'SEND':
- if data is tuple:
- (name, data,) = data
- self._sendData(name, data)
- elif command == 'STOP_SERVER':
- self._stopServ(name)
- elif command == 'STOP_THREAD':
- self._stop()
- break
- self._rwConnections()
- def _getQueue(self):
- try:
- if not self._inQueue.empty():
- data = self._inQueue.get_nowait()
- return data
- except BaseException as error:
- print error
- return ('', '', '')
- def __init__(self, inQueue, outQueue):
- sys.path.append('.')
- self._inQueue = inQueue
- self._outQueue = outQueue
- threading.Thread.__init__(self)
- class wutwut(threading.Thread):
- _pingInterval = 60
- _lastPing = time.time()
- _recvPong = True
- _onChan = False
- _joinDelay = 20
- _sentJoin = 0
- _id = uuid.uuid4().hex
- _isMute = False
- _defaultConfigs = {'port': 6667,
- 'channel': 'eip',
- 'modules': ['stuff'],
- 'alias': {},
- 'restrictedCommand': {'messages': 1,
- 'fortune': 1,
- 'kick': 0,
- 'reload': 0},
- 'ignore': ['key'],
- 'botName': 'riprelative',
- 'nickServPass': '',
- 'about': 'wutwut. Try !help for information'}
- _essentialConfigs = []
- _getQueue = Queue.Queue()
- _sendQueue = Queue.Queue()
- config = {}
- _external = []
- def sendLns(self, target, lines):
- if self._isMute:
- return
- if not lines:
- return
- if type(lines) is list:
- for i in range(0, len(lines)):
- lines[i] = 'PRIVMSG ' + target + ' :' + lines[i] + '\r\n'
- lines = ''.join(lines)
- else:
- lines = 'PRIVMSG ' + target + ' :' + lines + '\r\n'
- self._sendQueue.put(('SEND', self._id, lines))
- def sendRaw(self, lines):
- if self._isMute:
- return
- if not lines:
- return
- if type(lines) is list:
- for i in range(0, len(lines) - 1):
- lines[i] = unicode(lines[i]) + u'\r\n'
- lines = ''.join(lines)
- else:
- lines = unicode(str(lines)) + u'\r\n'
- self._sendQueue.put(('SEND', self._id, lines))
- def run(self):
- while True:
- data = ''
- try:
- if not self._getQueue.empty():
- data = self._getQueue.get_nowait()
- except:
- print 'x'
- if not data:
- self._pingServer('')
- continue
- if data == 'THREAD_STOPPED':
- break
- (junk, (name, data,),) = data
- self._pingServer(data)
- if not self._onChan:
- lusers = re.findall(self.config['botName'] + '\\w* . ' + self.config['channel'] + ' (\\:[^\r\n]*\r\n\\:)', data)
- if lusers:
- if re.findall(self.config['botName'], lusers[0]):
- self._onChan = True
- elif self._joinDelay + self._sentJoin < time.time():
- self.sendRaw('JOIN ' + self.config['channel'] + '\r\n')
- else:
- self.sendRaw('NAMES ' + self.config['channel'] + '\r\n')
- if name == self._id:
- if re.findall('ERROR :Closing Link', data):
- self._reconnect()
- continue
- ping = re.findall('PING :([^\r]+)\r\n', data)
- if ping:
- self.sendRaw('PONG :' + ping[0] + '\r\n')
- continue
- try:
- self._runCommand(data)
- except Exception as error:
- print 'GOT ERROR',
- print repr(error)
- def _authorized(self, user, command):
- if not self.config['admins'].has_key(user):
- userLevel = 999
- else:
- userLevel = self.config['admins'][user]
- if userLevel > 1000 or self.config['restrictedCommand'].has_key(command) and userLevel > self.config['restrictedCommand'][command]:
- return False
- else:
- return True
- def _connect(self):
- self._sendQueue.put(('ADDCLIENT', self._id, (self._ip, 6667, 4096)))
- self._nick(self.config['botName'])
- time.sleep(5)
- self.sendRaw('JOIN ' + self.config['channel'] + '\r\n')
- def _list2dict(self, inList):
- outDict = {}
- if type(inList) is list:
- for line in inList:
- keyval = line.split()
- outDict.update({keyval[0]: keyval[1]})
- else:
- data = inList.split()
- outDict = {data[0]: data[1]}
- return outDict
- def _loadConfig(self, configFile):
- self.config = {}
- configFile = []
- for line in configFile:
- line = re.findall('\\W*([\\w]+)\\W+(.*)', line)
- if not line:
- continue
- (key, val,) = line[0]
- if self.config.has_key(key):
- oldVal = self.config[key]
- if type(oldVal) is not list:
- self.config[key] = [oldVal]
- self.config[key].append(val)
- else:
- self.config.update({key: val})
- if self.config.has_key('admins'):
- data = self.config['admins'].split(':')
- self.config['admins'] = {}
- for line in data:
- (key, val,) = line.split(' ')
- self.config['admins'].update({key: int(val)})
- else:
- self.config['admins'] = {}
- if self.config.has_key('modules'):
- self.config['modules'] = self.config['modules'].split(':')
- for conf in self._defaultConfigs:
- if not self.config.has_key(conf):
- self.config[conf] = self._defaultConfigs[conf]
- for conf in self._essentialConfigs:
- if not self.config.has_key(conf):
- raise ConfigError('No entry in config file for ' + conf)
- self.config['port'] = int(self.config['port'])
- self.config['channel'] = '#' + self.config['channel']
- if self.config.has_key('alias') and len(self.config['alias']):
- self.config['alias'] = self._list2dict(self.config['alias'])
- self._reloadModules()
- def _nick(self, nick):
- self.sendRaw(['NICK ' + nick + '\r\n', 'USER ' + nick + ' ' + nick + ' ' + nick + ' :Python IRC\r\n'])
- def _pingServer(self, data):
- if re.findall('PONG', data):
- self._recvPong = True
- if self._pingInterval + self._lastPing < time.time():
- if self._recvPong == False:
- self._reconnect()
- self._lastPing = time.time()
- return
- self._recvPong = False
- self.sendRaw('PING : ' + self.config['botName'] + '\r\n')
- self._lastPing = time.time()
- def _reloadModules(self):
- if self.config.has_key('modules'):
- modules = self.config['modules']
- for mod in modules:
- try:
- self._external.append(__import__(mod))
- except BaseException as error:
- pass
- def _reconnect(self):
- self._onChan = False
- self._sendQueue.put(('CLOSE', self._id, ''))
- time.sleep(5)
- self._connect()
- def _runCommand(self, data):
- if re.findall('KICK', data):
- self.sendRaw('JOIN ' + self.config['channel'] + '\r\n')
- self._onChan = False
- if re.findall('please choose a different nick.', data):
- self.sendLns('nickserv', 'identify ' + self.config['nickServPass'])
- if re.findall('Nickname is already in use.', data):
- self._nick(self.config['botName'] + str(random.randint(100, 999)))
- self.sendLns('nickserv', 'GHOST ' + self.config['botName'] + ' ' + self.config['nickServPass'])
- if re.findall('Ghost with your nick has been killed', data):
- self._nick(self.config['botName'])
- utca = re.findall('\\:([^\\!]+)[^ ]+ PRIVMSG ([^ ]+) \\:[\t ]*\\!([^\r\n\t ]+)[\t ]*([^\r\n]*)', data)
- if not utca:
- for mod in self._external:
- if hasattr(mod, 'idle'):
- mod.idle(self, data)
- break
- return
- if 'key' in data:
- return
- (user, target, command, argument,) = utca[0]
- if user in self.config['ignore']:
- return
- if target == self.config['botName']:
- target = user
- if self.config['alias'].has_key(command):
- command = self.config['alias'][command]
- if not self._authorized(user, command):
- self.sendLns(user, 'Permission Denied.')
- return
- if command == 'reload':
- self._loadConfig(self._configFile)
- self._reloadModules()
- return
- for mod in self._external:
- if hasattr(mod, command):
- getattr(mod, command)(self, user, target, argument)
- break
- def gogogo(self):
- SocketHandler(self._sendQueue, self._getQueue).start()
- self._connect()
- threading.Thread.__init__(self)
- self.start()
- def __init__(self, configFile):
- self._configFile = configFile
- self._ip = configFile
- self._loadConfig(configFile)
- def drop_privileges(username):
- import os
- import pwd
- import grp
- uid = pwd.getpwnam(username).pw_uid
- gid = grp.getgrnam(username).gr_gid
- _dir = pwd.getpwnam(username).pw_dir
- os.chdir(_dir)
- os.setgroups([])
- os.setgid(gid)
- os.setegid(gid)
- os.setuid(uid)
- os.seteuid(uid)
- if os.getuid() != uid or os.getgid() != gid:
- raise Exception('unable to drop to %s' % username)
- old_umask = os.umask(63)
- if __name__ == '__main__':
- bot = wutwut(get_server())
- drop_privileges('torqux')
- bot.gogogo()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement