Home | History | Annotate | Download | only in src
      1 /*-
      2  * Copyright (c) 1997 Brian Somers <brian (at) Awfulhak.org>
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     24  * SUCH DAMAGE.
     25  *
     26  * $FreeBSD: src/usr.sbin/ppp/iplist.c,v 1.10.26.1 2010/12/21 17:10:29 kensmith Exp $
     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