Logo Search packages:      
Sourcecode: aggregate version File versions

cidr_net.c

/**********************************************************************
 * cidr_bet.c                                                March 2001
 * Horms                                             horms@verge.net.au
 *
 * aggregate
 * CIDR network aggregation and filtering
 * Copyright (C) 1999-2002  Horms
 * 
 * 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 2 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 * 02111-1307  USA
 *
 **********************************************************************/


#include "cidr_net.h"
#include "log.h"
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

/*Lookup table for 2^index */
unsigned int cidr_pow_2_lookup[IP_BITS];


/**********************************************************************
 * cidr_net_create
 * Initialise a cidr_net and seed values
 * pre: a: base address of network
 *      p: prefix of network
 * post: network is initialise and values are seeded
 * return: network
 *         NULL on error
 **********************************************************************/

cidr_net_t *cidr_net_create(ip_address_t a, prefix_t p){
  cidr_net_t *n;

  extern int errno;

  if((n=(cidr_net_t*)malloc(sizeof(cidr_net_t)))==NULL){
    AGGREGATE_DEBUG_ERRNO("cidr_net_create: malloc", errno);
    return(NULL);
  }

  if(cidr_net_assign(n, a, p)==NULL){
    AGGREGATE_DEBUG("cidr_net_create: cidr_net_assign");
    free(n);
    return(NULL);
  }

  return(n);
}


/**********************************************************************
 * cidr_net_assign
 * Assign values to a cidr_net structure
 * pre: n: pointer to cidr_net structure
 *      a: base address of network
 *      p: prefix of network
 * post: n is initialised
 *       n is destroyed on error
 * return: n
 *         NULL on error
 **********************************************************************/

cidr_net_t *cidr_net_assign(cidr_net_t *n, ip_address_t a, prefix_t p){
  extern ip_address_t cidr_pow_2_lookup[];

  if(n==NULL){ return(NULL); }
  if( (a>>(IP_BITS-p)<<(IP_BITS-p)) != a ){
    AGGREGATE_LOG(
      LOG_INFO,
      "invalid prefix (%d) for network (%s)",
      p,
      ip_address_decimal_to_dotted_quad(a)
    );
    AGGREGATE_LOG(
      LOG_DEBUG,
      "cidr_net_assign: invalid prefix (%d) for network (%s)",
      p,
      ip_address_decimal_to_dotted_quad(a)
    );
    return(NULL);
  }
  n->address=a;
  n->prefix=p;
  n->top_address=a-1+cidr_pow_2_lookup[IP_BITS-p];

  return(n);
}


/**********************************************************************
 * cidr_net_destroy
 * Destory a cidr_net
 * pre: n: pointer to cidr_net to destroy
 * post: n is destroyed
 * return: none
 **********************************************************************/

void cidr_net_destroy(cidr_net_t *n){
  if(n==NULL){ return; }
  free(n);

  return;
}


/**********************************************************************
 * cidr_net_to_a
 * Print to stdout the network in address/prefix notation, where
 * address is in dotted quad notation
 * pre: n: network to display
 *      minimim_prefix: Don't display networks with a prefix less than
 *                      this value. Valid values 0-32. 
 *                      -1 for no mimimium prefix.
 *      maximim_prefix: Don't display networks with a prefix greater than
 *                      this value. Valid values 0-32. 
 *                      -1 for no maximium prefix.
 *      flag: as per cidr_net.h
 * post: network is displayed to rendered to ASCII
 * return: String containing network
 *         NULL on error
 * Note: Result is rendered into a static buffer
 **********************************************************************/

static char __cidr_net_str[CIDR_NET_STR_LEN];

char *cidr_net_to_a(
  cidr_net_t *n, 
  prefix_t minimum_prefix,
  prefix_t maximum_prefix,
  cidr_flag_t flag
){
  int status;

  if(n==NULL){
    return(NULL);
  }

  if( 
    (maximum_prefix!=-1 && n->prefix > maximum_prefix) ||
    (minimum_prefix!=-1 && n->prefix < minimum_prefix)
  ){
    *__cidr_net_str='\0';
    return(__cidr_net_str);
  }
  if(flag&CIDR_ADDRESS_RANGE){
    if((status=snprintf(
      __cidr_net_str,
      CIDR_NET_STR_LEN,
      "%s - ", 
      ip_address_decimal_to_dotted_quad(n->address)
    ))<0){
      return(NULL);
    }
    if((status=snprintf(
      __cidr_net_str+status,
      CIDR_NET_STR_LEN-status,
      "%s",  
      ip_address_decimal_to_dotted_quad(n->top_address)
    ))<0){
      return(NULL);
    }
  }
  if(flag&CIDR_NET_NETMASK){
    if((status=snprintf(
      __cidr_net_str,
      CIDR_NET_STR_LEN,
      "%s/", 
      ip_address_decimal_to_dotted_quad(n->address)
    ))<0){
      return(NULL);
    }
    if((status=snprintf(
      __cidr_net_str+status,
      CIDR_NET_STR_LEN-status,
      "%s", 
      ip_address_decimal_to_dotted_quad(cidr_netmask(n->prefix))
    ))<0){
      return(NULL);
    }
  }
  if(flag&CIDR_NET_PREFIX){
    if((status=snprintf(
      __cidr_net_str,
      CIDR_NET_STR_LEN,
      "%s/%s", 
      ip_address_decimal_to_dotted_quad(n->address), 
      prefix_decimal_to_a(n->prefix)
    ))<0){
      return(NULL);
    }
  }

  return(__cidr_net_str);
}


