1 module myip.private_;
2 
3 import std.string : fromStringz;
4 
5 version(Windows) {
6 	
7 	import core.sys.windows.windef;
8 	import core.sys.windows.winsock2;
9 
10 } else version(Posix) {
11 
12 	import core.sys.posix.netdb;
13 	import core.sys.posix.netinet.in_;
14 	import core.sys.posix.sys.socket;
15 
16 }
17 
18 enum Exclude {
19 
20 	IPV4 = 1<<0,
21 	IPV6 = 1<<1,
22 	INTERFACE = 1<<2,
23 
24 }
25 
26 /**
27  * Gets the private ip addresses of the machine.
28  */
29 nothrow string[] privateAddresses(uint exclude=0) {
30 
31 	string[] addresses;
32 
33 	immutable ipv4 = !(exclude & Exclude.IPV4);
34 	immutable ipv6 = !(exclude & Exclude.IPV6);
35 	immutable interface_ = exclude & Exclude.INTERFACE;
36 
37 	nothrow string add(const(sockaddr)* sa, socklen_t salen) {
38 		char[64] ip;
39 		getnameinfo(sa, salen, ip.ptr, 64, null, 0, NI_NUMERICHOST);
40 		return fromStringz(ip.ptr).idup;
41 	}
42 
43 	nothrow void add4(const(sockaddr)* sa) {
44 		if(ipv4) {
45 			string address = add(sa, sockaddr_in.sizeof);
46 			version(Posix) if(address == "127.0.0.1") return;
47 			addresses ~= address;
48 		}
49 	}
50 
51 	nothrow void add6(const(sockaddr)* sa) {
52 		if(ipv6) {
53 			string address = add(sa, sockaddr_in6.sizeof);
54 			if(interface_) {
55 				// std.string.indexOf is not nothrow
56 				foreach(i, c; address) {
57 					if(c == '%') {
58 						address = address[0..i];
59 						break;
60 					}
61 				}
62 			}
63 			version(Posix) if(address == "::1") return;
64 			addresses ~= address;
65 		}
66 	}
67 
68 	version(Windows) {
69 
70 		WORD versionRequested = MAKEWORD(1, 0);
71 		WSADATA wsaData;
72 		char[255] name;
73 		
74 		if(WSAStartup(versionRequested, &wsaData) == 0 && gethostname(name.ptr, 255) == 0) {
75 
76 			addrinfo* result, ptr;
77 
78 			addrinfo hints;
79 			hints.ai_family = AF_UNSPEC;
80 			hints.ai_socktype = SOCK_STREAM;
81 			hints.ai_protocol = IPPROTO_TCP;
82 
83 			if(getaddrinfo(name.ptr, null, &hints, &result) == 0) {
84 
85 				for(ptr=result; ptr !is null; ptr=ptr.ai_next) {
86 					switch(ptr.ai_family) {
87 						case AF_INET:
88 							add4(ptr.ai_addr);
89 							break;
90 						case AF_INET6:
91 							add6(ptr.ai_addr);
92 							break;
93 						default:
94 							break;
95 					}
96 				}
97 
98 				freeaddrinfo(result);
99 
100 			}
101 
102 		}
103 
104 	} else version(Posix) {
105 
106 		ifaddrs* ifap, ifa;
107 		void* in_addr;
108 
109 		if(getifaddrs(&ifap) == 0) {
110 
111 			for(ifa=ifap; ifa; ifa=ifa.ifa_next) {
112 				if(ifa.ifa_addr) {
113 					switch(ifa.ifa_addr.sa_family) {
114 						case AF_INET:
115 							add4(ifa.ifa_addr);
116 							break;
117 						case AF_INET6:
118 							add6(ifa.ifa_addr);
119 							break;
120 						default:
121 							continue;
122 					}
123 				}
124 			}
125 
126 			freeifaddrs(ifap);
127 			
128 		}
129 	
130 	}
131 	
132 	return addresses;
133 
134 }
135 
136 nothrow string[] privateAddresses4() {
137 	return privateAddresses(Exclude.IPV6);
138 }
139 
140 nothrow string[] privateAddresses6(bool excludeInterface=false) {
141 	if(excludeInterface) return privateAddresses(Exclude.IPV4 | Exclude.INTERFACE);
142 	else return privateAddresses(Exclude.IPV4);
143 }
144 
145 version(Posix) {
146 
147 	extern (C):
148 	nothrow:
149 	@nogc:
150 
151 	struct ifaddrs {
152 
153 		ifaddrs* ifa_next;
154 		char* ifa_name;
155 		uint ifa_flags;
156 		sockaddr* ifa_addr;
157 		sockaddr* ifa_netmask;
158 		
159 		union {
160 
161 			sockaddr* ifu_broadaddr;
162 			sockaddr* ifu_dstaddr;
163 
164 		}
165 
166 		void* ifa_data;
167 
168 	}
169 
170 	int getifaddrs(ifaddrs**);
171 	void freeifaddrs(ifaddrs*);
172 	
173 	int getnameinfo(const(sockaddr)*, socklen_t, char*, socklen_t, char*, socklen_t, int);
174 
175 }