diff options
-rw-r--r-- | comsat/cfg.c | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/comsat/cfg.c b/comsat/cfg.c new file mode 100644 index 000000000..a1a7a9bd4 --- /dev/null +++ b/comsat/cfg.c @@ -0,0 +1,295 @@ +/* Copyright (C) 1998,2001 Free Software Foundation, Inc. + + This file is part of GNU Inetutils. + + GNU Inetutils 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, or (at your option) + any later version. + + GNU Inetutils is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR 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 GNU Inetutils; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include "comsat.h" +#include <argcv.h> +#include <ctype.h> + +typedef struct netdef netdef_t; + +struct netdef +{ + netdef_t *next; + unsigned int ipaddr; + unsigned int netmask; +}; + +#define ACT_ALLOW 0 +#define ACT_DENY 1 + +typedef struct acl acl_t; + +struct acl +{ + acl_t *next; + netdef_t *netlist; + int action; +}; + + +acl_t *acl_head, *acl_tail; + +#define DOTTED_QUAD_LEN 16 + +static int +read_address (char **line_ptr, char *ptr) +{ + char *startp = *line_ptr; + char *endp; + int dotcount = 0; + + for (endp = startp; *endp; endp++, ptr++) + if (!(isdigit (*endp) || *endp == '.')) + break; + else if (endp < startp + DOTTED_QUAD_LEN) + { + if (*endp == '.') + dotcount++; + *ptr = *endp; + } + else + break; + *line_ptr = endp; + *ptr = 0; + return dotcount; +} + +static netdef_t * +netdef_parse (char *str) +{ + unsigned int ipaddr, netmask; + netdef_t *netdef; + char ipbuf[DOTTED_QUAD_LEN+1]; + + if (strcmp (str, "any") == 0) + { + ipaddr = 0; + netmask = 0; + } + else + { + read_address (&str, ipbuf); + ipaddr = inet_addr (ipbuf); + if (ipaddr == INADDR_NONE) + return NULL; + if (*str == 0) + netmask = 0xfffffffful; + else if (*str != '/') + return NULL; + else + { + str++; + if (read_address (&str, ipbuf) == 0) + { + /* netmask length */ + unsigned int len = strtoul (ipbuf, NULL, 0); + if (len > 32) + return NULL; + netmask = 0xfffffffful >> (32-len); + netmask <<= (32-len); + /*FIXME: hostorder?*/ + } + else + netmask = inet_network (ipbuf); + netmask = htonl (netmask); + } + } + + netdef = malloc (sizeof *netdef); + if (!netdef) + { + syslog (LOG_ERR, "out of memory"); + exit (1); + } + + netdef->next = NULL; + netdef->ipaddr = ipaddr; + netdef->netmask = netmask; + + return netdef; +} + +void +read_config (char *config_file) +{ + FILE *fp; + int line; + char buf[128]; + char *ptr; + + if (!config_file) + return; + + fp = fopen (config_file, "r"); + if (!fp) + { + syslog (LOG_ERR, "can't open config file %s: %m", config_file); + return; + } + + line = 0; + while ((ptr = fgets (buf, sizeof buf, fp))) + { + int len, i; + int argc; + char **argv; + int action; + netdef_t *head, *tail; + acl_t *acl; + + line++; + len = strlen (ptr); + if (len > 0 && ptr[len-1] == '\n') + ptr[--len] = 0; + + while (*ptr && isspace (*ptr)) + ptr++; + if (!*ptr || *ptr == '#') + continue; + + argcv_get (ptr, "", &argc, &argv); + if (argc < 2) + { + syslog (LOG_ERR, "%s:%d: too few fields", config_file, line); + argcv_free (argc, argv); + continue; + } + + if (strcmp (argv[0], "max-requests") == 0) + maxrequests = strtoul (argv[1], NULL, 0); + else if (strcmp (argv[0], "request-control-interval") == 0) + request_control_interval = strtoul (argv[1], NULL, 0); + else if (strcmp (argv[0], "overflow-control-interval") == 0) + overflow_control_interval = strtoul (argv[1], NULL, 0); + else if (strcmp (argv[0], "overflow-delay-time") == 0) + overflow_delay_time = strtoul (argv[1], NULL, 0); + else if (strcmp (argv[0], "max-lines") == 0) + maxlines = strtoul (argv[1], NULL, 0); + else if (strcmp (argv[0], "acl") == 0) + { + if (strcmp (argv[1], "allow") == 0) + action = ACT_ALLOW; + else if (strcmp (argv[1], "deny") == 0) + action = ACT_DENY; + else + { + syslog (LOG_ERR, "%s:%d: unknown keyword", config_file, line); + argcv_free (argc, argv); + continue; + } + + head = tail = NULL; + for (i = 2; i < argc; i++) + { + netdef_t *cur = netdef_parse (argv[i]); + if (!cur) + { + syslog (LOG_ERR, "%s:%d: can't parse netdef: %s", + config_file, line, argv[i]); + continue; + } + if (!tail) + head = cur; + else + tail->next = cur; + tail = cur; + } + + argcv_free (argc, argv); + + acl = malloc (sizeof *acl); + if (!acl) + { + syslog (LOG_CRIT, "out of memory"); + exit (1); + } + acl->next = NULL; + acl->action = action; + acl->netlist = head; + + if (!acl_tail) + acl_head = acl; + else + acl_tail->next = acl; + acl_tail = acl; + } + } + fclose (fp); +} + +static void +netdef_free (netdef_t *netdef) +{ + netdef_t *next; + + while (netdef) + { + next = netdef->next; + free (netdef); + netdef = next; + } +} + +static void +acl_free (acl_t *acl) +{ + acl_t *next; + + while (acl) + { + next = acl->next; + netdef_free (acl->netlist); + free (acl); + acl = next; + } +} + +/*NOTE: currently unused. */ +void +discard_acl (acl_t *mark) +{ + if (mark) + { + acl_free (mark->next); + acl_tail = mark; + acl_tail->next = NULL; + } + else + acl_head = acl_tail = NULL; +} + +int +acl_match (struct sockaddr_in *sa_in) +{ + acl_t *acl; + unsigned int ip; + + ip = sa_in->sin_addr.s_addr; + for (acl = acl_head; acl; acl = acl->next) + { + netdef_t *net; + + for (net = acl->netlist; net; net = net->next) + { + if (net->ipaddr == (ip & net->netmask)) + return acl->action; + } + } + return ACT_ALLOW; +} |