owipcalc: separate in client and lib
authorNick Hainke <vincent@systemli.org>
Sat, 23 Jan 2021 12:54:41 +0000 (13:54 +0100)
committerPolynomdivision <vincent@systemli.org>
Mon, 15 Feb 2021 09:45:41 +0000 (10:45 +0100)
Separate owipcalc in client and lib part. Owipcalc brings a lot of nice
functionality with it, e.g. parsing and calculating prefixes.

Signed-off-by: Nick Hainke <vincent@systemli.org>
net/owipcalc/Makefile
net/owipcalc/src/main.c [new file with mode: 0644]
net/owipcalc/src/owipcalc.c
net/owipcalc/src/owipcalc.h [new file with mode: 0644]

index c7857f5c87172e65cf1207b9637d3efea5b08d1c..2865b1c7c4ea03c91b8757e4d21dce2dcbc0082b 100644 (file)
@@ -12,12 +12,12 @@ PKG_LICENSE:=Apache-2.0
 
 include $(INCLUDE_DIR)/package.mk
 
-
 define Package/owipcalc
   SECTION:=utils
   CATEGORY:=Utilities
   TITLE:=Simple IPv4/IPv6 address calculator
   MAINTAINER:=Jo-Philipp Wich <jo@mein.io>
+  DEPENDS:=+libowipcalc
 endef
 
 define Package/owipcalc/description
@@ -27,18 +27,45 @@ define Package/owipcalc/description
   for dhcp pools.
 endef
 
+define Package/libowipcalc
+  SECTION:=libs
+  CATEGORY:=Libraries
+  TITLE:=Owipcalc Library
+endef
+
+define Package/libowipcalc/description
+  The owipcalc library supports a number of calculations and tests to work
+  with ip-address ranges, this is useful for programms that e.g. need to
+  partition ipv6-prefixes into small subnets or to calculate address ranges
+  for dhcp pools.
+endef
+
 define Build/Configure
 endef
 
 define Build/Compile
        $(TARGET_CC) $(TARGET_CFLAGS) \
-               -o $(PKG_BUILD_DIR)/owipcalc $(PKG_BUILD_DIR)/owipcalc.c
+               -shared -fPIC -o $(PKG_BUILD_DIR)/libowipcalc.so $(PKG_BUILD_DIR)/owipcalc.c
+       $(TARGET_CC) $(TARGET_CFLAGS) \
+               -o $(PKG_BUILD_DIR)/owipcalc $(PKG_BUILD_DIR)/main.c -L$(PKG_BUILD_DIR)/ -lowipcalc
 endef
 
+define Build/InstallDev
+       $(INSTALL_DIR) $(1)/usr/include/
+       $(CP) $(PKG_BUILD_DIR)/owipcalc.h $(1)/usr/include/
+       $(INSTALL_DIR) $(1)/usr/lib
+       $(INSTALL_BIN) $(PKG_BUILD_DIR)/libowipcalc.so $(1)/usr/lib/libowipcalc.so
+endef
 
 define Package/owipcalc/install
        $(INSTALL_DIR) $(1)/usr/bin
        $(INSTALL_BIN) $(PKG_BUILD_DIR)/owipcalc $(1)/usr/bin/owipcalc
 endef
 
+define Package/libowipcalc/install
+       $(INSTALL_DIR) $(1)/usr/lib
+       $(INSTALL_BIN) $(PKG_BUILD_DIR)/libowipcalc.so $(1)/usr/lib/libowipcalc.so
+endef
+
+$(eval $(call BuildPackage,libowipcalc))
 $(eval $(call BuildPackage,owipcalc))
