Package org.jwall.rbl.dns

Source Code of org.jwall.rbl.dns.QueryHandler

/*******************************************************************************
* Copyright (C) 2010 Christian Bockermann <chris@jwall.org>
* This file is part of the jwall-rbld program. jwall-rbld is an implementation
* of a simple DNS server for running a local, customized real time block-list.
* More information and documentation for the jwall-rbld can be found at
*
*                    http://www.jwall.org/jwall-rbld
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this
* program; if not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package org.jwall.rbl.dns;

import java.net.InetAddress;

import org.jwall.rbl.RblServer;
import org.jwall.rbl.data.RBListEntry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
* <p>
*
* </p>
*
* @author chris
*
*/
public class QueryHandler {

  static Logger log = LoggerFactory.getLogger( QueryHandler.class );

  /** This pattern is used to check for actions in DNS query values */
  String pattern = ".*(block-\\d+|unblock)\\.rbl\\.localnet$";

  /** The for which this handler processes queries */
  String domain = "rbl.localnet";

  /** The rbl server to which this handler belongs */
  RblServer server;

  public QueryHandler( RblServer server ){
    this.server = server;
    domain = server.getDomain();
    pattern = ".*(block-\\d+|unblock)\\." + domain + "$";
  }


  public synchronized Response process( InetAddress source, Query q ){

    Response response = new Response( q );
    for( QuerySection sect : q.getSections() ){
      String queryValue = sect.getQName();
      log.debug( "Received query for '{}'", queryValue );
      if( !queryValue.endsWith( "." ) && !queryValue.endsWith( domain ) )
        queryValue = queryValue + "." + domain;

      if( sect.getQClass() == QuerySection.QUERY_TYPE_PTR ){

        RBListEntry entry = server.getBlockList().lookup( queryValue );
        if( entry != null && ! entry.isExpired() ){
          response.add( new PtrRecord( queryValue, queryValue, entry.getRemainingLifetime() ) );
        } else {
          response.setStatus( Response.RC_NAME_ERROR );
          break;
        }
      }

      if( sect.getQType() == QuerySection.QUERY_TYPE_A ){
        queryValue = this.preprocess( source, queryValue );

        RBListEntry entry = server.getBlockList().lookup( queryValue );
        if( entry != null && !entry.isExpired() ){
          log.debug( "Entry '{}' is on block list and will expire in {} seconds", queryValue, entry.getRemainingLifetime() );
          response.add( new ARecord( queryValue, RblServer.BLOCKED_VALUE, entry.getRemainingLifetime() ) );
        } else {
          log.debug( "Removing expired entry..." );
          response.setStatus( Response.RC_NAME_ERROR );
          if( entry != null )
            server.getBlockList().remove( entry.getName() );
        }
      } else {
        response.setStatus( Response.RC_NAME_ERROR );
      }
    }

    return response;
  }


  /**
   * <p>
   * This method checks for any actions, which may be contained in the
   * query-value. The actions are processed and removed from the query-value,
   * yielding the final block-entry key.
   * </p>
   *
   * @param source The source address from which this query has been sent
   * @param query  The query value of the DNS query
   * @return
   */
  protected String preprocess( InetAddress source, String queryValue ){

    if( !queryValue.matches( pattern ) )
      return queryValue;

    int idx = queryValue.lastIndexOf( "." + domain );
    String part = queryValue.substring( 0, idx );
    int start = part.lastIndexOf( "." );
    String action = part.substring( start );


    // make 'key' the final query-value by removing the action value
    //
    String key = queryValue.replaceFirst( action, "" );


    // process the actions...
    //
    if( action.startsWith(".block-") ){

      // check permissions
      if( ! server.getRblSecurityManager().hasPermission( source, RblSecurityManager.BLOCK_PERMISSION ) ){
        log.error( "No permission for action 'block' for address '{}'", source.getHostAddress() );
        return key;
      }

      try {
        Integer ttl = new Integer( action.substring( 7 ) );
        log.debug( "Need to block key: '{}' for {} seconds", key, ttl );
        server.block( key, ttl );
        queryValue = key;
      } catch (Exception e) {
        log.error( "Failed to block entry: '{}': {}", queryValue, e.getMessage() );
        if( log.isDebugEnabled() )
          e.printStackTrace();
      }

      return queryValue;
    }

    // handle .unblock.domain  queries, which unblock the corresponding entry
    //
    if( action.equals( ".unblock" ) ){

      // check permissions
      if( ! server.getRblSecurityManager().hasPermission( source, RblSecurityManager.UNBLOCK_PERMISSION ) ){
        log.error( "No permission for action 'block' for address '{}'", source.getHostAddress() );
        return key;
      }

      server.unblock( key );
    }

    return key;
  }


  /**
   * <p>
   * To speed up lookups, RBLs are stored as Hashmaps. Usually, queries contain an address
   * value in the form
   * </p>
   * <pre>
   *    1.0.16.172.rbl.localnet
   * </pre>
   * </p>
   * <p>
   * This method will convert addresses like <code>172.16.0.1</code> into this reversed format
   * and append the specified domain.
   * </p>
   * <p>
   * If the address already ends with the given domain, this method assumes the address value
   * to already match the reversed format and will simply return it as is.
   * </p>
   *
   * @param address
   * @param domain
   * @return
   */
  public static String getKeyForAddress( String address, String domain ){

    // if the input already in reverse-domain format, simply return it
    //
    if( address.endsWith( domain ) )
      return address;

   
    // otherwise we need to reverse the addresses octets and append
    // the domain name
    //
    StringBuffer key = new StringBuffer( address );

    String[] tok = address.split( "\\." );
    key = new StringBuffer();
    for( int i = tok.length - 1; i >= 0; i--){
      key.append( tok[i] );
      if( i > 0 )
        key.append( "." );
    }

    // append the domain name
    //
    if( !domain.startsWith( "." ) )
      key.append( "." );
    key.append( domain );

    return key.toString();
  }
}
TOP

Related Classes of org.jwall.rbl.dns.QueryHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.