summaryrefslogtreecommitdiff
path: root/src/iptool.c
blob: c31161e9c7452209e702d4eba64eb1906d286aef (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// SPDX-License-Identifier: GPL-2.0
/*
 * iptool.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>

#define PROGRAM_NAME "iptool"

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", PROGRAM_NAME);
		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;
}