From owner-freebsd-questions@FreeBSD.ORG Sun Feb 18 19:02:41 2007 Return-Path: X-Original-To: freebsd-questions@freebsd.org Delivered-To: freebsd-questions@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 4773716A408 for ; Sun, 18 Feb 2007 19:02:41 +0000 (UTC) (envelope-from admin@azuni.net) Received: from mail.azuni.net (ns0.azuni.net [217.25.25.3]) by mx1.freebsd.org (Postfix) with ESMTP id 76B8F13C4BE for ; Sun, 18 Feb 2007 19:02:40 +0000 (UTC) (envelope-from admin@azuni.net) Received: (qmail 66426 invoked by uid 1004); 18 Feb 2007 19:02:38 -0000 Received: from admin@azuni.net by mail.azuni.net by uid 89 with qmail-scanner-1.20 (clamscan: 0.65. spamassassin: 2.63. Clear:RC:1(217.25.23.2):. Processed in 0.860367 secs); 18 Feb 2007 19:02:38 -0000 Received: from unknown (HELO ?217.25.23.2?) (217.25.23.2) by ns0.azuni.net with AES256-SHA encrypted SMTP; 18 Feb 2007 19:02:37 -0000 Message-ID: <45D8A2BD.2020903@azuni.net> Date: Sun, 18 Feb 2007 23:02:21 +0400 From: admin Organization: UniNet User-Agent: Debian Thunderbird 1.0.2 (X11/20070113) X-Accept-Language: en-us, en MIME-Version: 1.0 To: freebsd-questions@freebsd.org Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Cc: Kees Plonsz Subject: Re: ipfw limit src-addr woes X-BeenThere: freebsd-questions@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: User questions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 18 Feb 2007 19:02:41 -0000 > admin wrote in msgid: > > >> Hi, I'm trying to use ipfw's limit clause to limit the number of >> connections a single IP can have at the same time in a transparent >> web-proxy environment: >> >> 00350 skipto 401 tcp from x.x.x.x/x,y.y.y.y/y,z.z.z.z/z to any dst-port >> 80 in via if0 setup limit src-addr 10 >> 00401 fwd local.ip.ad.dr,8080 tcp from x.x.x.x/x to any dst-port 80 >> ... the rest fwd... >> >> as I understand the manpage, when the current number of connectiions is >> below 10, the action "skipto" is performed, else, the packet is dropped >> and the search terminates. But... >> >> the problem is that the src-addr limit is not enforced as some clients >> somehow open a huge number (3-5 times the prescribed value) of >> www-connections to some single address Out There, forcing you to bump up >> certain sysctl variables (such as kern.ipc.nmbclusters, >> kern.ipc.maxsockets, etc.) to mitigate the DOS effects. What might be >> going on? Is ipfw broken, or am I misusing it? >> >> OS: FreeBSD 6.2 > > > I tested ipfw with the "limit" option and it works just fine. > I can open only one http connection from "194.109.21.3" and hangs on > opening a second one with an error in the logfile. > > > rule: > # add 03000 allow log logamount 50 tcp from any to any dst-port 80 in limit dst-addr 1 > > My logfile: > Feb 18 16:16:57 jeremino kernel: ipfw: 3000 Accept TCP 194.109.21.3:3626 10.0.0.6:80 in via dc1 > Feb 18 16:16:58 jeremino kernel: drop session, too many entries You get the point. I know, indeed it works just great for many clients, including myself, but *some* clients manage to ignore the firewall rule and open many more connections in the ESTABLISHED state than allowed and eat up lots of memory with their send/recv queues... Instead of knocking my head on the wall I opted for posting here for help ;-) I've decided to prove that I'm not crazy. This little code utilizes the BSD sockets API trying to open many connections to some outside web-site but just halts after crossing the limit (assuming the connections get transparently proxied by the problem firewalled-FreeBSD-proxy box on its path). The question remains: why could some clients be immune to the limit? #include #include #include #include #include #include #include #define NUM_CONNS_TO_TRY_TO_OPEN 150 int main(void) { struct sockaddr_in sock_addr; struct in_addr in_addr; int i; if (inet_aton("66.94.234.13", &in_addr) == 0) { perror("inet_aton"); return EXIT_FAILURE; } sock_addr.sin_family = AF_INET; sock_addr.sin_addr = in_addr; sock_addr.sin_port = htons(80); for (i = 0; i < NUM_CONNS_TO_TRY_TO_OPEN; i++) { int s; if ((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { perror("socket"); return EXIT_FAILURE; } if (connect(s, (struct sockaddr *) &sock_addr, sizeof sock_addr) != -1) { fprintf(stderr, "%d ", i); } else { perror("connect"); return EXIT_FAILURE; } } getchar(); return 0; }