ip2cidr

Small and simple program for converting a netmask into a CIDR
git clone git://git.noxz.tech/ip2cidr
Log | Files | Refs | 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

Diffstat:
AMakefile | 35+++++++++++++++++++++++++++++++++++
Aconfig.mk | 15+++++++++++++++
Dip2cidr | 135-------------------------------------------------------------------------------
Aip2cidr.c | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aip2cidr.h | 20++++++++++++++++++++
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);