-
Notifications
You must be signed in to change notification settings - Fork 2
/
cidrl.c
144 lines (124 loc) · 3.86 KB
/
cidrl.c
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
133
134
135
136
137
138
139
140
141
142
143
144
/*
* cidrl
*
* Lists all IPv4 addresses within a CIDR block.
*
* @author Damien Bezborodov
* @link https://github.com/emden-norfolk/cidrl
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <arpa/inet.h>
#include "version.h"
#define EXIT_NOT_EXISTS 64
extern char *optarg;
extern int optind;
int main(int argc, char **argv)
{
char addr_buffer[INET_ADDRSTRLEN];
struct in_addr addr;
uint32_t hladdr, hlmask, hlend, hlhost;
uint8_t bits;
// Options.
uint8_t subnet = 0;
bool analyse = false;
bool exists = false;
int opt;
while ((opt = getopt(argc, argv, "vas:e:")) != -1) {
switch (opt) {
case 'v':
printf("%s\n", version());
exit(EXIT_SUCCESS);
break;
case 's':
subnet = atoi(optarg);
break;
case 'a':
analyse = true;
break;
case 'e':
if (inet_aton(optarg, &addr) == 0) {
fprintf(stderr, "Error: Invalid IPv4 address given.\n");
exit(EXIT_FAILURE);
}
hlhost = ntohl(addr.s_addr);
exists = true;
break;
default:
exit(EXIT_FAILURE);
}
}
// Input, conversion, and error detection.
if (argc - optind != 1) {
fprintf(stderr, "Error: An IPv4 CIDR must be given as the first argument.\n");
exit(EXIT_FAILURE);
}
char whitespace; // Detect trailing characters in sscanf.
if (sscanf(argv[optind], "%[^/]/%hhu %c", addr_buffer, &bits, &whitespace) != 2) {
fprintf(stderr, "Error: Invalid IPv4 CIDR given.\n");
exit(EXIT_FAILURE);
}
if (inet_aton(addr_buffer, &addr) == 0) {
fprintf(stderr, "Error: Invalid IPv4 address given.\n");
exit(EXIT_FAILURE);
}
if (bits > 32) {
fprintf(stderr, "Error: Invalid network prefix given.\n");
exit(EXIT_FAILURE);
}
// Calculate IPv4 network range and mask.
hlmask = bits ? ~0 << (32 - bits) : 0;
hladdr = ntohl(addr.s_addr) & hlmask;
hlend = hladdr | ~hlmask;
// Split a CIDR block into smaller subnetworks.
if (subnet) {
if (subnet <= bits) {
fprintf(stderr, "Error: Subnet must have less hosts than the network.\n");
exit(EXIT_FAILURE);
}
if (subnet > 32) {
fprintf(stderr, "Error: Invalid subnet network prefix.\n");
exit(EXIT_FAILURE);
}
for (uint32_t i = hladdr; i <= hlend; i += (1 << (32 - subnet))) {
addr.s_addr = htonl(i);
printf("%s/%hhu\n", inet_ntoa(addr), subnet);
}
exit(EXIT_SUCCESS);
}
// Analyse a CIDR block.
if (analyse) {
addr.s_addr = htonl(hladdr);
printf("Network: %s\n", inet_ntoa(addr));
addr.s_addr = htonl(hlend);
printf("Broadcast: %s\n", inet_ntoa(addr));
addr.s_addr = htonl(hlmask);
printf("Netmask: %s\n", inet_ntoa(addr));
if (bits)
printf("Hosts: %u\n", hlend - hladdr + 1);
else
printf("Hosts: 4294967296\n");
if (exists) {
addr.s_addr = htonl(hlhost);
printf("\nThe host %s %s within this network.\n",
inet_ntoa(addr),
(hlhost & hlmask) == hladdr ? "exists" : "does not exist");
}
exit(EXIT_SUCCESS);
}
// Check if host exists within network.
if (exists) {
if ((hlhost & hlmask) == hladdr)
exit(EXIT_SUCCESS);
else
exit(EXIT_NOT_EXISTS);
}
// List all IP addresses in a CIDR block.
for (uint32_t i = hladdr; i <= hlend; i++) {
addr.s_addr = htonl(i);
printf("%s\n", inet_ntoa(addr));
}
exit(EXIT_SUCCESS);
}