diff --git a/.env.sample b/.env.sample index 8996b35..c0f05b5 100644 --- a/.env.sample +++ b/.env.sample @@ -1,4 +1,5 @@ DEBUG=True +DISABLE_IPV4_BLOCK=False ALLOWED_HOSTS=.localhost, .ipv6.work AUTH_LDAP_SERVER_URI=ldap:// AUTH_LDAP_BIND_DN=cn=admin,dc=example,dc=com diff --git a/ipv6work/ipv6middleware.py b/ipv6work/ipv6middleware.py new file mode 100644 index 0000000..972a01d --- /dev/null +++ b/ipv6work/ipv6middleware.py @@ -0,0 +1,38 @@ +import re +import socket +from django.conf import settings +from django.http import HttpResponse + + +def is_valid_ipv6(ip_address): + try: + socket.inet_pton(socket.AF_INET6, ip_address) + return True + except socket.error: + return False + + +def is_ipv6_exempt(path): + return any(re.match(m, path) for m in settings.IPV6_EXEMPT_URLS) + + +def block_ipv4(get_response): + ''' block IPv4 requests except if the url is in IPV6_EXEMPT_URLS''' + + def middleware(request): + if getattr(settings, 'DISABLE_IPV4_BLOCK', False): + return get_response(request) + + path = request.path_info.lstrip('/') + x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') + if x_forwarded_for: + client_ip = x_forwarded_for + else: + client_ip = request.META.get('REMOTE_ADDR') + print(is_ipv6_exempt(path), is_valid_ipv6(client_ip)) + if is_valid_ipv6(client_ip) or is_ipv6_exempt(path): + return get_response(request) + else: + return HttpResponse('Sorry, only reachable by IPv6') + + return middleware diff --git a/ipv6work/settings.py b/ipv6work/settings.py index a007bb8..8c9808f 100644 --- a/ipv6work/settings.py +++ b/ipv6work/settings.py @@ -67,8 +67,13 @@ MIDDLEWARE = [ 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'ipv6work.ipv6middleware.block_ipv4' ] +IPV6_EXEMPT_URLS = [r'^$'] +DISABLE_IPV4_BLOCK = config('DISABLE_IPV4_BLOCK', cast=bool, default=False) + + ROOT_URLCONF = 'ipv6work.urls' TEMPLATES = [