For more information regarding the security incident at F5, the actions we are taking to address it, and our ongoing efforts to protect our customers, click here.

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
 

        
        



\"Enterprise

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.

" }
Published Mar 17, 2015
Version 1.0