iplist.c revision 31690
131690Sbrian/*
231690Sbrian * $Id:$
331690Sbrian */
431690Sbrian
531690Sbrian#include <sys/types.h>
631690Sbrian#include <netinet/in.h>
731690Sbrian#include <arpa/inet.h>
831690Sbrian
931690Sbrian#include <stdlib.h>
1031690Sbrian#include <string.h>
1131690Sbrian
1231690Sbrian#include "command.h"
1331690Sbrian#include "mbuf.h"
1431690Sbrian#include "log.h"
1531690Sbrian#include "defs.h"
1631690Sbrian#include "iplist.h"
1731690Sbrian
1831690Sbrianstatic int
1931690Sbriando_inet_aton(const char *start, const char *end, struct in_addr *ip)
2031690Sbrian{
2131690Sbrian  static char ipstr[16];
2231690Sbrian
2331690Sbrian  if (end - start > 15) {
2431690Sbrian    LogPrintf(LogWARN, "%.*s: Invalid IP address\n", end-start, start);
2531690Sbrian    return 0;
2631690Sbrian  }
2731690Sbrian  strncpy(ipstr, start, end-start);
2831690Sbrian  ipstr[end-start] = '\0';
2931690Sbrian  return inet_aton(ipstr, ip);
3031690Sbrian}
3131690Sbrian
3231690Sbrianstatic void
3331690Sbrianiplist_first(struct iplist *list)
3431690Sbrian{
3531690Sbrian  list->cur.pos = -1;
3631690Sbrian}
3731690Sbrian
3831690Sbrianstatic int
3931690Sbrianiplist_setrange(struct iplist *list, char *range)
4031690Sbrian{
4131690Sbrian  char *ptr, *to;
4231690Sbrian
4331690Sbrian  if ((ptr = strpbrk(range, ",-")) == NULL) {
4431690Sbrian    if (!inet_aton(range, &list->cur.ip))
4531690Sbrian      return 0;
4631690Sbrian    list->cur.lstart = ntohl(list->cur.ip.s_addr);
4731690Sbrian    list->cur.nItems = 1;
4831690Sbrian  } else {
4931690Sbrian    if (!do_inet_aton(range, ptr, &list->cur.ip))
5031690Sbrian      return 0;
5131690Sbrian    if (*ptr == ',') {
5231690Sbrian      list->cur.lstart = ntohl(list->cur.ip.s_addr);
5331690Sbrian      list->cur.nItems = 1;
5431690Sbrian    } else {
5531690Sbrian      struct in_addr endip;
5631690Sbrian
5731690Sbrian      to = ptr+1;
5831690Sbrian      if ((ptr = strpbrk(to, ",-")) == NULL)
5931690Sbrian        ptr = to + strlen(to);
6031690Sbrian      if (*to == '-')
6131690Sbrian        return 0;
6231690Sbrian      if (!do_inet_aton(to, ptr, &endip))
6331690Sbrian        return 0;
6431690Sbrian      list->cur.lstart = ntohl(list->cur.ip.s_addr);
6531690Sbrian      list->cur.nItems = ntohl(endip.s_addr) - list->cur.lstart + 1;
6631690Sbrian      if (list->cur.nItems < 1)
6731690Sbrian        return 0;
6831690Sbrian    }
6931690Sbrian  }
7031690Sbrian  list->cur.srcitem = 0;
7131690Sbrian  list->cur.srcptr = range;
7231690Sbrian  return 1;
7331690Sbrian}
7431690Sbrian
7531690Sbrianstatic int
7631690Sbrianiplist_nextrange(struct iplist *list)
7731690Sbrian{
7831690Sbrian  char *ptr, *to, *end;
7931690Sbrian
8031690Sbrian  ptr = list->cur.srcptr;
8131690Sbrian  if (ptr != NULL && (ptr = strchr(ptr, ',')) != NULL)
8231690Sbrian    ptr++;
8331690Sbrian  else
8431690Sbrian    ptr = list->src;
8531690Sbrian
8631690Sbrian  while (*ptr != '\0' && !iplist_setrange(list, ptr)) {
8731690Sbrian    if ((end = strchr(ptr, ',')) == NULL)
8831690Sbrian      end = ptr + strlen(ptr);
8931690Sbrian    if (end == ptr)
9031690Sbrian      return 0;
9131690Sbrian    LogPrintf(LogWARN, "%.*s: Invalid IP range (skipping)\n", end - ptr, ptr);
9231690Sbrian    to = ptr;
9331690Sbrian    do
9431690Sbrian      *to = *end++;
9531690Sbrian    while (*to++ != '\0');
9631690Sbrian    if (*ptr == '\0')
9731690Sbrian      ptr = list->src;
9831690Sbrian  }
9931690Sbrian
10031690Sbrian  return 1;
10131690Sbrian}
10231690Sbrian
10331690Sbrianstruct in_addr
10431690Sbrianiplist_next(struct iplist *list)
10531690Sbrian{
10631690Sbrian  if (list->cur.pos == -1) {
10731690Sbrian    list->cur.srcptr = NULL;
10831690Sbrian    if (!iplist_nextrange(list)) {
10931690Sbrian      list->cur.ip.s_addr = INADDR_ANY;
11031690Sbrian      return list->cur.ip;
11131690Sbrian    }
11231690Sbrian  } else if (++list->cur.srcitem == list->cur.nItems) {
11331690Sbrian    if (!iplist_nextrange(list)) {
11431690Sbrian      list->cur.ip.s_addr = INADDR_ANY;
11531690Sbrian      list->cur.pos = -1;
11631690Sbrian      return list->cur.ip;
11731690Sbrian    }
11831690Sbrian  } else
11931690Sbrian    list->cur.ip.s_addr = htonl(list->cur.lstart + list->cur.srcitem);
12031690Sbrian  list->cur.pos++;
12131690Sbrian
12231690Sbrian  return list->cur.ip;
12331690Sbrian}
12431690Sbrian
12531690Sbrianint
12631690Sbrianiplist_setsrc(struct iplist *list, const char *src)
12731690Sbrian{
12831690Sbrian  strncpy(list->src, src, sizeof(list->src));
12931690Sbrian  list->src[sizeof(list->src)-1] = '\0';
13031690Sbrian  list->cur.srcptr = list->src;
13131690Sbrian  do {
13231690Sbrian    if (iplist_nextrange(list))
13331690Sbrian      list->nItems += list->cur.nItems;
13431690Sbrian    else
13531690Sbrian      return 0;
13631690Sbrian  } while (list->cur.srcptr != list->src);
13731690Sbrian  return 1;
13831690Sbrian}
13931690Sbrian
14031690Sbrianvoid
14131690Sbrianiplist_reset(struct iplist *list)
14231690Sbrian{
14331690Sbrian  list->src[0] = '\0';
14431690Sbrian  list->nItems = 0;
14531690Sbrian  list->cur.pos = -1;
14631690Sbrian}
14731690Sbrian
14831690Sbrianstruct in_addr
14931690Sbrianiplist_setcurpos(struct iplist *list, int pos)
15031690Sbrian{
15131690Sbrian  if (pos < 0 || pos >= list->nItems) {
15231690Sbrian    list->cur.pos = -1;
15331690Sbrian    list->cur.ip.s_addr = INADDR_ANY;
15431690Sbrian    return list->cur.ip;
15531690Sbrian  }
15631690Sbrian
15731690Sbrian  list->cur.srcptr = NULL;
15831690Sbrian  list->cur.pos = 0;
15931690Sbrian  while (1) {
16031690Sbrian    iplist_nextrange(list);
16131690Sbrian    if (pos < list->cur.nItems) {
16231690Sbrian      if (pos) {
16331690Sbrian        list->cur.srcitem = pos;
16431690Sbrian        list->cur.pos += pos;
16531690Sbrian        list->cur.ip.s_addr = htonl(list->cur.lstart + list->cur.srcitem);
16631690Sbrian      }
16731690Sbrian      break;
16831690Sbrian    }
16931690Sbrian    pos -= list->cur.nItems;
17031690Sbrian    list->cur.pos += list->cur.nItems;
17131690Sbrian  }
17231690Sbrian
17331690Sbrian  return list->cur.ip;
17431690Sbrian}
17531690Sbrian
17631690Sbrianstruct in_addr
17731690Sbrianiplist_setrandpos(struct iplist *list)
17831690Sbrian{
17931690Sbrian  randinit();
18031690Sbrian  return iplist_setcurpos(list, random() % list->nItems);
18131690Sbrian}
18231690Sbrian
18331690Sbrianint
18431690Sbrianiplist_ip2pos(struct iplist *list, struct in_addr ip)
18531690Sbrian{
18631690Sbrian  struct iplist_cur cur;
18731690Sbrian  int f, result;
18831690Sbrian
18931690Sbrian  result = -1;
19031690Sbrian  memcpy(&cur, &list->cur, sizeof(cur));
19131690Sbrian
19231690Sbrian  for (iplist_first(list), f = 0; f < list->nItems; f++)
19331690Sbrian    if (iplist_next(list).s_addr == ip.s_addr) {
19431690Sbrian      result = list->cur.pos;
19531690Sbrian      break;
19631690Sbrian    }
19731690Sbrian
19831690Sbrian  memcpy(&list->cur, &cur, sizeof(list->cur));
19931690Sbrian  return result;
20031690Sbrian}
201