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 *
2650479Speter * $FreeBSD$
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>
3546686Sbrian#include <termios.h>
3631690Sbrian
3731690Sbrian#include "log.h"
3831690Sbrian#include "defs.h"
3931690Sbrian#include "iplist.h"
4031690Sbrian
4131690Sbrianstatic int
4231690Sbriando_inet_aton(const char *start, const char *end, struct in_addr *ip)
4331690Sbrian{
4437010Sbrian  char ipstr[16];
4531690Sbrian
4631690Sbrian  if (end - start > 15) {
4737210Sbrian    log_Printf(LogWARN, "%.*s: Invalid IP address\n", (int)(end-start), start);
4831690Sbrian    return 0;
4931690Sbrian  }
5031690Sbrian  strncpy(ipstr, start, end-start);
5131690Sbrian  ipstr[end-start] = '\0';
5231690Sbrian  return inet_aton(ipstr, ip);
5331690Sbrian}
5431690Sbrian
5531690Sbrianstatic void
5631690Sbrianiplist_first(struct iplist *list)
5731690Sbrian{
5831690Sbrian  list->cur.pos = -1;
5931690Sbrian}
6031690Sbrian
6131690Sbrianstatic int
6231690Sbrianiplist_setrange(struct iplist *list, char *range)
6331690Sbrian{
6431690Sbrian  char *ptr, *to;
6531690Sbrian
6631690Sbrian  if ((ptr = strpbrk(range, ",-")) == NULL) {
6731690Sbrian    if (!inet_aton(range, &list->cur.ip))
6831690Sbrian      return 0;
6931690Sbrian    list->cur.lstart = ntohl(list->cur.ip.s_addr);
7031690Sbrian    list->cur.nItems = 1;
7131690Sbrian  } else {
7231690Sbrian    if (!do_inet_aton(range, ptr, &list->cur.ip))
7331690Sbrian      return 0;
7431690Sbrian    if (*ptr == ',') {
7531690Sbrian      list->cur.lstart = ntohl(list->cur.ip.s_addr);
7631690Sbrian      list->cur.nItems = 1;
7731690Sbrian    } else {
7831690Sbrian      struct in_addr endip;
7931690Sbrian
8031690Sbrian      to = ptr+1;
8131690Sbrian      if ((ptr = strpbrk(to, ",-")) == NULL)
8231690Sbrian        ptr = to + strlen(to);
8331690Sbrian      if (*to == '-')
8431690Sbrian        return 0;
8531690Sbrian      if (!do_inet_aton(to, ptr, &endip))
8631690Sbrian        return 0;
8731690Sbrian      list->cur.lstart = ntohl(list->cur.ip.s_addr);
8831690Sbrian      list->cur.nItems = ntohl(endip.s_addr) - list->cur.lstart + 1;
8931690Sbrian      if (list->cur.nItems < 1)
9031690Sbrian        return 0;
9131690Sbrian    }
9231690Sbrian  }
9331690Sbrian  list->cur.srcitem = 0;
9431690Sbrian  list->cur.srcptr = range;
9531690Sbrian  return 1;
9631690Sbrian}
9731690Sbrian
9831690Sbrianstatic int
9931690Sbrianiplist_nextrange(struct iplist *list)
10031690Sbrian{
10131690Sbrian  char *ptr, *to, *end;
10231690Sbrian
10331690Sbrian  ptr = list->cur.srcptr;
10431690Sbrian  if (ptr != NULL && (ptr = strchr(ptr, ',')) != NULL)
10531690Sbrian    ptr++;
10631690Sbrian  else
10731690Sbrian    ptr = list->src;
10831690Sbrian
10931690Sbrian  while (*ptr != '\0' && !iplist_setrange(list, ptr)) {
11031690Sbrian    if ((end = strchr(ptr, ',')) == NULL)
11131690Sbrian      end = ptr + strlen(ptr);
11231690Sbrian    if (end == ptr)
11331690Sbrian      return 0;
11437210Sbrian    log_Printf(LogWARN, "%.*s: Invalid IP range (skipping)\n",
11537210Sbrian               (int)(end - ptr), ptr);
11631690Sbrian    to = ptr;
11731690Sbrian    do
11831690Sbrian      *to = *end++;
11931690Sbrian    while (*to++ != '\0');
12031690Sbrian    if (*ptr == '\0')
12131690Sbrian      ptr = list->src;
12231690Sbrian  }
12331690Sbrian
12431690Sbrian  return 1;
12531690Sbrian}
12631690Sbrian
12731690Sbrianstruct in_addr
12831690Sbrianiplist_next(struct iplist *list)
12931690Sbrian{
13031690Sbrian  if (list->cur.pos == -1) {
13131690Sbrian    list->cur.srcptr = NULL;
13231690Sbrian    if (!iplist_nextrange(list)) {
13331690Sbrian      list->cur.ip.s_addr = INADDR_ANY;
13431690Sbrian      return list->cur.ip;
13531690Sbrian    }
13631690Sbrian  } else if (++list->cur.srcitem == list->cur.nItems) {
13731690Sbrian    if (!iplist_nextrange(list)) {
13831690Sbrian      list->cur.ip.s_addr = INADDR_ANY;
13931690Sbrian      list->cur.pos = -1;
14031690Sbrian      return list->cur.ip;
14131690Sbrian    }
14231690Sbrian  } else
14331690Sbrian    list->cur.ip.s_addr = htonl(list->cur.lstart + list->cur.srcitem);
14431690Sbrian  list->cur.pos++;
14531690Sbrian
14631690Sbrian  return list->cur.ip;
14731690Sbrian}
14831690Sbrian
14931690Sbrianint
15031690Sbrianiplist_setsrc(struct iplist *list, const char *src)
15131690Sbrian{
15231962Sbrian  strncpy(list->src, src, sizeof list->src - 1);
15331962Sbrian  list->src[sizeof list->src - 1] = '\0';
15431690Sbrian  list->cur.srcptr = list->src;
15531690Sbrian  do {
15631690Sbrian    if (iplist_nextrange(list))
15731690Sbrian      list->nItems += list->cur.nItems;
15831690Sbrian    else
15931690Sbrian      return 0;
16031690Sbrian  } while (list->cur.srcptr != list->src);
16131690Sbrian  return 1;
16231690Sbrian}
16331690Sbrian
16431690Sbrianvoid
16531690Sbrianiplist_reset(struct iplist *list)
16631690Sbrian{
16731690Sbrian  list->src[0] = '\0';
16831690Sbrian  list->nItems = 0;
16931690Sbrian  list->cur.pos = -1;
17031690Sbrian}
17131690Sbrian
17231690Sbrianstruct in_addr
17337210Sbrianiplist_setcurpos(struct iplist *list, long pos)
17431690Sbrian{
175134789Sbrian  if (pos < 0 || (unsigned)pos >= list->nItems) {
17631690Sbrian    list->cur.pos = -1;
17731690Sbrian    list->cur.ip.s_addr = INADDR_ANY;
17831690Sbrian    return list->cur.ip;
17931690Sbrian  }
18031690Sbrian
18131690Sbrian  list->cur.srcptr = NULL;
18231690Sbrian  list->cur.pos = 0;
18331690Sbrian  while (1) {
18431690Sbrian    iplist_nextrange(list);
185134789Sbrian    if (pos < (int)list->cur.nItems) {
18631690Sbrian      if (pos) {
18731690Sbrian        list->cur.srcitem = pos;
18831690Sbrian        list->cur.pos += pos;
18931690Sbrian        list->cur.ip.s_addr = htonl(list->cur.lstart + list->cur.srcitem);
19031690Sbrian      }
19131690Sbrian      break;
19231690Sbrian    }
19331690Sbrian    pos -= list->cur.nItems;
19431690Sbrian    list->cur.pos += list->cur.nItems;
19531690Sbrian  }
19631690Sbrian
19731690Sbrian  return list->cur.ip;
19831690Sbrian}
19931690Sbrian
20031690Sbrianstruct in_addr
20131690Sbrianiplist_setrandpos(struct iplist *list)
20231690Sbrian{
20331690Sbrian  randinit();
20431690Sbrian  return iplist_setcurpos(list, random() % list->nItems);
20531690Sbrian}
20631690Sbrian
20731690Sbrianint
20831690Sbrianiplist_ip2pos(struct iplist *list, struct in_addr ip)
20931690Sbrian{
21031690Sbrian  struct iplist_cur cur;
21137210Sbrian  u_long f;
21237210Sbrian  int result;
21331690Sbrian
21431690Sbrian  result = -1;
21531962Sbrian  memcpy(&cur, &list->cur, sizeof cur);
21631690Sbrian
21731690Sbrian  for (iplist_first(list), f = 0; f < list->nItems; f++)
21831690Sbrian    if (iplist_next(list).s_addr == ip.s_addr) {
21931690Sbrian      result = list->cur.pos;
22031690Sbrian      break;
22131690Sbrian    }
22231690Sbrian
22331962Sbrian  memcpy(&list->cur, &cur, sizeof list->cur);
22431690Sbrian  return result;
22531690Sbrian}
226