SHARE
TWEET

Untitled

a guest Aug 6th, 2012 134 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #torqux.py:
  2.  
  3. import Queue
  4. import re
  5. import sys
  6. import threading
  7. import time
  8. import uuid
  9. import random
  10. import Queue
  11. import socket
  12. import select
  13. import threading
  14. import time
  15. import uuid
  16. import os
  17. from socket import AF_INET, AF_INET6, ntohs, ntohl, inet_ntop
  18. 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
  19. import collections
  20. import ctypes.util
  21. import ctypes
  22. IFF_LOOPBACK = 8
  23. sa_family_t = c_ushort
  24.  
  25. class struct_sockaddr(Structure):
  26.     _fields_ = [('sa_family', c_ushort), ('sa_data', c_byte * 14)]
  27.  
  28. struct_in_addr = c_byte * 4
  29.  
  30. class struct_sockaddr_in(Structure):
  31.     _fields_ = [('sin_family', sa_family_t), ('sin_port', c_uint16), ('sin_addr', struct_in_addr)]
  32.  
  33. struct_in6_addr = c_byte * 16
  34.  
  35. class struct_sockaddr_in6(Structure):
  36.     _fields_ = [('sin6_family', c_ushort),
  37.      ('sin6_port', c_uint16),
  38.      ('sin6_flowinfo', c_uint32),
  39.      ('sin6_addr', struct_in6_addr),
  40.      ('sin6_scope_id', c_uint32)]
  41.  
  42.  
  43. class union_ifa_ifu(Union):
  44.     _fields_ = [('ifu_broadaddr', POINTER(struct_sockaddr)), ('ifu_dstaddr', POINTER(struct_sockaddr))]
  45.  
  46.  
  47. class struct_ifaddrs(Structure):
  48.     pass
  49. struct_ifaddrs._fields_ = [('ifa_next', POINTER(struct_ifaddrs)),
  50.  ('ifa_name', c_char_p),
  51.  ('ifa_flags', c_uint),
  52.  ('ifa_addr', POINTER(struct_sockaddr)),
  53.  ('ifa_netmask', POINTER(struct_sockaddr)),
  54.  ('ifa_ifu', union_ifa_ifu),
  55.  ('ifa_data', c_void_p)]
  56.  
  57. class py_ifaddrs():
  58.     __slots__ = ('name', 'flags', 'family', 'addr', 'netmask')
  59.  
  60.     def __init__(self, **kwds):
  61.         for (key, value,) in kwds.items():
  62.             setattr(self, key, value)
  63.  
  64.  
  65.  
  66.  
  67.     def __repr__(self):
  68.         s = self.__class__.__name__ + '('
  69.         kwargs = {slot:getattr(self, slot) for slot in self.__slots__}
  70.         kwargs['flags'] = hex(kwargs['flags'])
  71.         s += ', '.join(('{}={}'.format(k, v) for (k, v,) in kwargs.items()))
  72.         return s + ')'
  73.  
  74.  
  75.  
  76.  
  77. class struct_in_pktinfo(Structure):
  78.     _fields_ = [('ipi_ifindex', ctypes.c_uint), ('ipi_spec_dst', struct_in_addr), ('ipi_addr', struct_in_addr)]
  79.  
  80. libc = ctypes.CDLL(ctypes.util.find_library('c'))
  81. _getifaddrs = libc.getifaddrs
  82. _getifaddrs.restype = c_int
  83. _getifaddrs.argtypes = [POINTER(POINTER(struct_ifaddrs))]
  84. _freeifaddrs = libc.freeifaddrs
  85. _freeifaddrs.restype = None
  86. _freeifaddrs.argtypes = [POINTER(struct_ifaddrs)]
  87.  
  88. def ifap_iter(ifap):
  89.     """Iterate over linked list of ifaddrs"""
  90.     ifa = ifap.contents
  91.     while True:
  92.         yield ifa
  93.         if not ifa.ifa_next:
  94.             break
  95.         ifa = ifa.ifa_next.contents
  96.  
  97.  
  98.  
  99.  
  100. class uniquedict(dict):
  101.  
  102.     def __setitem__(self, key, value):
  103.         if key in self:
  104.             raise KeyError('Key {!r} already set'.format(key))
  105.         else:
  106.             super().__setitem__(key, value)
  107.  
  108.  
  109.  
  110.  
  111. def pythonize_sockaddr(sa):
  112.     """Convert ctypes Structure of sockaddr into the Python tuple used in the socket module"""
  113.     family = sa.sa_family
  114.     if family == 528:
  115.         family = AF_INET
  116.     if family == 7196:
  117.         family = AF_INET6
  118.     if family == AF_INET:
  119.         sa = cast(pointer(sa), POINTER(struct_sockaddr_in)).contents
  120.         addr = (inet_ntop(AF_INET, sa.sin_addr), ntohs(sa.sin_port))
  121.     elif family == AF_INET6:
  122.         sa = cast(pointer(sa), POINTER(struct_sockaddr_in6)).contents
  123.         addr = (inet_ntop(AF_INET6, sa.sin6_addr),
  124.          ntohs(sa.sin6_port),
  125.          ntohl(sa.sin6_flowinfo),
  126.          sa.sin6_scope_id)
  127.     else:
  128.         addr = None
  129.     return (family, addr)
  130.  
  131.  
  132.  
  133. def getifaddrs():
  134.     """Wraps the C getifaddrs call, returns a list of pythonic ifaddrs"""
  135.     ifap = POINTER(struct_ifaddrs)()
  136.     result = _getifaddrs(pointer(ifap))
  137.     if result == -1:
  138.         raise OSError(get_errno())
  139.     elif result == 0:
  140.         pass
  141.     else:
  142.         assert False, result
  143.     del result
  144.     try:
  145.         retval = []
  146.         for ifa in ifap_iter(ifap):
  147.             (family, addr,) = pythonize_sockaddr(ifa.ifa_addr.contents)
  148.             retval.append(py_ifaddrs(name=ifa.ifa_name, family=family, flags=ifa.ifa_flags, addr=addr, netmask=ifa.ifa_netmask))
  149.  
  150.         return retval
  151.     finally:
  152.         _freeifaddrs(ifap)
  153.  
  154.  
  155.  
  156. def get_ip(interface, ip_class):
  157.     for i in getifaddrs():
  158.         if i.name == interface and i.family == ip_class:
  159.             return i.addr[0]
  160.  
  161.  
  162.  
  163.  
  164. def get_server():
  165.     ip = get_ip('em1', AF_INET6)
  166.     good = ':'.join(ip.split(':')[:-1] + ['7'])
  167.     return good
  168.  
  169.  
  170.  
  171. class SocketHandler(threading.Thread):
  172.     _sendBuffer = {}
  173.     _masterDict = {}
  174.  
  175.     def _addClient(self, name, data):
  176.         (host, port, recvSize,) = data
  177.         sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
  178.         sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  179.         sock.connect((host, port))
  180.         sock.setblocking(0)
  181.         self._masterDict.update({name: ('CLIENT', (sock, recvSize))})
  182.  
  183.  
  184.  
  185.     def _addServer(self, name, data):
  186.         (host, port, recvSize, timeOut, backlog,) = data
  187.         server = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
  188.         server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  189.         server.bind((host, port))
  190.         server.listen(backlog)
  191.         self._masterDict.update({name: ('SERVER', (server,
  192.                  recvSize,
  193.                  timeOut,
  194.                  []))})
  195.  
  196.  
  197.  
  198.     def _close(self, name):
  199.         (itemType, data,) = self._masterDict[name]
  200.         if itemType == 'SERVCLIENT':
  201.             parent = data[2]
  202.             self._masterDict[parent][1][3].remove(name)
  203.         sock = data[0]
  204.         sock.shutdown(1)
  205.         sock.close()
  206.         del self._masterDict[name]
  207.         if self._sendBuffer.has_key(name):
  208.             del self._sendBuffer[name]
  209.  
  210.  
  211.  
  212.     def _rwConnections(self):
  213.         names = self._masterDict.keys()
  214.         for name in names:
  215.             if not self._masterDict.has_key(name):
  216.                 continue
  217.             (itemType, data,) = self._masterDict[name]
  218.             if itemType == 'SERVER':
  219.                 (server, recvSize, timeOut, connectionNames,) = data
  220.                 (r2r, r2w, error,) = select.select([server], [], [server], 0)
  221.                 if r2r:
  222.                     (client, address,) = server.accept()
  223.                     cName = uuid.uuid4().hex
  224.                     self._masterDict.update({cName: ('SERVCLIENT', (client,
  225.                               recvSize,
  226.                               name,
  227.                               time.time()))})
  228.                     self._masterDict[name][1][3].append(cName)
  229.                     self._outQueue.put(('SERV_NEW_CLIENT', (name, cName, address)))
  230.             elif itemType == 'SERVCLIENT':
  231.                 (sock, recvSize, parent, timeOut,) = data
  232.                 toTimeOut = self._masterDict[parent][1][2]
  233.                 if timeOut <= time.time() - toTimeOut:
  234.                     self._close(name)
  235.                     continue
  236.                 (r2r, r2w, error,) = select.select([sock], [sock], [sock], 0)
  237.                 if r2w:
  238.                     if self._sendBuffer.has_key(name):
  239.                         line = self._sendBuffer[name]
  240.                         sock.send(line)
  241.                         del self._sendBuffer[name]
  242.                 else:
  243.                     self._close(name)
  244.                     self._outQueue.put(('SERVCLIENT_DISCON', name))
  245.                 if r2r:
  246.                     data = sock.recv(recvSize)
  247.                     if data:
  248.                         (junk, (client, recvSize, parent, junk,),) = self._masterDict[name]
  249.                         self._masterDict[name] = ('SERVCLIENT', (client,
  250.                           recvSize,
  251.                           parent,
  252.                           time.time()))
  253.                         self._outQueue.put(('SERVCLIENT_RECV', (parent, name, data)))
  254.             elif itemType == 'CLIENT':
  255.                 (sock, recvSize,) = data
  256.                 (r2r, r2w, error,) = select.select([sock], [sock], [sock], 0)
  257.                 if r2w:
  258.                     if self._sendBuffer.has_key(name):
  259.                         line = self._sendBuffer[name]
  260.                         sock.send(line)
  261.                         del self._sendBuffer[name]
  262.                 if r2r:
  263.                     data = sock.recv(recvSize)
  264.                     if data:
  265.                         self._outQueue.put(('CLIENT_RECV', (name, data)))
  266.  
  267.  
  268.  
  269.  
  270.     def _sendData(self, name, data):
  271.         if type(data) is tuple:
  272.             (name, data,) = data
  273.         self._sendBuffer.update({name: data})
  274.  
  275.  
  276.  
  277.     def _stop(self):
  278.         names = self._masterDict.keys()
  279.         for name in names:
  280.             (itemType, data,) = self._masterDict[name]
  281.             if itemType == 'SERVER':
  282.                 continue
  283.             self._close(name)
  284.  
  285.         names = self._masterDict.keys()
  286.         for name in names:
  287.             (itemType, data,) = self._masterDict[name]
  288.             socket = data[0]
  289.             socket.close(name, '')
  290.  
  291.         self._outQueue.put('THREAD_STOPPED')
  292.  
  293.  
  294.  
  295.     def _stopServ(self, name):
  296.         (type, (server, recvSize, timeOut, connectionNames,),) = self._masterDict[name]
  297.         del self._masterDict[name]
  298.         for name in connectionNames:
  299.             self._close(name)
  300.             server.shutdown(1)
  301.             server.close()
  302.             self._outQueue.put(('CLOSE', (name, '')))
  303.  
  304.  
  305.  
  306.  
  307.     def run(self):
  308.         while True:
  309.             (command, name, data,) = self._getQueue()
  310.             if command == 'ADDCLIENT':
  311.                 self._addClient(name, data)
  312.             elif command == 'ADDSERVER':
  313.                 self._addServer(name, data)
  314.             elif command == 'CLOSE' or command == 'DISCON':
  315.                 self._close(name)
  316.             elif command == 'SEND':
  317.                 if data is tuple:
  318.                     (name, data,) = data
  319.                 self._sendData(name, data)
  320.             elif command == 'STOP_SERVER':
  321.                 self._stopServ(name)
  322.             elif command == 'STOP_THREAD':
  323.                 self._stop()
  324.                 break
  325.             self._rwConnections()
  326.  
  327.  
  328.  
  329.  
  330.     def _getQueue(self):
  331.         try:
  332.             if not self._inQueue.empty():
  333.                 data = self._inQueue.get_nowait()
  334.                 return data
  335.         except BaseException as error:
  336.             print error
  337.         return ('', '', '')
  338.  
  339.  
  340.  
  341.     def __init__(self, inQueue, outQueue):
  342.         sys.path.append('.')
  343.         self._inQueue = inQueue
  344.         self._outQueue = outQueue
  345.         threading.Thread.__init__(self)
  346.  
  347.  
  348.  
  349.  
  350. class wutwut(threading.Thread):
  351.     _pingInterval = 60
  352.     _lastPing = time.time()
  353.     _recvPong = True
  354.     _onChan = False
  355.     _joinDelay = 20
  356.     _sentJoin = 0
  357.     _id = uuid.uuid4().hex
  358.     _isMute = False
  359.     _defaultConfigs = {'port': 6667,
  360.      'channel': 'eip',
  361.      'modules': ['stuff'],
  362.      'alias': {},
  363.      'restrictedCommand': {'messages': 1,
  364.                            'fortune': 1,
  365.                            'kick': 0,
  366.                            'reload': 0},
  367.      'ignore': ['key'],
  368.      'botName': 'riprelative',
  369.      'nickServPass': '',
  370.      'about': 'wutwut.  Try !help for information'}
  371.     _essentialConfigs = []
  372.     _getQueue = Queue.Queue()
  373.     _sendQueue = Queue.Queue()
  374.     config = {}
  375.     _external = []
  376.  
  377.     def sendLns(self, target, lines):
  378.         if self._isMute:
  379.             return
  380.         if not lines:
  381.             return
  382.         if type(lines) is list:
  383.             for i in range(0, len(lines)):
  384.                 lines[i] = 'PRIVMSG ' + target + ' :' + lines[i] + '\r\n'
  385.  
  386.             lines = ''.join(lines)
  387.         else:
  388.             lines = 'PRIVMSG ' + target + ' :' + lines + '\r\n'
  389.         self._sendQueue.put(('SEND', self._id, lines))
  390.  
  391.  
  392.  
  393.     def sendRaw(self, lines):
  394.         if self._isMute:
  395.             return
  396.         if not lines:
  397.             return
  398.         if type(lines) is list:
  399.             for i in range(0, len(lines) - 1):
  400.                 lines[i] = unicode(lines[i]) + u'\r\n'
  401.  
  402.             lines = ''.join(lines)
  403.         else:
  404.             lines = unicode(str(lines)) + u'\r\n'
  405.         self._sendQueue.put(('SEND', self._id, lines))
  406.  
  407.  
  408.  
  409.     def run(self):
  410.         while True:
  411.             data = ''
  412.             try:
  413.                 if not self._getQueue.empty():
  414.                     data = self._getQueue.get_nowait()
  415.             except:
  416.                 print 'x'
  417.             if not data:
  418.                 self._pingServer('')
  419.                 continue
  420.             if data == 'THREAD_STOPPED':
  421.                 break
  422.             (junk, (name, data,),) = data
  423.             self._pingServer(data)
  424.             if not self._onChan:
  425.                 lusers = re.findall(self.config['botName'] + '\\w* . ' + self.config['channel'] + ' (\\:[^\r\n]*\r\n\\:)', data)
  426.                 if lusers:
  427.                     if re.findall(self.config['botName'], lusers[0]):
  428.                         self._onChan = True
  429.                     elif self._joinDelay + self._sentJoin < time.time():
  430.                         self.sendRaw('JOIN ' + self.config['channel'] + '\r\n')
  431.                 else:
  432.                     self.sendRaw('NAMES ' + self.config['channel'] + '\r\n')
  433.             if name == self._id:
  434.                 if re.findall('ERROR :Closing Link', data):
  435.                     self._reconnect()
  436.                     continue
  437.                 ping = re.findall('PING :([^\r]+)\r\n', data)
  438.                 if ping:
  439.                     self.sendRaw('PONG :' + ping[0] + '\r\n')
  440.                     continue
  441.                 try:
  442.                     self._runCommand(data)
  443.                 except Exception as error:
  444.                     print 'GOT ERROR',
  445.                     print repr(error)
  446.  
  447.  
  448.  
  449.  
  450.     def _authorized(self, user, command):
  451.         if not self.config['admins'].has_key(user):
  452.             userLevel = 999
  453.         else:
  454.             userLevel = self.config['admins'][user]
  455.         if userLevel > 1000 or self.config['restrictedCommand'].has_key(command) and userLevel > self.config['restrictedCommand'][command]:
  456.             return False
  457.         else:
  458.             return True
  459.  
  460.  
  461.  
  462.     def _connect(self):
  463.         self._sendQueue.put(('ADDCLIENT', self._id, (self._ip, 6667, 4096)))
  464.         self._nick(self.config['botName'])
  465.         time.sleep(5)
  466.         self.sendRaw('JOIN ' + self.config['channel'] + '\r\n')
  467.  
  468.  
  469.  
  470.     def _list2dict(self, inList):
  471.         outDict = {}
  472.         if type(inList) is list:
  473.             for line in inList:
  474.                 keyval = line.split()
  475.                 outDict.update({keyval[0]: keyval[1]})
  476.  
  477.         else:
  478.             data = inList.split()
  479.             outDict = {data[0]: data[1]}
  480.         return outDict
  481.  
  482.  
  483.  
  484.     def _loadConfig(self, configFile):
  485.         self.config = {}
  486.         configFile = []
  487.         for line in configFile:
  488.             line = re.findall('\\W*([\\w]+)\\W+(.*)', line)
  489.             if not line:
  490.                 continue
  491.             (key, val,) = line[0]
  492.             if self.config.has_key(key):
  493.                 oldVal = self.config[key]
  494.                 if type(oldVal) is not list:
  495.                     self.config[key] = [oldVal]
  496.                 self.config[key].append(val)
  497.             else:
  498.                 self.config.update({key: val})
  499.  
  500.         if self.config.has_key('admins'):
  501.             data = self.config['admins'].split(':')
  502.             self.config['admins'] = {}
  503.             for line in data:
  504.                 (key, val,) = line.split(' ')
  505.                 self.config['admins'].update({key: int(val)})
  506.  
  507.         else:
  508.             self.config['admins'] = {}
  509.         if self.config.has_key('modules'):
  510.             self.config['modules'] = self.config['modules'].split(':')
  511.         for conf in self._defaultConfigs:
  512.             if not self.config.has_key(conf):
  513.                 self.config[conf] = self._defaultConfigs[conf]
  514.  
  515.         for conf in self._essentialConfigs:
  516.             if not self.config.has_key(conf):
  517.                 raise ConfigError('No entry in config file for ' + conf)
  518.  
  519.         self.config['port'] = int(self.config['port'])
  520.         self.config['channel'] = '#' + self.config['channel']
  521.         if self.config.has_key('alias') and len(self.config['alias']):
  522.             self.config['alias'] = self._list2dict(self.config['alias'])
  523.         self._reloadModules()
  524.  
  525.  
  526.  
  527.     def _nick(self, nick):
  528.         self.sendRaw(['NICK ' + nick + '\r\n', 'USER ' + nick + ' ' + nick + ' ' + nick + ' :Python IRC\r\n'])
  529.  
  530.  
  531.  
  532.     def _pingServer(self, data):
  533.         if re.findall('PONG', data):
  534.             self._recvPong = True
  535.         if self._pingInterval + self._lastPing < time.time():
  536.             if self._recvPong == False:
  537.                 self._reconnect()
  538.                 self._lastPing = time.time()
  539.                 return
  540.             self._recvPong = False
  541.             self.sendRaw('PING : ' + self.config['botName'] + '\r\n')
  542.             self._lastPing = time.time()
  543.  
  544.  
  545.  
  546.     def _reloadModules(self):
  547.         if self.config.has_key('modules'):
  548.             modules = self.config['modules']
  549.             for mod in modules:
  550.                 try:
  551.                     self._external.append(__import__(mod))
  552.                 except BaseException as error:
  553.                     pass
  554.  
  555.  
  556.  
  557.  
  558.     def _reconnect(self):
  559.         self._onChan = False
  560.         self._sendQueue.put(('CLOSE', self._id, ''))
  561.         time.sleep(5)
  562.         self._connect()
  563.  
  564.  
  565.  
  566.     def _runCommand(self, data):
  567.         if re.findall('KICK', data):
  568.             self.sendRaw('JOIN ' + self.config['channel'] + '\r\n')
  569.             self._onChan = False
  570.         if re.findall('please choose a different nick.', data):
  571.             self.sendLns('nickserv', 'identify ' + self.config['nickServPass'])
  572.         if re.findall('Nickname is already in use.', data):
  573.             self._nick(self.config['botName'] + str(random.randint(100, 999)))
  574.             self.sendLns('nickserv', 'GHOST ' + self.config['botName'] + ' ' + self.config['nickServPass'])
  575.         if re.findall('Ghost with your nick has been killed', data):
  576.             self._nick(self.config['botName'])
  577.         utca = re.findall('\\:([^\\!]+)[^ ]+ PRIVMSG ([^ ]+) \\:[\t ]*\\!([^\r\n\t ]+)[\t ]*([^\r\n]*)', data)
  578.         if not utca:
  579.             for mod in self._external:
  580.                 if hasattr(mod, 'idle'):
  581.                     mod.idle(self, data)
  582.                     break
  583.  
  584.             return
  585.         if 'key' in data:
  586.             return
  587.         (user, target, command, argument,) = utca[0]
  588.         if user in self.config['ignore']:
  589.             return
  590.         if target == self.config['botName']:
  591.             target = user
  592.         if self.config['alias'].has_key(command):
  593.             command = self.config['alias'][command]
  594.         if not self._authorized(user, command):
  595.             self.sendLns(user, 'Permission Denied.')
  596.             return
  597.         if command == 'reload':
  598.             self._loadConfig(self._configFile)
  599.             self._reloadModules()
  600.             return
  601.         for mod in self._external:
  602.             if hasattr(mod, command):
  603.                 getattr(mod, command)(self, user, target, argument)
  604.                 break
  605.  
  606.  
  607.  
  608.  
  609.     def gogogo(self):
  610.         SocketHandler(self._sendQueue, self._getQueue).start()
  611.         self._connect()
  612.         threading.Thread.__init__(self)
  613.         self.start()
  614.  
  615.  
  616.  
  617.     def __init__(self, configFile):
  618.         self._configFile = configFile
  619.         self._ip = configFile
  620.         self._loadConfig(configFile)
  621.  
  622.  
  623.  
  624.  
  625. def drop_privileges(username):
  626.     import os
  627.     import pwd
  628.     import grp
  629.     uid = pwd.getpwnam(username).pw_uid
  630.     gid = grp.getgrnam(username).gr_gid
  631.     _dir = pwd.getpwnam(username).pw_dir
  632.     os.chdir(_dir)
  633.     os.setgroups([])
  634.     os.setgid(gid)
  635.     os.setegid(gid)
  636.     os.setuid(uid)
  637.     os.seteuid(uid)
  638.     if os.getuid() != uid or os.getgid() != gid:
  639.         raise Exception('unable to drop to %s' % username)
  640.     old_umask = os.umask(63)
  641.  
  642.  
  643. if __name__ == '__main__':
  644.     bot = wutwut(get_server())
  645.     drop_privileges('torqux')
  646.     bot.gogogo()
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Not a member of Pastebin yet?
Sign Up, it unlocks many cool features!
 
Top