1 /// Some helper functions for using CIDR format network ranges. 2 module arsd.cidr; 3 4 /// 5 uint addressToUint(string address) { 6 import std.algorithm.iteration, std.conv; 7 8 uint result; 9 int place = 3; 10 foreach(part; splitter(address, ".")) { 11 assert(place >= 0); 12 result |= to!int(part) << (place * 8); 13 place--; 14 } 15 16 return result; 17 } 18 19 /// 20 string uintToAddress(uint addr) { 21 import std.conv; 22 string res; 23 res ~= to!string(addr >> 24); 24 res ~= "."; 25 res ~= to!string((addr >> 16) & 0xff); 26 res ~= "."; 27 res ~= to!string((addr >> 8) & 0xff); 28 res ~= "."; 29 res ~= to!string((addr >> 0) & 0xff); 30 31 return res; 32 } 33 34 /// 35 struct IPv4Block { 36 this(string cidr) { 37 import std.algorithm.searching, std.conv; 38 auto parts = findSplit(cidr, "/"); 39 this.currentAddress = addressToUint(parts[0]); 40 auto count = to!int(parts[2]); 41 42 if(count != 0) { 43 this.netmask = ((1L << count) - 1) & 0xffffffff; 44 this.netmask <<= 32-count; 45 } 46 47 this.startingAddress = this.currentAddress & this.netmask; 48 49 validate(); 50 51 restart(); 52 } 53 54 this(string address, string netmask) { 55 this.currentAddress = addressToUint(address); 56 this.netmask = addressToUint(netmask); 57 this.startingAddress = this.currentAddress & this.netmask; 58 59 validate(); 60 61 restart(); 62 } 63 64 void validate() { 65 if(!isValid()) 66 throw new Exception("invalid"); 67 } 68 69 bool isValid() { 70 return (startingAddress & netmask) == (currentAddress & netmask); 71 } 72 73 void restart() { 74 remaining = ~this.netmask - (currentAddress - startingAddress); 75 } 76 77 @property string front() { 78 return uintToAddress(currentAddress); 79 } 80 81 @property bool empty() { 82 return remaining < 0; 83 } 84 85 void popFront() { 86 currentAddress++; 87 remaining--; 88 } 89 90 string toString() { 91 import std.conv; 92 return uintToAddress(startingAddress) ~ "/" ~ to!string(maskBits); 93 } 94 95 int maskBits() { 96 import core.bitop; 97 if(netmask == 0) 98 return 0; 99 return 32-bsf(netmask); 100 } 101 102 int numberOfAddresses() { 103 return ~netmask + 1; 104 } 105 106 uint startingAddress; 107 uint netmask; 108 109 uint currentAddress; 110 int remaining; 111 } 112 113 version(none) 114 void main() { 115 // make one with cidr or address + mask notation 116 117 // auto i = IPv4Block("192.168.1.0", "255.255.255.0"); 118 auto i = IPv4Block("192.168.1.50/29"); 119 120 // loop over all addresses in the block 121 import std.stdio; 122 foreach(addr; i) 123 writeln(addr); 124 125 // show info about the block too 126 writefln("%s netmask %s", uintToAddress(i.startingAddress), uintToAddress(i.netmask)); 127 writeln(i); 128 writeln(i.numberOfAddresses, " addresses in block"); 129 }