jetty的org.eclipse.jetty.servlets.DoSFilter类是用来实现Dos攻击预防的filter,里面涉及到一些变量,先了解下变量的含义:



protected long _delayMs;超过最大处理请求数当前请求的等待时间,-1立即拒绝,0,无限等待,正数表达等待的毫秒数

protected long _throttleMs;异步等待获取信号量的时间

protected long _maxWaitMs;阻塞等待获取信号量的时间

protected long _maxRequestMs;请求处理最大时间限制

protected long _maxIdleTrackerMs;跟踪连接是否断开的最大等待时间

protected int _throttledRequests;允许在等待队列中等待获取信号量的请求数

protected int _maxRequestsPerSec; 每秒允许处理最多的请求数,超过将延迟,异步等待。



protected boolean _insertHeaders; 是否往response写入dosfilter信息,默认true

protected boolean _trackSessions;是否根据session来检测dos攻击,默认true

protected boolean _remotePort;是否根据ip+port来检测dos攻击,默认false

protected String _whitelistStr; 白名单 ip白名单列表,这些通过都通过配置servlet的init-p


aram可以来重新设置。


首先看看init方法的初始化设置:



public void init(FilterConfig filterConfig)     {         _context = filterConfig.getServletContext();          _queue = new Queue[getMaxPriority() + 1];         _listener = new ContinuationListener[getMaxPriority() + 1];         for (int p = 0; p < _queue.length; p++)         {             _queue[p] = new ConcurrentLinkedQueue<Continuation>();              final int priority=p;             _listener[p] = new ContinuationListener()             {                 public void onComplete(Continuation continuation)                 {                 }                  public void onTimeout(Continuation continuation)                 {                     _queue[priority].remove(continuation);                 }             };         }          _rateTrackers.clear();          int baseRateLimit = __DEFAULT_MAX_REQUESTS_PER_SEC;         if (filterConfig.getInitParameter(MAX_REQUESTS_PER_S_INIT_PARAM) != null)             baseRateLimit = Integer.parseInt(filterConfig.getInitParameter(MAX_REQUESTS_PER_S_INIT_PARAM));         _maxRequestsPerSec = baseRateLimit;          long delay = __DEFAULT_DELAY_MS;         if (filterConfig.getInitParameter(DELAY_MS_INIT_PARAM) != null)             delay = Integer.parseInt(filterConfig.getInitParameter(DELAY_MS_INIT_PARAM));         _delayMs = delay;          int throttledRequests = __DEFAULT_THROTTLE;         if (filterConfig.getInitParameter(THROTTLED_REQUESTS_INIT_PARAM) != null)             throttledRequests = Integer.parseInt(filterConfig.getInitParameter(THROTTLED_REQUESTS_INIT_PARAM));         _passes = new Semaphore(throttledRequests,true);         _throttledRequests = throttledRequests;          long wait = __DEFAULT_WAIT_MS;         if (filterConfig.getInitParameter(MAX_WAIT_INIT_PARAM) != null)             wait = Integer.parseInt(filterConfig.getInitParameter(MAX_WAIT_INIT_PARAM));         _maxWaitMs = wait;          long suspend = __DEFAULT_THROTTLE_MS;         if (filterConfig.getInitParameter(THROTTLE_MS_INIT_PARAM) != null)             suspend = Integer.parseInt(filterConfig.getInitParameter(THROTTLE_MS_INIT_PARAM));         _throttleMs = suspend;          long maxRequestMs = __DEFAULT_MAX_REQUEST_MS_INIT_PARAM;         if (filterConfig.getInitParameter(MAX_REQUEST_MS_INIT_PARAM) != null )             maxRequestMs = Long.parseLong(filterConfig.getInitParameter(MAX_REQUEST_MS_INIT_PARAM));         _maxRequestMs = maxRequestMs;          long maxIdleTrackerMs = __DEFAULT_MAX_IDLE_TRACKER_MS_INIT_PARAM;         if (filterConfig.getInitParameter(MAX_IDLE_TRACKER_MS_INIT_PARAM) != null )             maxIdleTrackerMs = Long.parseLong(filterConfig.getInitParameter(MAX_IDLE_TRACKER_MS_INIT_PARAM));         _maxIdleTrackerMs = maxIdleTrackerMs;          _whitelistStr = "";         if (filterConfig.getInitParameter(IP_WHITELIST_INIT_PARAM) !=null )             _whitelistStr = filterConfig.getInitParameter(IP_WHITELIST_INIT_PARAM);         initWhitelist();          String tmp = filterConfig.getInitParameter(INSERT_HEADERS_INIT_PARAM);         _insertHeaders = tmp==null || Boolean.parseBoolean(tmp);          tmp = filterConfig.getInitParameter(TRACK_SESSIONS_INIT_PARAM);         _trackSessions = tmp==null || Boolean.parseBoolean(tmp);          tmp = filterConfig.getInitParameter(REMOTE_PORT_INIT_PARAM);         _remotePort = tmp!=null&& Boolean.parseBoolean(tmp);          _requestTimeoutQ.setNow();         _requestTimeoutQ.setDuration(_maxRequestMs);          _trackerTimeoutQ.setNow();         _trackerTimeoutQ.setDuration(_maxIdleTrackerMs);          _running=true;         _timerThread = (new Thread()         {             public void run()             {                 try                 {                     while (_running)                     {                         long now;                         synchronized (_requestTimeoutQ)                         {                             now = _requestTimeoutQ.setNow();                             _requestTimeoutQ.tick();                         }                         synchronized (_trackerTimeoutQ)                         {                             _trackerTimeoutQ.setNow(now);                             _trackerTimeoutQ.tick();                         }                         try                         {                             Thread.sleep(100);                         }                         catch (InterruptedException e)                         {                             Log.ignore(e);                         }                     }                 }                 finally                 {                     Log.info("DoSFilter timer exited");                 }             }         });         _timerThread.start();          if (_context!=null && Boolean.parseBoolean(filterConfig.getInitParameter(MANAGED_ATTR_INIT_PARAM)))             _context.setAttribute(filterConfig.getFilterName(),this);     }


