diff --git a/ennstatus/api/functions.py b/ennstatus/api/functions.py --- a/ennstatus/api/functions.py +++ b/ennstatus/api/functions.py @@ -1,6 +1,7 @@ import re import json +import ipaddress from datetime import datetime @@ -13,15 +14,6 @@ from ennstatus.status.functions import _ FINGERPRINT_REGEX = re.compile(r'^[A-Z0-9]{40}$', re.I) -IP_REGEX = (r'^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}' - r'(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$') -IP_REGEX = re.compile(IP_REGEX) - -PRIVATE_IP_REGEX = (r'(^127\.)|(^192\.168\.)|(^10\.)|(^172\.1[6-9]\.)' - r'|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|' - r'255\.255\.255\.255') -PRIVATE_IP_REGEX = re.compile(PRIVATE_IP_REGEX) - DATE_FORMAT = '%d-%m-%Y %H:%M:%S' gi4 = pygeoip.GeoIP('/usr/share/GeoIP/GeoIP.dat', pygeoip.MEMORY_CACHE) @@ -66,10 +58,27 @@ def check_json_format(server): check_bridge(key, server) if 'ip' in server: - if IP_REGEX.match(server['ip']) is None: + try: + address = ipaddress.IPv4Address(server['ip']) + + if any([address.is_private, address.is_multicast, + address.is_unspecified, address.is_reserved, + address.is_loopback, address.link_local]): + raise ValueError('ip is not accepted!\n') + + except ipaddress.AddressValueError: raise ValueError('ip is not the right format!\n') - elif PRIVATE_IP_REGEX.match(server['ip']) is not None: - raise ValueError('ip is not accepted!\n') + + if 'ip6' in server: + try: + address = ipaddress.IPv6Address(server['ip6']) + if any([address.is_private, address.is_multicast, + address.is_unspecified, address.is_reserved, + address.is_loopback, address.link_local]): + raise ValueError('ip is not accepted!\n') + + except ipaddress.AddressValueError: + raise ValueError('ip is not the right format!\n') return True @@ -92,12 +101,20 @@ def update_server(server, ip): if server['server_type'] == 'Bridge': if 'ip' in server: del server['ip'] + + if 'ip6' in server: + del server['ip6'] else: for key in ('obfs', 'fteproxy', 'flashproxy', 'meek'): if key in server: del server[key] - if 'ip' not in server: - server['ip'] = ip + + if isinstance(ip, ipaddress.IPv4Address): + if 'ip' not in server: + server['ip'] = ip + elif isinstance(ip, ipaddress.IPv6Address): + if 'ip6' not in server: + server['ip6'] = ip try: filename = ''.join(['data/', server_name.lower(), '.json']) diff --git a/ennstatus/api/views.py b/ennstatus/api/views.py --- a/ennstatus/api/views.py +++ b/ennstatus/api/views.py @@ -1,3 +1,5 @@ +import ipaddress + from flask import (Blueprint, request, current_app, jsonify, render_template, abort) @@ -30,9 +32,16 @@ def update(): if 'ip' in json: ip = json['ip'] + elif 'ip6' in json: + ip = json['ip6'] else: ip = request.remote_addr + try: + ip = ipaddress.ip_address(ip) + except ipaddress.AddressValueError: + return 'IP not allowed!\n', 403, {'Content-Type': 'text/plain'} + if request.remote_addr not in accepted_ips: current_app.logger.warn('Unallowed IP %s tried to update data!' % ip)