/**********************************************************************
 * cidr_net_distance
 * Find the distance between two networks base address
 * pre: a, b: networks to find the distance between
 * return: absolute diffrence of the base address of a and b
 **********************************************************************/

ip_address_t cidr_net_distance(cidr_net_t *a, cidr_net_t *b){
  if(a==NULL || b==NULL) return(~0);
  return(a->address>b->address)?a->address-b->address:b->address-a->address;
}


/**********************************************************************
 * cidr_net_cmp
 * Compare two cidr networks 
 * pre: a, b: networks to compare
 * return: 1 if a and b are the same
 *         0 if and are be are not the same
 *         -1 on error
 **********************************************************************/

int cidr_net_cmp(cidr_net_t *a, cidr_net_t *b){
  if(a==NULL || b==NULL) return(-1);
  return((a->address==b->address)&&(a->prefix==b->prefix))?1:0;
}


/**********************************************************************
 * cidr_generate_pow_2_lookup
 * Generate an array with IP_BITS elements where element n = 2^n
 * pre: none
 * post: @bit_loookup is seeded (or seedy as the case may be)
 **********************************************************************/

void cidr_generate_pow_2_lookup(void){
  int i;
  unsigned int current_seed;

  extern unsigned int cidr_pow_2_lookup[];

  for(i=0,current_seed=1;i<IP_BITS;i++,current_seed=current_seed<<1){
    cidr_pow_2_lookup[i]=current_seed;
  }
}


/**********************************************************************
 * cidr_log_2
 * Arghh this is really nasty, I am sure there is a better way to do 
 * this.
 * Get log base 2 of a IP_BITS bit integer, rounded down to the nearest 
 * integer.
 * Works on IP_BITSbit numbers.
 * pre: address: address to find log base 2 of
 * post: integer log base 2
 **********************************************************************/

int cidr_log_2 (ip_address_t address) {
  int i;
  int j;

  for(i=IP_BITS-1,j=1<<(IP_BITS-1);i>0;i--,j>>=1){
    if(address & j){
      goto leave;
    }
  }
 
  leave:
  return(i);
}


/**********************************************************************
 * cidr_netmask
 * Calculate the netmask given a prefix
 * pre: prefix: prefix to find the netmask off
 * return: netmask in decimal
 **********************************************************************/

ip_address_t cidr_netmask(prefix_t prefix){
  extern unsigned int cidr_pow_2_lookup[];

  if(prefix==0) return (ip_address_t)0;
  return( ~(cidr_pow_2_lookup[IP_BITS-prefix]-1) );
}
  

/**********************************************************************
 * cidr_prefix
 * Arghh this is really nasty, I am sure there is a better way to do 
 * this.
 * Get the network prefix (IP_BITS-number of trailing zeros)
 * Works on IP_BITSbit numbers
 * pre: address: the address to find the prefix of
 * post: number of trailing zeros.
 **********************************************************************/

prefix_t cidr_prefix (ip_address_t address){
  int i;
  int j;

  for(i=IP_BITS,j=1;i>0;i--,j<<=1){
    if(address & j){
      goto leave;
    }
  }
 
  leave:
  return(i);
}


/**********************************************************************
 * cidr_classful_prefix
 * Given an ip address find the classful network prefix length
 * pre: address: the address to find the prefix of
 * post: The number of trailing zeros, rounded to the nearest 
 *       classful prefix length. That is one of 0, 8, 16, 24 or 32.
 **********************************************************************/

prefix_t cidr_classful_prefix(ip_address_t address){
  if(address==0){
    return((prefix_t)0);
  }
  if(!(address&0xffffff)){
    return((prefix_t)8);
  }
  else if(!(address&0xffff)){
    return((prefix_t)16);
  }
  else if(!(address&0xff)){
    return((prefix_t)24);
  }
  
  return((prefix_t)32);
}

Generated by  Doxygen 1.6.0   Back to index