"Fossies" - the Fresh Open Source Software Archive

Member "haproxy-2.0.9/contrib/iprange/iprange.c" (15 Nov 2019, 6051 Bytes) of package /linux/misc/haproxy-2.0.9.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "iprange.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * network range to IP+mask converter
    3  *
    4  * Copyright 2011-2012 Willy Tarreau <w@1wt.eu>
    5  *
    6  * This program reads lines starting by two IP addresses and outputs them with
    7  * the two IP addresses replaced by a netmask covering the range between these
    8  * IPs (inclusive). When multiple ranges are needed, as many lines are emitted.
    9  * The IP addresses may be delimited by spaces, tabs or commas. Quotes are
   10  * stripped, and lines beginning with a sharp character ('#') are ignored. The
   11  * IP addresses may be either in the dotted format or represented as a 32-bit
   12  * integer value in network byte order.
   13  *
   14  * This program is free software; you can redistribute it and/or
   15  * modify it under the terms of the GNU General Public License
   16  * as published by the Free Software Foundation; either version
   17  * 2 of the License, or (at your option) any later version.
   18  */
   19 
   20 #include <sys/types.h>
   21 #include <sys/socket.h>
   22 #include <arpa/inet.h>
   23 #include <stdio.h>
   24 #include <stdlib.h>
   25 #include <string.h>
   26 
   27 #define MAXLINE 1024
   28 
   29 /* returns a string version of an IPv4 address in host order */
   30 static const char *get_ipv4_addr(unsigned int addr)
   31 {
   32     struct in_addr a;
   33 
   34     a.s_addr = ntohl(addr);
   35     return inet_ntoa(a);
   36 }
   37 
   38 /* print all networks present between address <low> and address <high> in
   39  * cidr format, followed by <eol>.
   40  */
   41 static void convert_range(unsigned int low, unsigned int high, const char *eol, const char *pfx)
   42 {
   43     int bit;
   44 
   45     if (low == high) {
   46         /* single value */
   47         printf("%s%s%s%s\n", pfx?pfx:"", pfx?" ":"", get_ipv4_addr(low), eol);
   48         return;
   49     }
   50     else if (low > high) {
   51         int swap = low;
   52         low = high;
   53         high = swap;
   54     }
   55 
   56     if (low == high + 1) {
   57         /* full range */
   58         printf("%s%s0.0.0.0/0%s\n", pfx?pfx:"", pfx?" ":"", eol);
   59         return;
   60     }
   61     //printf("low=%08x high=%08x\n", low, high);
   62 
   63     bit = 0;
   64     while (bit < 32 && low + (1 << bit) - 1 <= high) {
   65         /* enlarge mask */
   66         if (low & (1 << bit)) {
   67             /* can't aggregate anymore, dump and retry from the same bit */
   68             printf("%s%s%s/%d%s\n", pfx?pfx:"", pfx?" ":"", get_ipv4_addr(low), 32-bit, eol);
   69             low += (1 << bit);
   70         }
   71         else {
   72             /* try to enlarge the mask as much as possible first */
   73             bit++;
   74             //printf("  ++bit=%d\n", bit);
   75         }
   76     }
   77     //printf("stopped 1 at low=%08x, bit=%d\n", low, bit);
   78 
   79     bit = 31;
   80     while (bit >= 0 && high - low + 1 != 0) {
   81         /* shrink mask */
   82         if ((high - low + 1) & (1 << bit)) {
   83             /* large bit accepted, dump and go on from the same bit */
   84             //printf("max: %08x/%d\n", low, 32-bit);
   85             printf("%s%s%s/%d%s\n", pfx?pfx:"", pfx?" ":"", get_ipv4_addr(low), 32-bit, eol);
   86             low += (1 << bit);
   87         }
   88         else {
   89             bit--;
   90             //printf("  --bit=%d, low=%08x\n", bit, low);
   91         }
   92     }
   93     //printf("stopped at low=%08x\n", low);
   94 }
   95 
   96 static void usage(const char *argv0)
   97 {
   98     fprintf(stderr,
   99             "Usage: %s [<addr> ...] < iplist.csv\n"
  100             "\n"
  101             "This program reads lines starting by two IP addresses and outputs them with\n"
  102             "the two IP addresses replaced by a netmask covering the range between these\n"
  103             "IPs (inclusive). When multiple ranges are needed, as many lines are emitted.\n"
  104             "The IP addresses may be delimited by spaces, tabs or commas. Quotes are\n"
  105             "stripped, and lines beginning with a sharp character ('#') are ignored. The\n"
  106             "IP addresses may be either in the dotted format or represented as a 32-bit\n"
  107             "integer value in network byte order.\n"
  108         "\n"
  109         "For each optional <addr> specified, only the network it belongs to is returned,\n"
  110         "prefixed with the <addr> value.\n"
  111         "\n", argv0);
  112 }
  113 
  114 int main(int argc, char **argv)
  115 {
  116     char line[MAXLINE];
  117     int l, lnum;
  118     char *lb, *le, *hb, *he, *err;
  119     struct in_addr src_addr, dst_addr;
  120     unsigned int sa, da, ta;
  121 
  122     if (argc > 1 && *argv[1] == '-') {
  123         usage(argv[0]);
  124         exit(1);
  125     }
  126 
  127     lnum = 0;
  128     while (fgets(line, sizeof(line), stdin) != NULL) {
  129         l = strlen(line);
  130         if (l && line[l - 1] == '\n')
  131             line[--l] = '\0';
  132 
  133         lnum++;
  134         /* look for the first field which must be the low address of a range,
  135          * in dotted IPv4 format or as an integer. spaces and commas are
  136          * considered as delimiters, quotes are removed.
  137          */
  138         for (lb = line; *lb == ' ' || *lb == '\t' || *lb == ',' || *lb == '"'; lb++);
  139         if (!*lb || *lb == '#')
  140             continue;
  141         for (le = lb + 1; *le != ' ' && *le != '\t' && *le != ',' && *le != '"' && *le; le++);
  142         if (!*le)
  143             continue;
  144         /* we have the low address between lb(included) and le(excluded) */
  145         *(le++) = 0;
  146 
  147         for (hb = le; *hb == ' ' || *hb == '\t' || *hb == ',' || *hb == '"'; hb++);
  148         if (!*hb || *hb == '#')
  149             continue;
  150         for (he = hb + 1; *he != ' ' && *he != '\t' && *he != ',' && *he != '"' && *he; he++);
  151         if (!*he)
  152             continue;
  153         /* we have the high address between hb(included) and he(excluded) */
  154         *(he++) = 0;
  155 
  156         /* we want to remove a possible ending quote and a possible comma,
  157          * not more.
  158          */
  159         while (*he == '"')
  160             *(he++) = ' ';
  161         while (*he == ',' || *he == ' ' || *he == '\t')
  162             *(he++) = ' ';
  163 
  164         /* if the trailing string is not empty, prefix it with a space */
  165         if (*(he-1) == ' ')
  166             he--;
  167 
  168         if (inet_pton(AF_INET, lb, &src_addr) <= 0) {
  169             /* parsing failed, retry with a plain numeric IP */
  170             src_addr.s_addr = ntohl(strtoul(lb, &err, 10));
  171             if (err && *err) {
  172                 fprintf(stderr, "Failed to parse source address <%s> at line %d, skipping line\n", lb, lnum);
  173                 continue;
  174             }
  175         }
  176 
  177         if (inet_pton(AF_INET, hb, &dst_addr) <= 0) {
  178             /* parsing failed, retry with a plain numeric IP */
  179             dst_addr.s_addr = ntohl(strtoul(hb, &err, 10));
  180             if (err && *err) {
  181                 fprintf(stderr, "Failed to parse destination address <%s> at line %d, skipping line\n", hb, lnum);
  182                 continue;
  183             }
  184         }
  185 
  186         sa = htonl(src_addr.s_addr);
  187         da = htonl(dst_addr.s_addr);
  188         if (argc > 1) {
  189             for (l = 1; l < argc; l++) {
  190                 if (inet_pton(AF_INET, argv[l], &dst_addr) <= 0)
  191                     continue;
  192                 ta = htonl(dst_addr.s_addr);
  193                 if ((sa <= ta && ta <= da) || (da <= ta && ta <= sa))
  194                     convert_range(sa, da, he, argv[l]);
  195             }
  196         }
  197         else {
  198             convert_range(sa, da, he, NULL);
  199         }
  200     }
  201     exit(0);
  202 }