diff --git a/config.example.toml b/config.example.toml index 7ad4df9..800652a 100644 --- a/config.example.toml +++ b/config.example.toml @@ -15,6 +15,8 @@ #port = 6697 # Possible values: 'yes' (connect over SSL/TLS and verify certificates), 'no' (connect without SSL/TLS), and 'insecure' (connect over SSL/TLS but disable all certificate checks) #ssl = 'yes' + # Possible values: 'inet' or 'INET' (force IPv4), 'inet6' or 'INET6' (force IPv6); if unspecified, both are used (if supported) + #family = #nick = 'irclogbot' #real = 'I am an irclog bot.' # Certificate and key for SASL EXTERNAL authentication with NickServ; certfile is a string containing the path to a .pem file which has the certificate and the key, certkeyfile similarly for one containing only the key; default values are empty (None in Python) to disable authentication; the connection is terminated if authentication fails; relative paths are evaluated relative to the config file. diff --git a/irclog.py b/irclog.py index 98e1b70..98a4881 100644 --- a/irclog.py +++ b/irclog.py @@ -126,7 +126,7 @@ class Config(dict): if not isinstance(obj['storage']['flushTime'], (int, float)) or obj['storage']['flushTime'] <= 0: raise InvalidConfig('Invalid storage flushTime: must be a positive int or float') if 'irc' in obj: - if any(x not in ('host', 'port', 'ssl', 'nick', 'real', 'certfile', 'certkeyfile') for x in obj['irc']): + if any(x not in ('host', 'port', 'ssl', 'family', 'nick', 'real', 'certfile', 'certkeyfile') for x in obj['irc']): raise InvalidConfig('Unknown key found in irc section') if 'host' in obj['irc'] and not isinstance(obj['irc']['host'], str): #TODO: Check whether it's a valid hostname raise InvalidConfig('Invalid IRC host') @@ -134,6 +134,10 @@ class Config(dict): raise InvalidConfig('Invalid IRC port') if 'ssl' in obj['irc'] and obj['irc']['ssl'] not in ('yes', 'no', 'insecure'): raise InvalidConfig(f'Invalid IRC SSL setting: {obj["irc"]["ssl"]!r}') + if 'family' in obj['irc']: + if obj['irc']['family'] not in ('inet', 'INET', 'inet6', 'INET6'): + raise InvalidConfig('Invalid IRC family') + obj['irc']['family'] = getattr(socket, f'AF_{obj["irc"]["family"].upper()}') if 'nick' in obj['irc'] and not isinstance(obj['irc']['nick'], str): #TODO: Check whether it's a valid nickname, username, etc. raise InvalidConfig('Invalid IRC nick') if len(IRCClientProtocol.nick_command(obj['irc']['nick'])) > 510: @@ -259,7 +263,7 @@ class Config(dict): defaults = { 'logging': {'level': 'INFO', 'format': '{asctime} {levelname} {name} {message}'}, 'storage': {'path': os.path.abspath(os.path.dirname(self._filename)), 'flushTime': 60}, - 'irc': {'host': 'irc.hackint.org', 'port': 6697, 'ssl': 'yes', 'nick': 'irclogbot', 'real': 'I am an irclog bot.', 'certfile': None, 'certkeyfile': None}, + 'irc': {'host': 'irc.hackint.org', 'port': 6697, 'ssl': 'yes', 'family': 0, 'nick': 'irclogbot', 'real': 'I am an irclog bot.', 'certfile': None, 'certkeyfile': None}, 'web': {'host': '127.0.0.1', 'port': 8080, 'search': {'maxTime': 10, 'maxSize': 1048576, 'nice': 10, 'maxMemory': 52428800}}, 'channels': obj['channels'], # _merge_dicts expects the same structure, and this is the easiest way to achieve that } @@ -708,6 +712,7 @@ class IRCClient: host = self.config['irc']['host'], port = self.config['irc']['port'], ssl = self._get_ssl_context(), + family = self.config['irc']['family'], )) # No automatic cancellation of t because it's handled manually below. done, _ = await wait_cancel_pending({asyncio.create_task(sigintEvent.wait())}, paws = {t}, return_when = asyncio.FIRST_COMPLETED, timeout = 30)