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
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);