void swd::connection::handle_read(const boost::system::error_code& e, std::size_t bytes_transferred) { /** * If an error occurs then no new asynchronous operations are started. This * means that all shared_ptr references to the connection object will disappear * and the object will be destroyed automatically after this handler returns. * The connection class's destructor closes the socket. */ if (e) { return; } /** * Since there was no error we can start parsing the input now. The parser * fills the object request_ with data. */ boost::tribool result; boost::tie(result, boost::tuples::ignore) = request_parser_.parse( request_, buffer_.data(), buffer_.data() + bytes_transferred ); /** * If result is true the complete request is parsed. If it is false there was * an error. If it is indeterminate then the parsing is not complete yet and * the program will read more input and append it to the old request_ object. */ if (indeterminate(result)) { /* Not finished yet with this request, start reading again. */ this->start_read(); /* And don't process the input yet. */ return; } /* The handler used to process the reply. */ swd::reply_handler reply_handler(reply_); try { if (!result) { swd::log::i()->send(swd::warning, "Bad request from " + remote_address_.to_string()); throw swd::exceptions::connection_exception(STATUS_BAD_REQUEST); } /* Try to add a profile for the request. */ try { swd::profile_ptr profile = swd::database::i()->get_profile( remote_address_.to_string(), request_->get_profile_id() ); request_->set_profile(profile); } catch (swd::exceptions::database_exception& e) { swd::log::i()->send(swd::uncritical_error, e.what()); throw swd::exceptions::connection_exception(STATUS_BAD_REQUEST); } /* The handler used to process the incoming request. */ swd::request_handler request_handler(request_); /* Only continue processing the reply if it is signed correctly. */ if (!request_handler.valid_signature()) { swd::log::i()->send(swd::warning, "Bad signature from " + remote_address_.to_string()); throw swd::exceptions::connection_exception(STATUS_BAD_SIGNATURE); } /** * Before the request can be processed the input has to be transfered * from the encoded json string to a swd::parameters list. */ if (!request_handler.decode()) { swd::log::i()->send(swd::warning, "Bad json from " + remote_address_.to_string()); throw swd::exceptions::connection_exception(STATUS_BAD_JSON); } /* Process the request. */ std::vector<std::string> threats; try { if (swd::database::i()->is_flooding(request_->get_client_ip(), request_->get_profile_id())) { throw swd::exceptions::connection_exception(STATUS_BAD_REQUEST); } threats = request_handler.process(); } catch (swd::exceptions::database_exception& e) { swd::log::i()->send(swd::uncritical_error, e.what()); /** * Problems with the database result in a bad request. If protection * is enabled access to the site will not be granted. */ throw swd::exceptions::connection_exception(STATUS_BAD_REQUEST); } if (!threats.empty()) { reply_->set_threats(threats); reply_->set_status(STATUS_ATTACK); } else { reply_->set_status(STATUS_OK); } } catch(swd::exceptions::connection_exception& e) { reply_->set_status(e.code()); } /* Encode the reply. */ reply_handler.encode(); /* Send the answer to the client. */ if (ssl_) { boost::asio::async_write( ssl_socket_, reply_->to_buffers(), strand_.wrap( boost::bind( &connection::handle_write, shared_from_this(), boost::asio::placeholders::error ) ) ); } else { boost::asio::async_write( socket_, reply_->to_buffers(), strand_.wrap( boost::bind( &connection::handle_write, shared_from_this(), boost::asio::placeholders::error ) ) ); } }
void swd::connection::handle_read(const boost::system::error_code& e, std::size_t bytes_transferred) { /** * If an error occurs then no new asynchronous operations are started. This * means that all shared_ptr references to the connection object will disappear * and the object will be destroyed automatically after this handler returns. * The connection class's destructor closes the socket. */ if (e) { return; } /** * Since there was no error we can start parsing the input now. The parser * fills the object request_ with data. */ boost::tribool result; boost::tie(result, boost::tuples::ignore) = request_parser_.parse( request_, buffer_.data(), buffer_.data() + bytes_transferred ); /** * If result is true the complete request is parsed. If it is false there was * an error. If it is indeterminate then the parsing is not complete yet and * the program will read more input and append it to the old request_ object. */ if (indeterminate(result)) { /* Not finished yet with this request, start reading again. */ this->start_read(); /* And don't process the input yet. */ return; } /* The handler used to process the reply. */ swd::reply_handler reply_handler(reply_); try { if (!result) { swd::log::i()->send(swd::warning, "Bad request from " + remote_address_.to_string()); throw swd::exceptions::connection_exception(STATUS_BAD_REQUEST); } /* Try to add a profile for the request. */ try { swd::profile_ptr profile = database_->get_profile( remote_address_.to_string(), request_->get_profile_id() ); request_->set_profile(profile); } catch (swd::exceptions::database_exception& e) { swd::log::i()->send(swd::uncritical_error, e.what()); throw swd::exceptions::connection_exception(STATUS_BAD_REQUEST); } /* The handler used to process the incoming request. */ swd::request_handler request_handler(request_, cache_, storage_); /* Only continue processing the reply if it is signed correctly. */ if (!request_handler.valid_signature()) { swd::log::i()->send(swd::warning, "Bad signature from " + remote_address_.to_string()); throw swd::exceptions::connection_exception(STATUS_BAD_SIGNATURE); } /** * Before the request can be processed the input has to be transfered * from the encoded json string to a swd::parameters list. */ if (!request_handler.decode()) { swd::log::i()->send(swd::warning, "Bad json from " + remote_address_.to_string()); throw swd::exceptions::connection_exception(STATUS_BAD_JSON); } /* Check profile for outdated cache. */ swd::profile_ptr profile = request_->get_profile(); if (profile->is_cache_outdated()) { cache_->reset(profile->get_id()); } /* Process the request. */ std::vector<std::string> threats; try { swd::parameters parameters = request_->get_parameters(); /** * Check security limitations first. */ int max_params = swd::config::i()->get<int>("max-parameters"); if ((max_params > -1) && (parameters.size() > max_params)) { swd::log::i()->send(swd::notice, "Too many parameters"); throw swd::exceptions::connection_exception(STATUS_BAD_REQUEST); } int max_length_path = swd::config::i()->get<int>("max-length-path"); int max_length_value = swd::config::i()->get<int>("max-length-value"); if ((max_length_path > -1) || (max_length_value > -1)) { for (swd::parameters::iterator it_parameter = parameters.begin(); it_parameter != parameters.end(); it_parameter++) { swd::parameter_ptr parameter(*it_parameter); if ((max_length_path > -1) && (parameter->get_path().length() > max_length_path)) { swd::log::i()->send(swd::notice, "Too long parameter path"); throw swd::exceptions::connection_exception(STATUS_BAD_REQUEST); } if ((max_length_value > -1) && (parameter->get_value().length() > max_length_value)) { swd::log::i()->send(swd::notice, "Too long parameter value"); throw swd::exceptions::connection_exception(STATUS_BAD_REQUEST); } } } if (profile->is_flooding_enabled()) { if (database_->is_flooding(request_->get_client_ip(), profile->get_id())) { swd::log::i()->send(swd::notice, "Too many requests"); throw swd::exceptions::connection_exception(STATUS_BAD_REQUEST); } } /* Time to analyze the request. */ request_handler.process(); } catch (swd::exceptions::database_exception& e) { swd::log::i()->send(swd::uncritical_error, e.what()); /** * Problems with the database result in a bad request. If protection * is enabled access to the site will not be granted. */ throw swd::exceptions::connection_exception(STATUS_BAD_REQUEST); } if (profile->get_mode() == MODE_ACTIVE) { if (request_->is_threat()) { reply_->set_status(STATUS_CRITICAL_ATTACK); } else if (request_->has_threats()) { reply_->set_threats(request_handler.get_threats()); reply_->set_status(STATUS_ATTACK); } else { reply_->set_status(STATUS_OK); } } else { reply_->set_status(STATUS_OK); } } catch(swd::exceptions::connection_exception& e) { if (!request_->get_profile()) { reply_->set_status(STATUS_BAD_REQUEST); } else if (request_->get_profile()->get_mode() == MODE_ACTIVE) { reply_->set_status(e.code()); } else { reply_->set_status(STATUS_OK); } } /* Encode the reply. */ reply_handler.encode(); /* Send the answer to the client. */ if (ssl_) { boost::asio::async_write( ssl_socket_, reply_->to_buffers(), strand_.wrap( boost::bind( &connection::handle_write, shared_from_this(), boost::asio::placeholders::error ) ) ); } else { boost::asio::async_write( socket_, reply_->to_buffers(), strand_.wrap( boost::bind( &connection::handle_write, shared_from_this(), boost::asio::placeholders::error ) ) ); } }