forked from adamdruppe/arsd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cidr.d
129 lines (101 loc) · 2.43 KB
/
cidr.d
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
/// Some helper functions for using CIDR format network ranges.
module arsd.cidr;
///
uint addressToUint(string address) {
import std.algorithm.iteration, std.conv;
uint result;
int place = 3;
foreach(part; splitter(address, ".")) {
assert(place >= 0);
result |= to!int(part) << (place * 8);
place--;
}
return result;
}
///
string uintToAddress(uint addr) {
import std.conv;
string res;
res ~= to!string(addr >> 24);
res ~= ".";
res ~= to!string((addr >> 16) & 0xff);
res ~= ".";
res ~= to!string((addr >> 8) & 0xff);
res ~= ".";
res ~= to!string((addr >> 0) & 0xff);
return res;
}
///
struct IPv4Block {
this(string cidr) {
import std.algorithm.searching, std.conv;
auto parts = findSplit(cidr, "/");
this.currentAddress = addressToUint(parts[0]);
auto count = to!int(parts[2]);
if(count != 0) {
this.netmask = ((1L << count) - 1) & 0xffffffff;
this.netmask <<= 32-count;
}
this.startingAddress = this.currentAddress & this.netmask;
validate();
restart();
}
this(string address, string netmask) {
this.currentAddress = addressToUint(address);
this.netmask = addressToUint(netmask);
this.startingAddress = this.currentAddress & this.netmask;
validate();
restart();
}
void validate() {
if(!isValid())
throw new Exception("invalid");
}
bool isValid() {
return (startingAddress & netmask) == (currentAddress & netmask);
}
void restart() {
remaining = ~this.netmask - (currentAddress - startingAddress);
}
@property string front() {
return uintToAddress(currentAddress);
}
@property bool empty() {
return remaining < 0;
}
void popFront() {
currentAddress++;
remaining--;
}
string toString() {
import std.conv;
return uintToAddress(startingAddress) ~ "/" ~ to!string(maskBits);
}
int maskBits() {
import core.bitop;
if(netmask == 0)
return 0;
return 32-bsf(netmask);
}
int numberOfAddresses() {
return ~netmask + 1;
}
uint startingAddress;
uint netmask;
uint currentAddress;
int remaining;
}
version(none)
void main() {
// make one with cidr or address + mask notation
// auto i = IPv4Block("192.168.1.0", "255.255.255.0");
auto i = IPv4Block("192.168.1.50/29");
// loop over all addresses in the block
import std.stdio;
foreach(addr; i)
writeln(addr);
// show info about the block too
writefln("%s netmask %s", uintToAddress(i.startingAddress), uintToAddress(i.netmask));
writeln(i);
writeln(i.numberOfAddresses, " addresses in block");
}