iplist.c revision 37210
131921Sbrian/*-
231921Sbrian * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>
331921Sbrian * All rights reserved.
431921Sbrian *
531921Sbrian * Redistribution and use in source and binary forms, with or without
631921Sbrian * modification, are permitted provided that the following conditions
731921Sbrian * are met:
831921Sbrian * 1. Redistributions of source code must retain the above copyright
931921Sbrian *    notice, this list of conditions and the following disclaimer.
1031921Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1131921Sbrian *    notice, this list of conditions and the following disclaimer in the
1231921Sbrian *    documentation and/or other materials provided with the distribution.
1331921Sbrian *
1431921Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1531921Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1631921Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1731921Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1831921Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1931921Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2031921Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2131921Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2231921Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2331921Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2431921Sbrian * SUCH DAMAGE.
2531921Sbrian *
2637210Sbrian *	$Id: iplist.c,v 1.6 1998/06/15 19:06:47 brian Exp $
2731690Sbrian */
2831690Sbrian
2931690Sbrian#include <sys/types.h>
3031690Sbrian#include <netinet/in.h>
3131690Sbrian#include <arpa/inet.h>
3231690Sbrian
3331690Sbrian#include <stdlib.h>
3431690Sbrian#include <string.h>
3531690Sbrian
3631690Sbrian#include "log.h"
3731690Sbrian#include "defs.h"
3831690Sbrian#include "iplist.h"
3931690Sbrian
4031690Sbrianstatic int
4131690Sbriando_inet_aton(const char *start, const char *end, struct in_addr *ip)
4231690Sbrian{
4337010Sbrian  char ipstr[16];
4431690Sbrian
4531690Sbrian  if (end - start > 15) {
4637210Sbrian    log_Printf(LogWARN, "%.*s: Invalid IP address\n", (int)(end-start), start);
4731690Sbrian    return 0;
4831690Sbrian  }
4931690Sbrian  strncpy(ipstr, start, end-start);
5031690Sbrian  ipstr[end-start] = '\0';
5131690Sbrian  return inet_aton(ipstr, ip);
5231690Sbrian}
5331690Sbrian
5431690Sbrianstatic void
5531690Sbrianiplist_first(struct iplist *list)
5631690Sbrian{
5731690Sbrian  list->cur.pos = -1;
5831690Sbrian}
5931690Sbrian
6031690Sbrianstatic int
6131690Sbrianiplist_setrange(struct iplist *list, char *range)
6231690Sbrian{
6331690Sbrian  char *ptr, *to;
6431690Sbrian
6531690Sbrian  if ((ptr = strpbrk(range, ",-")) == NULL) {
6631690Sbrian    if (!inet_aton(range, &list->cur.ip))
6731690Sbrian      return 0;
6831690Sbrian    list->cur.lstart = ntohl(list->cur.ip.s_addr);
6931690Sbrian    list->cur.nItems = 1;
7031690Sbrian  } else {
7131690Sbrian    if (!do_inet_aton(range, ptr, &list->cur.ip))
7231690Sbrian      return 0;
7331690Sbrian    if (*ptr == ',') {
7431690Sbrian      list->cur.lstart = ntohl(list->cur.ip.s_addr);
7531690Sbrian      list->cur.nItems = 1;
7631690Sbrian    } else {
7731690Sbrian      struct in_addr endip;
7831690Sbrian
7931690Sbrian      to = ptr+1;
8031690Sbrian      if ((ptr = strpbrk(to, ",-")) == NULL)
8131690Sbrian        ptr = to + strlen(to);
8231690Sbrian      if (*to == '-')
8331690Sbrian        return 0;
8431690Sbrian      if (!do_inet_aton(to, ptr, &endip))
8531690Sbrian        return 0;
8631690Sbrian      list->cur.lstart = ntohl(list->cur.ip.s_addr);
8731690Sbrian      list->cur.nItems = ntohl(endip.s_addr) - list->cur.lstart + 1;
8831690Sbrian      if (list->cur.nItems < 1)
8931690Sbrian        return 0;
9031690Sbrian    }
9131690Sbrian  }
9231690Sbrian  list->cur.srcitem = 0;
9331690Sbrian  list->cur.srcptr = range;
9431690Sbrian  return 1;
9531690Sbrian}
9631690Sbrian
9731690Sbrianstatic int
9831690Sbrianiplist_nextrange(struct iplist *list)
9931690Sbrian{
10031690Sbrian  char *ptr, *to, *end;
10131690Sbrian
10231690Sbrian  ptr = list->cur.srcptr;
10331690Sbrian  if (ptr != NULL && (ptr = strchr(ptr, ',')) != NULL)
10431690Sbrian    ptr++;
10531690Sbrian  else
10631690Sbrian    ptr = list->src;
10731690Sbrian
10831690Sbrian  while (*ptr != '\0' && !iplist_setrange(list, ptr)) {
10931690Sbrian    if ((end = strchr(ptr, ',')) == NULL)
11031690Sbrian      end = ptr + strlen(ptr);
11131690Sbrian    if (end == ptr)
11231690Sbrian      return 0;
11337210Sbrian    log_Printf(LogWARN, "%.*s: Invalid IP range (skipping)\n",
11437210Sbrian               (int)(end - ptr), ptr);
11531690Sbrian    to = ptr;
11631690Sbrian    do
11731690Sbrian      *to = *end++;
11831690Sbrian    while (*to++ != '\0');
11931690Sbrian    if (*ptr == '\0')
12031690Sbrian      ptr = list->src;
12131690Sbrian  }
12231690Sbrian
12331690Sbrian  return 1;
12431690Sbrian}
12531690Sbrian
12631690Sbrianstruct in_addr
12731690Sbrianiplist_next(struct iplist *list)
12831690Sbrian{
12931690Sbrian  if (list->cur.pos == -1) {
13031690Sbrian    list->cur.srcptr = NULL;
13131690Sbrian    if (!iplist_nextrange(list)) {
13231690Sbrian      list->cur.ip.s_addr = INADDR_ANY;
13331690Sbrian      return list->cur.ip;
13431690Sbrian    }
13531690Sbrian  } else if (++list->cur.srcitem == list->cur.nItems) {
13631690Sbrian    if (!iplist_nextrange(list)) {
13731690Sbrian      list->cur.ip.s_addr = INADDR_ANY;
13831690Sbrian      list->cur.pos = -1;
13931690Sbrian      return list->cur.ip;
14031690Sbrian    }
14131690Sbrian  } else
14231690Sbrian    list->cur.ip.s_addr = htonl(list->cur.lstart + list->cur.srcitem);
14331690Sbrian  list->cur.pos++;
14431690Sbrian
14531690Sbrian  return list->cur.ip;
14631690Sbrian}
14731690Sbrian
14831690Sbrianint
14931690Sbrianiplist_setsrc(struct iplist *list, const char *src)
15031690Sbrian{
15131962Sbrian  strncpy(list->src, src, sizeof list->src - 1);
15231962Sbrian  list->src[sizeof list->src - 1] = '\0';
15331690Sbrian  list->cur.srcptr = list->src;
15431690Sbrian  do {
15531690Sbrian    if (iplist_nextrange(list))
15631690Sbrian      list->nItems += list->cur.nItems;
15731690Sbrian    else
15831690Sbrian      return 0;
15931690Sbrian  } while (list->cur.srcptr != list->src);
16031690Sbrian  return 1;
16131690Sbrian}
16231690Sbrian
16331690Sbrianvoid
16431690Sbrianiplist_reset(struct iplist *list)
16531690Sbrian{
16631690Sbrian  list->src[0] = '\0';
16731690Sbrian  list->nItems = 0;
16831690Sbrian  list->cur.pos = -1;
16931690Sbrian}
17031690Sbrian
17131690Sbrianstruct in_addr
17237210Sbrianiplist_setcurpos(struct iplist *list, long pos)
17331690Sbrian{
17431690Sbrian  if (pos < 0 || pos >= list->nItems) {
17531690Sbrian    list->cur.pos = -1;
17631690Sbrian    list->cur.ip.s_addr = INADDR_ANY;
17731690Sbrian    return list->cur.ip;
17831690Sbrian  }
17931690Sbrian
18031690Sbrian  list->cur.srcptr = NULL;
18131690Sbrian  list->cur.pos = 0;
18231690Sbrian  while (1) {
18331690Sbrian    iplist_nextrange(list);
18431690Sbrian    if (pos < list->cur.nItems) {
18531690Sbrian      if (pos) {
18631690Sbrian        list->cur.srcitem = pos;
18731690Sbrian        list->cur.pos += pos;
18831690Sbrian        list->cur.ip.s_addr = htonl(list->cur.lstart + list->cur.srcitem);
18931690Sbrian      }
19031690Sbrian      break;
19131690Sbrian    }
19231690Sbrian    pos -= list->cur.nItems;
19331690Sbrian    list->cur.pos += list->cur.nItems;
19431690Sbrian  }
19531690Sbrian
19631690Sbrian  return list->cur.ip;
19731690Sbrian}
19831690Sbrian
19931690Sbrianstruct in_addr
20031690Sbrianiplist_setrandpos(struct iplist *list)
20131690Sbrian{
20231690Sbrian  randinit();
20331690Sbrian  return iplist_setcurpos(list, random() % list->nItems);
20431690Sbrian}
20531690Sbrian
20631690Sbrianint
20731690Sbrianiplist_ip2pos(struct iplist *list, struct in_addr ip)
20831690Sbrian{
20931690Sbrian  struct iplist_cur cur;
21037210Sbrian  u_long f;
21137210Sbrian  int result;
21231690Sbrian
21331690Sbrian  result = -1;
21431962Sbrian  memcpy(&cur, &list->cur, sizeof cur);
21531690Sbrian
21631690Sbrian  for (iplist_first(list), f = 0; f < list->nItems; f++)
21731690Sbrian    if (iplist_next(list).s_addr == ip.s_addr) {
21831690Sbrian      result = list->cur.pos;
21931690Sbrian      break;
22031690Sbrian    }
22131690Sbrian
22231962Sbrian  memcpy(&list->cur, &cur, sizeof list->cur);
22331690Sbrian  return result;
22431690Sbrian}
225