1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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 29 #include <sys/types.h> 30 #include <netinet/in.h> 31 #include <arpa/inet.h> 32 33 #include <stdlib.h> 34 #include <string.h> 35 #include <termios.h> 36 37 #include "log.h" 38 #include "defs.h" 39 #include "iplist.h" 40 41 static int 42 do_inet_aton(const char *start, const char *end, struct in_addr *ip) 43 { 44 char ipstr[16]; 45 46 if (end - start > 15) { 47 log_Printf(LogWARN, "%.*s: Invalid IP address\n", (int)(end-start), start); 48 return 0; 49 } 50 strncpy(ipstr, start, end-start); 51 ipstr[end-start] = '\0'; 52 return inet_aton(ipstr, ip); 53 } 54 55 static void 56 iplist_first(struct iplist *list) 57 { 58 list->cur.pos = -1; 59 } 60 61 static int 62 iplist_setrange(struct iplist *list, char *range) 63 { 64 char *ptr, *to; 65 66 if ((ptr = strpbrk(range, ",-")) == NULL) { 67 if (!inet_aton(range, &list->cur.ip)) 68 return 0; 69 list->cur.lstart = ntohl(list->cur.ip.s_addr); 70 list->cur.nItems = 1; 71 } else { 72 if (!do_inet_aton(range, ptr, &list->cur.ip)) 73 return 0; 74 if (*ptr == ',') { 75 list->cur.lstart = ntohl(list->cur.ip.s_addr); 76 list->cur.nItems = 1; 77 } else { 78 struct in_addr endip; 79 80 to = ptr+1; 81 if ((ptr = strpbrk(to, ",-")) == NULL) 82 ptr = to + strlen(to); 83 if (*to == '-') 84 return 0; 85 if (!do_inet_aton(to, ptr, &endip)) 86 return 0; 87 list->cur.lstart = ntohl(list->cur.ip.s_addr); 88 list->cur.nItems = ntohl(endip.s_addr) - list->cur.lstart + 1; 89 if (list->cur.nItems < 1) 90 return 0; 91 } 92 } 93 list->cur.srcitem = 0; 94 list->cur.srcptr = range; 95 return 1; 96 } 97 98 static int 99 iplist_nextrange(struct iplist *list) 100 { 101 char *ptr, *to, *end; 102 103 ptr = list->cur.srcptr; 104 if (ptr != NULL && (ptr = strchr(ptr, ',')) != NULL) 105 ptr++; 106 else 107 ptr = list->src; 108 109 while (*ptr != '\0' && !iplist_setrange(list, ptr)) { 110 if ((end = strchr(ptr, ',')) == NULL) 111 end = ptr + strlen(ptr); 112 if (end == ptr) 113 return 0; 114 log_Printf(LogWARN, "%.*s: Invalid IP range (skipping)\n", 115 (int)(end - ptr), ptr); 116 to = ptr; 117 do 118 *to = *end++; 119 while (*to++ != '\0'); 120 if (*ptr == '\0') 121 ptr = list->src; 122 } 123 124 return 1; 125 } 126 127 struct in_addr 128 iplist_next(struct iplist *list) 129 { 130 if (list->cur.pos == -1) { 131 list->cur.srcptr = NULL; 132 if (!iplist_nextrange(list)) { 133 list->cur.ip.s_addr = INADDR_ANY; 134 return list->cur.ip; 135 } 136 } else if (++list->cur.srcitem == list->cur.nItems) { 137 if (!iplist_nextrange(list)) { 138 list->cur.ip.s_addr = INADDR_ANY; 139 list->cur.pos = -1; 140 return list->cur.ip; 141 } 142 } else 143 list->cur.ip.s_addr = htonl(list->cur.lstart + list->cur.srcitem); 144 list->cur.pos++; 145 146 return list->cur.ip; 147 } 148 149 int 150 iplist_setsrc(struct iplist *list, const char *src) 151 { 152 strncpy(list->src, src, sizeof list->src - 1); 153 list->src[sizeof list->src - 1] = '\0'; 154 list->cur.srcptr = list->src; 155 do { 156 if (iplist_nextrange(list)) 157 list->nItems += list->cur.nItems; 158 else 159 return 0; 160 } while (list->cur.srcptr != list->src); 161 return 1; 162 } 163 164 void 165 iplist_reset(struct iplist *list) 166 { 167 list->src[0] = '\0'; 168 list->nItems = 0; 169 list->cur.pos = -1; 170 } 171 172 struct in_addr 173 iplist_setcurpos(struct iplist *list, long pos) 174 { 175 if (pos < 0 || (unsigned)pos >= list->nItems) { 176 list->cur.pos = -1; 177 list->cur.ip.s_addr = INADDR_ANY; 178 return list->cur.ip; 179 } 180 181 list->cur.srcptr = NULL; 182 list->cur.pos = 0; 183 while (1) { 184 iplist_nextrange(list); 185 if (pos < (int)list->cur.nItems) { 186 if (pos) { 187 list->cur.srcitem = pos; 188 list->cur.pos += pos; 189 list->cur.ip.s_addr = htonl(list->cur.lstart + list->cur.srcitem); 190 } 191 break; 192 } 193 pos -= list->cur.nItems; 194 list->cur.pos += list->cur.nItems; 195 } 196 197 return list->cur.ip; 198 } 199 200 struct in_addr 201 iplist_setrandpos(struct iplist *list) 202 { 203 randinit(); 204 return iplist_setcurpos(list, random() % list->nItems); 205 } 206 207 int 208 iplist_ip2pos(struct iplist *list, struct in_addr ip) 209 { 210 struct iplist_cur cur; 211 u_long f; 212 int result; 213 214 result = -1; 215 memcpy(&cur, &list->cur, sizeof cur); 216 217 for (iplist_first(list), f = 0; f < list->nItems; f++) 218 if (iplist_next(list).s_addr == ip.s_addr) { 219 result = list->cur.pos; 220 break; 221 } 222 223 memcpy(&list->cur, &cur, sizeof list->cur); 224 return result; 225 } 226