3
0
mirror of https://github.com/jlu5/PyLink.git synced 2024-12-24 19:52:53 +01:00

unreal: fix #137

a.k.a. fix the mess I made encoding IPs by not knowing about socket.inet_pton / socket.inet_ntop.
This commit is contained in:
James Lu 2015-11-26 22:15:52 -08:00
parent 197532c1be
commit 0c068c6543

View File

@ -3,6 +3,7 @@ import sys
import os
import time
import codecs
import socket
import re
curdir = os.path.dirname(__file__)
@ -64,12 +65,31 @@ class UnrealProtocol(TS6BaseProtocol):
realhost=realhost, ip=ip, manipulatable=manipulatable)
utils.applyModes(self.irc, uid, modes)
self.irc.servers[server].users.add(uid)
# UnrealIRCd requires encoding the IP by first packing it into a binary format,
# and then encoding the binary with Base64.
if ip == '0.0.0.0': # Dummy IP (for services, etc.) use a single *.
encoded_ip = '*'
else:
try: # Try encoding as IPv4 first.
binary_ip = socket.inet_pton(socket.AF_INET, ip)
except OSError:
try: # That failed, try IPv6 next.
binary_ip = socket.inet_pton(socket.AF_INET6, ip)
except OSError:
raise ValueError("Invalid IPv4 or IPv6 address %r." % ip)
# Encode in Base64.
encoded_ip = codecs.encode(binary_ip, "base64")
# Now, strip the trailing \n and decode into a string again.
encoded_ip = encoded_ip.strip().decode()
# <- :001 UID GL 0 1441306929 gl localhost 0018S7901 0 +iowx * midnight-1C620195 fwAAAQ== :realname
self._send(server, "UID {nick} 0 {ts} {ident} {realhost} {uid} 0 {modes} "
"{host} * * :{realname}".format(ts=ts, host=host,
"{host} * {ip} :{realname}".format(ts=ts, host=host,
nick=nick, ident=ident, uid=uid,
modes=raw_modes, realname=realname,
realhost=realhost))
realhost=realhost, ip=encoded_ip))
return u
def joinClient(self, client, channel):
@ -292,14 +312,18 @@ class UnrealProtocol(TS6BaseProtocol):
if raw_ip == b'*': # Dummy IP (for services, etc.)
ip = '0.0.0.0'
else:
# Each base64-encoded character represents a bit in the IP.
raw_ip = codecs.decode(raw_ip, "base64")
ipbits = list(map(str, raw_ip)) # Decode every bit
# First, decode the Base64 string into a packed binary IP address.
ip = codecs.decode(raw_ip, "base64")
if len(ipbits) == 4: # IPv4 address.
ip = '.'.join(ipbits)
elif len(ipbits) == 16: # IPv6 address.
ip = ':'.join(ipbits)
try: # IPv4 address.
ip = socket.inet_ntop(socket.AF_INET, ip)
except ValueError: # IPv6 address.
ip = socket.inet_ntop(socket.AF_INET6, ip)
# HACK: make sure a leading ":" in the IPv6 address (e.g. ::1)
# doesn't cause it to be misinterpreted as the last argument
# in a line, should it be mirrored to other networks.
if ip.startswith(':'):
ip = '0' + ip
else:
raise ProtocolError("Invalid number of bits in IP address field (got %s, expected 4 or 16)." % len(ipbits))
realname = args[-1]