_queue是用来保存当前当前通过header,session,ip等检测类型的请求队列,然后就是一堆参数的初始化设置,最后

又有两个queue _requestTimeoutQ是来保存每个请求的处理时间超时检测的队列;_trackerTimeoutQ是来检测请求对应连接是否已经关闭超时的检测队列;最后启动一个_timerThread线程来进行这两个队列的超时检测。


然后再看下dofilter的处理



public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterchain) throws IOException, ServletException     {         final HttpServletRequest srequest = (HttpServletRequest)request;         final HttpServletResponse sresponse = (HttpServletResponse)response;          final long now=_requestTimeoutQ.getNow();          // Look for the rate tracker for this request         RateTracker tracker = (RateTracker)request.getAttribute(__TRACKER);           if (tracker==null) //如果request没有进行过dosfilter的处理         {             // This is the first time we have seen this request.              // get a rate tracker associated with this request, and record one hit             tracker = getRateTracker(request); //根据request生成dos跟踪的对象,看下面方法              // Calculate the rate and check it is over the allowed limit             final boolean overRateLimit = tracker.isRateExceeded(now);//判断是否已经超过每秒最大处理请求数              // pass it through if  we are not currently over the rate limit             if (!overRateLimit)//如果没有超过,则正常处理             {                 doFilterChain(filterchain,srequest,sresponse);                 return;             }              // We are over the limit.             Log.warn("DOS ALERT: ip="+srequest.getRemoteAddr()+",session="+srequest.getRequestedSessionId()+",user="+srequest.getUserPrincipal());              // So either reject it, delay it or throttle it             switch((int)_delayMs) //根据当前配置的延时时间             {                 case -1: //如果为-1,则直接拒绝                 {                     // Reject this request                     if (_insertHeaders) //是否把dosfilter处理插入response的header                         ((HttpServletResponse)response).addHeader("DoSFilter","unavailable");                     ((HttpServletResponse)response).sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);                     return;                 }                 case 0: //如果为0,则当前线程继续等待处理,                 {                     // fall through to throttle code                     request.setAttribute(__TRACKER,tracker);                     break;                 }                 default://其他字段,则设置request的timeout时间为_delayMs,并且挂起当前线程,返回                 {                     // insert a delay before throttling the request                     if (_insertHeaders)                         ((HttpServletResponse)response).addHeader("DoSFilter","delayed");                     Continuation continuation = ContinuationSupport.getContinuation(request);                     request.setAttribute(__TRACKER,tracker);                     if (_delayMs > 0)                         continuation.setTimeout(_delayMs);                     continuation.suspend();                     return;                 }             }         }  //_delayMs为0是,当前请求继续等待         // Throttle the request         boolean accepted = false;         try         {             // check if we can afford to accept another request at this time             accepted = _passes.tryAcquire(_maxWaitMs,TimeUnit.MILLISECONDS);//判断当前处理请求队列是否已经有处理完的请求,处理完的会释放信号量,则当前请求线程可以获取信号量              if (!accepted) //如果不能获取,则把当前请求设置为异步等待,异步等待的时间为_throttleMs,             {                 // we were not accepted, so either we suspend to wait,or if we were woken up we insist or we fail                 final Continuation continuation = ContinuationSupport.getContinuation(request);                  Boolean throttled = (Boolean)request.getAttribute(__THROTTLED);                 if (throttled!=Boolean.TRUE && _throttleMs>0)                 {                     int priority = getPriority(request,tracker);                     request.setAttribute(__THROTTLED,Boolean.TRUE);                     if (_insertHeaders)                         ((HttpServletResponse)response).addHeader("DoSFilter","throttled");                     if (_throttleMs > 0)                         continuation.setTimeout(_throttleMs);                     continuation.suspend();                      continuation.addContinuationListener(_listener[priority]);                     _queue[priority].add(continuation);                     return;                 }                 // else were we resumed?                 else if  (request.getAttribute("javax.servlet.resumed")==Boolean.TRUE)                  {//如果线程中心被唤醒,则可以获取到信号量,                     // we were resumed and somebody stole our pass, so we wait for the next one.                     _passes.acquire();                     accepted = true;                 }             }              // if we were accepted (either immediately or after throttle)             if (accepted) //获取到了,继续执行,                 // call the chain                 doFilterChain(filterchain,srequest,sresponse);             else             {                 // fail the request                 if (_insertHeaders)                     ((HttpServletResponse)response).addHeader("DoSFilter","unavailable");                 ((HttpServletResponse)response).sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);             }         }         catch (InterruptedException e)         {             _context.log("DoS",e);             ((HttpServletResponse)response).sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);         }         finally         {             if (accepted) //执行完了之后释放当前的信号量,唤醒等待队列中的第一个请求进行处理             {                 // wake up the next highest priority request.                 for (int p = _queue.length; p-- > 0;)                 {                     Continuation continuation = _queue[p].poll();                     if (continuation != null && continuation.isSuspended())                     {                         continuation.resume();                         break;                     }                 }                 _passes.release();             }         }     }    public RateTracker getRateTracker(ServletRequest request)     {         HttpServletRequest srequest = (HttpServletRequest)request;         HttpSession session=srequest.getSession(false);          String loadId = extractUserId(request);         final int type;         if (loadId != null)         {             type = USER_AUTH;         }         else         {             if (_trackSessions && session!=null && !session.isNew())             {                 loadId=session.getId();                 type = USER_SESSION;             }             else             {                 loadId = _remotePort?(request.getRemoteAddr()+request.getRemotePort()):request.getRemoteAddr();                 type = USER_IP;             }         }          RateTracker tracker=_rateTrackers.get(loadId);          if (tracker==null)         {             RateTracker t;             if (_whitelist.contains(request.getRemoteAddr())) //如果在白名单中,则isRateExceeded一直返回false             {                 t = new FixedRateTracker(loadId,type,_maxRequestsPerSec);             }             else             {                 t = new RateTracker(loadId,type,_maxRequestsPerSec);             }              tracker=_rateTrackers.putIfAbsent(loadId,t);             if (tracker==null)                 tracker=t;              if (type == USER_IP)             {                 // USER_IP expiration from _rateTrackers is handled by the _trackerTimeoutQ                 synchronized (_trackerTimeoutQ)                 {                     _trackerTimeoutQ.schedule(tracker);                 }             }             else if (session!=null)                 // USER_SESSION expiration from _rateTrackers are handled by the HttpSessionBindingListener                 session.setAttribute(__TRACKER,tracker);         }          return tracker;     }