From owner-freebsd-pf@FreeBSD.ORG Mon Aug 20 18:16:17 2012 Return-Path: Delivered-To: freebsd-pf@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id A9087106566B for ; Mon, 20 Aug 2012 18:16:17 +0000 (UTC) (envelope-from jdavidlists@gmail.com) Received: from mail-vc0-f182.google.com (mail-vc0-f182.google.com [209.85.220.182]) by mx1.freebsd.org (Postfix) with ESMTP id 32AB88FC0C for ; Mon, 20 Aug 2012 18:16:16 +0000 (UTC) Received: by vcbgb22 with SMTP id gb22so6804402vcb.13 for ; Mon, 20 Aug 2012 11:16:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:sender:in-reply-to:references:date :x-google-sender-auth:message-id:subject:from:to:content-type; bh=bbp+BdTG/mxtRGNMcW3+vMBAOORlVNtH+CTtPiDTnDQ=; b=PRVd3PDhJ68BipdYXqXDKUgtfaCXZBKAlzqNSZI9w6w4frEaUvZelS8c7eSnMyKq2z Zdnj/+Wd6goUujtRJQU31HJ5ctitrh7SGaeZiTaheK27iofGggGzsyyheXYrwQ42c9L8 HVJikO4V8WFhDyQYBrSMBziHuHcHbK9vzEzAUZIR2OHnCiJqoYtdNRrmP886OSYsa1QW Zvc5iUYqzTOcwZIi36Vf/tc45XdKxZ+WaiOnIoX4PPJPAAfOsiKA0rQMQ+lCnQIuPGKz ocqYO4Y0lXSZBWnHybSu7SlfVMukCoNTQ3h3Kfujpmt9qn6NWufEQPE3W7XhG31eUF2n 2QfQ== MIME-Version: 1.0 Received: by 10.58.102.48 with SMTP id fl16mr12056078veb.41.1345486576133; Mon, 20 Aug 2012 11:16:16 -0700 (PDT) Sender: jdavidlists@gmail.com Received: by 10.59.7.163 with HTTP; Mon, 20 Aug 2012 11:16:16 -0700 (PDT) In-Reply-To: <20120820162752.GA28945@DataIX.net> References: <20120820162752.GA28945@DataIX.net> Date: Mon, 20 Aug 2012 14:16:16 -0400 X-Google-Sender-Auth: -Fae9NQ5QA_qeEGfEL4tGe-wmXA Message-ID: From: J David To: freebsd-pf@freebsd.org Content-Type: text/plain; charset=ISO-8859-1 Subject: Re: Fighting DDOS attacks with pf X-BeenThere: freebsd-pf@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "Technical discussion and general questions about packet filter \(pf\)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 20 Aug 2012 18:16:17 -0000 Unfortunately, I think my reference to DDOS attacks has distracted from the underlying issue. PF allows a rule like this: pass in proto tcp from any to any port www keep state (max 100, source-track rule, max-src-states 3) (adapted from the man page) We want this rule: pass in proto tcp from any to any port www keep state (max 100, dest-track rule, max-dst-states 3) Obviously there is no such rule. I'm simply curious whether anyone has found a way to bend the PF syntax to create the same behavior. Perhaps I can offer a couple of examples that will clarify. If I do this: table { 10.0.0.0/30 } block drop pass in proto tcp from any to port 80 keep state ( max 4000 ) This will not work for us. If traffic to 10.0.0.2 creates all 4000 allowed states, packets to *all* of the protected IPs will stop matching the pass rule and all of the protected IPs are effectively knocked offline. If, however, I do this: ProtectedIPs = "{ 10.0.0.0, 10.0.0.1, 10.0.0.2, 10.0.0.3 }" block drop pass in proto tcp from any to $ProtectedIPs port 80 keep state ( max 1000 ) Then PF will create one rule for each destination IP, and will therefore limit the number of states on a per-destination-IP basis. Thus, when traffic to 10.0.0.2 creates 1000 states on its pass rule, further packets match "block drop" instead, but only for that IP; traffic for the other three IPs is unaffected. That is the effect we want to create. This works. The problem we have is that the scale is much larger. Listing four example IP's in the PF config is not difficult, hardcoding thousands of destination IPs into the config file individually would be unwieldy and difficult to maintain, as well as possibly creating performance problems within pf, as rule processing goes from O(1) to O(n). Since that doesn't seem practical, we use the script I mentioned earlier that scans the state table and adds targeted IPs to a pf table to be blocked. This is fine, except it introduces a period of up to a minute where spillover damage may occur. What I am hoping to find is a way of doing this entirely within pf, in order to cut the response time and to gracefully flow from overflow to non-overflow conditions. There are a couple of ways of doing this. One would be to find a couple of really clever rules that would create the effect we are looking for. This is what I was hoping to find by asking here. The other would be to find some manageable way to generate the individual rules for each IP -- shouldn't be tough to script if the pf.conf syntax isn't up to it -- if adding a few thousand "pass" rules won't crush performance. If anyone has worked with ridiculously large rulesets of that sort, I would love to hear about their experiences.. Thanks!