/* $Id: conf_variable.c,v 1.14 2005/08/01 08:39:48 gsson Exp $ */
/*
* Copyright (c) 2005 Henrik Gustafsson <henrik.gustafsson@fnord.se>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include "ip4_range.h"
#include "table_fileop.h"
#include "conf_variable.h"
#define MAXTOKLEN 32
#define TAILQ_REASSIGN(head, head2, field) do { \
(head2)->tqh_first = (head)->tqh_first; \
(head2)->tqh_last = (head)->tqh_last; \
if ((head2)->tqh_first != NULL) \
(head2)->tqh_first->field.tqe_prev = &(head2)->tqh_first; \
(head)->tqh_first = NULL; \
(head)->tqh_last = &(head)->tqh_first; \
} while(0)
/*
* Note: The variable_* functions disposes the pointers used as
* arguments. This kind of non-standard behavior was implemented to try
* to minimise the memory usage and the amount of memory copies.
* variable_list_variable_create takes care of the name pointer.
*
* This behaviour has as a side-effect that all
*/
void
variable_list_destroy(variable_list_t *list) {
struct variable_list_element *element;
element = TAILQ_FIRST(list);
while (!TAILQ_EMPTY(list)) {
TAILQ_REMOVE(list, element, variable_list_links);
variable_destroy(element->v);
free(element);
element = TAILQ_FIRST(list);
}
TAILQ_INIT(list);
}
void
variable_list_init(variable_list_t *list) {
TAILQ_INIT(list);
}
/* Note: Does not free 'c' */
struct variable *
variable_list_find(variable_list_t *vlist, char *c) {
struct variable_list_element *element;
if (TAILQ_EMPTY(vlist)) {
return NULL;
}
TAILQ_FOREACH(element, vlist, variable_list_links) {
if (strncmp(c, element->v->name, MAXTOKLEN) == 0) {
return element->v;
}
if (strncmp(c, element->v->name, MAXTOKLEN) < 0) {
return NULL;
}
}
return NULL;
}
struct variable *
variable_list_variable_create(variable_list_t *vlist, char *c) {
struct variable_list_element *element;
if (TAILQ_EMPTY(vlist)) {
element = malloc(sizeof(struct variable_list_element));
if (element == NULL) {
fprintf(stderr, "Allocation error\n");
exit(-1);
/* NOTREACHED */
}
element->v = variable_create();
element->v->name = c;
element->v->temporary = 0;
TAILQ_INSERT_HEAD(vlist, element, variable_list_links);
return element->v;
}
if (strncmp(c, TAILQ_LAST(vlist, variable_list)->v->name, MAXTOKLEN) > 0) {
element = malloc(sizeof(struct variable_list_element));
if (element == NULL) {
fprintf(stderr, "Allocation error\n");
exit(-1);
/* NOTREACHED */
}
element->v = variable_create();
element->v->name = c;
element->v->temporary = 0;
TAILQ_INSERT_TAIL(vlist, element, variable_list_links);
return element->v;
}
TAILQ_FOREACH(element, vlist, variable_list_links) {
if (strncmp(c, element->v->name, MAXTOKLEN) < 0) {
struct variable_list_element *new_element;
new_element = malloc(sizeof(struct variable_list_element));
if (new_element == NULL) {
fprintf(stderr, "Allocation error\n");
exit(-1);
/* NOTREACHED */
}
new_element->v = variable_create();
new_element->v->name = c;
new_element->v->temporary = 0;
TAILQ_INSERT_BEFORE(element, new_element, variable_list_links);
return new_element->v;
}
}
fprintf(stderr, "*dies*\n");
exit(-1);
/* NOTREACHED */
}
struct variable *
variable_find(variable_list_t *vlist, char *c) {
struct variable *v;
v = variable_list_find(vlist, c);
if (v != NULL) {
free(c);
return v;
}
v = variable_list_variable_create(vlist, c);
return v;
}
struct variable *
variable_dup(struct variable *var) {
struct variable *new_var;
if (var->temporary) {
return var;
}
new_var = variable_create();
if (var->name != NULL) {
new_var->name = strdup(var->name);
}
ip4_range_list_dup(&(var->table), &(new_var->table));
return new_var;
}
struct variable *
variable_assign(variable_list_t *vlist, char *c, struct variable *src) {
struct variable *dst = variable_find(vlist, c);
if (src->temporary) {
ip4_range_list_destroy(&(dst->table));
TAILQ_REASSIGN(&(src->table), &(dst->table), ip4_range_list_links);
variable_destroy(src);
}
else {
ip4_range_list_dup(&(src->table), &(dst->table));
}
return dst;
}
struct variable *
variable_get(variable_list_t *vlist, char *c) {
if (c != NULL) {
struct variable *v;
v = variable_list_find(vlist, c);
if (v != NULL) {
free(c);
return v;
}
fprintf(stderr, "Variable '%s' does not exist.\n", c);
return variable_list_variable_create(vlist, c);
}
return NULL;
}
void
variable_destroy(struct variable *var) {
if (var != NULL) {
ip4_range_list_destroy(&(var->table));
if (var->name != NULL) {
free(var->name);
}
free(var);
}
}
struct variable *
variable_create() {
struct variable *var = malloc(sizeof(struct variable));
if (var == NULL) {
fprintf(stderr, "Allocation error\n");
exit(-1);
/* NOTREACHED */
}
TAILQ_INIT(&(var->table));
var->temporary=1;
var->name = NULL;
return var;
}
struct variable *
variable_insert_range(struct variable *list, char *address) {
int a, b, c, d;
int a1, b1, c1, d1;
if (sscanf(address, "%d.%d.%d.%d-%d.%d.%d.%d", &a, &b, &c, &d, &a1, &b1, &c1, &d1 ) == 8 &&
a >= 0 && a < 256 &&
b >= 0 && b < 256 &&
c >= 0 && c < 256 &&
d >= 0 && d < 256 &&
a1 >= 0 && a1 < 256 &&
b1 >= 0 && b1 < 256 &&
c1 >= 0 && c1 < 256 &&
d1 >= 0 && d1 < 256) {
ip4_range_list_insert_range_raw(&(list->table), IP(a,b,c,d), IP(a1,b1,c1,d1), NULL);
}
free(address);
return list;
}
struct variable *
variable_insert_cidr(struct variable *list, char *address) {
int a, b, c, d;
int p;
if (sscanf(address, "%d.%d.%d.%d/%d", &a, &b, &c, &d, &p) == 5 &&
a >= 0 && a < 256 &&
b >= 0 && b < 256 &&
c >= 0 && c < 256 &&
d >= 0 && d < 256 &&
p >= 0 && p < 33) {
ip4_range_list_insert_cidr(&(list->table), IP(a,b,c,d), p, NULL);
}
free(address);
return list;
}
struct variable *
variable_insert_hostname(struct variable *list, char *hostname) {
struct addrinfo *ai_result;
struct addrinfo *ai;
struct sockaddr_in *sa;
int result;
struct addrinfo hint;
memset(&hint, 0, sizeof(struct addrinfo));
hint.ai_family = AF_INET;
hint.ai_socktype = SOCK_STREAM;
result = getaddrinfo(hostname, NULL, &hint, &ai_result);
if (result) {
fprintf(stderr, "Host lookup for host '%s' failed: %s\n", hostname, gai_strerror(result));
free(hostname);
return list;
}
for (ai = ai_result; ai; ai = ai->ai_next) {
sa = (struct sockaddr_in *) ai->ai_addr;
ip4_range_list_insert_cidr(&(list->table), ntohl(sa->sin_addr.s_addr), 32, NULL);
}
freeaddrinfo(ai_result);
free(hostname);
return list;
}
struct variable *
variable_insert_single(struct variable *list, char *address) {
int a, b, c, d;
if (sscanf(address, "%d.%d.%d.%d", &a, &b, &c, &d) == 4 &&
a >= 0 && a < 256 &&
b >= 0 && b < 256 &&
c >= 0 && c < 256 &&
d >= 0 && d < 256) {
ip4_range_list_insert_cidr(&(list->table), IP(a,b,c,d), 32, NULL);
}
free(address);
return list;
}
struct variable *
variable_load_text(char *file) {
struct variable *var = NULL;
var = variable_create();
ip4_text_load(file, &(var->table));
if (file != NULL) free(file);
return var;
}
struct variable *
variable_load_p2b(char *file) {
struct variable *var = NULL;
var = variable_create();
ip4_p2b_load(file, &(var->table));
if (file != NULL) free(file);
return var;
}
struct variable *
variable_union(struct variable *lhs, struct variable *rhs) {
struct variable *var = NULL;
var = variable_create();
ip4_range_list_union(&(lhs->table), &(rhs->table), &(var->table));
if (lhs->temporary) {
variable_destroy(lhs);
}
if (rhs->temporary) {
variable_destroy(rhs);
}
return var;
}
struct variable *
variable_intersect(struct variable *lhs, struct variable *rhs) {
struct variable *var = NULL;
var = variable_create();
ip4_range_list_intersect(&(lhs->table), &(rhs->table), &(var->table));
if (lhs->temporary) {
variable_destroy(lhs);
}
if (rhs->temporary) {
variable_destroy(rhs);
}
return var;
}
struct variable *
variable_difference(struct variable *lhs, struct variable *rhs) {
struct variable *var = NULL;
var = variable_create();
ip4_range_list_difference(&(lhs->table), &(rhs->table), &(var->table));
if (lhs->temporary) {
variable_destroy(lhs);
}
if (rhs->temporary) {
variable_destroy(rhs);
}
return var;
}
struct variable *
variable_invert(struct variable *rhs) {
struct variable *var = NULL;
var = variable_create();
ip4_range_list_invert(&(rhs->table), &(var->table));
if (rhs->temporary) {
variable_destroy(rhs);
}
return var;
}
void
variable_save_cidr(char *file, struct variable *rhs) {
ip4_cidr_save(file, &(rhs->table));
if (rhs->temporary) {
variable_destroy(rhs);
}
if (file != NULL) free(file);
return;
}
void
variable_save_range(char *file, struct variable *rhs) {
ip4_range_save(file, &(rhs->table));
if (rhs->temporary) {
variable_destroy(rhs);
}
if (file != NULL) free(file);
return;
}
void
variable_save_single(char *file, struct variable *rhs) {
ip4_single_save(file, &(rhs->table));
if (rhs->temporary) {
variable_destroy(rhs);
}
if (file != NULL) free(file);
return;
}
syntax highlighted by Code2HTML, v. 0.9.1