Codebase list filtergen / HEAD resolver.c
HEAD

Tree @HEAD (Download .tar.gz)

resolver.c @HEADraw · history · blame

/* argument name resolver
 *
 * Copyright (c) 2004 Jamie Wilkinson <jaq@spacepants.org>
 *
 * 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 <stdio.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "resolver.h"
#include "ast.h"
#include "icmpent.h"

void resolve_option_specifier(struct option_specifier_s *n
                              __attribute__((unused))) {}

void resolve_icmptype_argument(struct icmptype_argument_s *n) {
  struct icmpent_s *i;

  if (n->icmptype) {
    if ((i = geticmpbyname(n->icmptype))) {
      free(n->icmptype);
      if (asprintf(&n->icmptype, "%s", i->i_type) < 0) {
        n->icmptype = NULL;
        fprintf(
            stderr,
            "error: asprintf allocation failed when converting icmptype %s\n",
            i->i_type);
      }
    } else {
      /* check that the icmptype is a number if we can't resolve it */
      long m;
      char *e;

      m = strtol(n->icmptype, &e, 10);
      if (*e || m == LONG_MIN || m == LONG_MAX) {
        fprintf(stderr, "warning: suspicious icmp type encountered: %s\n",
                n->icmptype);
      }
    }
  }
}

void resolve_icmptype_argument_list(struct icmptype_argument_list_s *n) {
  if (n->list) {
    resolve_icmptype_argument_list(n->list);
  }
  if (n->arg) {
    resolve_icmptype_argument(n->arg);
  }
}

void resolve_icmptype_specifier(struct icmptype_specifier_s *n) {
  if (n->list) {
    resolve_icmptype_argument_list(n->list);
  }
}

void resolve_port_argument(struct port_argument_s *n) {
  struct servent *s;

  if (n->port_min) {
    /* try to resolve the port name */
    if ((s = getservbyname(n->port_min, NULL))) {
      free(n->port_min);
      if (asprintf(&n->port_min, "%d", ntohs(s->s_port)) < 0) {
        n->port_min = NULL;
        fprintf(stderr,
                "error: asprintf allocation failed when resolving port %d\n",
                ntohs(s->s_port));
      }
    } else {
      /* check that the port is a number if we can't resolve it */
      long m;
      char *e;

      m = strtol(n->port_min, &e, 10);
      if (*e || m == LONG_MIN || m == LONG_MAX) {
        fprintf(stderr, "warning: suspicious port name encountered: %s\n",
                n->port_min);
      }
    }
  }
  if (n->port_max) {
    /* try to resolve the port name */
    if ((s = getservbyname(n->port_max, NULL))) {
      free(n->port_max);
      if (asprintf(&n->port_max, "%d", ntohs(s->s_port)) < 0) {
        n->port_max = NULL;
        fprintf(stderr,
                "error: asprintf allocation failed when resolving port %d\n",
                ntohs(s->s_port));
      }
    } else {
      /* check that the port is a number if we can't resolve it */
      long m;
      char *e;

      m = strtol(n->port_max, &e, 10);
      if (*e || m == LONG_MIN || m == LONG_MAX) {
        fprintf(stderr, "warning: suspicious port name encountered: %s\n",
                n->port_max);
      }
    }
  }
}

void resolve_port_argument_list(struct port_argument_list_s *n) {
  if (n->list) {
    resolve_port_argument_list(n->list);
  }
  if (n->arg) {
    resolve_port_argument(n->arg);
  }
}

void resolve_port_specifier(struct port_specifier_s *n) {
  if (n->list) {
    resolve_port_argument_list(n->list);
  }
}

void resolve_protocol_argument(struct protocol_argument_s *n) {
  struct protoent *p;

  if (n->proto) {
    if ((p = getprotobyname(n->proto))) {
      free(n->proto);
      if (asprintf(&n->proto, "%d", p->p_proto) < 0) {
        n->proto = NULL;
        fprintf(
            stderr,
            "error: asprintf allocation failed when converting protocol %d\n",
            p->p_proto);
      }
    } else {
      /* check that the proto is a number if we can't resolve it */
      long m;
      char *e;

      m = strtol(n->proto, &e, 10);
      if (*e || m == LONG_MIN || m == LONG_MAX) {
        fprintf(stderr, "warning: suspicious protocol name encountered: %s\n",
                n->proto);
      }
    }
  }
}

void resolve_protocol_argument_list(struct protocol_argument_list_s *n) {
  if (n->list) {
    resolve_protocol_argument_list(n->list);
  }
  if (n->arg) {
    resolve_protocol_argument(n->arg);
  }
}

void resolve_protocol_specifier(struct protocol_specifier_s *n) {
  if (n->list) {
    resolve_protocol_argument_list(n->list);
  }
}

void resolve_host_argument(struct host_argument_s *n __attribute__((unused))) {}

