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$ 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