tree checksum vpatch file split hunks
all signers:
antecedents: 9991-improved-logging
press order:
genesis | |
9992-handle-edge-cases-add-feedback | |
9991-improved-logging | |
9990-keep-ephemeral-ports-open |
patch:
(5 . 6)(5 . 8)- 0646687DE5D54FD0278B8265786D9E5BB65492DC81F323249B57C129D5293CF605F384B13354379D970AAF04C1757866529320F2B0D8226F64A0F269398DE6CB
5 import string
6 import os
7 import base64
8 import traceback
9 from lib.message import Message
10 from lib.server import VERSION
11 from funcs import *
12 from lib.commands import BROADCAST
(150 . 7)(152 . 7)
14 self.disconnect("Client quit")
15 return
16 if self.nickname and self.user:
17 self.reply("001 %s :Hi, welcome to IRC" % self.nickname)
18 self.reply("001 %s :Hi, welcome to Pest" % self.nickname)
19 self.reply("002 %s :Your host is %s, running version blatta-%s"
20 % (self.nickname, server.name, VERSION))
21 self.reply("003 %s :This server was created sometime"
(341 . 13)(343 . 13)
23 self.channel_log(channel, message)
24 else:
25 formatted_message = ":%s %s %s :%s" % (self.prefix, command, targetname, message)
26 self.server.peer_message({
27 self.server.peer_message(Message({
28 "speaker": self.nickname,
29 "handle": targetname,
30 "body": formatted_message,
31 "bounces": 0,
32 "command": DIRECT
33 })
34 }, self.server))
35 if(client):
36 client.message(formatted_message)
37
(537 . 13)(539 . 18)
39 handle = arguments[0]
40 at = self.server.state.get_at(handle)
41 elif len(arguments) == 2:
42 handle, address = arguments
43 address_ip, port = string.split(address, ":")
44 self.server.state.update_address_table({"handle": handle,
45 "address": address_ip,
46 "port": port},
47 False)
48 self.pest_reply("updated address table: %s %s" % (handle, address))
49 try:
50 handle, address = arguments
51 address_ip, port = string.split(address, ":")
52 self.server.state.update_address_table({"handle": handle,
53 "address": address_ip,
54 "port": port},
55 False)
56 self.pest_reply("updated address table: %s %s" % (handle, address))
57 except Exception as ex:
58 self.pest_reply("Error attempting to update address table")
59 stack = traceback.format_exc()
60 print(stack)
61 return
62 elif len(arguments) > 2:
63 self.pest_reply("Usage: AT [<HANDLE>] [<ADDRESS>]")
(588 . 7)(595 . 9)
65 try:
66 handler_table[command]()
67 except KeyError:
68 self.reply("421 %s %s :Unknown command" % (self.nickname, command))
69 self.reply("421 %s %s :Unknown command" % (self.nickname, command))
70 stack = traceback.format_exc()
71 print(stack)
72
73 def socket_readable_notification(self):
74 try:
(647 . 12)(656 . 14)
76 if client != self or include_self:
77 client.message(line)
78 # send the channel message to peers as well
79 self.server.peer_message({
80 self.server.peer_message(
81 Message(
82 {
83 "speaker": self.nickname,
84 "command": BROADCAST,
85 "bounces": 0,
86 "body": line
87 })
88 }, self.server))
89
90 def channel_log(self, channel, message, meta=False):
91 if not self.server.logdir:
(5 . 6)(5 . 8)-
96 from lib.serpent import serpent_cbc_decrypt
97 from commands import BROADCAST
98 from commands import DIRECT
99 from commands import IGNORE
100 from lib.message import Message
101 import base64
102 import binascii
103 import time
(12 . 6)(14 . 7)
105 import sys
106 import hmac
107 import random
108 import os
109 import pprint
110 pp = pprint.PrettyPrinter(indent=4)
111
(28 . 6)(31 . 7)
113 DUPLICATE_PACKET = 1
114 MALFORMED_PACKET = 2
115 INVALID_SIGNATURE = 3
116 IGNORED = 4
117
118 class Infosec(object):
119 def __init__(self, server=None):
(35 . 11)(39 . 11)
121
122 def pack(self, peer, message):
123 try:
124 timestamp = message["timestamp"]
125 timestamp = message.timestamp
126 except:
127 timestamp = None
128 command = message["command"]
129 speaker = self._pad(message["speaker"], MAX_SPEAKER_SIZE)
130 command = message.command
131 speaker = self._pad(message.speaker, MAX_SPEAKER_SIZE)
132
133 # if we are rebroadcasting we need to use the original timestamp
134
(56 . 32)(60 . 34)
136 # there this is the first message
137
138
139 if message["original"]:
140 if message.original:
141 if command == DIRECT:
142 self_chain = self.server.state.get_last_message_hash(message["speaker"], peer.peer_id)
143 self_chain = self.server.state.get_last_message_hash(message.speaker, peer.peer_id)
144 elif command == BROADCAST:
145 self_chain = self.server.state.get_last_message_hash(message["speaker"])
146 self_chain = self.server.state.get_last_message_hash(message.speaker)
147 elif command == IGNORE:
148 self_chain = "\x00" * 32
149 net_chain = "\x00" * 32
150 else:
151 self_chain = message["self_chain"]
152 net_chain = message["net_chain"]
153 self_chain = message.self_chain
154 net_chain = message.net_chain
155
156 # pack message bytes
157
158 message_bytes = struct.pack(MESSAGE_PACKET_FORMAT, int_ts, self_chain, net_chain, speaker, message["body"].encode("ascii"))
159 message_bytes = struct.pack(MESSAGE_PACKET_FORMAT, int_ts, self_chain, net_chain, speaker, message.body)
160
161 # log messages
162
163 if message["original"]:
164 if message.original:
165 if command == DIRECT:
166 self.server.state.log(message["speaker"], message_bytes, peer.peer_id)
167 self.server.state.log(message.speaker, message_bytes, peer.peer_id)
168 elif command == BROADCAST:
169 self.server.state.log(message["speaker"], message_bytes)
170 self.server.state.log(message.speaker, message_bytes)
171
172 # pack packet bytes
173
174 nonce = self._generate_nonce(16)
175 bounces = message["bounces"]
176 bounces = message.bounces
177 version = 0xfe
178 red_packet_bytes = struct.pack(RED_PACKET_FORMAT, nonce, bounces, version, command, self._pad(message_bytes, MAX_MESSAGE_LENGTH))
179
(114 . 14)(120 . 14)
181 black_packet_bytes, signature_bytes = struct.unpack(BLACK_PACKET_FORMAT, black_packet)
182 except:
183 self.server.print_error("Discarding malformed black packet from %s" % peer.get_key())
184 return { "error_code": MALFORMED_PACKET }
185 return Message({ "error_code": MALFORMED_PACKET }, self.server)
186
187 # check signature
188
189 signature_check_bytes = hmac.new(signing_key, black_packet_bytes, hashlib.sha384).digest()
190
191 if(signature_check_bytes != signature_bytes):
192 return { "error_code": INVALID_SIGNATURE }
193 return Message({ "error_code": INVALID_SIGNATURE }, self.server)
194
195 # try to decrypt black packet
196
(132 . 6)(138 . 11)
198
199 nonce, bounces, version, command, message_bytes = struct.unpack(RED_PACKET_FORMAT, red_packet_bytes)
200
201 # nothing to be done for an IGNORE command
202
203 if command == IGNORE:
204 return Message({"error_code": IGNORED})
205
206 # unpack message
207
208 int_ts, self_chain, net_chain, speaker, message = struct.unpack(MESSAGE_PACKET_FORMAT, message_bytes)
(140 . 10)(151 . 10)
210 # check timestamp
211
212 if(int_ts not in self._ts_range()):
213 return { "error_code": STALE_PACKET }
214 return Message({ "error_code": STALE_PACKET }, self.server)
215
216 if(self.server.recent.has(int_ts)):
217 return { "error_code": DUPLICATE_PACKET }
218 return Message({ "error_code": DUPLICATE_PACKET }, self.server)
219 else:
220 self.server.recent.insert(int_ts)
221
(167 . 17)(178 . 19)
223 unpadded_message = message[0:index]
224 break
225
226 # return the message, timestamp, and command (command replaces propagate)
227
228 return { "body": unpadded_message.rstrip(),
229 "timestamp": int_ts,
230 "command": command,
231 "speaker": speaker,
232 "bounces": bounces,
233 "self_chain": self_chain,
234 "net_chain": net_chain,
235 "self_chain_valid": self_chain_valid,
236 "error_code": None}
237 return Message({
238 "peer": peer,
239 "body": unpadded_message.rstrip(),
240 "timestamp": int_ts,
241 "command": command,
242 "speaker": speaker,
243 "bounces": bounces,
244 "self_chain": self_chain,
245 "net_chain": net_chain,
246 "self_chain_valid": self_chain_valid,
247 "error_code": None
248 },
249 self.server)
250
251 def _pad(self, text, size):
252 return text.ljust(size)
(189 . 3)(202 . 6)
254 def _generate_nonce(self, length=8):
255 """Generate pseudorandom number."""
256 return ''.join([str(random.randint(0, 9)) for i in range(length)])
257
258 def gen_rubbish_body(self):
259 return os.urandom(MAX_MESSAGE_LENGTH)
(0 . 0)(1 . 17)
264 class Message(object):
265 def __init__(self, message, server=None):
266 self.original = True
267 self.server = server
268 self.handle = message.get("handle")
269 self.peer = message.get("peer")
270 self.body = message.get("body")
271 self.timestamp = message.get("timestamp")
272 self.command = message.get("command")
273 self.speaker = message.get("speaker")
274 self.bounces = message.get("bounces")
275 self.self_chain = message.get("self_chain")
276 self.net_chain = message.get("net_chain")
277 self.self_chain_valid = message.get("self_chain_valid")
278 self.error_code = message.get("error_code")
279 if server:
280 self.state = server.state
- 351A587CEDCDC65AB2989A2F27A2C57D3CBC196376B9C3DE1E41A6A407CC94727B24C73BD13B768A722E229C80A416668A372209FF273DF0A8F41BF1F79E8064(1 . 7)(1 . 9)- 44B1B3516F89AD8B7E7B9769A5C6089E22E9D459D012C1B72232926E0ABBDF42FBF74D2CD38F1344FE29143386C21432A61DC1DF454BF1CBA19ABDD8910C05CF
285 import socket
286 from infosec import Infosec
287 from commands import IGNORE
288 import sys
289 import binascii
290 import traceback
291
292 class Peer(object):
293 def __init__(self, server, peer_entry):
(22 . 14)(24 . 14)
295
296 def send(self, msg):
297 try:
298 full_message = str.encode(msg["body"])
299
300 signed_packet_bytes = self.infosec.pack(self, msg)
301 self.server.print_debug("packing message: %s" % full_message)
302 if msg.command != IGNORE:
303 self.server.print_debug("packing message: %s" % msg.body)
304 self.socket.sendto(signed_packet_bytes, (self.address, self.port))
305 self.server.print_debug("[%s:%d] <- %s" % (self.address,
306 self.port,
307 binascii.hexlify(signed_packet_bytes)[0:16]))
308
309 except Exception as ex:
310 print("Exception while attempting to encode message: %s" % ex)
311 stack = traceback.format_exc()
312 print(stack)
(1 . 4)(1 . 4)
317 VERSION = "9991"
318 VERSION = "9990"
319
320 import os
321 import select
(20 . 12)(20 . 15)
323 from lib.infosec import DUPLICATE_PACKET
324 from lib.infosec import MALFORMED_PACKET
325 from lib.infosec import INVALID_SIGNATURE
326 from lib.infosec import IGNORED
327 from lib.infosec import Infosec
328 from lib.peer import Peer
329 from lib.message import Message
330 from lib.ringbuffer import Ringbuffer
331 from funcs import *
332 from commands import BROADCAST
333 from commands import DIRECT
334 from commands import IGNORE
335 import imp
336 import pprint
337
(156 . 29)(159 . 28)
339 for peer in self.state.get_peers():
340 if peer.get_key() != None:
341 message = self.infosec.unpack(peer, data)
342 error_code = message["error_code"]
343 error_code = message.error_code
344 if(error_code == None):
345 self.print_debug("[%s] -> %s" % (peer.handles[0], message["body"]))
346 self.print_debug("[%s] -> %s" % (peer.handles[0], message.body))
347
348 # we only update the address table if the speaker is same as peer
349
350 try:
351 idx = peer.handles.index(message["speaker"])
352 idx = peer.handles.index(message.speaker)
353 except:
354 idx = None
355
356 if idx != None:
357 self.state.update_address_table({"handle": message["speaker"],
358 self.state.update_address_table({"handle": message.speaker,
359 "address": address[0],
360 "port": address[1]
361 })
362 # send the message to all clients
363 for c in self.clients:
364 # self.clients[c].udp_socket_readable_notification(message)
365 if (self.clients[c].is_addressed_to_me(message["body"])):
366 self.clients[c].message(message["body"])
367 if (self.clients[c].is_addressed_to_me(message.body)):
368 self.clients[c].message(message.body)
369 # send the message to all other peers if it should be propagated
370 if(message["command"] == BROADCAST) and message["bounces"] < MAX_BOUNCES:
371 if(message.command == BROADCAST) and message.bounces < MAX_BOUNCES:
372 self.rebroadcast(peer, message)
373 return
374 elif error_code == STALE_PACKET:
(190 . 34)(192 . 47)
376 elif error_code == MALFORMED_PACKET:
377 self.print_debug("[%s:%d] -> malformed packet: %s" % packet_info)
378 return
379 elif error_code == IGNORED:
380 self.print_debug("[%s:%d] -> ignoring packet: %s" % packet_info)
381 return
382 elif error_code == INVALID_SIGNATURE:
383 pass
384 self.print_debug("[%s:%d] -> martian packet: %s" % packet_info)
385
386 def peer_message(self, message):
387 message["original"] = True
388 if message["command"] == DIRECT:
389 peer = self.state.get_peer_by_handle(message["handle"])
390 message.original = True
391 if message.command == DIRECT:
392 peer = self.state.get_peer_by_handle(message.handle)
393 if peer and (peer.get_key() != None):
394 peer.send(message)
395 else:
396 self.print_debug("Discarding message to unknown handle or handle with no key: %s" % message["handle"])
397 self.print_debug("Discarding message to unknown handle or handle with no key: %s" % message.handle)
398 else:
399 for peer in self.state.get_peers():
400 if peer.get_key() != None:
401 peer.send(message)
402 else:
403 self.print_debug("Discarding message to handle with no key: %s" % message["handle"])
404 self.print_debug("Discarding message to handle with no key: %s" % message.handle)
405
406 def rebroadcast(self, source_peer, message):
407 message["original"] = False
408 message.original = False
409 for peer in self.state.get_peers():
410 if(peer.peer_id != source_peer.peer_id):
411 message["command"] = BROADCAST
412 message["bounces"] = message["bounces"] + 1
413 message.command = BROADCAST
414 message.bounces = message.bounces + 1
415 peer.send(message)
416
417
418 def sendrubbish(self):
419 for peer in self.state.get_peers():
420 for socket in self.clients:
421 self.peer_message(Message({
422 "speaker": self.clients[socket].nickname,
423 "command": IGNORE,
424 "bounces": 0,
425 "body": self.infosec.gen_rubbish_body()
426 }, self))
427
428 def start(self):
429 # Setup UDP first
430 self.udp_server_socket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
(254 . 7)(269 . 7)
432 [x.socket for x in self.clients.values()
433 if x.write_queue_size() > 0],
434 [],
435 1)
436 .2)
437 for x in inputready:
438 if x == self.udp_server_socket:
439 bytes_address_pair = self.udp_server_socket.recvfrom(PACKET_SIZE)
(275 . 7)(290 . 7)
441 for client in self.clients.values():
442 client.check_aliveness()
443 last_aliveness_check = now
444
445 self.sendrubbish() # Kludge to keep ephemeral port open when NATed
446
447 def create_directory(path):
448 if not os.path.isdir(path):