DNS Blackhole
Problem this snippet solves:
The blackhole requirement is to intercept DNS requests for prohibited FQDNs, not sent those to BIND for recursive look-up, return a DNS response with an A record to an LTM virtual server, and have a LTM virtual server with a second iRule that will log the request and serve a static page. The solution uses an iRule to the listener virtual server. This virtual server processes all GTM/BIND traffic. Incoming requests are matched against an external data group that contains a list of prohibited FQDNs. This data group file can be edited directly in the GUI at System - File Management - Data Group File List (line terminator should be LF only, not CR-LF). Alternately, the file can be edited manually and re-loaded by doing a "tmsh load sys config verify" then "tmsh load sys config". The blackhole iRule will log all requests for prohibited FQDNs and return a DNS response that matches an LTM virtual server. The blackhole iRule only provides valid responses for A records, however all blackhole DNS requests are logged.
How to use this snippet:
-
Create the list of FQDNs for the BIG-IP external data group. Example format is below. File can be stored in /config/Blackhole_Class, although v11.1 provides a method to upload via GUI which is recommended. The second field is the reason why the site was added to the Blackhole class.
-
".3322.org" := "virus", ".3322.com" := "malware", ".3322.net" := "phishing",
-
-
Make the external file accessible
- On Internal-GTM's GUI, go to System - File Management - Data Group File List - Import.
- File Name: upload Blackhole_Class file
- Name: Blackhole_Class
- File Contents: String
- Key / Value Pair Separator: :=
-
Create data group as external file:
- On Internal-GTM's GUI, go to Local Traffic - iRules - Data Group List - Create
- Name: Blackhole_Class
- Type: (External File)
- Path/Filename: Blackhole_Class
- File Contents: string
- Access Mode: Read Only
-
Create the Blackhole iRule
- On Internal-GTM's GUI, go to Local Traffic - iRules - Create.
- Name: DNS_blackhole (can be renamed)
- iRule Source is attached below.
-
Apply the Blackhole iRule to the GTM listener virtual server.
- Go to Local Traffic - Virtual Servers.
- Click on the Virtual Server created automatically for the GTM listener. Name will be of form: vs_10_1_1_152_53_gtm, where the first 4 numbers are the IP address of the Listener.
- Go to the resources tab and assign the DNS_Blackhole iRule created above.
-
Create iFile for the Organization's Logo that will be used with the block page.
- Download a copy of the image to be used
- Rename file to corp-logo.gif (optional)
- Go to System - File Management - iFile List - Import
- Name: corp-logo.gif
- Go to Local Traffic - iRules - iFile List - Create
- Name: corp-logo.gif
- File name:
-
Create iRule to log client requests and send an HTML page to notify customers they have violated the Blackhole. This iRule should be copied from the attached file.
- Go to Local Traffic - iRules - Create
- Name: DNS_blackhole_block_page
- iRule Source attached below.
-
Create virtual server for client requests. The IP address should match the DNS response defined in ::blackhole_reply in the DNS_Blackhole iRule.
- Go to Local Traffic - Virtual Servers - Create
- Name: DNS_blackhole_block_page
- Destination: 10.1.1.80 (update per local requirements)
- Port: 80
- HTTP profile: http
- iRules: DNS_blackhole_block_page
Code :
# DNS Blackhole # This iRule interrogates all queries that arrive on the GTM listener. If the query matches # a list of prohibited FQDNs, a standardized response is given and the request is logged. # This response IP address could be a honeypot server or an LTM virtual server. # Blackhole functionality can be used to prevent malware, virus C2 servers, adware, or other sites. # # Author: Hugh O'Donnell, F5 Consulting # # Usage: # 1) apply to GTM listener virtual server that is defined at Local Traffic - Virtual Servers # 2) create a string data group called "Blackhole_Class". The FQDNs must start with a period. # 3) update the answer static variable with the IP address to return # # Known Issues: # 1) Only A and AAAA records are returned for blackhole requests. The response for other request # types will be logged and returned with no answer. # # Revision history: # 12-11-2011: Initial Revision when RULE_INIT { # Set IPV4 address that is returned for Blackhole matches for A records set static::blackhole_reply_IPV4 "10.1.1.26" # Set IPV6 address that is returned for Blackhole matches for AAAA records set static::blackhole_reply_IPV6 "2001:19b8:101:2::f5f5:1d" # Set TTL used for all Blackhole replies set static::blackhole_ttl "300" } when DNS_REQUEST { # debugging statement see all questions and request details # log -noname local0. "Client: [IP::client_addr] Question:[DNS::question name] Type:[DNS::question type] Class:[DNS::question class] Origin:[DNS::origin]" # Blackhole_Match is used to track when a Query matches the blackhole list # Ensure it is always set to 0 or false at beginning of the DNS request set Blackhole_Match 0 # Blackhole_Type is used to track why this FQDN was added to the Blackhole_Class set Blackhole_Type "" # When the FQDN from the DNS Query is checked against the Blackhole class, the FQDN must start with a # period. This ensures we match a FQDN and all names to the left of it. This prevents against # malware that dynamically prepends characters to the domain name in order to bypass exact matches if {!([DNS::question name] == ".")} { set fqdn_name .[DNS::question name] } if { [class match $fqdn_name ends_with Blackhole_Class] } { # Client made a DNS request for a Blackhole site. set Blackhole_Match 1 set Blackhole_Type [class match -value $fqdn_name ends_with Blackhole_Class ] # Prevent processing by GTM, DNS Express, BIND and GTM Listener's pool. # Want to ensure we don't request a prohibited site and allow their server to identify or track the GTM source IP. DNS::return } } when DNS_RESPONSE { # debugging statement to see all questions and request details # log -noname local0. "Request: $fqdn_name Answer: [DNS::answer] Origin:[DNS::origin] Status: [DNS::header rcode] Flags: RD [DNS::header rd] RA [DNS::header ra]" if { $Blackhole_Match } { # This DNS request was for a Blackhole FQDN. Take different actions based on the request type. switch [DNS::question type] { "A" { # Clear out any DNS responses and insert the custom response. RA header = recursive answer DNS::answer clear DNS::answer insert "[DNS::question name]. $static::blackhole_ttl [DNS::question class] [DNS::question type] $static::blackhole_reply_IPV4" DNS::header ra "1" # log example: Apr 3 14:54:23 local/tmm info tmm[4694]: # Blackhole: 10.1.1.148#4902 requested foo.com query type: A class IN A-response: 10.1.1.60 log -noname local0. "Blackhole: [IP::client_addr]#[UDP::client_port] requested [DNS::question name] query type: [DNS::question type] class [DNS::question class] A-response: $static::blackhole_reply_IPV4 BH type: $Blackhole_Type" } "AAAA" { # Clear out any DNS responses and insert the custom response. RA header = recursive answer DNS::answer clear DNS::answer insert "[DNS::question name]. $static::blackhole_ttl [DNS::question class] [DNS::question type] $static::blackhole_reply_IPV6" DNS::header ra "1" # log example: Apr 3 14:54:23 local/tmm info tmm[4694]: # Blackhole: 10.1.1.148#4902 requested foo.com query type: A class IN AAAA-response: 2001:19b8:101:2::f5f5:1d log -noname local0. "Blackhole: [IP::client_addr]#[UDP::client_port] requested [DNS::question name] query type: [DNS::question type] class [DNS::question class] AAAA-response: $static::blackhole_reply_IPV6 BH type: $Blackhole_Type" } default { # For other record types, e.g. MX, NS, TXT, etc, provide a blank NOERROR response DNS::last_act reject # log example: Apr 3 14:54:23 local/tmm info tmm[4694]: # Blackhole: 10.1.1.148#4902 requested foo.com query type: A class IN unable to respond log -noname local0. "Blackhole: [IP::client_addr]#[UDP::client_port] requested [DNS::question name] query type: [DNS::question type] class [DNS::question class] unable to respond BH type: $Blackhole_Type" } } } } # DNS Blackhole Block Page # # This iRule presents an HTML page to the user and logs details of the HTML request. # It is used in conjuction with the DNS Blackhole iRule to ensure users are aware that # their request was blocked by the Blackhole and actions to take if this block was in error. # # Author: Hugh O'Donnell, F5 Consulting # # Usage: # 1) Add the corporate logo that will be displayed to System - File Management - iFile List # 2) Make the iFile accessible to be used in this iRule by giving associating the iFile name corp_logo_gif # with the iFile at: Local Traffic - iRules - iFile List. # 3) Ensure list of FQDNs in the DNS Blackhole is in a data group called "Blackhole_Class". This can be # verified at Local Traffic - iRules - Data Group List. # 4) Apply this iRule to the port 80 virtual server that the Blackhole iRule sends out, which is specified in variables # static::blackhole_reply_IPV4 and static::blackhole_reply_IPV6 in v11.1+ version of Blackhole iRule when HTTP_REQUEST { # the static HTML pages include the logo that is referenced in HTML as corp-logo.gif # intercept requests for this and reply with the image that is stored in an iFile defined in RULE_INIT below if {[HTTP::uri] ends_with "/_maintenance-page/corp-logo.gif" } { # Present HTTP::respond 200 content $static::corp_logo_gif } else { # Request for Blackhole webpage. Identify what type of block was in place switch -glob [class match -value ".[HTTP::host]" ends_with Blackhole_Class ] { "virus" { set block_reason "Virus site" } "phishing" { set block_reason "Phishing site" } "generic" { set block_reason "Unacceptable Usage" } default { set block_reason "Denied Per Policy - Other Sites" } } # Log details about the blackhole request to the remote syslog server log -noname local0. "Blackhole: From [IP::client_addr]:[TCP::client_port] \ to [IP::local_addr]:[TCP::local_port], [HTTP::request_num], \ [HTTP::method],[HTTP::uri],[HTTP::version], [HTTP::host], [HTTP::header value Referer], \ [HTTP::header User-Agent], [HTTP::header names],[HTTP::cookie names], BH category: $block_reason," # Send an HTML page to the user. The page is defined in the RULE_INIT event below HTTP::respond 200 content "$static::block_page [HTTP::host][HTTP::uri] $static::after_url $block_reason $static::after_block_reason " } } when RULE_INIT { # load the logo that was stored as an iFile set static::corp_logo_gif [ifile get "/Common/corp-logo.gif"] # Beginning of the block page set static::block_page "Web Access Denied - Enterprise Network Operations Center " }
Access has been denied.
URL: " set static::after_url "
Your request was denied because it is blacklisted in DNS.
Blacklist category: " set static::after_block_reason "
The Internet Gateways are for official use only. Misuse violates policy. If you believe that this site is categorized incorrectly, and that you have a valid business reason for access to this site please contact your manager for approval and the Enterprise Network Operations Center via
E-mail: enoc@example.com
Please use the Web Access Request Form and include a business justification. Only e-mail that originates from valid internal e-mail addresses will be processed. If you do not have a valid e-mail address, your manager will need to submit a request on your behalf.Generated by bigip1.f5.com.
- 1305063818Nimbostratus
thanks! your shared!