void resolve_host_argument_list(struct host_argument_list_s *n,
                                struct filtergen_opts *o) {
  struct addrinfo *a = NULL, *i;
  struct addrinfo hints;
  int r;
  struct host_argument_list_s *list = NULL;
  struct host_argument_s *host = NULL;

  if (n->list) {
    resolve_host_argument_list(n->list, o);
  }

  if (n->arg) {
    memset(&hints, 0, sizeof(struct addrinfo));
    /* use our chosen address family */
    hints.ai_family = o->family;
    /* return hostname, though we don't use it, for debugging */
    hints.ai_flags = AI_CANONNAME;
    /* limit so duplicate hosts aren't returned for each socktype */
    hints.ai_socktype = SOCK_STREAM;

    if (n->arg->host) {
      r = getaddrinfo(n->arg->host, NULL, &hints, &a);
      switch (r) {
      case 0:
        /* replace the hostname with the IP */
        free(n->arg->host);
        /* getnameinfo does no allocation. */
        n->arg->host = malloc(NI_MAXHOST + 1);
        if (getnameinfo(a->ai_addr, a->ai_addrlen, n->arg->host, NI_MAXHOST,
                        NULL, 0, NI_NUMERICHOST) == 0) {
          /* if there's more, create some more hosts */
          for (i = a->ai_next; i; i = i->ai_next) {
            list = malloc(sizeof(struct host_argument_list_s));
            host = malloc(sizeof(struct host_argument_s));
            host->host = malloc(NI_MAXHOST + 1);
            if (getnameinfo(i->ai_addr, i->ai_addrlen, host->host, NI_MAXHOST,
                            NULL, 0, NI_NUMERICHOST) == 0) {
              if (n->arg->mask) {
                host->mask = strdup(n->arg->mask);
              }

              /* insert the new node */
              list->arg = host;
              list->list = n->list;
              n->list = list;
            } else {
              fprintf(stderr, "warning: %s\n", strerror(errno));
            }
          }
        } else {
          fprintf(stderr, "warning: %s\n", strerror(errno));
        }
        freeaddrinfo(a);
        break;
      default:
        fprintf(stderr, "warning: %s: %s\n", gai_strerror(r), n->arg->host);
        break;
      }
    }
  }
}

void resolve_host_specifier(struct host_specifier_s *n,
                            struct filtergen_opts *o) {
  if (n->list) {
    resolve_host_argument_list(n->list, o);
  }
}

void resolve_target_specifier(struct target_specifier_s *n
                              __attribute__((unused))) {}

void resolve_direction_argument(struct direction_argument_s *n
                                __attribute__((unused))) {}

void resolve_direction_argument_list(struct direction_argument_list_s *n) {
  if (n->list) {
    resolve_direction_argument_list(n->list);
  }
  if (n->arg) {
    resolve_direction_argument(n->arg);
  }
}

void resolve_direction_specifier(struct direction_specifier_s *n) {
  if (n->list) {
    resolve_direction_argument_list(n->list);
  }
}

void resolve_specifier_list(struct specifier_list_s *n,
                            struct filtergen_opts *o);

void resolve_subrule_list(struct subrule_list_s *n, struct filtergen_opts *o) {
  if (n->subrule_list) {
    resolve_subrule_list(n->subrule_list, o);
  }
  if (n->specifier_list) {
    resolve_specifier_list(n->specifier_list, o);
  }
}

void resolve_chaingroup_specifier(struct chaingroup_specifier_s *n,
                                  struct filtergen_opts *o) {
  if (n->list) {
    resolve_subrule_list(n->list, o);
  }
}

void resolve_compound_specifier(struct compound_specifier_s *n,
                                struct filtergen_opts *o) {
  if (n->list) {
    resolve_subrule_list(n->list, o);
  }
}

void resolve_specifier(struct specifier_s *n, struct filtergen_opts *o) {
  if (n->compound) {
    resolve_compound_specifier(n->compound, o);
  } else if (n->direction) {
    resolve_direction_specifier(n->direction);
  } else if (n->target) {
    resolve_target_specifier(n->target);
  } else if (n->host) {
    resolve_host_specifier(n->host, o);
  } else if (n->port) {
    resolve_port_specifier(n->port);
  } else if (n->protocol) {
    resolve_protocol_specifier(n->protocol);
  } else if (n->icmptype) {
    resolve_icmptype_specifier(n->icmptype);
  } else if (n->option) {
    resolve_option_specifier(n->option);
  } else if (n->chaingroup) {
    resolve_chaingroup_specifier(n->chaingroup, o);
  }
}

void resolve_negated_specifier(struct negated_specifier_s *n,
                               struct filtergen_opts *o) {
  if (n->spec) {
    resolve_specifier(n->spec, o);
  }
}

void resolve_specifier_list(struct specifier_list_s *n,
                            struct filtergen_opts *o) {
  if (n->list) {
    resolve_specifier_list(n->list, o);
  }
  if (n->spec) {
    resolve_negated_specifier(n->spec, o);
  }
}

void resolve_rule(struct rule_s *n, struct filtergen_opts *o) {
  if (n->list) {
    resolve_specifier_list(n->list, o);
  }
}

void resolve_rule_list(struct rule_list_s *n, struct filtergen_opts *o) {
  if (n->list) {
    resolve_rule_list(n->list, o);
  }
  if (n->rule) {
    resolve_rule(n->rule, o);
  }
}

void resolve_ast(struct ast_s *n, struct filtergen_opts *o) {
  if (n->list) {
    resolve_rule_list(n->list, o);
  }
}

void resolve(struct ast_s *n, struct filtergen_opts *o) {
  if (n) {
    resolve_ast(n, o);
  }
}