from ipaddress import ip_address from sanic import Sanic from sanic.response import text, json from sanic.views import HTTPMethodView class GetClientIpMixin: def get_client_ip(self, request): possible_ip = request.ip for header_name in ('x-real-ip', 'x-forwarded-for'): candidate_ip = None header_value = request.headers.get(header_name) if not header_value: continue for ip in header_value.split(',')[::-1]: try: candidate_ip = ip_address(ip.strip()) except ValueError: continue if candidate_ip.is_global: break if candidate_ip: possible_ip = candidate_ip break return str(possible_ip) class MainView(HTTPMethodView, GetClientIpMixin): def get(self, request): return text(self.get_client_ip(request)) class JsonView(HTTPMethodView, GetClientIpMixin): def get(self, request): return json({'ip_address': self.get_client_ip(request)}) class Application(object): app = Sanic() def __init__(self, args): self.args = args self.app.add_route(MainView.as_view(), '/') self.app.add_route(JsonView.as_view(), '/json') def run(self): self.app.run(host=self.args.interface, port=self.args.port) if __name__ == '__main__': import os from argparse import ArgumentParser default_host = os.environ.get('APP_HOST', '0.0.0.0') default_port = int(os.environ.get('APP_PORT', 8080)) default_trusted = os.environ.get('TRUSTED_PROXIES') or None parser = ArgumentParser('app.py') parser.add_argument('--interface', '-i', type=str, help='Interface to listen on', default=default_host) parser.add_argument('--port', '-p', type=int, help='Port to listen on', default=default_port) parser.add_argument('--proxies', type=str, help='A list of trusted proxies, comma separated. you can use CIDRs.', default=default_trusted) args = parser.parse_args() zero_if = Application(args) zero_if.run()