summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpankunull <panku_null@proton.me>2025-09-05 23:27:18 +0200
committerpankunull <panku_null@proton.me>2025-09-05 23:27:18 +0200
commit1acd14aa77268bd75afd465496bba57d6b1e5436 (patch)
tree85638a9405aab8fb67e267d699559b5582956493
Initial commit
-rw-r--r--Makefile67
-rw-r--r--src/iptool.c130
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;
+}
+