diff --git a/net/owipcalc/src/main.c b/net/owipcalc/src/main.c
new file mode 100644 (file)
index 0000000..c47ba3f
--- /dev/null
@@ -0,0 +1,279 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <arpa/inet.h>
+
+#include "owipcalc.h"
+
+struct op {
+       const char *name;
+       const char *desc;
+       struct {
+               bool (*a1)(struct cidr *a);
+               bool (*a2)(struct cidr *a, struct cidr *b);
+       } f4;
+       struct {
+               bool (*a1)(struct cidr *a);
+               bool (*a2)(struct cidr *a, struct cidr *b);
+       } f6;
+};
+
+struct op ops[] = {
+       { .name = "add",
+         .desc = "Add argument to base address",
+         .f4.a2 = cidr_add4,
+         .f6.a2 = cidr_add6 },
+
+       { .name = "sub",
+         .desc = "Substract argument from base address",
+         .f4.a2 = cidr_sub4,
+         .f6.a2 = cidr_sub6 },
+
+       { .name = "next",
+         .desc = "Advance base address to next prefix of given size",
+         .f4.a2 = cidr_next4,
+         .f6.a2 = cidr_next6 },
+
+       { .name = "prev",
+         .desc = "Lower base address to previous prefix of give size",
+         .f4.a2 = cidr_prev4,
+         .f6.a2 = cidr_prev6 },
+
+       { .name = "network",
+         .desc = "Turn base address into network address",
+         .f4.a1 = cidr_network4,
+         .f6.a1 = cidr_network6 },
+
+       { .name = "broadcast",
+         .desc = "Turn base address into broadcast address",
+         .f4.a1 = cidr_broadcast4 },
+
+       { .name = "prefix",
+         .desc = "Set the prefix of base address to argument",
+         .f4.a2 = cidr_prefix,
+         .f6.a2 = cidr_prefix },
+
+       { .name = "netmask",
+         .desc = "Calculate netmask of base address",
+         .f4.a1 = cidr_netmask4 },
+
+       { .name = "6to4",
+         .desc = "Calculate 6to4 prefix of given ipv4-address",
+         .f4.a1 = cidr_6to4 },
+
+       { .name = "howmany",
+         .desc = "Print amount of righ-hand prefixes that fit into base address",
+         .f4.a2 = cidr_howmany,
+         .f6.a2 = cidr_howmany },
+
+       { .name = "contains",
+         .desc = "Print '1' if argument fits into base address or '0' if not",
+         .f4.a2 = cidr_contains4,
+         .f6.a2 = cidr_contains6 },
+
+       { .name = "private",
+         .desc = "Print '1' if base address is in RFC1918 private space or '0' "
+                 "if not",
+         .f4.a1 = cidr_private4 },
+
+       { .name = "linklocal",
+         .desc = "Print '1' if base address is in 169.254.0.0/16 or FE80::/10 "
+                 "link local space or '0' if not",
+         .f4.a1 = cidr_linklocal4,
+         .f6.a1 = cidr_linklocal6 },
+
+       { .name = "ula",
+         .desc = "Print '1' if base address is in FC00::/7 unique local address "
+                 "(ULA) space or '0' if not",
+         .f6.a1 = cidr_ula6 },
+
+       { .name = "quiet",
+         .desc = "Suppress output, useful for test operation where the result can "
+                 "be inferred from the exit code",
+         .f4.a1 = cidr_quiet,
+         .f6.a1 = cidr_quiet },
+
+       { .name = "pop",
+         .desc = "Pop intermediate result from stack",
+         .f4.a1 = cidr_pop,
+         .f6.a1 = cidr_pop },
+
+       { .name = "print",
+         .desc = "Print intermediate result and pop it from stack, invoked "
+                 "implicitely at the end of calculation if no intermediate prints "
+                 "happened",
+         .f4.a1 = cidr_print4,
+         .f6.a1 = cidr_print6 },
+};
+
+static void usage(const char *prog)
+{
+       int i;
+
+       fprintf(stderr,
+               "\n"
+               "Usage:\n\n"
+               "  %s {base address} operation [argument] "
+               "[operation [argument] ...]\n\n"
+               "Operations:\n\n",
+               prog);
+
+       for (i = 0; i < sizeof(ops) / sizeof(ops[0]); i++)
+       {
+               if (ops[i].f4.a2 || ops[i].f6.a2)
+               {
+                       fprintf(stderr, "  %s %s\n",
+                               ops[i].name,
+                               (ops[i].f4.a2 && ops[i].f6.a2) ? "{ipv4/ipv6/amount}" :
+                                (ops[i].f6.a2 ? "{ipv6/amount}" : "{ipv4/amount}"));
+               }
+               else
+               {
+                       fprintf(stderr, "  %s\n", ops[i].name);
+               }
+
+               fprintf(stderr, "    %s.\n", ops[i].desc);
+
+               if ((ops[i].f4.a1 && ops[i].f6.a1) || (ops[i].f4.a2 && ops[i].f6.a2))
+                       fprintf(stderr, "    Applicable to ipv4- and ipv6-addresses.\n\n");
+               else if (ops[i].f6.a2 || ops[i].f6.a1)
+                       fprintf(stderr, "    Only applicable to ipv6-addresses.\n\n");
+               else
+                       fprintf(stderr, "    Only applicable to ipv4-addresses.\n\n");
+       }
+
+       fprintf(stderr,
+               "Examples:\n\n"
+               " Calculate a DHCP range:\n\n"
+               "  $ %s 192.168.1.1/255.255.255.0 network add 100 print add 150 print\n"
+                       "  192.168.1.100\n"
+                       "  192.168.1.250\n\n"
+                       " Count number of prefixes:\n\n"
+                       "  $ %s 2001:0DB8:FDEF::/48 howmany ::/64\n"
+                       "  65536\n\n",
+               prog, prog);
+
+       exit(1);
+}
+
+static bool runop(char ***arg, int *status)
+{
+       int i;
+       char *arg1 = **arg;
+       char *arg2 = *(*arg+1);
+       struct cidr *a = stack;
+       struct cidr *b = NULL;
+
+       if (!arg1)
+               return false;
+
+       for (i = 0; i < sizeof(ops) / sizeof(ops[0]); i++)
+       {
+               if (!strcmp(ops[i].name, arg1))
+               {
+                       if (ops[i].f4.a2 || ops[i].f6.a2)
+                       {
+                               if (!arg2)
+                               {
+                                       fprintf(stderr, "'%s' requires an argument\n",
+                                                       ops[i].name);
+
+                                       *status = 2;
+                                       return false;
+                               }
+
+                               b = cidr_parse(ops[i].name, arg2, a->family);
+
+                               if (!b)
+                               {
+                                       fprintf(stderr, "invalid address argument for '%s'\n",
+                                                       ops[i].name);
+
+                                       *status = 3;
+                                       return false;
+                               }
+
+                               *arg += 2;
+
+                               if (((a->family == AF_INET)  && !ops[i].f4.a2) ||
+                                       ((a->family == AF_INET6) && !ops[i].f6.a2))
+                               {
+                                       fprintf(stderr, "'%s' not supported for %s addresses\n",
+                                               ops[i].name,
+                                                       (a->family == AF_INET) ? "ipv4" : "ipv6");
+
+                                       *status = 5;
+                                       return false;
+                               }
+
+                               *status = !((a->family == AF_INET) ? ops[i].f4.a2(a, b)
+                                                                  : ops[i].f6.a2(a, b));
+
+                               return true;
+                       }
+                       else
+                       {
+                               *arg += 1;
+
+                               if (((a->family == AF_INET)  && !ops[i].f4.a1) ||
+                                       ((a->family == AF_INET6) && !ops[i].f6.a1))
+                               {
+                                       fprintf(stderr, "'%s' not supported for %s addresses\n",
+                                               ops[i].name,
+                                                       (a->family == AF_INET) ? "ipv4" : "ipv6");
+
+                                       *status = 5;
+                                       return false;
+                               }
+
+                               *status = !((a->family == AF_INET) ? ops[i].f4.a1(a)
+                                                                  : ops[i].f6.a1(a));
+
+                               return true;
+                       }
+               }
+       }
+
+       return false;
+}
+
+int main(int argc, char **argv)
+{
+       int status = 0;
+       char **arg = argv+2;
+       struct cidr *a;
+
+       // enable printing
+       quiet = false;
+
+       if (argc < 3)
+               usage(argv[0]);
+
+       a = strchr(argv[1], ':') ? cidr_parse6(argv[1]) : cidr_parse4(argv[1]);
+
+       if (!a)
+               usage(argv[0]);
+
+       cidr_push(a);
+
+       while (runop(&arg, &status));
+
+       if (*arg)
+       {
+               fprintf(stderr, "unknown operation '%s'\n", *arg);
+               exit(6);
+       }
+
+       if (!printed && (status < 2))
+       {
+               if (stack->family == AF_INET)
+                       cidr_print4(stack);
+               else
+                       cidr_print6(stack);
+       }
+
+       qprintf("\n");
+
+       exit(status);
+}
index fa656948b0756fe0914e1580460ae2bf46e89f18..e69654715ba2d646b2292e5d3d58f6e2a7957816 100644 (file)
@@ -1,72 +1,18 @@
-/*
- * owipcalc - OpenWrt IP Calculator
- *
- *   Copyright (C) 2012 Jo-Philipp Wich <jo@mein.io>
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-
-#include <stdio.h>
 #include <stdint.h>
-#include <stdbool.h>
 #include <stdlib.h>
-
 #include <string.h>
 #include <unistd.h>
 
 #include <arpa/inet.h>
 
+#include "owipcalc.h"
+
+bool quiet = true;
+bool printed = false;
+
+struct cidr *stack = NULL;
 
-struct cidr {
-       uint8_t family;
-       uint32_t prefix;
-       union {
-               struct in_addr v4;
-               struct in6_addr v6;
-       } addr;
-       union {
-               char v4[sizeof("255.255.255.255/255.255.255.255 ")];
-               char v6[sizeof("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:255.255.255.255/128 ")];
-       } buf;
-       struct cidr *next;
-};
-
-struct op {
-       const char *name;
-       const char *desc;
-       struct {
-               bool (*a1)(struct cidr *a);
-               bool (*a2)(struct cidr *a, struct cidr *b);
-       } f4;
-       struct {
-               bool (*a1)(struct cidr *a);
-               bool (*a2)(struct cidr *a, struct cidr *b);
-       } f6;
-};
-
-
-static bool quiet = false;
-static bool printed = false;
-
-static struct cidr *stack = NULL;
-
-#define qprintf(...) \
-       do { \
-               if (!quiet) printf(__VA_ARGS__); \
-               printed = true; \
-       } while(0)
-
-static void cidr_push(struct cidr *a)
+void cidr_push(struct cidr *a)
 {
        if (a)
        {
@@ -75,7 +21,7 @@ static void cidr_push(struct cidr *a)
        }
 }
 
-static bool cidr_pop(struct cidr *a)
+bool cidr_pop(struct cidr *a)
 {
        struct cidr *old = stack;
 
@@ -107,7 +53,7 @@ static struct cidr * cidr_clone(struct cidr *a)
 }
 
 
-static struct cidr * cidr_parse4(const char *s)
+struct cidr * cidr_parse4(const char *s)
 {
        char *p = NULL, *r;
        struct in_addr mask;
@@ -159,7 +105,7 @@ err:
        return NULL;
 }
 
-static bool cidr_add4(struct cidr *a, struct cidr *b)
+bool cidr_add4(struct cidr *a, struct cidr *b)
 {
        uint32_t x = ntohl(a->addr.v4.s_addr);
        uint32_t y = ntohl(b->addr.v4.s_addr);
@@ -179,7 +125,7 @@ static bool cidr_add4(struct cidr *a, struct cidr *b)
        return true;
 }
 
-static bool cidr_sub4(struct cidr *a, struct cidr *b)
+bool cidr_sub4(struct cidr *a, struct cidr *b)
 {
        uint32_t x = ntohl(a->addr.v4.s_addr);
        uint32_t y = ntohl(b->addr.v4.s_addr);
@@ -199,7 +145,7 @@ static bool cidr_sub4(struct cidr *a, struct cidr *b)
        return true;
 }
 
-static bool cidr_network4(struct cidr *a)
+bool cidr_network4(struct cidr *a)
 {
        struct cidr *n = cidr_clone(a);
 
@@ -209,7 +155,7 @@ static bool cidr_network4(struct cidr *a)
        return true;
 }
 
-static bool cidr_broadcast4(struct cidr *a)
+bool cidr_broadcast4(struct cidr *a)
 {
        struct cidr *n = cidr_clone(a);
 
@@ -219,7 +165,7 @@ static bool cidr_broadcast4(struct cidr *a)
        return true;
 }
 
-static bool cidr_contains4(struct cidr *a, struct cidr *b)
+bool cidr_contains4(struct cidr *a, struct cidr *b)
 {
        uint32_t net1 = a->addr.v4.s_addr & htonl(~((1 << (32 - a->prefix)) - 1));
        uint32_t net2 = b->addr.v4.s_addr & htonl(~((1 << (32 - a->prefix)) - 1));
@@ -239,7 +185,7 @@ static bool cidr_contains4(struct cidr *a, struct cidr *b)
        }
 }
 
-static bool cidr_netmask4(struct cidr *a)
+bool cidr_netmask4(struct cidr *a)
 {
        struct cidr *n = cidr_clone(a);
 
@@ -249,7 +195,7 @@ static bool cidr_netmask4(struct cidr *a)
        return true;
 }
 
-static bool cidr_private4(struct cidr *a)
+bool cidr_private4(struct cidr *a)
 {
        uint32_t x = ntohl(a->addr.v4.s_addr);
 
@@ -270,7 +216,7 @@ static bool cidr_private4(struct cidr *a)
        }
 }
 
-static bool cidr_linklocal4(struct cidr *a)
+bool cidr_linklocal4(struct cidr *a)
 {
        uint32_t x = ntohl(a->addr.v4.s_addr);
 
@@ -289,7 +235,7 @@ static bool cidr_linklocal4(struct cidr *a)
        }
 }
 
-static bool cidr_prev4(struct cidr *a, struct cidr *b)
+bool cidr_prev4(struct cidr *a, struct cidr *b)
 {
        struct cidr *n = cidr_clone(a);
 
@@ -299,7 +245,7 @@ static bool cidr_prev4(struct cidr *a, struct cidr *b)
        return true;
 }
 
-static bool cidr_next4(struct cidr *a, struct cidr *b)
+bool cidr_next4(struct cidr *a, struct cidr *b)
 {
        struct cidr *n = cidr_clone(a);
 
@@ -309,7 +255,7 @@ static bool cidr_next4(struct cidr *a, struct cidr *b)
        return true;
 }
 
-static bool cidr_6to4(struct cidr *a)
+bool cidr_6to4(struct cidr *a)
 {
        struct cidr *n = cidr_clone(a);
        uint32_t x = a->addr.v4.s_addr;
@@ -329,7 +275,7 @@ static bool cidr_6to4(struct cidr *a)
        return true;
 }
 
-static bool cidr_print4(struct cidr *a)
+bool cidr_print4(struct cidr *a)
 {
        char *p;
 
@@ -353,7 +299,7 @@ static bool cidr_print4(struct cidr *a)
 }
 
 
-static struct cidr * cidr_parse6(const char *s)
+struct cidr * cidr_parse6(const char *s)
 {
        char *p = NULL, *r;
        struct cidr *addr = malloc(sizeof(struct cidr));
@@ -393,7 +339,7 @@ err:
        return NULL;
 }
 
-static bool cidr_add6(struct cidr *a, struct cidr *b)
+bool cidr_add6(struct cidr *a, struct cidr *b)
 {
        uint8_t idx = 15, carry = 0, overflow = 0;
 
@@ -420,7 +366,7 @@ static bool cidr_add6(struct cidr *a, struct cidr *b)
        return true;
 }
 
-static bool cidr_sub6(struct cidr *a, struct cidr *b)
+bool cidr_sub6(struct cidr *a, struct cidr *b)
 {
        uint8_t idx = 15, carry = 0, underflow = 0;
 
@@ -447,7 +393,7 @@ static bool cidr_sub6(struct cidr *a, struct cidr *b)
        return true;
 }
 
-static bool cidr_prev6(struct cidr *a, struct cidr *b)
+bool cidr_prev6(struct cidr *a, struct cidr *b)
 {
        uint8_t idx, carry = 1, underflow = 0;
        struct cidr *n = cidr_clone(a);
@@ -479,7 +425,7 @@ static bool cidr_prev6(struct cidr *a, struct cidr *b)
        return true;
 }
 
-static bool cidr_next6(struct cidr *a, struct cidr *b)
+bool cidr_next6(struct cidr *a, struct cidr *b)
 {
        uint8_t idx, carry = 1, overflow = 0;
        struct cidr *n = cidr_clone(a);
@@ -511,7 +457,7 @@ static bool cidr_next6(struct cidr *a, struct cidr *b)
        return true;
 }
 
-static bool cidr_network6(struct cidr *a)
+bool cidr_network6(struct cidr *a)
 {
        uint8_t i;
        struct cidr *n = cidr_clone(a);
@@ -525,7 +471,7 @@ static bool cidr_network6(struct cidr *a)
        return true;
 }
 
-static bool cidr_contains6(struct cidr *a, struct cidr *b)
+bool cidr_contains6(struct cidr *a, struct cidr *b)
 {
        struct in6_addr *x = &a->addr.v6;
        struct in6_addr *y = &b->addr.v6;
@@ -551,7 +497,7 @@ static bool cidr_contains6(struct cidr *a, struct cidr *b)
        }
 }
 
-static bool cidr_linklocal6(struct cidr *a)
+bool cidr_linklocal6(struct cidr *a)
 {
        if (printed)
                qprintf(" ");
@@ -570,7 +516,7 @@ static bool cidr_linklocal6(struct cidr *a)
        }
 }
 
-static bool cidr_ula6(struct cidr *a)
+bool cidr_ula6(struct cidr *a)
 {
        if (printed)
                qprintf(" ");
@@ -588,7 +534,7 @@ static bool cidr_ula6(struct cidr *a)
        }
 }
 
-static bool cidr_print6(struct cidr *a)
+bool cidr_print6(struct cidr *a)
 {
        char *p;
 
@@ -612,7 +558,7 @@ static bool cidr_print6(struct cidr *a)
 }
 
 
-static struct cidr * cidr_parse(const char *op, const char *s, int af_hint)
+struct cidr * cidr_parse(const char *op, const char *s, int af_hint)
 {
        char *r;
        struct cidr *a;
@@ -668,7 +614,7 @@ static struct cidr * cidr_parse(const char *op, const char *s, int af_hint)
        return a;
 }
 
-static bool cidr_howmany(struct cidr *a, struct cidr *b)
+bool cidr_howmany(struct cidr *a, struct cidr *b)
 {
        if (printed)
                qprintf(" ");
@@ -681,271 +627,14 @@ static bool cidr_howmany(struct cidr *a, struct cidr *b)
        return true;
 }
 
-static bool cidr_prefix(struct cidr *a, struct cidr *b)
+bool cidr_prefix(struct cidr *a, struct cidr *b)
 {
        a->prefix = b->prefix;
        return true;
 }
 
-static bool cidr_quiet(struct cidr *a)
+bool cidr_quiet(struct cidr *a)
 {
        quiet = true;
        return true;
 }
-
-
-struct op ops[] = {
-       { .name = "add",
-         .desc = "Add argument to base address",
-         .f4.a2 = cidr_add4,
-         .f6.a2 = cidr_add6 },
-
-       { .name = "sub",
-         .desc = "Substract argument from base address",
-         .f4.a2 = cidr_sub4,
-         .f6.a2 = cidr_sub6 },
-
-       { .name = "next",
-         .desc = "Advance base address to next prefix of given size",
-         .f4.a2 = cidr_next4,
-         .f6.a2 = cidr_next6 },
-
-       { .name = "prev",
-         .desc = "Lower base address to previous prefix of give size",
-         .f4.a2 = cidr_prev4,
-         .f6.a2 = cidr_prev6 },
-
-       { .name = "network",
-         .desc = "Turn base address into network address",
-         .f4.a1 = cidr_network4,
-         .f6.a1 = cidr_network6 },
-
-       { .name = "broadcast",
-         .desc = "Turn base address into broadcast address",
-         .f4.a1 = cidr_broadcast4 },
-
-       { .name = "prefix",
-         .desc = "Set the prefix of base address to argument",
-         .f4.a2 = cidr_prefix,
-         .f6.a2 = cidr_prefix },
-
-       { .name = "netmask",
-         .desc = "Calculate netmask of base address",
-         .f4.a1 = cidr_netmask4 },
-
-       { .name = "6to4",
-         .desc = "Calculate 6to4 prefix of given ipv4-address",
-         .f4.a1 = cidr_6to4 },
-
-       { .name = "howmany",
-         .desc = "Print amount of righ-hand prefixes that fit into base address",
-         .f4.a2 = cidr_howmany,
-         .f6.a2 = cidr_howmany },
-
-       { .name = "contains",
-         .desc = "Print '1' if argument fits into base address or '0' if not",
-         .f4.a2 = cidr_contains4,
-         .f6.a2 = cidr_contains6 },
-
-       { .name = "private",
-         .desc = "Print '1' if base address is in RFC1918 private space or '0' "
-                 "if not",
-         .f4.a1 = cidr_private4 },
-
-       { .name = "linklocal",
-         .desc = "Print '1' if base address is in 169.254.0.0/16 or FE80::/10 "
-                 "link local space or '0' if not",
-         .f4.a1 = cidr_linklocal4,
-         .f6.a1 = cidr_linklocal6 },
-
-       { .name = "ula",
-         .desc = "Print '1' if base address is in FC00::/7 unique local address "
-                 "(ULA) space or '0' if not",
-         .f6.a1 = cidr_ula6 },
-
-       { .name = "quiet",
-         .desc = "Suppress output, useful for test operation where the result can "
-                 "be inferred from the exit code",
-         .f4.a1 = cidr_quiet,
-         .f6.a1 = cidr_quiet },
-
-       { .name = "pop",
-         .desc = "Pop intermediate result from stack",
-         .f4.a1 = cidr_pop,
-         .f6.a1 = cidr_pop },
-
-       { .name = "print",
-         .desc = "Print intermediate result and pop it from stack, invoked "
-                 "implicitely at the end of calculation if no intermediate prints "
-                 "happened",
-         .f4.a1 = cidr_print4,
-         .f6.a1 = cidr_print6 },
-};
-
-static void usage(const char *prog)
-{
-       int i;
-
-       fprintf(stderr,
-               "\n"
-               "Usage:\n\n"
-               "  %s {base address} operation [argument] "
-               "[operation [argument] ...]\n\n"
-               "Operations:\n\n",
-               prog);
-
-       for (i = 0; i < sizeof(ops) / sizeof(ops[0]); i++)
-       {
-               if (ops[i].f4.a2 || ops[i].f6.a2)
-               {
-                       fprintf(stderr, "  %s %s\n",
-                               ops[i].name,
-                               (ops[i].f4.a2 && ops[i].f6.a2) ? "{ipv4/ipv6/amount}" :
-                                (ops[i].f6.a2 ? "{ipv6/amount}" : "{ipv4/amount}"));
-               }
-               else
-               {
-                       fprintf(stderr, "  %s\n", ops[i].name);
-               }
-
-               fprintf(stderr, "    %s.\n", ops[i].desc);
-
-               if ((ops[i].f4.a1 && ops[i].f6.a1) || (ops[i].f4.a2 && ops[i].f6.a2))
-                       fprintf(stderr, "    Applicable to ipv4- and ipv6-addresses.\n\n");
-               else if (ops[i].f6.a2 || ops[i].f6.a1)
-                       fprintf(stderr, "    Only applicable to ipv6-addresses.\n\n");
-               else
-                       fprintf(stderr, "    Only applicable to ipv4-addresses.\n\n");
-       }
-
-       fprintf(stderr,
-               "Examples:\n\n"
-               " Calculate a DHCP range:\n\n"
-               "  $ %s 192.168.1.1/255.255.255.0 network add 100 print add 150 print\n"
-                       "  192.168.1.100\n"
-                       "  192.168.1.250\n\n"
-                       " Count number of prefixes:\n\n"
-                       "  $ %s 2001:0DB8:FDEF::/48 howmany ::/64\n"
-                       "  65536\n\n",
-               prog, prog);
-
-       exit(1);
-}
-
-static bool runop(char ***arg, int *status)
-{
-       int i;
-       char *arg1 = **arg;
-       char *arg2 = *(*arg+1);
-       struct cidr *a = stack;
-       struct cidr *b = NULL;
-
-       if (!arg1)
-               return false;
-
-       for (i = 0; i < sizeof(ops) / sizeof(ops[0]); i++)
-       {
-               if (!strcmp(ops[i].name, arg1))
-               {
-                       if (ops[i].f4.a2 || ops[i].f6.a2)
-                       {
-                               if (!arg2)
-                               {
-                                       fprintf(stderr, "'%s' requires an argument\n",
-                                                       ops[i].name);
-
-                                       *status = 2;
-                                       return false;
-                               }
-
-                               b = cidr_parse(ops[i].name, arg2, a->family);
-
-                               if (!b)
-                               {
-                                       fprintf(stderr, "invalid address argument for '%s'\n",
-                                                       ops[i].name);
-
-                                       *status = 3;
-                                       return false;
-                               }
-
-                               *arg += 2;
-
-                               if (((a->family == AF_INET)  && !ops[i].f4.a2) ||
-                                       ((a->family == AF_INET6) && !ops[i].f6.a2))
-                               {
-                                       fprintf(stderr, "'%s' not supported for %s addresses\n",
-                                               ops[i].name,
-                                                       (a->family == AF_INET) ? "ipv4" : "ipv6");
-
-                                       *status = 5;
-                                       return false;
-                               }
-
-                               *status = !((a->family == AF_INET) ? ops[i].f4.a2(a, b)
-                                                                  : ops[i].f6.a2(a, b));
-
-                               return true;
-                       }
-                       else
-                       {
-                               *arg += 1;
-
-                               if (((a->family == AF_INET)  && !ops[i].f4.a1) ||
-                                       ((a->family == AF_INET6) && !ops[i].f6.a1))
-                               {
-                                       fprintf(stderr, "'%s' not supported for %s addresses\n",
-                                               ops[i].name,
-                                                       (a->family == AF_INET) ? "ipv4" : "ipv6");
-
-                                       *status = 5;
-                                       return false;
-                               }
-
-                               *status = !((a->family == AF_INET) ? ops[i].f4.a1(a)
-                                                                  : ops[i].f6.a1(a));
-
-                               return true;
-                       }
-               }
-       }
-
-       return false;
-}
-
-int main(int argc, char **argv)
-{
-       int status = 0;
-       char **arg = argv+2;
-       struct cidr *a;
-
-       if (argc < 3)
-               usage(argv[0]);
-
-       a = strchr(argv[1], ':') ? cidr_parse6(argv[1]) : cidr_parse4(argv[1]);
-
-       if (!a)
-               usage(argv[0]);
-
-       cidr_push(a);
-
-       while (runop(&arg, &status));
-
-       if (*arg)
-       {
-               fprintf(stderr, "unknown operation '%s'\n", *arg);
-               exit(6);
-       }
-
-       if (!printed && (status < 2))
-       {
-               if (stack->family == AF_INET)
-                       cidr_print4(stack);
-               else
-                       cidr_print6(stack);
-       }
-
-       qprintf("\n");
-
-       exit(status);
-}
diff --git a/net/owipcalc/src/owipcalc.h b/net/owipcalc/src/owipcalc.h
new file mode 100644 (file)
index 0000000..8257ca1
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * owipcalc - OpenWrt IP Calculator
+ *
+ *   Copyright (C) 2012 Jo-Philipp Wich <jo@mein.io>
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+#ifndef __OWIPCALC_H__
+#define __OWIPCALC_H__
+
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <arpa/inet.h>
+
+#define qprintf(...) \
+       do { \
+               if (!quiet) printf(__VA_ARGS__); \
+               printed = true; \
+       } while(0)
+
+struct cidr {
+       uint8_t family;
+       uint32_t prefix;
+       union {
+               struct in_addr v4;
+               struct in6_addr v6;
+       } addr;
+       union {
+               char v4[sizeof("255.255.255.255/255.255.255.255 ")];
+               char v6[sizeof("FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:255.255.255.255/128 ")];
+       } buf;
+       struct cidr *next;
+};
+
+void cidr_push(struct cidr *a);
+bool cidr_pop(struct cidr *a);
+
+struct cidr * cidr_parse4(const char *s);
+bool cidr_add4(struct cidr *a, struct cidr *b);
+bool cidr_sub4(struct cidr *a, struct cidr *b);
+bool cidr_network4(struct cidr *a);
+bool cidr_broadcast4(struct cidr *a);
+bool cidr_contains4(struct cidr *a, struct cidr *b);
+bool cidr_netmask4(struct cidr *a);
+bool cidr_private4(struct cidr *a);
+bool cidr_linklocal4(struct cidr *a);
+bool cidr_prev4(struct cidr *a, struct cidr *b);
+bool cidr_next4(struct cidr *a, struct cidr *b);
+bool cidr_6to4(struct cidr *a);
+bool cidr_print4(struct cidr *a);
+struct cidr * cidr_parse6(const char *s);
+bool cidr_add6(struct cidr *a, struct cidr *b);
+bool cidr_sub6(struct cidr *a, struct cidr *b);
+bool cidr_prev6(struct cidr *a, struct cidr *b);
+bool cidr_next6(struct cidr *a, struct cidr *b);
+bool cidr_network6(struct cidr *a);
+bool cidr_contains6(struct cidr *a, struct cidr *b);
+bool cidr_linklocal6(struct cidr *a);
+bool cidr_ula6(struct cidr *a);
+bool cidr_print6(struct cidr *a);
+struct cidr * cidr_parse(const char *op, const char *s, int af_hint);
+bool cidr_howmany(struct cidr *a, struct cidr *b);
+bool cidr_prefix(struct cidr *a, struct cidr *b);
+bool cidr_quiet(struct cidr *a);
+
+extern struct cidr *stack;
+extern bool quiet;
+extern bool printed;
+
+#endif