iplist.c revision 330449
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 1997 Brian Somers <brian@Awfulhak.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $FreeBSD: stable/11/usr.sbin/ppp/iplist.c 330449 2018-03-05 07:26:05Z eadler $
29 */
30
31#include <sys/types.h>
32#include <netinet/in.h>
33#include <arpa/inet.h>
34
35#include <stdlib.h>
36#include <string.h>
37#include <termios.h>
38
39#include "log.h"
40#include "defs.h"
41#include "iplist.h"
42
43static int
44do_inet_aton(const char *start, const char *end, struct in_addr *ip)
45{
46  char ipstr[16];
47
48  if (end - start > 15) {
49    log_Printf(LogWARN, "%.*s: Invalid IP address\n", (int)(end-start), start);
50    return 0;
51  }
52  strncpy(ipstr, start, end-start);
53  ipstr[end-start] = '\0';
54  return inet_aton(ipstr, ip);
55}
56
57static void
58iplist_first(struct iplist *list)
59{
60  list->cur.pos = -1;
61}
62
63static int
64iplist_setrange(struct iplist *list, char *range)
65{
66  char *ptr, *to;
67
68  if ((ptr = strpbrk(range, ",-")) == NULL) {
69    if (!inet_aton(range, &list->cur.ip))
70      return 0;
71    list->cur.lstart = ntohl(list->cur.ip.s_addr);
72    list->cur.nItems = 1;
73  } else {
74    if (!do_inet_aton(range, ptr, &list->cur.ip))
75      return 0;
76    if (*ptr == ',') {
77      list->cur.lstart = ntohl(list->cur.ip.s_addr);
78      list->cur.nItems = 1;
79    } else {
80      struct in_addr endip;
81
82      to = ptr+1;
83      if ((ptr = strpbrk(to, ",-")) == NULL)
84        ptr = to + strlen(to);
85      if (*to == '-')
86        return 0;
87      if (!do_inet_aton(to, ptr, &endip))
88        return 0;
89      list->cur.lstart = ntohl(list->cur.ip.s_addr);
90      list->cur.nItems = ntohl(endip.s_addr) - list->cur.lstart + 1;
91      if (list->cur.nItems < 1)
92        return 0;
93    }
94  }
95  list->cur.srcitem = 0;
96  list->cur.srcptr = range;
97  return 1;
98}
99
100static int
101iplist_nextrange(struct iplist *list)
102{
103  char *ptr, *to, *end;
104
105  ptr = list->cur.srcptr;
106  if (ptr != NULL && (ptr = strchr(ptr, ',')) != NULL)
107    ptr++;
108  else
109    ptr = list->src;
110
111  while (*ptr != '\0' && !iplist_setrange(list, ptr)) {
112    if ((end = strchr(ptr, ',')) == NULL)
113      end = ptr + strlen(ptr);
114    if (end == ptr)
115      return 0;
116    log_Printf(LogWARN, "%.*s: Invalid IP range (skipping)\n",
117               (int)(end - ptr), ptr);
118    to = ptr;
119    do
120      *to = *end++;
121    while (*to++ != '\0');
122    if (*ptr == '\0')
123      ptr = list->src;
124  }
125
126  return 1;
127}
128
129struct in_addr
130iplist_next(struct iplist *list)
131{
132  if (list->cur.pos == -1) {
133    list->cur.srcptr = NULL;
134    if (!iplist_nextrange(list)) {
135      list->cur.ip.s_addr = INADDR_ANY;
136      return list->cur.ip;
137    }
138  } else if (++list->cur.srcitem == list->cur.nItems) {
139    if (!iplist_nextrange(list)) {
140      list->cur.ip.s_addr = INADDR_ANY;
141      list->cur.pos = -1;
142      return list->cur.ip;
143    }
144  } else
145    list->cur.ip.s_addr = htonl(list->cur.lstart + list->cur.srcitem);
146  list->cur.pos++;
147
148  return list->cur.ip;
149}
150
151int
152iplist_setsrc(struct iplist *list, const char *src)
153{
154  strncpy(list->src, src, sizeof list->src - 1);
155  list->src[sizeof list->src - 1] = '\0';
156  list->cur.srcptr = list->src;
157  do {
158    if (iplist_nextrange(list))
159      list->nItems += list->cur.nItems;
160    else
161      return 0;
162  } while (list->cur.srcptr != list->src);
163  return 1;
164}
165
166void
167iplist_reset(struct iplist *list)
168{
169  list->src[0] = '\0';
170  list->nItems = 0;
171  list->cur.pos = -1;
172}
173
174struct in_addr
175iplist_setcurpos(struct iplist *list, long pos)
176{
177  if (pos < 0 || (unsigned)pos >= list->nItems) {
178    list->cur.pos = -1;
179    list->cur.ip.s_addr = INADDR_ANY;
180    return list->cur.ip;
181  }
182
183  list->cur.srcptr = NULL;
184  list->cur.pos = 0;
185  while (1) {
186    iplist_nextrange(list);
187    if (pos < (int)list->cur.nItems) {
188      if (pos) {
189        list->cur.srcitem = pos;
190        list->cur.pos += pos;
191        list->cur.ip.s_addr = htonl(list->cur.lstart + list->cur.srcitem);
192      }
193      break;
194    }
195    pos -= list->cur.nItems;
196    list->cur.pos += list->cur.nItems;
197  }
198
199  return list->cur.ip;
200}
201
202struct in_addr
203iplist_setrandpos(struct iplist *list)
204{
205  randinit();
206  return iplist_setcurpos(list, random() % list->nItems);
207}
208
209int
210iplist_ip2pos(struct iplist *list, struct in_addr ip)
211{
212  struct iplist_cur cur;
213  u_long f;
214  int result;
215
216  result = -1;
217  memcpy(&cur, &list->cur, sizeof cur);
218
219  for (iplist_first(list), f = 0; f < list->nItems; f++)
220    if (iplist_next(list).s_addr == ip.s_addr) {
221      result = list->cur.pos;
222      break;
223    }
224
225  memcpy(&list->cur, &cur, sizeof list->cur);
226  return result;
227}
228