raw
9992-handle-edge-...    1 VERSION = "9992"
genesis 2
genesis 3 import os
genesis 4 import select
genesis 5 import socket
genesis 6 import sys
genesis 7 import sys
genesis 8 import tempfile
genesis 9 import time
genesis 10 import string
genesis 11 from datetime import datetime
genesis 12 from lib.client import Client
genesis 13 from lib.state import State
genesis 14 from lib.channel import Channel
genesis 15 from lib.infosec import PACKET_SIZE
genesis 16 from lib.infosec import MAX_BOUNCES
genesis 17 from lib.infosec import Infosec
genesis 18 from lib.peer import Peer
genesis 19 from lib.ringbuffer import Ringbuffer
genesis 20 from funcs import *
genesis 21 from commands import BROADCAST
genesis 22 from commands import DIRECT
genesis 23 import imp
genesis 24 import pprint
genesis 25
genesis 26 class Server(object):
genesis 27 def __init__(self, options):
genesis 28 self.ports = options.ports
genesis 29 self.udp_port = options.udp_port
genesis 30 self.password = options.password
genesis 31 self.ssl_pem_file = options.ssl_pem_file
genesis 32 self.motdfile = options.motd
genesis 33 self.verbose = options.verbose
genesis 34 self.debug = options.debug
genesis 35 self.logdir = options.logdir
genesis 36 self.chroot = options.chroot
genesis 37 self.setuid = options.setuid
genesis 38 self.statedir = options.statedir
genesis 39 self.infosec = Infosec(self)
genesis 40 self.config_file_path = options.config_file_path
genesis 41 self.state = State(self, options.db_path)
genesis 42 self.pp = pprint.PrettyPrinter(indent=4)
genesis 43
genesis 44 if options.address_table_path != None:
genesis 45 self.state.import_at_and_wot(options.address_table_path)
genesis 46
genesis 47 if options.listen:
genesis 48 self.address = socket.gethostbyname(options.listen)
genesis 49 else:
genesis 50 self.address = ""
genesis 51 server_name_limit = 63 # From the RFC.
genesis 52 self.name = socket.getfqdn(self.address)[:server_name_limit]
genesis 53
genesis 54 self.channels = {} # irc_lower(Channel name) --> Channel instance.
genesis 55 self.clients = {} # Socket --> Client instance..peers = ""
genesis 56 self.nicknames = {} # irc_lower(Nickname) --> Client instance.
genesis 57 self.recent = Ringbuffer(100)
genesis 58 if self.logdir:
genesis 59 create_directory(self.logdir)
genesis 60 if self.statedir:
genesis 61 create_directory(self.statedir)
genesis 62
genesis 63 def daemonize(self):
genesis 64 try:
genesis 65 pid = os.fork()
genesis 66 if pid > 0:
genesis 67 sys.exit(0)
genesis 68 except OSError:
genesis 69 sys.exit(1)
genesis 70 os.setsid()
genesis 71 try:
genesis 72 pid = os.fork()
genesis 73 if pid > 0:
genesis 74 self.print_info("PID: %d" % pid)
genesis 75 sys.exit(0)
genesis 76 except OSError:
genesis 77 sys.exit(1)
genesis 78 os.chdir("/")
genesis 79 os.umask(0)
genesis 80 dev_null = open("/dev/null", "r+")
genesis 81 os.dup2(dev_null.fileno(), sys.stdout.fileno())
genesis 82 os.dup2(dev_null.fileno(), sys.stderr.fileno())
genesis 83 os.dup2(dev_null.fileno(), sys.stdin.fileno())
genesis 84
genesis 85 def get_client(self, nickname):
genesis 86 return self.nicknames.get(irc_lower(nickname))
genesis 87
genesis 88 def has_channel(self, name):
genesis 89 return irc_lower(name) in self.channels
genesis 90
genesis 91 def get_channel(self, channelname):
genesis 92 if irc_lower(channelname) in self.channels:
genesis 93 channel = self.channels[irc_lower(channelname)]
genesis 94 else:
genesis 95 channel = Channel(self, channelname)
genesis 96 self.channels[irc_lower(channelname)] = channel
genesis 97 return channel
genesis 98
genesis 99 def get_motd_lines(self):
genesis 100 if self.motdfile:
genesis 101 try:
genesis 102 return open(self.motdfile).readlines()
genesis 103 except IOError:
genesis 104 return ["Could not read MOTD file %r." % self.motdfile]
genesis 105 else:
genesis 106 return []
genesis 107
genesis 108 def print_info(self, msg):
genesis 109 if self.verbose:
genesis 110 print(msg)
genesis 111 sys.stdout.flush()
genesis 112
genesis 113 def print_debug(self, msg):
genesis 114 if self.debug:
genesis 115 print(msg)
genesis 116 sys.stdout.flush()
genesis 117
genesis 118 def print_error(self, msg):
genesis 119 sys.stderr.write("%s\n" % msg)
genesis 120
genesis 121 def client_changed_nickname(self, client, oldnickname):
genesis 122 if oldnickname:
genesis 123 del self.nicknames[irc_lower(oldnickname)]
genesis 124 self.nicknames[irc_lower(client.nickname)] = client
genesis 125
genesis 126 def remove_member_from_channel(self, client, channelname):
genesis 127 if irc_lower(channelname) in self.channels:
genesis 128 channel = self.channels[irc_lower(channelname)]
genesis 129 channel.remove_client(client)
genesis 130
genesis 131 def remove_client(self, client, quitmsg):
genesis 132 client.message_related(":%s QUIT :%s" % (client.prefix, quitmsg))
genesis 133 for x in client.channels.values():
genesis 134 client.channel_log(x, "quit (%s)" % quitmsg, meta=True)
genesis 135 x.remove_client(client)
genesis 136 if client.nickname \
genesis 137 and irc_lower(client.nickname) in self.nicknames:
genesis 138 del self.nicknames[irc_lower(client.nickname)]
genesis 139 del self.clients[client.socket]
genesis 140
genesis 141 def remove_channel(self, channel):
genesis 142 del self.channels[irc_lower(channel.name)]
genesis 143
genesis 144 def handle_udp_data(self, bytes_address_pair):
9992-handle-edge-... 145 data = bytes_address_pair[0]
9992-handle-edge-... 146 address = bytes_address_pair[1]
genesis 147 for peer in self.state.get_peers():
9992-handle-edge-... 148 if peer.get_key() != None:
9992-handle-edge-... 149 message = self.infosec.unpack(peer, data)
9992-handle-edge-... 150 if(message != None):
9992-handle-edge-... 151 self.print_debug("valid message from peer: %s" % peer.handles[0])
9992-handle-edge-... 152
9992-handle-edge-... 153 # we only update the address table if the speaker is same as peer
9992-handle-edge-... 154
9992-handle-edge-... 155 try:
9992-handle-edge-... 156 idx = peer.handles.index(message["speaker"])
9992-handle-edge-... 157 except:
9992-handle-edge-... 158 idx = None
9992-handle-edge-... 159
9992-handle-edge-... 160 if idx != None:
9992-handle-edge-... 161 self.state.update_address_table({"handle": message["speaker"],
9992-handle-edge-... 162 "address": address[0],
9992-handle-edge-... 163 "port": address[1]
9992-handle-edge-... 164 })
9992-handle-edge-... 165 # send the message to all clients
9992-handle-edge-... 166 for c in self.clients:
9992-handle-edge-... 167 # self.clients[c].udp_socket_readable_notification(message)
9992-handle-edge-... 168 if (self.clients[c].is_addressed_to_me(message["body"])):
9992-handle-edge-... 169 self.clients[c].message(message["body"])
9992-handle-edge-... 170 # send the message to all other peers if it should be propagated
9992-handle-edge-... 171 if(message["command"] == BROADCAST) and message["bounces"] < MAX_BOUNCES:
9992-handle-edge-... 172 self.rebroadcast(peer, message)
9992-handle-edge-... 173 return
genesis 174 self.print_debug("Unknown peer: %s %d" % (address[0], address[1]))
genesis 175
genesis 176 def peer_message(self, message):
genesis 177 message["original"] = True
genesis 178 if message["command"] == DIRECT:
genesis 179 peer = self.state.get_peer_by_handle(message["handle"])
9992-handle-edge-... 180 if peer and (peer.get_key() != None):
genesis 181 peer.send(message)
genesis 182 else:
9992-handle-edge-... 183 self.print_debug("Discarding message to unknown handle or handle with no key: %s" % message["handle"])
genesis 184 else:
genesis 185 for peer in self.state.get_peers():
9992-handle-edge-... 186 if peer.get_key() != None:
9992-handle-edge-... 187 peer.send(message)
9992-handle-edge-... 188 else:
9992-handle-edge-... 189 self.print_debug("Discarding message to handle with no key: %s" % message["handle"])
genesis 190
genesis 191 def rebroadcast(self, source_peer, message):
genesis 192 message["original"] = False
genesis 193 for peer in self.state.get_peers():
genesis 194 if(peer.peer_id != source_peer.peer_id):
genesis 195 message["command"] = BROADCAST
genesis 196 message["bounces"] = message["bounces"] + 1
genesis 197 peer.send(message)
genesis 198
genesis 199
genesis 200 def start(self):
genesis 201 # Setup UDP first
genesis 202 self.udp_server_socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
genesis 203 self.udp_server_socket.bind((self.address, self.udp_port))
genesis 204
genesis 205 serversockets = []
genesis 206 for port in self.ports:
genesis 207 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
genesis 208 s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
genesis 209 try:
genesis 210 s.bind((self.address, port))
genesis 211 except socket.error as e:
genesis 212 self.print_error("Could not bind port %s: %s." % (port, e))
genesis 213 sys.exit(1)
genesis 214 s.listen(5)
genesis 215 serversockets.append(s)
genesis 216 del s
genesis 217 self.print_info("Listening on port %d." % port)
genesis 218 if self.chroot:
genesis 219 os.chdir(self.chroot)
genesis 220 os.chroot(self.chroot)
genesis 221 self.print_info("Changed root directory to %s" % self.chroot)
genesis 222 if self.setuid:
genesis 223 os.setgid(self.setuid[1])
genesis 224 os.setuid(self.setuid[0])
genesis 225 self.print_info("Setting uid:gid to %s:%s"
genesis 226 % (self.setuid[0], self.setuid[1]))
genesis 227 last_aliveness_check = time.time()
genesis 228 while True:
genesis 229 (inputready,outputready,exceptready) = select.select([self.udp_server_socket],[],[],0)
genesis 230 (iwtd, owtd, ewtd) = select.select(
genesis 231 serversockets + [x.socket for x in self.clients.values()],
genesis 232 [x.socket for x in self.clients.values()
genesis 233 if x.write_queue_size() > 0],
genesis 234 [],
genesis 235 0)
genesis 236 for x in inputready:
genesis 237 if x == self.udp_server_socket:
genesis 238 bytes_address_pair = self.udp_server_socket.recvfrom(PACKET_SIZE)
genesis 239 self.handle_udp_data(bytes_address_pair)
genesis 240 for x in iwtd:
genesis 241 if x in self.clients:
genesis 242 self.clients[x].socket_readable_notification()
genesis 243 else:
genesis 244 (conn, addr) = x.accept()
genesis 245 if self.ssl_pem_file:
genesis 246 import ssl
genesis 247 try:
genesis 248 conn = ssl.wrap_socket(
genesis 249 conn,
genesis 250 server_side=True,
genesis 251 certfile=self.ssl_pem_file,
genesis 252 keyfile=self.ssl_pem_file)
genesis 253 except ssl.SSLError as e:
genesis 254 self.print_error(
genesis 255 "SSL error for connection from %s:%s: %s" % (
genesis 256 addr[0], addr[1], e))
genesis 257 continue
genesis 258 self.clients[conn] = Client(self, conn)
genesis 259 self.print_info("Accepted connection from %s:%s." % (
genesis 260 addr[0], addr[1]))
genesis 261 for x in owtd:
genesis 262 if x in self.clients: # client may have been disconnected
genesis 263 self.clients[x].socket_writable_notification()
genesis 264 now = time.time()
genesis 265 if last_aliveness_check + 10 < now:
genesis 266 for client in self.clients.values():
genesis 267 client.check_aliveness()
genesis 268 last_aliveness_check = now
genesis 269
genesis 270
genesis 271 def create_directory(path):
genesis 272 if not os.path.isdir(path):
genesis 273 os.makedirs(path)
genesis 274