diff options
-rw-r--r-- | Makefile | 67 | ||||
-rw-r--r-- | src/iptool.c | 130 |
2 files changed, 197 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5f352d9 --- /dev/null +++ b/Makefile @@ -0,0 +1,67 @@ +# Compiler and flags +CC = gcc +CFLAGS = -Wall -O2 + +# Directories +SRC_DIR = src +BIN_DIR = bin + +# Source and target names +TARGET = iptool +SRC = $(SRC_DIR)/$(TARGET).c +PRE = $(BIN_DIR)/$(TARGET).i +ASM = $(BIN_DIR)/$(TARGET).s +OBJ = $(BIN_DIR)/$(TARGET).o +BIN = $(BIN_DIR)/$(TARGET) + +# Example argument for test +ARG = + +# Default: build executable +all: $(BIN) + +# Ensure bin directory exists +$(BIN_DIR): + mkdir -p $(BIN_DIR) + +# Stage 1: Preprocess +$(PRE): $(SRC) | $(BIN_DIR) + $(CC) -E $(CFLAGS) $< -o $@ + +# Stage 2: Compile to assembly +$(ASM): $(PRE) + $(CC) -S $(CFLAGS) $< -o $@ + +# Stage 3: Assemble to object file +$(OBJ): $(ASM) + $(CC) -c $(CFLAGS) $< -o $@ + +# Stage 4: Link object to executable +$(BIN): $(OBJ) + $(CC) $(CFLAGS) $< -o $@ + +# Run tests +define run_test + @name="$(1) $(2)"; \ + width=40; \ + printf "%s" "$$name"; \ + dots=$$((width - $${#name})); \ + for i in $$(seq 1 $$dots); do printf "."; done; \ + ./$(BIN) $(2) >/dev/null 2>&1; \ + ec=$$?; \ + if [ $$ec -eq 0 ] || [ $$ec -eq 2 ]; then \ + echo " OK"; \ + else \ + echo " FAILED (exit $$ec)"; \ + exit 1; \ + fi +endef + +test: $(BIN) + $(call run_test,$(TARGET),no args) + $(call run_test,$(TARGET),$(ARG)) + +# Clean all generated files +clean: + rm -v -f $(BIN_DIR)/$(TARGET).* $(BIN) + diff --git a/src/iptool.c b/src/iptool.c new file mode 100644 index 0000000..e940c52 --- /dev/null +++ b/src/iptool.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * subnet_calc.c - Simple IP subnet calculator + * + * Takes an IPv4 address and a prefix length, then calculates: + * - IP class + * - Network address + * - Broadcast address + * - Total hosts + * - Usable hosts + * - Usable IP range + */ + +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +static uint32_t ip_to_u32(const char *ip_str) +{ + int o1, o2, o3, o4; + + if (sscanf(ip_str, "%d.%d.%d.%d", &o1, &o2, &o3, &o4) != 4) { + fprintf(stderr, "Invalid IP format: %s\n", ip_str); + exit(1); + } + + if (o1 < 0 || o1 > 255 || o2 < 0 || o2 > 255 || + o3 < 0 || o3 > 255 || o4 < 0 || o4 > 255) { + fprintf(stderr, "IP octet out of range: %s\n", ip_str); + exit(1); + } + + return (o1 << 24) | (o2 << 16) | (o3 << 8) | o4; +} + +static uint32_t netmask_from_prefix(int prefix) +{ + return prefix ? 0xFFFFFFFFU << (32 - prefix) : 0; +} + +static uint32_t network_addr(uint32_t ip, uint32_t netmask) +{ + return ip & netmask; +} + +static uint32_t broadcast_addr(uint32_t ip, uint32_t netmask) +{ + return (ip & netmask) | ~netmask; +} + +static uint32_t total_hosts(int prefix) +{ + return 1U << (32 - prefix); +} + +static uint32_t usable_hosts(int prefix) +{ + uint32_t th = total_hosts(prefix); + + return (th <= 2) ? 0 : th - 2; +} + +static char ip_class(uint32_t ip) +{ + uint8_t first_octet = ip >> 24; + + if (first_octet <= 127) + return 'A'; + if (first_octet <= 191) + return 'B'; + if (first_octet <= 223) + return 'C'; + if (first_octet <= 239) + return 'D'; + return 'E'; +} + +static void print_ip(uint32_t ip) +{ + printf("%u.%u.%u.%u", + (ip >> 24) & 0xFF, + (ip >> 16) & 0xFF, + (ip >> 8) & 0xFF, + ip & 0xFF); +} + +int main(int argc, char *argv[]) +{ + uint32_t ip, netmask, network, broadcast; + int prefix; + uint32_t total, usable; + + if (argc < 3) { + fprintf(stderr, "Usage: %s <ip> <prefix>\n", argv[0]); + return 1; + } + + ip = ip_to_u32(argv[1]); + prefix = atoi(argv[2]); + + if (prefix < 0 || prefix > 32) { + fprintf(stderr, "Prefix must be 0-32\n"); + return 1; + } + + netmask = netmask_from_prefix(prefix); + network = network_addr(ip, netmask); + broadcast = broadcast_addr(ip, netmask); + total = total_hosts(prefix); + usable = usable_hosts(prefix); + + printf("IP Class: %c\n", ip_class(ip)); + printf("Network: "); print_ip(network); printf("\n"); + printf("Broadcast: "); print_ip(broadcast); printf("\n"); + printf("Total hosts: %u\n", total); + printf("Usable hosts: %u\n", usable); + + if (usable > 0) { + printf("Usable IP range: "); + print_ip(network + 1); + printf(" - "); + print_ip(broadcast - 1); + printf("\n"); + } else { + printf("No usable IPs in this subnet\n"); + } + + return 0; +} + |