Redirect specific destination addresses thru DNS (or some other way…)



  • Greetings from a devoted pfSense user and FOSS lover –

    I am running pfsense 2.01 on an old thin client (CF install) for my network.  So far everything has been great -- guest access through the captive portal, bandwidth limiting, etc.

    I was wondering if there was a way to perform transparent DNS redirects somehow.  My purpose for this would be to prevent user from using Google's SSL search to circumvent any filtering I put in place (Currenty OpenDNS; maybe squidguard or dansguardian later)

    In short, I would like google.com, https://www.google.com, and https://encrypted.google.com to transparently redirect to nosslsearch.google.com.  (I  am using openDNS and dnsmasq with a combination of firewall rules to restrict all port 53 (DNS) traffic to my DNS servers.)

    Is this possible?  I am currently not a pfsense expert, but willing to experiment and to learn.

    TIA



  • @techmed:

    In short, I would like google.com, https://www.google.com, and https://encrypted.google.com to transparently redirect to nosslsearch.google.com.

    In Services -> DNS Forwarder add Host Overrides for google.com, www.google.com and encrypted.google.com to the IP address of nosslsearch.google.com.

    Unfortunately (for you) there is no general way to tell a DNS to return IP address a.b.c.d if the current DNS lookup will be used for protocol https and return IP address w.x.y.z if the current DNS lookup will be used for some other protocol. (Your question seemed to suggest you were looking for that sort of granularity.)

    I don't have experience with Squid, but I believe it (and other web proxies) have the capability of rewriting URLs. There is a pfSense package for squid. There are probably wikipedia articles for web proxy and squid.



  • Thanks a lot.

    I've been looking at wildcards as well.

    I don't need granularity per se, I just want to have those rules in place to ensure that google isn't over ssl.

    I'll look into URL rewriting with squid



  • @techmed:

    Thanks a lot.

    I've been looking at wildcards as well.

    I don't need granularity per se, I just want to have those rules in place to ensure that google isn't over ssl.

    I'll look into URL rewriting with squid

    The dnsmasq override solution works fine with the caveat that your overrides will quit working if the address of nosslsearch.google.com ever changes. With that in mind, I wrote a little hack to keep it up to date. The attached php code will udpate the ip address in the override to the nslookup ip address of a domain specified in the overrides description field. For the override rules for www.google.com, google.com, etc, you can set the description field to "ip=nosslsearch.google.com" and every time this script is executed it will lookup the ip address of 'nosslsearch.com" and update it in the override (if it has changed). I'm planning to just run the script from cron every half hour or so…

    Apologize up front if this isn't the most elegant php code. I don't claim to know php - I just hacked this together looking at the gui code for services_dnsmasq.php.

    
    /*
            update_hosts.php
    
    Process the config settings of the dnsmasq service and set the host override
    IP addresses to values that we lookup using nslookup.
    
    If the description in the host override contains the string
    ip=domain (such as ip=nosslsearch.google.com) then lookup
    the domain value and put it into the ip address field
    */
    
    require("config.inc");
    require_once("functions.inc");
    require_once("filter.inc");
    require_once("shaper.inc");
    
    if (!is_array($config['dnsmasq']['hosts']))
            $config['dnsmasq']['hosts'] = array();
    
    if (!is_array($config['dnsmasq']['domainoverrides']))
            $config['dnsmasq']['domainoverrides'] = array();
    
    $a_hosts = &$config['dnsmasq']['hosts'];
    $a_domainOverrides = &$config['dnsmasq']['domainoverrides'];
    
    $write_it = 0;
    $i = 0;
    foreach ($a_hosts as $hostent) {
    
            /* If the description starts with "ip=", then we want to lookup the
               domain specified
            */
            $descr=ltrim(strtolower($hostent['descr']));
            $str_part=explode("=",$descr);
            if ( $str_part[0] == "ip" ) {
    
                    /* Pull the domain out (second part of 'ip=domain')
                    */
                    $ret_val=0;
                    $out_array=array();
                    $check_domain=$str_part[1];
    
                    echo "Checking override address for {$hostent['domain']}\n";
                    echo "should be set to resolution of {$check_domain}\n";
    
                    /* Try to lookup the domain and get an address back for it
                    */
                    $tmp=exec("nslookup -timeout=2 " . $check_domain, $out_array, $ret_val);
                    $str_part=explode(" ", $out_array[4]);
                    if ($str_part[0] == "Address:") {
                            $lookup_addr=$str_part[1];
                            echo "nslookup of {$check_domain} returned {$lookup_addr}\n";
    
                            /* If the address is different than the IP alread stored for this
                               override record, then update it
                            */
                            if ($lookup_addr != $hostent['ip']) {
                                    echo "{$hostent[ip]} != {$lookup_addr}\n";
                                    echo "updating address {$hostent['ip']} ---> {$lookup_addr}\n\n";
    
                                    $hostent['ip']=$lookup_addr;
                                    $a_hosts[$i]=$hostent;
                                    $write_it=1;
                            }
                            else {
                                    echo "{$hostent[ip]} == {$lookup_addr}\n";
                                    echo "skipping address update...\n\n";
                            }
                    }
                    else {
                            echo "unable to resolve {$check_domain}\n";
                            echo "skipping address update...\n\n";
                    }
            }
            $i++;
    }
    
    /* Only rewrite things if something actually changed
    */
    if ($write_it > 0) {
            echo "writing config\n";
            write_config();
            $retval = services_dnsmasq_configure();
    
            /* Relaod filter (we might need to sync to CARP hosts)
               don't know if this is really necessary or not
            */
            filter_configure();
    }
    
    

Locked