def start(self): """ Start web2py server """ password = self.password.get() if not password: self.error('no password, no web admin interface') ip = self.selected_ip.get() if not is_valid_ip_address(ip): return self.error('invalid host ip address') try: port = int(self.port_number.get()) except: return self.error('invalid port number') # Check for non default value for ssl inputs if (len(self.options.ssl_certificate) > 0 or len(self.options.ssl_private_key) > 0): proto = 'https' else: proto = 'http' self.url = get_url(ip, proto=proto, port=port) self.connect_pages() self.button_start.configure(state='disabled') try: options = self.options req_queue_size = options.request_queue_size self.server = main.HttpServer( ip, port, password, pid_filename=options.pid_filename, log_filename=options.log_filename, profiler_dir=options.profiler_dir, ssl_certificate=options.ssl_certificate, ssl_private_key=options.ssl_private_key, ssl_ca_certificate=options.ssl_ca_certificate, min_threads=options.minthreads, max_threads=options.maxthreads, server_name=options.server_name, request_queue_size=req_queue_size, timeout=options.timeout, shutdown_timeout=options.shutdown_timeout, path=options.folder, interfaces=options.interfaces) thread.start_new_thread(self.server.start, ()) except Exception, e: self.button_start.configure(state='normal') return self.error(str(e))
def start(self): """ Start web2py server """ password = self.password.get() if not password: self.error("no password, no web admin interface") ip = self.selected_ip.get() if not is_valid_ip_address(ip): return self.error("invalid host ip address") try: port = int(self.port_number.get()) except: return self.error("invalid port number") # Check for non default value for ssl inputs if len(self.options.ssl_certificate) > 0 or len(self.options.ssl_private_key) > 0: proto = "https" else: proto = "http" self.url = get_url(ip, proto=proto, port=port) self.connect_pages() self.button_start.configure(state="disabled") try: options = self.options req_queue_size = options.request_queue_size self.server = main.HttpServer( ip, port, password, pid_filename=options.pid_filename, log_filename=options.log_filename, profiler_dir=options.profiler_dir, ssl_certificate=options.ssl_certificate, ssl_private_key=options.ssl_private_key, ssl_ca_certificate=options.ssl_ca_certificate, min_threads=options.minthreads, max_threads=options.maxthreads, server_name=options.server_name, request_queue_size=req_queue_size, timeout=options.timeout, shutdown_timeout=options.shutdown_timeout, path=options.folder, interfaces=options.interfaces, ) thread.start_new_thread(self.server.start, ()) except Exception, e: self.button_start.configure(state="normal") return self.error(str(e))
def test_is_valid_ip_address(self): # IPv4 # False # self.assertEqual(is_valid_ip_address('127.0'), False) # Fail with AppVeyor?? should pass self.assertEqual(is_valid_ip_address("unknown"), False) self.assertEqual(is_valid_ip_address(""), False) # True self.assertEqual(is_valid_ip_address("127.0.0.1"), True) self.assertEqual(is_valid_ip_address("localhost"), True) self.assertEqual(is_valid_ip_address("::1"), True) # IPv6 # True # Compressed self.assertEqual(is_valid_ip_address("::ffff:7f00:1"), True) # IPv6 127.0.0.1 compressed self.assertEqual(is_valid_ip_address("2001:660::1"), True) # Expanded self.assertEqual(is_valid_ip_address("0:0:0:0:0:ffff:7f00:1"), True) # IPv6 127.0.0.1 expanded self.assertEqual(is_valid_ip_address("2607:fa48:6d50:69f1:21f:3cff:fe9d:9be3"), True) # Any address
def xmlrpc_get_cracker_info(self, ip): if not utils.is_valid_ip_address(ip): logging.warning("Illegal host ip address {}".format(ip)) raise xmlrpc.Fault(101, "Illegal IP address \"{}\".".format(ip)) #logging.info("Getting info for cracker {}".format(ip_address)) cracker = yield controllers.get_cracker(ip) if cracker is None: raise xmlrpc.Fault(104, "Cracker {} unknown".format(ip)) returnValue([]) #logging.info("found cracker: {}".format(cracker)) reports = yield cracker.reports.get() #logging.info("found reports: {}".format(reports)) cracker_cols=['ip_address','first_time', 'latest_time', 'resiliency', 'total_reports', 'current_reports'] report_cols=['ip_address','first_report_time', 'latest_report_time'] returnValue( [cracker.toHash(cracker_cols), [r.toHash(report_cols) for r in reports]] )
def test_is_valid_ip_address(self): # IPv4 # False # self.assertEqual(is_valid_ip_address('127.0'), False) # Fail with AppVeyor?? should pass self.assertEqual(is_valid_ip_address('unknown'), False) self.assertEqual(is_valid_ip_address(''), False) # True self.assertEqual(is_valid_ip_address('127.0.0.1'), True) self.assertEqual(is_valid_ip_address('localhost'), True) self.assertEqual(is_valid_ip_address('::1'), True) # IPv6 # True # Compressed self.assertEqual(is_valid_ip_address('::ffff:7f00:1'), True) # IPv6 127.0.0.1 compressed self.assertEqual(is_valid_ip_address('2001:660::1'), True) # Expanded self.assertEqual(is_valid_ip_address('0:0:0:0:0:ffff:7f00:1'), True) # IPv6 127.0.0.1 expanded self.assertEqual( is_valid_ip_address('2607:fa48:6d50:69f1:21f:3cff:fe9d:9be3'), True) # Any address
def handle_report_from_client(client_ip, timestamp, hosts): for cracker_ip in hosts: if not utils.is_valid_ip_address(cracker_ip): logging.warning("Illegal host ip address {} from {}".format(cracker_ip, client_ip)) raise Exception("Illegal IP address \"{}\".".format(cracker_ip)) logging.debug("Adding report for {} from {}".format(cracker_ip, client_ip)) yield utils.wait_and_lock_host(cracker_ip) try: cracker = yield Cracker.find(where=['ip_address=?', cracker_ip], limit=1) if cracker is None: cracker = Cracker(ip_address=cracker_ip, first_time=timestamp, latest_time=timestamp, resiliency=0, total_reports=0, current_reports=0) yield cracker.save() yield add_report_to_cracker(cracker, client_ip, when=timestamp) finally: utils.unlock_host(cracker_ip) logging.debug("Done adding report for {} from {}".format(cracker_ip,client_ip))
def get_client(env): """ guess the client address from the environment variables first tries 'http_x_forwarded_for', secondly 'remote_addr' if all fails assume '127.0.0.1' (running locally) """ g = regex_client.search(env.get('http_x_forwarded_for', '')) if g: client = (g.group() or '').split(',')[0] else: g = regex_client.search(env.get('remote_addr', '')) if g: client = g.group() else: client = '127.0.0.1' if not is_valid_ip_address(client): raise HTTP(400,"Bad Request (request.client=%s)" % client) return client
def get_client(env): """ guess the client address from the environment variables first tries 'http_x_forwarded_for', secondly 'remote_addr' if all fails assume '127.0.0.1' (running locally) """ g = regex_client.search(env.get('http_x_forwarded_for', '')) if g: client = g.group() else: g = regex_client.search(env.get('remote_addr', '')) if g: client = g.group() else: client = '127.0.0.1' if not is_valid_ip_address(client): raise HTTP(400, "Bad Request (request.client=%s)" % client) return client
def get_client(env): """ guess the client address from the environment variables first tries 'http_x_forwarded_for', secondly 'remote_addr' if all fails, assume '127.0.0.1' or '::1' (running locally) """ g = regex_client.search(env.get('http_x_forwarded_for', '')) client = (g.group() or '').split(',')[0] if g else None if client in (None, '', 'unknown'): g = regex_client.search(env.get('remote_addr', '')) if g: client = g.group() elif env.http_host.startswith('['): # IPv6 client = '::1' else: client = '127.0.0.1' # IPv4 if not is_valid_ip_address(client): raise HTTP(400, "Bad Request (request.client=%s)" % client) return client
def xmlrpc_get_new_hosts(self, request, timestamp, threshold, hosts_added, resiliency): try: x_real_ip = request.requestHeaders.getRawHeaders("X-Real-IP") remote_ip = x_real_ip[0] if x_real_ip else request.getClientIP() logging.debug("get_new_hosts({},{},{},{}) from {}".format(timestamp, threshold, hosts_added, resiliency, remote_ip)) try: timestamp = long(timestamp) threshold = int(threshold) resiliency = long(resiliency) except: logging.warning("Illegal arguments to get_new_hosts from client {}".format(remote_ip)) raise xmlrpc.Fault(102, "Illegal parameters.") now = time.time() # refuse timestamps from the future if timestamp > now: logging.warning("Illegal timestamp to get_new_hosts from client {}".format(remote_ip)) raise xmlrpc.Fault(103, "Illegal timestamp.") for host in hosts_added: if not utils.is_valid_ip_address(host): logging.warning("Illegal host ip address {}".format(host)) raise xmlrpc.Fault(101, "Illegal IP address \"{}\".".format(host)) # TODO: maybe refuse timestamp from far past because it will # cause much work? OTOH, denyhosts will use timestamp=0 for # the first run! # TODO: check if client IP is a known cracker result = {} result['timestamp'] = str(long(time.time())) result['hosts'] = yield controllers.get_qualifying_crackers( threshold, resiliency, timestamp, config.max_reported_crackers, set(hosts_added)) logging.debug("returning: {}".format(result)) except xmlrpc.Fault, e: raise e
def wsgibase(environ, responder): """ this is the gluon wsgi application. the first function called when a page is requested (static or dynamic). it can be called by paste.httpserver or by apache mod_wsgi. - fills request with info - the environment variables, replacing '.' with '_' - adds web2py path and version info - compensates for fcgi missing path_info and query_string - validates the path in url The url path must be either: 1. for static pages: - /<application>/static/<file> 2. for dynamic pages: - /<application>[/<controller>[/<function>[/<sub>]]][.<extension>] - (sub may go several levels deep, currently 3 levels are supported: sub1/sub2/sub3) The naming conventions are: - application, controller, function and extension may only contain [a-zA-Z0-9_] - file and sub may also contain '-', '=', '.' and '/' """ current.__dict__.clear() request = Request() response = Response() session = Session() request.env.web2py_path = global_settings.applications_parent request.env.web2py_version = web2py_version request.env.update(global_settings) static_file = False try: try: try: # ################################################## # handle fcgi missing path_info and query_string # select rewrite parameters # rewrite incoming URL # parse rewritten header variables # parse rewritten URL # serve file if static # ################################################## if not environ.get('PATH_INFO',None) and \ environ.get('REQUEST_URI',None): # for fcgi, get path_info and query_string from request_uri items = environ['REQUEST_URI'].split('?') environ['PATH_INFO'] = items[0] if len(items) > 1: environ['QUERY_STRING'] = items[1] else: environ['QUERY_STRING'] = '' if not environ.get('HTTP_HOST',None): environ['HTTP_HOST'] = '%s:%s' % (environ.get('SERVER_NAME'), environ.get('SERVER_PORT')) (static_file, environ) = rewrite.url_in(request, environ) if static_file: if environ.get('QUERY_STRING', '')[:10] == 'attachment': response.headers['Content-Disposition'] = 'attachment' response.stream(static_file, request=request) # ################################################## # fill in request items # ################################################## http_host = request.env.http_host.split(':',1)[0] local_hosts = [http_host,'::1','127.0.0.1','::ffff:127.0.0.1'] if not global_settings.web2py_runtime_gae: local_hosts.append(socket.gethostname()) try: local_hosts.append(socket.gethostbyname(http_host)) except socket.gaierror: pass request.client = get_client(request.env) if not is_valid_ip_address(request.client): raise HTTP(400,"Bad Request (request.client=%s)" % \ request.client) request.folder = abspath('applications', request.application) + os.sep x_req_with = str(request.env.http_x_requested_with).lower() request.ajax = x_req_with == 'xmlhttprequest' request.cid = request.env.http_web2py_component_element request.is_local = request.env.remote_addr in local_hosts request.is_https = request.env.wsgi_url_scheme \ in ['https', 'HTTPS'] or request.env.https == 'on' # ################################################## # compute a request.uuid to be used for tickets and toolbar # ################################################## response.uuid = request.compute_uuid() # ################################################## # access the requested application # ################################################## if not os.path.exists(request.folder): if request.application == \ rewrite.thread.routes.default_application \ and request.application != 'welcome': request.application = 'welcome' redirect(Url(r=request)) elif rewrite.thread.routes.error_handler: _handler = rewrite.thread.routes.error_handler redirect(Url(_handler['application'], _handler['controller'], _handler['function'], args=request.application)) else: raise HTTP(404, rewrite.thread.routes.error_message \ % 'invalid request', web2py_error='invalid application') elif not request.is_local and \ os.path.exists(os.path.join(request.folder,'DISABLED')): raise HTTP(503, "<html><body><h1>Temporarily down for maintenance</h1></body></html>") request.url = Url(r=request, args=request.args, extension=request.raw_extension) # ################################################## # build missing folders # ################################################## create_missing_app_folders(request) # ################################################## # get the GET and POST data # ################################################## parse_get_post_vars(request, environ) # ################################################## # expose wsgi hooks for convenience # ################################################## request.wsgi.environ = environ_aux(environ,request) request.wsgi.start_response = \ lambda status='200', headers=[], \ exec_info=None, response=response: \ start_response_aux(status, headers, exec_info, response) request.wsgi.middleware = \ lambda *a: middleware_aux(request,response,*a) # ################################################## # load cookies # ################################################## if request.env.http_cookie: try: request.cookies.load(request.env.http_cookie) except Cookie.CookieError, e: pass # invalid cookies # ################################################## # try load session or create new session file # ################################################## session.connect(request, response) # ################################################## # set no-cache headers # ################################################## response.headers['Content-Type'] = \ contenttype('.'+request.extension) response.headers['Cache-Control'] = \ 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0' response.headers['Expires'] = \ time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime()) response.headers['Pragma'] = 'no-cache' # ################################################## # run controller # ################################################## if global_settings.debugging and request.application != "admin": import gluon.debug # activate the debugger and wait to reach application code gluon.debug.dbg.do_debug(mainpyfile=request.folder) serve_controller(request, response, session) except HTTP, http_response: if static_file: return http_response.to(responder) if request.body: request.body.close() # ################################################## # on success, try store session in database # ################################################## session._try_store_in_db(request, response) # ################################################## # on success, commit database # ################################################## if response.do_not_commit is True: BaseAdapter.close_all_instances(None) # elif response._custom_commit: # response._custom_commit() elif response.custom_commit: BaseAdapter.close_all_instances(response.custom_commit) else: BaseAdapter.close_all_instances('commit') # ################################################## # if session not in db try store session on filesystem # this must be done after trying to commit database! # ################################################## session._try_store_on_disk(request, response) # ################################################## # store cookies in headers # ################################################## if request.cid: if response.flash and not 'web2py-component-flash' \ in http_response.headers: http_response.headers['web2py-component-flash'] = \ urllib2.quote(xmlescape(response.flash)\ .replace('\n','')) if response.js and not 'web2py-component-command' \ in http_response.headers: http_response.headers['web2py-component-command'] = \ response.js.replace('\n','') if session._forget and \ response.session_id_name in response.cookies: del response.cookies[response.session_id_name] elif session._secure: response.cookies[response.session_id_name]['secure'] = True http_response.cookies2headers(response.cookies) ticket=None except RestrictedError, e: if request.body: request.body.close() # ################################################## # on application error, rollback database # ################################################## ticket = e.log(request) or 'unknown' if response._custom_rollback: response._custom_rollback() else: BaseAdapter.close_all_instances('rollback') http_response = \ HTTP(500, rewrite.thread.routes.error_message_ticket % \ dict(ticket=ticket), web2py_error='ticket %s' % ticket)
def get_hostname(self): value = self.get_value('hostname') if not (is_valid_hostname(value) | is_valid_ip_address(value)): raise InvalidValueError('Invalid hostname: {}'.format(value)) return value
def wsgibase(environ, responder): """ this is the gluon wsgi application. the first function called when a page is requested (static or dynamic). it can be called by paste.httpserver or by apache mod_wsgi. - fills request with info - the environment variables, replacing '.' with '_' - adds web2py path and version info - compensates for fcgi missing path_info and query_string - validates the path in url The url path must be either: 1. for static pages: - /<application>/static/<file> 2. for dynamic pages: - /<application>[/<controller>[/<function>[/<sub>]]][.<extension>] - (sub may go several levels deep, currently 3 levels are supported: sub1/sub2/sub3) The naming conventions are: - application, controller, function and extension may only contain [a-zA-Z0-9_] - file and sub may also contain '-', '=', '.' and '/' """ current.__dict__.clear() request = Request() response = Response() session = Session() request.env.web2py_path = global_settings.applications_parent request.env.web2py_version = web2py_version request.env.update(global_settings) static_file = False try: try: try: # ################################################## # handle fcgi missing path_info and query_string # select rewrite parameters # rewrite incoming URL # parse rewritten header variables # parse rewritten URL # serve file if static # ################################################## if not environ.get('PATH_INFO',None) and \ environ.get('REQUEST_URI',None): # for fcgi, get path_info and query_string from request_uri items = environ['REQUEST_URI'].split('?') environ['PATH_INFO'] = items[0] if len(items) > 1: environ['QUERY_STRING'] = items[1] else: environ['QUERY_STRING'] = '' if not environ.get('HTTP_HOST',None): environ['HTTP_HOST'] = '%s:%s' % (environ.get('SERVER_NAME'), environ.get('SERVER_PORT')) (static_file, environ) = rewrite.url_in(request, environ) if static_file: if environ.get('QUERY_STRING', '')[:10] == 'attachment': response.headers['Content-Disposition'] = 'attachment' response.stream(static_file, request=request) # ################################################## # fill in request items # ################################################## http_host = request.env.http_host.split(':',1)[0] local_hosts = [http_host,'::1','127.0.0.1','::ffff:127.0.0.1'] if not global_settings.web2py_runtime_gae: local_hosts.append(socket.gethostname()) try: local_hosts.append(socket.gethostbyname(http_host)) except socket.gaierror: pass request.client = get_client(request.env) if not is_valid_ip_address(request.client): raise HTTP(400,"Bad Request (request.client=%s)" % \ request.client) request.folder = abspath('applications', request.application) + os.sep x_req_with = str(request.env.http_x_requested_with).lower() request.ajax = x_req_with == 'xmlhttprequest' request.cid = request.env.http_web2py_component_element request.is_local = request.env.remote_addr in local_hosts request.is_https = request.env.wsgi_url_scheme \ in ['https', 'HTTPS'] or request.env.https == 'on' # ################################################## # compute a request.uuid to be used for tickets and toolbar # ################################################## response.uuid = request.compute_uuid() # ################################################## # access the requested application # ################################################## if not os.path.exists(request.folder): if request.application == \ rewrite.thread.routes.default_application \ and request.application != 'welcome': request.application = 'welcome' redirect(Url(r=request)) elif rewrite.thread.routes.error_handler: _handler = rewrite.thread.routes.error_handler redirect(Url(_handler['application'], _handler['controller'], _handler['function'], args=request.application)) else: raise HTTP(404, rewrite.thread.routes.error_message \ % 'invalid request', web2py_error='invalid application') elif not request.is_local and \ os.path.exists(os.path.join(request.folder,'DISABLED')): raise HTTP(503, "<html><body><h1>Temporarily down for maintenance</h1></body></html>") request.url = Url(r=request, args=request.args, extension=request.raw_extension) # ################################################## # build missing folders # ################################################## create_missing_app_folders(request) # ################################################## # get the GET and POST data # ################################################## parse_get_post_vars(request, environ) # ################################################## # expose wsgi hooks for convenience # ################################################## request.wsgi.environ = environ_aux(environ,request) request.wsgi.start_response = \ lambda status='200', headers=[], \ exec_info=None, response=response: \ start_response_aux(status, headers, exec_info, response) request.wsgi.middleware = \ lambda *a: middleware_aux(request,response,*a) # ################################################## # load cookies # ################################################## if request.env.http_cookie: try: request.cookies.load(request.env.http_cookie) except Cookie.CookieError, e: pass # invalid cookies # ################################################## # try load session or create new session file # ################################################## session.connect(request, response) # ################################################## # set no-cache headers # ################################################## response.headers['Content-Type'] = \ contenttype('.'+request.extension) response.headers['Cache-Control'] = \ 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0' response.headers['Expires'] = \ time.strftime('%a, %d %b %Y %H:%M:%S GMT', time.gmtime()) response.headers['Pragma'] = 'no-cache' # ################################################## # run controller # ################################################## if global_settings.debugging and request.application != "admin": import gluon.debug # activate the debugger and wait to reach application code gluon.debug.dbg.do_debug(mainpyfile=request.folder) serve_controller(request, response, session) except HTTP, http_response: if static_file: return http_response.to(responder) if request.body: request.body.close() # ################################################## # on success, try store session in database # ################################################## session._try_store_in_db(request, response) # ################################################## # on success, commit database # ################################################## if response.do_not_commit is True: BaseAdapter.close_all_instances(None) # elif response._custom_commit: # response._custom_commit() elif response.custom_commit: BaseAdapter.close_all_instances(response.custom_commit) else: BaseAdapter.close_all_instances('commit') # ################################################## # if session not in db try store session on filesystem # this must be done after trying to commit database! # ################################################## session._try_store_on_disk(request, response) # ################################################## # store cookies in headers # ################################################## if request.cid: if response.flash and not 'web2py-component-flash' \ in http_response.headers: http_response.headers['web2py-component-flash'] = \ urllib2.quote(xmlescape(response.flash)\ .replace('\n','')) if response.js and not 'web2py-component-command' \ in http_response.headers: http_response.headers['web2py-component-command'] = \ response.js.replace('\n','') if session._forget and \ response.session_id_name in response.cookies: del response.cookies[response.session_id_name] elif session._secure: response.cookies[response.session_id_name]['secure'] = True if len(response.cookies)>0: http_response.headers['Set-Cookie'] = \ [str(cookie)[11:] for cookie in response.cookies.values()] ticket=None except RestrictedError, e: if request.body: request.body.close() # ################################################## # on application error, rollback database # ################################################## ticket = e.log(request) or 'unknown' if response._custom_rollback: response._custom_rollback() else: BaseAdapter.close_all_instances('rollback') http_response = \ HTTP(500, rewrite.thread.routes.error_message_ticket % \ dict(ticket=ticket), web2py_error='ticket %s' % ticket)
def random_ip_address(self): while True: ip = ".".join(map(str, (random.randint(0, 255) for _ in range(4)))) if utils.is_valid_ip_address(ip): return ip