ip2cidr

Small and simple program for converting a netmask into a CIDR
git clone https://noxz.tech/git/ip2cidr.git
Log | Files | README | LICENSE

commit: e7589a3458148f3d8f4331a80536861adf02bb07
parent: baace72c616e0c9b5263f4ea327e2c941d0a6bfa
author: z0noxz <chris@noxz.tech>
date:   Tue, 7 Aug 2018 13:50:14 +0200
port everything to c instead of POSIX sh
AMakefile35+++++
Aconfig.mk15+++
Dip2cidr135--------------------
Aip2cidr.c88+++++++++++++
Aip2cidr.h20+++
5 files changed, 158 insertions(+), 135 deletions(-)
diff --git a/Makefile b/Makefile
@@ -0,0 +1,35 @@
+.POSIX:
+
+include config.mk
+
+SRC = ip2cidr.c
+OBJ = $(SRC:.c=.o)
+
+all: options ip2cidr
+
+options:
+	@echo ip2cidr build options:
+	@echo "CC      = $(CC)"
+
+.c.o:
+	$(CC) $(STCFLAGS) -c $<
+
+ip2cidr.o: ip2cidr.h
+
+$(OBJ): config.mk
+
+ip2cidr: $(OBJ)
+	$(CC) -g -o $@ $(OBJ) $(STLDFLAGS)
+
+clean:
+	rm -f ip2cidr $(OBJ)
+
+install: ip2cidr
+	mkdir -p /usr/local/bin
+	cp -f ip2cidr /usr/local/bin
+	chmod 755 /usr/local/bin/ip2cidr
+
+uninstall:
+	rm -f /usr/local/bin/ip2cidr
+
+.PHONY: all options clean install uninstall
diff --git a/config.mk b/config.mk
@@ -0,0 +1,15 @@
+# ztatus version
+VERSION = 0.1.1
+
+# paths
+PREFIX = /usr/local
+MANPREFIX = $(PREFIX)/share/man
+
+# flags
+CFLAGS = -Wall -O3 -pedantic
+CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600
+STCFLAGS = $(CPPFLAGS) $(CFLAGS)
+STLDFLAGS = $(LDFLAGS)
+
+# compiler and linker
+CC = gcc
diff --git a/ip2cidr b/ip2cidr
@@ -1,135 +0,0 @@
-#!/bin/sh
-license='
-Converts IPADDRESS to CIDR, or returns CIDR if already a valid one
-Copyright (C) 2018 z0noxz, <chris@noxz.tech>
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-'
-
-count_ones() {
-
-    # variable declaration
-    dec=$1
-    base=2
-    result=0
-    found_zero=-1
-
-    # base convert decimal ip address to binary
-    while [ "$dec" -ne 0 ]; do
-        if [ $((dec % base)) -eq 1 ]; then
-            # check if mask is invalid
-            if [ "$found_zero" -eq 1 ]; then
-                printf '%d' "-1"
-                return 1
-            fi
-
-            # count one
-            result=$((result+1))
-            found_zero=0
-        else
-            # detect zero after a one
-            if [ "$found_zero" -eq 0 ]; then
-                found_zero=1
-            fi
-        fi
-        dec=$((dec / base))
-    done
-
-    # return value
-    printf '%d' "$result"
-    return 0
-}
-
-do_ip2cidr() {
-
-    # variable declaration
-    ip=$1
-    cidr=-1
-    OIFS=$IFS
-    result=0
-    i=0
-
-    # parse ip address
-    IFS=\.
-    for item in $ip; do
-        if [ "$item" -eq "$item" ] 2> /dev/null && \
-            [ "$item" -le 256 ] && [ "$item" -ge 0 ]; then
-            i=$((i+1))
-            case $i in
-                1)
-                    result=$((result+item*16777216))
-                    ;;
-                2)
-                    result=$((result+item*65536))
-                    ;;
-                3)
-                    result=$((result+item*256))
-                    ;;
-                4)
-                    result=$((result+item))
-                    ;;
-            esac
-        else
-            return 1
-        fi
-    done
-    IFS=$OIFS
-
-    # check if ip address was valid, and if not fail
-    if [ "$ip" = "" ] || [ "$i" -ne 4 ]; then
-        return 1
-    fi
-
-    # calculate CIDR
-    cidr=$(count_ones "$result")
-
-    # check if CIDR is valid, and if not fail
-    if [ "$cidr" -eq -1 ]; then
-        return 1
-    fi
-
-    # print CIDR
-    printf '%d\n' "$cidr"
-
-    # success
-    return 0
-}
-
-# read from stdin if applicable
-x="$1"
-if ! [ -t 0 ]; then
-    while read -r line; do
-        x="$line"
-    done
-fi
-
-# check if input already is a CIDR, and if not process it
-if [ "$x" -eq "$x" ] 2> /dev/null && [ "$x" -le 32 ] && [ "$x" -gt 0 ]; then
-    printf '%d\n' "$x" && exit 0
-else
-    do_ip2cidr "$x" && exit 0
-fi
-
-
-# if all fails print usage
-program_name="${0##*/}"
-printf 'Usage: %s IPADDRESS
-
-The IPADDRESS must be a valid subnet mask.
-
-LICENSE NOTICE
-%s
-' "$program_name" "$license" >&2
-
-exit 1
diff --git a/ip2cidr.c b/ip2cidr.c
@@ -0,0 +1,88 @@
+/*
+ * Converts IPADDRESS to CIDR, or returns CIDR if already a valid one
+ * Copyright (C) 2018 z0noxz, <chris@noxz.tech>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "ip2cidr.h"
+
+/* HAKMEM bit counter */
+int
+bit_count(unsigned int u) {
+    unsigned int u_count;
+
+    u_count = u - ((u >> 1) & 0333333333333) - ((u >> 2) & 011111111111);
+    return ((u_count + (u_count >> 3)) & 030707070707) % 63;
+}
+
+int
+main(int argc, char **argv) {
+    int ip, oip, cidr, n1, n2, n3, n4, input_size;
+    int buffer_size = 80;
+    char buffer[buffer_size];
+    char *input;
+
+    /* validate input from STDIN */
+    if (!isatty(fileno(stdin)) && fgets(buffer, buffer_size, stdin) != NULL) {
+        input_size = strlen(buffer);
+        input = malloc(input_size);
+        input[0] = '\0';
+        strcat(input, buffer);
+
+    /* validate input from CLI */
+    } else if (argc == 2) {
+        input_size = strlen(argv[1]);
+        input = malloc(input_size);
+        input[0] = '\0';
+        strcat(input, argv[1]);
+
+    /* no valid input, so show usage */
+    } else {
+        fprintf(stderr, "usage: ip2cidr IPADDRESS\n");
+        return 1;
+    }
+
+    /* validate ip address */
+    if (
+        sscanf(input, "%d.%d.%d.%d", &n1, &n2, &n3, &n4) == 4 &&
+        n1 >= 0 && n1 <= 255 &&
+        n2 >= 0 && n2 <= 255 &&
+        n3 >= 0 && n3 <= 255 &&
+        n4 >= 0 && n4 <= 255
+    ) {
+        ip = n1 * 16777216 + n2 * 65536 + n3 * 256 + n4;
+        oip = ip;
+        cidr = bit_count(ip);
+
+        /* check if ip is a valid subnet mask (ones are in succession) */
+        oip = oip >> (32-cidr) << (32-cidr);
+        if (oip != ip) {
+            fprintf(stderr, "error: not a subnet mask\n");
+            return 1;
+        }
+    } else if (sscanf(input, "%d", &n1) == 1 && n1 >= 1 && n1 <= 32) {
+        cidr = n1;
+    } else {
+        fprintf(stderr, "error: not a correctly formed ip address\n");
+        return 1;
+    }
+
+    /* finally print the CIDR */
+    printf("%d\n", cidr);
+    return 0;
+}
diff --git a/ip2cidr.h b/ip2cidr.h
@@ -0,0 +1,20 @@
+/*
+ * Converts IPADDRESS to CIDR, or returns CIDR if already a valid one
+ * Copyright (C) 2018 z0noxz, <chris@noxz.tech>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* function declarations */
+static int bit_count(unsigned int u);