{"id":99,"date":"2010-12-02T11:19:45","date_gmt":"2010-12-02T11:19:45","guid":{"rendered":"https:\/\/pgregg.com\/wp2\/?p=99"},"modified":"2020-06-02T11:30:24","modified_gmt":"2020-06-02T10:30:24","slug":"stage-2-httpbl-with-apache2-mod-perl","status":"publish","type":"post","link":"https:\/\/blog.pgregg.com\/blog\/2010\/12\/stage-2-httpbl-with-apache2-mod-perl\/","title":{"rendered":"Stage 2: http:BL with Apache2 mod_perl"},"content":{"rendered":"<p>After my earlier post <a href=\"https:\/\/blog.pgregg.com\/blog\/2010\/11\/referrer-and-comment-spammers-are-a-pita\/\">Referrer and Comment spammers are a PITA<\/a> I came up with two mod_perl plugins to Apache and an &#8220;apache level&#8221; firewall.<\/p>\n<p>The reason for the apache-level firewall is two-fold.\u00a0 There is no direct way for the Apache user to manipulate an iptables chain (as it doesn&#8217;t run as root), and second; I was not happy with suid root access or other forms of message passing to a daemon which would manipulate the firewall for me.<\/p>\n<p>Architecture is thus, in httpd.conf place the following two lines:<\/p>\n<blockquote><p>PerlPreConnectionHandler PGREGG::httpBLBlock<br \/>\nPerlLogHandler PGREGG::httpBLLog<\/p><\/blockquote>\n<p>The first tells apache to run the handler in my httpBLBlock.pm module when a connection is received (before the request has been sent by the client).\u00a0 In this handler, I am simply looking for a filename matching that IP in a directory that is writable by the apache user.\u00a0 The contents of the file are a SCORE:httpBL_answer:[LIST].\u00a0 Based on this, the module checks the mtime of the filename is in the last SCORE days, then the firewall is in effect. If so, we simply tell apache to drop the connection.\u00a0 If the file has expired, we delete the file.<\/p>\n<p>The second line is more interesting, and what creates the firewall filenames. In order to not impede the general speed of request handling, processing is performed in the Logging section of the Apache process. Our module is called by apache after the response has been sent, but before the access_log entry has been written.\u00a0 In our module we perform the <a href=\"http:\/\/www.projecthoneypot.org\/httpbl_api.php\">http:BL<\/a> API call and compute the above SCORE based upon the Threat* level and Age* of the API response. (* both Threat and Age are octets in the DNS lookup).\u00a0 We merely discount the Threat down to zero based on the Age (0-255) where an entry 255 days old reduces the SCORE to zero.<br \/>\nIf the SCORE is larger than our trigger level (3) then we create the firewall filename, log the entry in our own httpbl.log and return Apache2::Const::FORBIDDEN.\u00a0 This causes Apache to not log the entry in the normal access_log.\u00a0 Otherwise, if all is ok, we return Apache2::Const::OK and Apache logs the hit as normal.<\/p>\n<p>I have a bit of code tidy up, restructure the config\/firewall directory and pull some common code out to a shared module before I can release to the world.<\/p>\n<p>An interesting side effect to publishing the last story out through <a href=\"http:\/\/www.planet-php.net\/\">Planet PHP<\/a> and other news sources <i>along with the Project Honey Pot image<\/i> is that when browsers viewed those sources, they all asked for the image off my server. In several cases, these were known spammer, Comment spammer, and other abusers. My server then created the firewall entry blocking them before they were able to follow the links back to my server.<\/p>\n<p>I have been reading up more on <a href=\"http:\/\/perl.apache.org\/docs\/2.0\/api\/Apache2\/Filter.html\">Apache Bucket Brigades<\/a> in an attempt to allow the firewall filter to be placed immediately after the request has been received and allow a custom response to the browser. This may help an otherwise unsuspecting user if their machine had been trojaned. I don&#8217;t mind admitting I&#8217;m thoroughly confused right now \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>After my earlier post Referrer and Comment spammers are a PITA I came up with two mod_perl plugins to Apache and an &#8220;apache level&#8221; firewall. The reason for the apache-level firewall is two-fold.\u00a0 There is no direct way for the Apache user to manipulate an iptables chain (as it doesn&#8217;t run as root), and second; &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/blog.pgregg.com\/blog\/2010\/12\/stage-2-httpbl-with-apache2-mod-perl\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Stage 2: http:BL with Apache2 mod_perl&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"1","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[10],"tags":[18,41,68,80,81],"class_list":["post-99","post","type-post","status-publish","format-standard","hentry","category-php","tag-apache","tag-firewall","tag-mod_perl","tag-perl-2","tag-php-2"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pbQOUu-1B","jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/posts\/99","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/comments?post=99"}],"version-history":[{"count":1,"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/posts\/99\/revisions"}],"predecessor-version":[{"id":876,"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/posts\/99\/revisions\/876"}],"wp:attachment":[{"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/media?parent=99"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/categories?post=99"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/tags?post=99"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}