network_interface 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +11 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +30 -0
- data/LICENSE +45 -0
- data/README.md +29 -0
- data/Rakefile +11 -0
- data/ext/network_interface_ext/extconf.rb +95 -0
- data/ext/network_interface_ext/netifaces.c +1008 -0
- data/ext/network_interface_ext/netifaces.h +185 -0
- data/lib/network_interface.rb +6 -0
- data/lib/network_interface/version.rb +3 -0
- data/network_interface.gemspec +29 -0
- data/spec/netiface_spec.rb +48 -0
- data/spec/spec_helper.rb +107 -0
- metadata +138 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--format documentation
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
network_interface (0.0.1)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.2.4)
|
10
|
+
rake (10.0.3)
|
11
|
+
rake-compiler (0.8.3)
|
12
|
+
rake
|
13
|
+
rspec (2.13.0)
|
14
|
+
rspec-core (~> 2.13.0)
|
15
|
+
rspec-expectations (~> 2.13.0)
|
16
|
+
rspec-mocks (~> 2.13.0)
|
17
|
+
rspec-core (2.13.1)
|
18
|
+
rspec-expectations (2.13.0)
|
19
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
20
|
+
rspec-mocks (2.13.1)
|
21
|
+
|
22
|
+
PLATFORMS
|
23
|
+
ruby
|
24
|
+
|
25
|
+
DEPENDENCIES
|
26
|
+
bundler (~> 1.3)
|
27
|
+
network_interface!
|
28
|
+
rake
|
29
|
+
rake-compiler
|
30
|
+
rspec
|
data/LICENSE
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
Copyright (C) 2012, Rapid7, Inc.
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
MIT License
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
7
|
+
a copy of this software and associated documentation files (the
|
8
|
+
"Software"), to deal in the Software without restriction, including
|
9
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be
|
15
|
+
included in all copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
21
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
22
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
23
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
24
|
+
|
25
|
+
Original c/python netifaces code is under MIT-style license.
|
26
|
+
|
27
|
+
Copyright (c) 2007, 2008 Alastair Houghton
|
28
|
+
|
29
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
30
|
+
of this software and associated documentation files (the "Software"), to deal
|
31
|
+
in the Software without restriction, including without limitation the rights
|
32
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
33
|
+
copies of the Software, and to permit persons to whom the Software is
|
34
|
+
furnished to do so, subject to the following conditions:
|
35
|
+
|
36
|
+
The above copyright notice and this permission notice shall be included in all
|
37
|
+
copies or substantial portions of the Software.
|
38
|
+
|
39
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
40
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
41
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
42
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
43
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
44
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
45
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# NetworkInterface
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'network_interface'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install network_interface
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
# require "bundler/gem_tasks"
|
2
|
+
require 'bundler'
|
3
|
+
Bundler::GemHelper.install_tasks
|
4
|
+
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
RSpec::Core::RakeTask.new
|
7
|
+
|
8
|
+
require 'rake/extensiontask'
|
9
|
+
Rake::ExtensionTask.new('network_interface_ext')
|
10
|
+
|
11
|
+
task :default => [:clean, :compile, :spec]
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
extension_name = 'network_interface_ext'
|
3
|
+
|
4
|
+
########################
|
5
|
+
# Netifaces
|
6
|
+
########################
|
7
|
+
puts "\n[*] Running checks for netifaces code..."
|
8
|
+
#uncoment to force ioctl on non windows systems
|
9
|
+
#@force_ioctl = true
|
10
|
+
@supported_archs = [ "i386-mingw32", "i486-linux", "x86_64-linux",
|
11
|
+
"universal-darwin10.0", "i386-openbsd4.8", "i386-freebsd8",
|
12
|
+
"arm-linux-eabi", "x86_64-darwin12.3.0" ]
|
13
|
+
#arm-linux-eabi tested on maemo5 / N900
|
14
|
+
puts "[*] Warning : this platform as not been tested" unless @supported_archs.include? RUBY_PLATFORM
|
15
|
+
|
16
|
+
if RUBY_PLATFORM =~ /i386-mingw32/
|
17
|
+
unless have_library("ws2_32" ) and
|
18
|
+
have_library("iphlpapi") and
|
19
|
+
have_header("windows.h") and
|
20
|
+
have_header("winsock2.h") and
|
21
|
+
have_header("iphlpapi.h")
|
22
|
+
puts "\nNot all dependencies are satisfied, please check logs"
|
23
|
+
exit
|
24
|
+
end
|
25
|
+
|
26
|
+
else
|
27
|
+
headers = ['net/if_dl.h', 'netash/ash.h','netatalk/at.h', 'netax25/ax25.h',
|
28
|
+
'neteconet/ec.h', 'netipx/ipx.h','netpacket/packet.h', 'netrose/rose.h']
|
29
|
+
if RUBY_PLATFORM =~ /linux/
|
30
|
+
headers += [ 'linux/irda.h', 'linux/atm.h',
|
31
|
+
'linux/llc.h', 'linux/tipc.h',
|
32
|
+
'linux/dn.h']
|
33
|
+
end
|
34
|
+
additionnal_headers = ["sys/types.h","sys/socket.h","sys/un.h","net/if.h","netinet/in.h"]
|
35
|
+
optional_headers = []
|
36
|
+
sockaddrs = [ 'at', 'ax25', 'dl', 'eon', 'in', 'in6',
|
37
|
+
'inarp', 'ipx', 'iso', 'ns', 'un', 'x25',
|
38
|
+
'rose', 'ash', 'ec', 'll', 'atmpvc', 'atmsvc',
|
39
|
+
'dn', 'irda', 'llc']
|
40
|
+
|
41
|
+
# 1) Check for getifaddrs
|
42
|
+
unless @force_ioctl
|
43
|
+
need_ioctl = !(have_func("getifaddrs"))
|
44
|
+
end
|
45
|
+
|
46
|
+
# 2) Check for getnameinfo or redefine it in netifaces.c
|
47
|
+
have_func("getnameinfo")
|
48
|
+
|
49
|
+
# 3) Whitout getifaddrs we'll have to deal with ioctls
|
50
|
+
if need_ioctl or @force_ioctl
|
51
|
+
ioctls = [
|
52
|
+
'SIOCGIFCONF','SIOCGSIZIFCONF','SIOCGIFHWADDR','SIOCGIFADDR','SIOCGIFFLAGS','SIOCGIFDSTADDR',
|
53
|
+
'SIOCGIFBRDADDR','SIOCGIFNETMASK','SIOCGLIFNUM','SIOCGLIFCONF','SIOCGLIFFLAGS']
|
54
|
+
ioctls_headers = ['sys/types.h','sys/socket.h','sys/ioctl.h','net/if.h','netinet/in.h','arpa/inet.h']
|
55
|
+
#TODO Test this on sunos
|
56
|
+
#if RUBY_PLATFORM =~ /sunos/
|
57
|
+
# ioctls_headers += ['unistd.h','stropts.h','sys/sockio.h']
|
58
|
+
#end
|
59
|
+
$defs.push '-DHAVE_SOCKET_IOCTLS'
|
60
|
+
ioctls.each do |ioctl|
|
61
|
+
if have_macro(ioctl, ioctls_headers)
|
62
|
+
$defs.push "-DHAVE_#{ioctl}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# 4) Check for optional headers
|
68
|
+
headers.each do |header|
|
69
|
+
if have_header(header)
|
70
|
+
optional_headers.push(header)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# 5) On certain platforms (Linux), there's no sa_len.
|
75
|
+
# Unfortunately, getifaddrs() doesn't return the
|
76
|
+
# lengths, because they're in the sa_len field on just about
|
77
|
+
# everything but Linux.
|
78
|
+
# In this case we will define a macro that will return the sa_len from
|
79
|
+
# the sockaddr_xx structure if they are available
|
80
|
+
if (!have_struct_member("struct sockaddr", "sa_len", ["sys/types.h","sys/socket.h","net/if.h"]))
|
81
|
+
sockaddrs.each do |sockaddr|
|
82
|
+
have_type("struct sockaddr_" + sockaddr, additionnal_headers + optional_headers)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
#rework the defs to make them compatible with the original netifaces.c code
|
88
|
+
$defs = $defs.map do |a|
|
89
|
+
if a =~ /^-DHAVE_TYPE_STRUCT_SOCKADDR_.*$/ then a.gsub("TYPE_STRUCT_","")
|
90
|
+
elsif a == "-DHAVE_ST_SA_LEN" then a.gsub("HAVE_ST_","HAVE_SOCKADDR_")
|
91
|
+
else a
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
create_makefile(extension_name)
|
@@ -0,0 +1,1008 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include "netifaces.h"
|
3
|
+
|
4
|
+
#if !defined(WIN32)
|
5
|
+
#if !HAVE_GETNAMEINFO
|
6
|
+
#undef getnameinfo
|
7
|
+
#undef NI_NUMERICHOST
|
8
|
+
|
9
|
+
#define getnameinfo our_getnameinfo
|
10
|
+
#define NI_NUMERICHOST 1
|
11
|
+
|
12
|
+
/* A very simple getnameinfo() for platforms without */
|
13
|
+
static int
|
14
|
+
getnameinfo (const struct sockaddr *addr, int addr_len,
|
15
|
+
char *buffer, int buflen,
|
16
|
+
char *buf2, int buf2len,
|
17
|
+
int flags)
|
18
|
+
{
|
19
|
+
switch (addr->sa_family)
|
20
|
+
{
|
21
|
+
case AF_INET:
|
22
|
+
{
|
23
|
+
const struct sockaddr_in *sin = (struct sockaddr_in *)addr;
|
24
|
+
const unsigned char *bytes = (unsigned char *)&sin->sin_addr.s_addr;
|
25
|
+
char tmpbuf[20];
|
26
|
+
|
27
|
+
sprintf (tmpbuf, "%d.%d.%d.%d",
|
28
|
+
bytes[0], bytes[1], bytes[2], bytes[3]);
|
29
|
+
|
30
|
+
strncpy (buffer, tmpbuf, buflen);
|
31
|
+
}
|
32
|
+
break;
|
33
|
+
#ifdef AF_INET6
|
34
|
+
case AF_INET6:
|
35
|
+
{
|
36
|
+
const struct sockaddr_in6 *sin = (const struct sockaddr_in6 *)addr;
|
37
|
+
const unsigned char *bytes = sin->sin6_addr.s6_addr;
|
38
|
+
int n;
|
39
|
+
char tmpbuf[80], *ptr = tmpbuf;
|
40
|
+
int done_double_colon = FALSE;
|
41
|
+
int colon_mode = FALSE;
|
42
|
+
|
43
|
+
for (n = 0; n < 8; ++n)
|
44
|
+
{
|
45
|
+
unsigned char b1 = bytes[2 * n];
|
46
|
+
unsigned char b2 = bytes[2 * n + 1];
|
47
|
+
|
48
|
+
if (b1)
|
49
|
+
{
|
50
|
+
if (colon_mode)
|
51
|
+
{
|
52
|
+
colon_mode = FALSE;
|
53
|
+
*ptr++ = ':';
|
54
|
+
}
|
55
|
+
sprintf (ptr, "%x%02x", b1, b2);
|
56
|
+
ptr += strlen (ptr);
|
57
|
+
*ptr++ = ':';
|
58
|
+
}
|
59
|
+
else if (b2)
|
60
|
+
{
|
61
|
+
if (colon_mode)
|
62
|
+
{
|
63
|
+
colon_mode = FALSE;
|
64
|
+
*ptr++ = ':';
|
65
|
+
}
|
66
|
+
sprintf (ptr, "%x", b2);
|
67
|
+
ptr += strlen (ptr);
|
68
|
+
*ptr++ = ':';
|
69
|
+
}
|
70
|
+
else {
|
71
|
+
if (!colon_mode)
|
72
|
+
{
|
73
|
+
if (done_double_colon)
|
74
|
+
{
|
75
|
+
*ptr++ = '0';
|
76
|
+
*ptr++ = ':';
|
77
|
+
}
|
78
|
+
else
|
79
|
+
{
|
80
|
+
if (n == 0)
|
81
|
+
*ptr++ = ':';
|
82
|
+
colon_mode = TRUE;
|
83
|
+
done_double_colon = TRUE;
|
84
|
+
}
|
85
|
+
}
|
86
|
+
}
|
87
|
+
}
|
88
|
+
if (colon_mode)
|
89
|
+
{
|
90
|
+
colon_mode = FALSE;
|
91
|
+
*ptr++ = ':';
|
92
|
+
*ptr++ = '\0';
|
93
|
+
}
|
94
|
+
else
|
95
|
+
{
|
96
|
+
*--ptr = '\0';
|
97
|
+
}
|
98
|
+
|
99
|
+
strncpy (buffer, tmpbuf, buflen);
|
100
|
+
}
|
101
|
+
break;
|
102
|
+
#endif /* AF_INET6 */
|
103
|
+
default:
|
104
|
+
return -1;
|
105
|
+
}
|
106
|
+
|
107
|
+
return 0;
|
108
|
+
}
|
109
|
+
#endif
|
110
|
+
|
111
|
+
static int
|
112
|
+
string_from_sockaddr (struct sockaddr *addr,
|
113
|
+
char *buffer,
|
114
|
+
int buflen)
|
115
|
+
{
|
116
|
+
if (!addr || addr->sa_family == AF_UNSPEC)
|
117
|
+
return -1;
|
118
|
+
|
119
|
+
if (getnameinfo (addr, SA_LEN(addr),
|
120
|
+
buffer, buflen,
|
121
|
+
NULL, 0,
|
122
|
+
NI_NUMERICHOST) != 0)
|
123
|
+
{
|
124
|
+
int n, len;
|
125
|
+
char *ptr;
|
126
|
+
const char *data;
|
127
|
+
|
128
|
+
len = SA_LEN(addr);
|
129
|
+
|
130
|
+
#if HAVE_AF_LINK
|
131
|
+
/* BSD-like systems have AF_LINK */
|
132
|
+
if (addr->sa_family == AF_LINK)
|
133
|
+
{
|
134
|
+
struct sockaddr_dl *dladdr = (struct sockaddr_dl *)addr;
|
135
|
+
len = dladdr->sdl_alen;
|
136
|
+
if(len >=0)
|
137
|
+
data = LLADDR(dladdr);
|
138
|
+
}
|
139
|
+
else
|
140
|
+
{
|
141
|
+
#endif
|
142
|
+
#if defined(AF_PACKET)
|
143
|
+
/* Linux has AF_PACKET instead */
|
144
|
+
if (addr->sa_family == AF_PACKET)
|
145
|
+
{
|
146
|
+
struct sockaddr_ll *lladdr = (struct sockaddr_ll *)addr;
|
147
|
+
len = lladdr->sll_halen;
|
148
|
+
//amaloteaux: openbsd and maybe other systems have a len of 0 for enc0,pflog0 .. interfaces
|
149
|
+
if(len >=0)
|
150
|
+
data = (const char *)lladdr->sll_addr;
|
151
|
+
}
|
152
|
+
else
|
153
|
+
{
|
154
|
+
#endif
|
155
|
+
/* We don't know anything about this sockaddr, so just display
|
156
|
+
the entire data area in binary. */
|
157
|
+
len -= (int)(sizeof (struct sockaddr) - sizeof (addr->sa_data));
|
158
|
+
data = addr->sa_data;
|
159
|
+
#if defined(AF_PACKET)
|
160
|
+
}
|
161
|
+
#endif
|
162
|
+
#if HAVE_AF_LINK
|
163
|
+
}
|
164
|
+
#endif
|
165
|
+
|
166
|
+
if ((buflen < 3 * len) || len <= 0)
|
167
|
+
return -1;
|
168
|
+
|
169
|
+
ptr = buffer;
|
170
|
+
buffer[0] = '\0';
|
171
|
+
|
172
|
+
for (n = 0; n < len; ++n)
|
173
|
+
{
|
174
|
+
sprintf (ptr, "%02x:", data[n] & 0xff);
|
175
|
+
ptr += 3;
|
176
|
+
}
|
177
|
+
*--ptr = '\0';
|
178
|
+
}
|
179
|
+
|
180
|
+
return 0;
|
181
|
+
}
|
182
|
+
#endif /* !defined(WIN32) */
|
183
|
+
|
184
|
+
static VALUE add_to_family(VALUE result, VALUE family, VALUE value)
|
185
|
+
{
|
186
|
+
VALUE list;
|
187
|
+
Check_Type(result, T_HASH);
|
188
|
+
Check_Type(family, T_FIXNUM);
|
189
|
+
Check_Type(value, T_HASH);
|
190
|
+
|
191
|
+
list = rb_hash_aref(result, family);
|
192
|
+
|
193
|
+
if (list == Qnil)
|
194
|
+
list = rb_ary_new();
|
195
|
+
else
|
196
|
+
Check_Type(list, T_ARRAY);
|
197
|
+
|
198
|
+
rb_ary_push(list, value);
|
199
|
+
rb_hash_aset(result, family, list);
|
200
|
+
return result;
|
201
|
+
}
|
202
|
+
|
203
|
+
VALUE
|
204
|
+
rbnetifaces_s_addresses (VALUE class, VALUE dev)
|
205
|
+
{
|
206
|
+
VALUE result;
|
207
|
+
int found = FALSE;
|
208
|
+
#if defined(WIN32)
|
209
|
+
PIP_ADAPTER_INFO pAdapterInfo = NULL;
|
210
|
+
PIP_ADAPTER_INFO pInfo = NULL;
|
211
|
+
ULONG ulBufferLength = 0;
|
212
|
+
DWORD dwRet;
|
213
|
+
PIP_ADDR_STRING str;
|
214
|
+
#elif HAVE_GETIFADDRS
|
215
|
+
struct ifaddrs *addrs = NULL;
|
216
|
+
struct ifaddrs *addr = NULL;
|
217
|
+
VALUE result2;
|
218
|
+
#elif HAVE_SOCKET_IOCTLS
|
219
|
+
int sock;
|
220
|
+
struct CNAME(ifreq) ifr;
|
221
|
+
char buffer[256];
|
222
|
+
int is_p2p = FALSE;
|
223
|
+
VALUE rbaddr = Qnil;
|
224
|
+
VALUE rbnetmask = Qnil;
|
225
|
+
VALUE rbbraddr = Qnil;
|
226
|
+
VALUE rbdstaddr = Qnil;
|
227
|
+
VALUE result2;
|
228
|
+
#endif
|
229
|
+
|
230
|
+
Check_Type(dev, T_STRING);
|
231
|
+
result = rb_hash_new();
|
232
|
+
|
233
|
+
#if defined(WIN32)
|
234
|
+
//First, retrieve the adapter information. We do this in a loop, in
|
235
|
+
//case someone adds or removes adapters in the meantime.
|
236
|
+
do
|
237
|
+
{
|
238
|
+
dwRet = GetAdaptersInfo(pAdapterInfo, &ulBufferLength);
|
239
|
+
|
240
|
+
if (dwRet == ERROR_BUFFER_OVERFLOW)
|
241
|
+
{
|
242
|
+
if (pAdapterInfo)
|
243
|
+
free (pAdapterInfo);
|
244
|
+
pAdapterInfo = (PIP_ADAPTER_INFO)malloc (ulBufferLength);
|
245
|
+
|
246
|
+
if (!pAdapterInfo)
|
247
|
+
{
|
248
|
+
rb_raise(rb_eRuntimeError, "Unknow error at OS level");
|
249
|
+
return Qnil;
|
250
|
+
}
|
251
|
+
}
|
252
|
+
} while (dwRet == ERROR_BUFFER_OVERFLOW);
|
253
|
+
|
254
|
+
// If we failed, then fail in Ruby too
|
255
|
+
if (dwRet != ERROR_SUCCESS && dwRet != ERROR_NO_DATA)
|
256
|
+
{
|
257
|
+
if (pAdapterInfo)
|
258
|
+
free (pAdapterInfo);
|
259
|
+
rb_raise(rb_eRuntimeError, "Unable to obtain adapter information.");
|
260
|
+
return Qnil;
|
261
|
+
}
|
262
|
+
|
263
|
+
for (pInfo = pAdapterInfo; pInfo; pInfo = pInfo->Next)
|
264
|
+
{
|
265
|
+
char buffer[256];
|
266
|
+
//dev is the iface GUID on windows with "\\Device\\NPF_" prefix
|
267
|
+
int cmpAdapterNamelen = (MAX_ADAPTER_NAME_LENGTH + 4) + 12;
|
268
|
+
char cmpAdapterName[cmpAdapterNamelen];
|
269
|
+
int AdapterName_len = strlen(pInfo->AdapterName);
|
270
|
+
|
271
|
+
VALUE rbhardw = Qnil;
|
272
|
+
VALUE rbaddr = Qnil;
|
273
|
+
VALUE rbnetmask = Qnil;
|
274
|
+
VALUE rbbraddr = Qnil;
|
275
|
+
|
276
|
+
memset(cmpAdapterName, 0x00, cmpAdapterNamelen);
|
277
|
+
strncpy(cmpAdapterName, "\\Device\\NPF_", 12);
|
278
|
+
strncpy(cmpAdapterName + 12, pInfo->AdapterName, AdapterName_len);
|
279
|
+
if (strcmp (cmpAdapterName, StringValuePtr(dev)) != 0)
|
280
|
+
continue;
|
281
|
+
|
282
|
+
found = TRUE;
|
283
|
+
|
284
|
+
// Do the physical address
|
285
|
+
if (256 >= 3 * pInfo->AddressLength)
|
286
|
+
{
|
287
|
+
char *ptr = buffer;
|
288
|
+
unsigned n;
|
289
|
+
VALUE hash_hardw;
|
290
|
+
hash_hardw = rb_hash_new();
|
291
|
+
|
292
|
+
*ptr = '\0';
|
293
|
+
for (n = 0; n < pInfo->AddressLength; ++n)
|
294
|
+
{
|
295
|
+
sprintf (ptr, "%02x:", pInfo->Address[n] & 0xff);
|
296
|
+
ptr += 3;
|
297
|
+
}
|
298
|
+
*--ptr = '\0';
|
299
|
+
|
300
|
+
rbhardw = rb_str_new2(buffer);
|
301
|
+
rb_hash_aset(hash_hardw, rb_str_new2("addr"), rbhardw);
|
302
|
+
result = add_to_family(result, INT2FIX(AF_LINK), hash_hardw);
|
303
|
+
}
|
304
|
+
|
305
|
+
for (str = &pInfo->IpAddressList; str; str = str->Next)
|
306
|
+
{
|
307
|
+
|
308
|
+
VALUE result2;
|
309
|
+
result2 = rb_hash_new();
|
310
|
+
|
311
|
+
if(str->IpAddress.String)
|
312
|
+
rbaddr = rb_str_new2(str->IpAddress.String);
|
313
|
+
if(str->IpMask.String)
|
314
|
+
rbnetmask = rb_str_new2(str->IpMask.String);
|
315
|
+
|
316
|
+
//If this isn't the loopback interface, work out the broadcast
|
317
|
+
//address, for better compatibility with other platforms.
|
318
|
+
if (pInfo->Type != MIB_IF_TYPE_LOOPBACK)
|
319
|
+
{
|
320
|
+
unsigned long inaddr = inet_addr (str->IpAddress.String);
|
321
|
+
unsigned long inmask = inet_addr (str->IpMask.String);
|
322
|
+
struct in_addr in;
|
323
|
+
char *brstr;
|
324
|
+
|
325
|
+
in.S_un.S_addr = (inaddr | ~inmask) & 0xfffffffful;
|
326
|
+
|
327
|
+
brstr = inet_ntoa (in);
|
328
|
+
|
329
|
+
if (brstr)
|
330
|
+
rbbraddr = rb_str_new2(brstr);
|
331
|
+
}
|
332
|
+
|
333
|
+
if (rbaddr)
|
334
|
+
rb_hash_aset(result2, rb_str_new2("addr"), rbaddr);
|
335
|
+
if (rbnetmask)
|
336
|
+
rb_hash_aset(result2, rb_str_new2("netmask"), rbnetmask);
|
337
|
+
if (rbbraddr)
|
338
|
+
rb_hash_aset(result2, rb_str_new2("broadcast"), rbbraddr);
|
339
|
+
|
340
|
+
result = add_to_family(result, INT2FIX(AF_INET), result2);
|
341
|
+
|
342
|
+
}
|
343
|
+
} // for
|
344
|
+
|
345
|
+
free (pAdapterInfo);
|
346
|
+
|
347
|
+
#elif HAVE_GETIFADDRS
|
348
|
+
if (getifaddrs (&addrs) < 0)
|
349
|
+
{
|
350
|
+
rb_raise(rb_eRuntimeError, "Unknow error at OS level");
|
351
|
+
}
|
352
|
+
|
353
|
+
for (addr = addrs; addr; addr = addr->ifa_next)
|
354
|
+
{
|
355
|
+
char buffer[256];
|
356
|
+
VALUE rbaddr = Qnil;
|
357
|
+
VALUE rbnetmask = Qnil;
|
358
|
+
VALUE rbbraddr = Qnil;
|
359
|
+
|
360
|
+
if (strcmp (addr->ifa_name, StringValuePtr(dev)) != 0)
|
361
|
+
continue;
|
362
|
+
|
363
|
+
/* Sometimes there are records without addresses (e.g. in the case of a
|
364
|
+
dial-up connection via ppp, which on Linux can have a link address
|
365
|
+
record with no actual address). We skip these as they aren't useful.
|
366
|
+
Thanks to Christian Kauhaus for reporting this issue. */
|
367
|
+
if (!addr->ifa_addr)
|
368
|
+
continue;
|
369
|
+
|
370
|
+
found = TRUE;
|
371
|
+
|
372
|
+
if (string_from_sockaddr (addr->ifa_addr, buffer, sizeof (buffer)) == 0)
|
373
|
+
rbaddr = rb_str_new2(buffer);
|
374
|
+
|
375
|
+
if (string_from_sockaddr (addr->ifa_netmask, buffer, sizeof (buffer)) == 0)
|
376
|
+
rbnetmask = rb_str_new2(buffer);
|
377
|
+
|
378
|
+
if (string_from_sockaddr (addr->ifa_broadaddr, buffer, sizeof (buffer)) == 0)
|
379
|
+
rbbraddr = rb_str_new2(buffer);
|
380
|
+
|
381
|
+
result2 = rb_hash_new();
|
382
|
+
|
383
|
+
if (rbaddr)
|
384
|
+
rb_hash_aset(result2, rb_str_new2("addr"), rbaddr);
|
385
|
+
if (rbnetmask)
|
386
|
+
rb_hash_aset(result2, rb_str_new2("netmask"), rbnetmask);
|
387
|
+
if (rbbraddr)
|
388
|
+
{
|
389
|
+
if (addr->ifa_flags & (IFF_POINTOPOINT | IFF_LOOPBACK))
|
390
|
+
rb_hash_aset(result2, rb_str_new2("peer"), rbbraddr);
|
391
|
+
else
|
392
|
+
rb_hash_aset(result2, rb_str_new2("broadcast"), rbbraddr);
|
393
|
+
}
|
394
|
+
if (rbaddr || rbnetmask || rbbraddr)
|
395
|
+
result = add_to_family(result, INT2FIX(addr->ifa_addr->sa_family), result2);
|
396
|
+
}
|
397
|
+
freeifaddrs (addrs);
|
398
|
+
#elif HAVE_SOCKET_IOCTLS
|
399
|
+
|
400
|
+
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
401
|
+
|
402
|
+
if (sock < 0)
|
403
|
+
{
|
404
|
+
rb_raise(rb_eRuntimeError, "Unknow error at OS level");
|
405
|
+
return Qnil;
|
406
|
+
}
|
407
|
+
|
408
|
+
strncpy (ifr.CNAME(ifr_name), StringValuePtr(dev), IFNAMSIZ);
|
409
|
+
|
410
|
+
#if HAVE_SIOCGIFHWADDR
|
411
|
+
if (ioctl (sock, SIOCGIFHWADDR, &ifr) == 0)
|
412
|
+
{
|
413
|
+
if (string_from_sockaddr (&(ifr.CNAME(ifr_addr)), buffer, sizeof (buffer)) == 0)
|
414
|
+
{
|
415
|
+
found = TRUE;
|
416
|
+
|
417
|
+
VALUE rbhardw = Qnil;
|
418
|
+
VALUE hash_hardw;
|
419
|
+
hash_hardw = rb_hash_new();
|
420
|
+
rbhardw = rb_str_new2(buffer);
|
421
|
+
rb_hash_aset(hash_hardw, rb_str_new2("addr"), rbhardw);
|
422
|
+
result = add_to_family(result, INT2FIX(AF_LINK), hash_hardw);
|
423
|
+
}
|
424
|
+
}
|
425
|
+
#endif
|
426
|
+
|
427
|
+
|
428
|
+
#if HAVE_SIOCGIFADDR
|
429
|
+
#if HAVE_SIOCGLIFNUM
|
430
|
+
if (ioctl (sock, SIOCGLIFADDR, &ifr) == 0)
|
431
|
+
{
|
432
|
+
#else
|
433
|
+
if (ioctl (sock, SIOCGIFADDR, &ifr) == 0)
|
434
|
+
{
|
435
|
+
#endif
|
436
|
+
if (string_from_sockaddr ((struct sockaddr *)&ifr.CNAME(ifr_addr), buffer, sizeof (buffer)) == 0)
|
437
|
+
{
|
438
|
+
found = TRUE;
|
439
|
+
rbaddr = rb_str_new2(buffer);
|
440
|
+
}
|
441
|
+
}
|
442
|
+
#endif
|
443
|
+
|
444
|
+
#if HAVE_SIOCGIFNETMASK
|
445
|
+
#if HAVE_SIOCGLIFNUM
|
446
|
+
if (ioctl (sock, SIOCGLIFNETMASK, &ifr) == 0)
|
447
|
+
{
|
448
|
+
#else
|
449
|
+
if (ioctl (sock, SIOCGIFNETMASK, &ifr) == 0)
|
450
|
+
{
|
451
|
+
#endif
|
452
|
+
if (string_from_sockaddr ((struct sockaddr *)&ifr.CNAME(ifr_addr), buffer, sizeof (buffer)) == 0)
|
453
|
+
{
|
454
|
+
found = TRUE;
|
455
|
+
rbnetmask = rb_str_new2(buffer);
|
456
|
+
}
|
457
|
+
}
|
458
|
+
#endif
|
459
|
+
|
460
|
+
#if HAVE_SIOCGIFFLAGS
|
461
|
+
#if HAVE_SIOCGLIFNUM
|
462
|
+
if (ioctl (sock, SIOCGLIFFLAGS, &ifr) == 0)
|
463
|
+
{
|
464
|
+
#else
|
465
|
+
if (ioctl (sock, SIOCGIFFLAGS, &ifr) == 0)
|
466
|
+
{
|
467
|
+
#endif
|
468
|
+
|
469
|
+
if (ifr.CNAME(ifr_flags) & IFF_POINTOPOINT)
|
470
|
+
{
|
471
|
+
is_p2p = TRUE;
|
472
|
+
}
|
473
|
+
}
|
474
|
+
#endif
|
475
|
+
|
476
|
+
#if HAVE_SIOCGIFBRDADDR
|
477
|
+
#if HAVE_SIOCGLIFNUM
|
478
|
+
if (!is_p2p && ioctl (sock, SIOCGLIFBRDADDR, &ifr) == 0)
|
479
|
+
{
|
480
|
+
#else
|
481
|
+
if (!is_p2p && ioctl (sock, SIOCGIFBRDADDR, &ifr) == 0)
|
482
|
+
{
|
483
|
+
#endif
|
484
|
+
|
485
|
+
|
486
|
+
if (string_from_sockaddr ((struct sockaddr *)&ifr.CNAME(ifr_addr), buffer, sizeof (buffer)) == 0)
|
487
|
+
{
|
488
|
+
found = TRUE;
|
489
|
+
rbbraddr = rb_str_new2(buffer);
|
490
|
+
}
|
491
|
+
}
|
492
|
+
#endif
|
493
|
+
|
494
|
+
#if HAVE_SIOCGIFDSTADDR
|
495
|
+
#if HAVE_SIOCGLIFNUM
|
496
|
+
if (is_p2p && ioctl (sock, SIOCGLIFBRDADDR, &ifr) == 0)
|
497
|
+
{
|
498
|
+
#else
|
499
|
+
if (is_p2p && ioctl (sock, SIOCGIFBRDADDR, &ifr) == 0)
|
500
|
+
{
|
501
|
+
#endif
|
502
|
+
if (string_from_sockaddr ((struct sockaddr *)&ifr.CNAME(ifr_addr), buffer, sizeof (buffer)) == 0)
|
503
|
+
{
|
504
|
+
found = TRUE;
|
505
|
+
rbdstaddr = rb_str_new2(buffer);
|
506
|
+
}
|
507
|
+
}
|
508
|
+
|
509
|
+
#endif
|
510
|
+
result2 = rb_hash_new();
|
511
|
+
|
512
|
+
if (rbaddr)
|
513
|
+
rb_hash_aset(result2, rb_str_new2("addr"), rbaddr);
|
514
|
+
if (rbnetmask)
|
515
|
+
rb_hash_aset(result2, rb_str_new2("netmask"), rbnetmask);
|
516
|
+
if (rbbraddr)
|
517
|
+
rb_hash_aset(result2, rb_str_new2("broadcast"), rbbraddr);
|
518
|
+
if (rbdstaddr)
|
519
|
+
rb_hash_aset(result2, rb_str_new2("peer"), rbbraddr);
|
520
|
+
|
521
|
+
if (rbaddr || rbnetmask || rbbraddr || rbdstaddr)
|
522
|
+
result = add_to_family(result, INT2FIX(AF_INET), result2);
|
523
|
+
|
524
|
+
close (sock);
|
525
|
+
#endif /* HAVE_SOCKET_IOCTLS */
|
526
|
+
|
527
|
+
if (found)
|
528
|
+
return result;
|
529
|
+
else
|
530
|
+
return Qnil;
|
531
|
+
|
532
|
+
}
|
533
|
+
|
534
|
+
VALUE
|
535
|
+
rbnetifaces_s_interfaces (VALUE self)
|
536
|
+
{
|
537
|
+
VALUE result;
|
538
|
+
#if defined(WIN32)
|
539
|
+
PIP_ADAPTER_INFO pAdapterInfo = NULL;
|
540
|
+
PIP_ADAPTER_INFO pInfo = NULL;
|
541
|
+
ULONG ulBufferLength = 0;
|
542
|
+
DWORD dwRet;
|
543
|
+
#elif HAVE_GETIFADDRS
|
544
|
+
const char *prev_name = NULL;
|
545
|
+
struct ifaddrs *addrs = NULL;
|
546
|
+
struct ifaddrs *addr = NULL;
|
547
|
+
#elif HAVE_SIOCGIFCONF
|
548
|
+
const char *prev_name = NULL;
|
549
|
+
int fd, len, n;
|
550
|
+
struct CNAME(ifconf) ifc;
|
551
|
+
struct CNAME(ifreq) *pfreq;
|
552
|
+
#endif
|
553
|
+
|
554
|
+
result = rb_ary_new();
|
555
|
+
|
556
|
+
#if defined(WIN32)
|
557
|
+
// First, retrieve the adapter information
|
558
|
+
do {
|
559
|
+
dwRet = GetAdaptersInfo(pAdapterInfo, &ulBufferLength);
|
560
|
+
|
561
|
+
if (dwRet == ERROR_BUFFER_OVERFLOW)
|
562
|
+
{
|
563
|
+
if (pAdapterInfo)
|
564
|
+
free (pAdapterInfo);
|
565
|
+
pAdapterInfo = (PIP_ADAPTER_INFO)malloc (ulBufferLength);
|
566
|
+
|
567
|
+
if (!pAdapterInfo)
|
568
|
+
{
|
569
|
+
rb_raise(rb_eRuntimeError, "Unknow error at OS level");
|
570
|
+
}
|
571
|
+
}
|
572
|
+
} while (dwRet == ERROR_BUFFER_OVERFLOW);
|
573
|
+
|
574
|
+
// If we failed, then fail in Ruby too
|
575
|
+
if (dwRet != ERROR_SUCCESS && dwRet != ERROR_NO_DATA)
|
576
|
+
{
|
577
|
+
if (pAdapterInfo)
|
578
|
+
free (pAdapterInfo);
|
579
|
+
|
580
|
+
rb_raise(rb_eRuntimeError, "Unknow error at OS level");
|
581
|
+
return Qnil;
|
582
|
+
}
|
583
|
+
if (dwRet == ERROR_NO_DATA)
|
584
|
+
{
|
585
|
+
free (pAdapterInfo);
|
586
|
+
return result;
|
587
|
+
}
|
588
|
+
|
589
|
+
for (pInfo = pAdapterInfo; pInfo; pInfo = pInfo->Next)
|
590
|
+
{
|
591
|
+
int outputnamelen = (MAX_ADAPTER_NAME_LENGTH + 4) + 12;
|
592
|
+
char outputname[outputnamelen];
|
593
|
+
int AdapterName_len = strlen(pInfo->AdapterName);
|
594
|
+
VALUE ifname;
|
595
|
+
memset(outputname, 0x00, outputnamelen);
|
596
|
+
strncpy(outputname, "\\Device\\NPF_", 12);
|
597
|
+
strncpy(outputname + 12, pInfo->AdapterName, AdapterName_len);
|
598
|
+
ifname = rb_str_new2(outputname) ;
|
599
|
+
|
600
|
+
if(!rb_ary_includes(result, ifname))
|
601
|
+
rb_ary_push(result, ifname);
|
602
|
+
}
|
603
|
+
|
604
|
+
free (pAdapterInfo);
|
605
|
+
|
606
|
+
#elif HAVE_GETIFADDRS
|
607
|
+
if (getifaddrs (&addrs) < 0)
|
608
|
+
{
|
609
|
+
rb_raise(rb_eRuntimeError, "Unknow error at OS level");
|
610
|
+
}
|
611
|
+
|
612
|
+
for (addr = addrs; addr; addr = addr->ifa_next)
|
613
|
+
{
|
614
|
+
if (!prev_name || strncmp (addr->ifa_name, prev_name, IFNAMSIZ) != 0)
|
615
|
+
{
|
616
|
+
VALUE ifname = rb_str_new2(addr->ifa_name);
|
617
|
+
|
618
|
+
if(!rb_ary_includes(result, ifname))
|
619
|
+
rb_ary_push(result, ifname);
|
620
|
+
|
621
|
+
prev_name = addr->ifa_name;
|
622
|
+
}
|
623
|
+
}
|
624
|
+
|
625
|
+
freeifaddrs (addrs);
|
626
|
+
#elif HAVE_SIOCGIFCONF
|
627
|
+
|
628
|
+
fd = socket (AF_INET, SOCK_DGRAM, 0);
|
629
|
+
len = -1;
|
630
|
+
if (fd < 0) {
|
631
|
+
rb_raise(rb_eRuntimeError, "Unknow error at OS level");
|
632
|
+
return Qnil;
|
633
|
+
}
|
634
|
+
|
635
|
+
// Try to find out how much space we need
|
636
|
+
#if HAVE_SIOCGSIZIFCONF
|
637
|
+
if (ioctl (fd, SIOCGSIZIFCONF, &len) < 0)
|
638
|
+
len = -1;
|
639
|
+
#elif HAVE_SIOCGLIFNUM
|
640
|
+
#error This code need to be checked first
|
641
|
+
/*
|
642
|
+
{ struct lifnum lifn;
|
643
|
+
lifn.lifn_family = AF_UNSPEC;
|
644
|
+
lifn.lifn_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
|
645
|
+
ifc.lifc_family = AF_UNSPEC;
|
646
|
+
ifc.lifc_flags = LIFC_NOXMIT | LIFC_TEMPORARY | LIFC_ALLZONES;
|
647
|
+
if (ioctl (fd, SIOCGLIFNUM, (char *)&lifn) < 0)
|
648
|
+
len = -1;
|
649
|
+
else
|
650
|
+
len = lifn.lifn_count;
|
651
|
+
}
|
652
|
+
*/
|
653
|
+
#endif
|
654
|
+
|
655
|
+
// As a last resort, guess
|
656
|
+
if (len < 0)
|
657
|
+
len = 64;
|
658
|
+
|
659
|
+
ifc.CNAME(ifc_len) = len * sizeof (struct CNAME(ifreq));
|
660
|
+
ifc.CNAME(ifc_buf) = malloc (ifc.CNAME(ifc_len));
|
661
|
+
|
662
|
+
if (!ifc.CNAME(ifc_buf)) {
|
663
|
+
close (fd);
|
664
|
+
rb_raise(rb_eRuntimeError, "Not enough memory");
|
665
|
+
return Qnil;
|
666
|
+
}
|
667
|
+
|
668
|
+
#if HAVE_SIOCGLIFNUM
|
669
|
+
if (ioctl (fd, SIOCGLIFCONF, &ifc) < 0) {
|
670
|
+
#else
|
671
|
+
if (ioctl (fd, SIOCGIFCONF, &ifc) < 0) {
|
672
|
+
|
673
|
+
#endif
|
674
|
+
free (ifc.CNAME(ifc_req));
|
675
|
+
close (fd);
|
676
|
+
rb_raise(rb_eRuntimeError, "Unknow error at OS level");
|
677
|
+
return Qnil;
|
678
|
+
}
|
679
|
+
|
680
|
+
*pfreq = ifc.CNAME(ifc_req);
|
681
|
+
|
682
|
+
for (n = 0; n < ifc.CNAME(ifc_len)/sizeof(struct CNAME(ifreq));n++,pfreq++)
|
683
|
+
{
|
684
|
+
if (!prev_name || strncmp (prev_name, pfreq->CNAME(ifr_name), IFNAMSIZ) != 0)
|
685
|
+
{
|
686
|
+
VALUE ifname = rb_str_new2(pfreq->CNAME(ifr_name));
|
687
|
+
if(!rb_ary_includes(result, ifname))
|
688
|
+
rb_ary_push(result, ifname);
|
689
|
+
|
690
|
+
prev_name = pfreq->CNAME(ifr_name);
|
691
|
+
}
|
692
|
+
}
|
693
|
+
|
694
|
+
free (ifc.CNAME(ifc_buf));
|
695
|
+
close (fd);
|
696
|
+
|
697
|
+
#endif //
|
698
|
+
|
699
|
+
return result;
|
700
|
+
}
|
701
|
+
|
702
|
+
//This function is usefull only under windows to retrieve some additionnal interfaces informations
|
703
|
+
VALUE
|
704
|
+
rbnetifaces_s_interface_info (VALUE self, VALUE dev)
|
705
|
+
{
|
706
|
+
VALUE result = Qnil;
|
707
|
+
|
708
|
+
#if defined(WIN32)
|
709
|
+
|
710
|
+
PIP_ADAPTER_INFO pAdapterInfo = NULL;
|
711
|
+
PIP_ADAPTER_INFO pInfo = NULL;
|
712
|
+
ULONG ulBufferLength = 0;
|
713
|
+
DWORD dwRet;
|
714
|
+
|
715
|
+
// First, retrieve the adapter information
|
716
|
+
do {
|
717
|
+
dwRet = GetAdaptersInfo(pAdapterInfo, &ulBufferLength);
|
718
|
+
|
719
|
+
if (dwRet == ERROR_BUFFER_OVERFLOW)
|
720
|
+
{
|
721
|
+
if (pAdapterInfo)
|
722
|
+
free (pAdapterInfo);
|
723
|
+
pAdapterInfo = (PIP_ADAPTER_INFO)malloc (ulBufferLength);
|
724
|
+
|
725
|
+
if (!pAdapterInfo)
|
726
|
+
{
|
727
|
+
rb_raise(rb_eRuntimeError, "Unknow error at OS level");
|
728
|
+
}
|
729
|
+
}
|
730
|
+
} while (dwRet == ERROR_BUFFER_OVERFLOW);
|
731
|
+
|
732
|
+
// If we failed, then fail in Ruby too
|
733
|
+
if (dwRet != ERROR_SUCCESS && dwRet != ERROR_NO_DATA)
|
734
|
+
{
|
735
|
+
if (pAdapterInfo)
|
736
|
+
free (pAdapterInfo);
|
737
|
+
|
738
|
+
rb_raise(rb_eRuntimeError, "Unknow error at OS level");
|
739
|
+
return Qnil;
|
740
|
+
}
|
741
|
+
if (dwRet == ERROR_NO_DATA)
|
742
|
+
{
|
743
|
+
free (pAdapterInfo);
|
744
|
+
return result;
|
745
|
+
}
|
746
|
+
|
747
|
+
for (pInfo = pAdapterInfo; pInfo; pInfo = pInfo->Next)
|
748
|
+
{
|
749
|
+
// registry name location
|
750
|
+
const char* prefix = "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\";
|
751
|
+
const char* sufix = "\\Connection";
|
752
|
+
int prefix_len, sufix_len, adaptername_len;
|
753
|
+
char* keypath = NULL;
|
754
|
+
HKEY hKey;
|
755
|
+
LONG lRet = 0;
|
756
|
+
LPBYTE buffer = NULL;
|
757
|
+
DWORD dwSize = 0;
|
758
|
+
|
759
|
+
//dev is the iface GUID on windows with "\\Device\\NPF_" prefix
|
760
|
+
int cmpAdapterNamelen = (MAX_ADAPTER_NAME_LENGTH + 4) + 12;
|
761
|
+
char cmpAdapterName[cmpAdapterNamelen];
|
762
|
+
int AdapterName_len = strlen(pInfo->AdapterName);
|
763
|
+
memset(cmpAdapterName, 0x00, cmpAdapterNamelen);
|
764
|
+
strncpy(cmpAdapterName, "\\Device\\NPF_", 12);
|
765
|
+
strncpy(cmpAdapterName + 12, pInfo->AdapterName, AdapterName_len);
|
766
|
+
if (strcmp (cmpAdapterName, StringValuePtr(dev)) != 0)
|
767
|
+
continue;
|
768
|
+
|
769
|
+
result = rb_hash_new();
|
770
|
+
rb_hash_aset(result, rb_str_new2("description"), rb_str_new2(pInfo->Description));
|
771
|
+
rb_hash_aset(result, rb_str_new2("guid"), rb_str_new2(pInfo->AdapterName));
|
772
|
+
|
773
|
+
// Get the name from the registry
|
774
|
+
prefix_len = strlen(prefix);
|
775
|
+
sufix_len = strlen(sufix);
|
776
|
+
adaptername_len = strlen(pInfo->AdapterName);
|
777
|
+
keypath = malloc(prefix_len + sufix_len + adaptername_len + 1);
|
778
|
+
memset(keypath, 0x00, prefix_len + sufix_len + adaptername_len + 1);
|
779
|
+
strncpy(keypath, prefix, prefix_len);
|
780
|
+
strncpy(keypath + prefix_len, pInfo->AdapterName, adaptername_len);
|
781
|
+
strncpy(keypath + prefix_len + adaptername_len, sufix, sufix_len);
|
782
|
+
|
783
|
+
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keypath, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
784
|
+
{
|
785
|
+
// obtain current value size
|
786
|
+
lRet = RegQueryValueEx(hKey, "Name", NULL, NULL, NULL, &dwSize);
|
787
|
+
if (dwSize > 0 && ERROR_SUCCESS == lRet)
|
788
|
+
{
|
789
|
+
buffer = malloc((dwSize * sizeof(BYTE)) + 4);
|
790
|
+
memset(buffer, 0x00, (dwSize * sizeof(BYTE)) + 4);
|
791
|
+
lRet = RegQueryValueEx(hKey, "Name", NULL, NULL, buffer, &dwSize);
|
792
|
+
if (ERROR_SUCCESS == lRet)
|
793
|
+
{
|
794
|
+
rb_hash_aset(result, rb_str_new2("name"), rb_str_new2(buffer));
|
795
|
+
}
|
796
|
+
else
|
797
|
+
{
|
798
|
+
rb_hash_aset(result, rb_str_new2("name"), rb_str_new2(""));
|
799
|
+
}
|
800
|
+
free(buffer);
|
801
|
+
}
|
802
|
+
else
|
803
|
+
{
|
804
|
+
rb_hash_aset(result, rb_str_new2("name"), rb_str_new2(""));
|
805
|
+
}
|
806
|
+
RegCloseKey(hKey);
|
807
|
+
}
|
808
|
+
else
|
809
|
+
{
|
810
|
+
rb_hash_aset(result, rb_str_new2("name"), rb_str_new2(""));
|
811
|
+
}
|
812
|
+
free(keypath);
|
813
|
+
}
|
814
|
+
free (pAdapterInfo);
|
815
|
+
#endif
|
816
|
+
|
817
|
+
return result;
|
818
|
+
}
|
819
|
+
|
820
|
+
VALUE rb_cNetworkInterface;
|
821
|
+
void
|
822
|
+
Init_network_interface_ext()
|
823
|
+
{
|
824
|
+
rb_cNetworkInterface = rb_define_module("NetworkInterface");
|
825
|
+
rb_define_module_function(rb_cNetworkInterface, "interfaces", rbnetifaces_s_interfaces, 0);
|
826
|
+
rb_define_module_function(rb_cNetworkInterface, "addresses", rbnetifaces_s_addresses, 1);
|
827
|
+
rb_define_module_function(rb_cNetworkInterface, "interface_info", rbnetifaces_s_interface_info, 1);
|
828
|
+
|
829
|
+
//constants
|
830
|
+
// Address families (auto-detect using #ifdef)
|
831
|
+
|
832
|
+
#ifdef AF_INET
|
833
|
+
rb_define_const(rb_cNetworkInterface, "AF_INET", INT2NUM(AF_INET));
|
834
|
+
#endif
|
835
|
+
#ifdef AF_INET6
|
836
|
+
rb_define_const(rb_cNetworkInterface, "AF_INET6", INT2NUM(AF_INET6));
|
837
|
+
#endif
|
838
|
+
#ifdef AF_UNSPEC
|
839
|
+
rb_define_const(rb_cNetworkInterface, "AF_UNSPEC", INT2NUM(AF_UNSPEC));
|
840
|
+
#endif
|
841
|
+
#ifdef AF_UNIX
|
842
|
+
rb_define_const(rb_cNetworkInterface, "AF_UNIX", INT2NUM(AF_UNIX));
|
843
|
+
#endif
|
844
|
+
#ifdef AF_FILE
|
845
|
+
rb_define_const(rb_cNetworkInterface, "AF_FILE", INT2NUM(AF_FILE));
|
846
|
+
#endif
|
847
|
+
#ifdef AF_AX25
|
848
|
+
rb_define_const(rb_cNetworkInterface, "AF_AX25", INT2NUM(AF_AX25));
|
849
|
+
#endif
|
850
|
+
#ifdef AF_IMPLINK
|
851
|
+
rb_define_const(rb_cNetworkInterface, "AF_IMPLINK", INT2NUM(AF_IMPLINK));
|
852
|
+
#endif
|
853
|
+
#ifdef AF_PUP
|
854
|
+
rb_define_const(rb_cNetworkInterface, "AF_PUP", INT2NUM(AF_PUP));
|
855
|
+
#endif
|
856
|
+
#ifdef AF_CHAOS
|
857
|
+
rb_define_const(rb_cNetworkInterface, "AF_CHAOS", INT2NUM(AF_CHAOS));
|
858
|
+
#endif
|
859
|
+
#ifdef AF_NS
|
860
|
+
rb_define_const(rb_cNetworkInterface, "AF_NS", INT2NUM(AF_NS));
|
861
|
+
#endif
|
862
|
+
#ifdef AF_ISO
|
863
|
+
rb_define_const(rb_cNetworkInterface, "AF_ISO", INT2NUM(AF_ISO));
|
864
|
+
#endif
|
865
|
+
#ifdef AF_ECMA
|
866
|
+
rb_define_const(rb_cNetworkInterface, "AF_ECMA", INT2NUM(AF_ECMA));
|
867
|
+
#endif
|
868
|
+
#ifdef AF_DATAKIT
|
869
|
+
rb_define_const(rb_cNetworkInterface, "AF_DATAKIT", INT2NUM(AF_DATAKIT));
|
870
|
+
#endif
|
871
|
+
#ifdef AF_CCITT
|
872
|
+
rb_define_const(rb_cNetworkInterface, "AF_CCITT", INT2NUM(AF_CCITT));
|
873
|
+
#endif
|
874
|
+
#ifdef AF_SNA
|
875
|
+
rb_define_const(rb_cNetworkInterface, "AF_SNA", INT2NUM(AF_SNA));
|
876
|
+
#endif
|
877
|
+
#ifdef AF_DECnet
|
878
|
+
rb_define_const(rb_cNetworkInterface, "AF_DECnet", INT2NUM(AF_DECnet));
|
879
|
+
#endif
|
880
|
+
#ifdef AF_DLI
|
881
|
+
rb_define_const(rb_cNetworkInterface, "AF_DLI", INT2NUM(AF_DLI));
|
882
|
+
#endif
|
883
|
+
#ifdef AF_LAT
|
884
|
+
rb_define_const(rb_cNetworkInterface, "AF_LAT", INT2NUM(AF_LAT));
|
885
|
+
#endif
|
886
|
+
#ifdef AF_HYLINK
|
887
|
+
rb_define_const(rb_cNetworkInterface, "AF_HYLINK", INT2NUM(AF_HYLINK));
|
888
|
+
#endif
|
889
|
+
#ifdef AF_APPLETALK
|
890
|
+
rb_define_const(rb_cNetworkInterface, "AF_APPLETALK", INT2NUM(AF_APPLETALK));
|
891
|
+
#endif
|
892
|
+
#ifdef AF_ROUTE
|
893
|
+
rb_define_const(rb_cNetworkInterface, "AF_ROUTE", INT2NUM(AF_ROUTE));
|
894
|
+
#endif
|
895
|
+
#ifdef AF_LINK
|
896
|
+
rb_define_const(rb_cNetworkInterface, "AF_LINK", INT2NUM(AF_LINK));
|
897
|
+
#endif
|
898
|
+
#ifdef AF_PACKET
|
899
|
+
rb_define_const(rb_cNetworkInterface, "AF_PACKET", INT2NUM(AF_PACKET));
|
900
|
+
#endif
|
901
|
+
#ifdef AF_COIP
|
902
|
+
rb_define_const(rb_cNetworkInterface, "AF_COIP", INT2NUM(AF_COIP));
|
903
|
+
#endif
|
904
|
+
#ifdef AF_CNT
|
905
|
+
rb_define_const(rb_cNetworkInterface, "AF_CNT", INT2NUM(AF_CNT));
|
906
|
+
#endif
|
907
|
+
#ifdef AF_IPX
|
908
|
+
rb_define_const(rb_cNetworkInterface, "AF_IPX", INT2NUM(AF_IPX));
|
909
|
+
#endif
|
910
|
+
#ifdef AF_SIP
|
911
|
+
rb_define_const(rb_cNetworkInterface, "AF_SIP", INT2NUM(AF_SIP));
|
912
|
+
#endif
|
913
|
+
#ifdef AF_NDRV
|
914
|
+
rb_define_const(rb_cNetworkInterface, "AF_NDRV", INT2NUM(AF_NDRV));
|
915
|
+
#endif
|
916
|
+
#ifdef AF_ISDN
|
917
|
+
rb_define_const(rb_cNetworkInterface, "AF_ISDN", INT2NUM(AF_ISDN));
|
918
|
+
#endif
|
919
|
+
#ifdef AF_NATM
|
920
|
+
rb_define_const(rb_cNetworkInterface, "AF_NATM", INT2NUM(AF_NATM));
|
921
|
+
#endif
|
922
|
+
#ifdef AF_SYSTEM
|
923
|
+
rb_define_const(rb_cNetworkInterface, "AF_SYSTEM", INT2NUM(AF_SYSTEM));
|
924
|
+
#endif
|
925
|
+
#ifdef AF_NETBIOS
|
926
|
+
rb_define_const(rb_cNetworkInterface, "AF_NETBIOS", INT2NUM(AF_NETBIOS));
|
927
|
+
#endif
|
928
|
+
#ifdef AF_NETBEUI
|
929
|
+
rb_define_const(rb_cNetworkInterface, "AF_NETBEUI", INT2NUM(AF_NETBEUI));
|
930
|
+
#endif
|
931
|
+
#ifdef AF_PPP
|
932
|
+
rb_define_const(rb_cNetworkInterface, "AF_PPP", INT2NUM(AF_PPP));
|
933
|
+
#endif
|
934
|
+
#ifdef AF_ATM
|
935
|
+
rb_define_const(rb_cNetworkInterface, "AF_ATM", INT2NUM(AF_ATM));
|
936
|
+
#endif
|
937
|
+
#ifdef AF_ATMPVC
|
938
|
+
rb_define_const(rb_cNetworkInterface, "AF_ATMPVC", INT2NUM(AF_ATMPVC));
|
939
|
+
#endif
|
940
|
+
#ifdef AF_ATMSVC
|
941
|
+
rb_define_const(rb_cNetworkInterface, "AF_ATMSVC", INT2NUM(AF_ATMSVC));
|
942
|
+
#endif
|
943
|
+
#ifdef AF_NETGRAPH
|
944
|
+
rb_define_const(rb_cNetworkInterface, "AF_NETGRAPH", INT2NUM(AF_NETGRAPH));
|
945
|
+
#endif
|
946
|
+
#ifdef AF_VOICEVIEW
|
947
|
+
rb_define_const(rb_cNetworkInterface, "AF_VOICEVIEW", INT2NUM(AF_VOICEVIEW));
|
948
|
+
#endif
|
949
|
+
#ifdef AF_FIREFOX
|
950
|
+
rb_define_const(rb_cNetworkInterface, "AF_FIREFOX", INT2NUM(AF_FIREFOX));
|
951
|
+
#endif
|
952
|
+
#ifdef AF_UNKNOWN1
|
953
|
+
rb_define_const(rb_cNetworkInterface, "AF_UNKNOWN1", INT2NUM(AF_UNKNOWN1));
|
954
|
+
#endif
|
955
|
+
#ifdef AF_BAN
|
956
|
+
rb_define_const(rb_cNetworkInterface, "AF_BAN", INT2NUM(AF_BAN));
|
957
|
+
#endif
|
958
|
+
#ifdef AF_CLUSTER
|
959
|
+
rb_define_const(rb_cNetworkInterface, "AF_CLUSTER", INT2NUM(AF_CLUSTER));
|
960
|
+
#endif
|
961
|
+
#ifdef AF_12844
|
962
|
+
rb_define_const(rb_cNetworkInterface, "AF_12844", INT2NUM(AF_12844));
|
963
|
+
#endif
|
964
|
+
#ifdef AF_IRDA
|
965
|
+
rb_define_const(rb_cNetworkInterface, "AF_IRDA", INT2NUM(AF_IRDA));
|
966
|
+
#endif
|
967
|
+
#ifdef AF_NETDES
|
968
|
+
rb_define_const(rb_cNetworkInterface, "AF_NETDES", INT2NUM(AF_NETDES));
|
969
|
+
#endif
|
970
|
+
#ifdef AF_NETROM
|
971
|
+
rb_define_const(rb_cNetworkInterface, "AF_NETROM", INT2NUM(AF_NETROM));
|
972
|
+
#endif
|
973
|
+
#ifdef AF_BRIDGE
|
974
|
+
rb_define_const(rb_cNetworkInterface, "AF_BRIDGE", INT2NUM(AF_BRIDGE));
|
975
|
+
#endif
|
976
|
+
#ifdef AF_X25
|
977
|
+
rb_define_const(rb_cNetworkInterface, "AF_X25", INT2NUM(AF_X25));
|
978
|
+
#endif
|
979
|
+
#ifdef AF_ROSE
|
980
|
+
rb_define_const(rb_cNetworkInterface, "AF_ROSE", INT2NUM(AF_ROSE));
|
981
|
+
#endif
|
982
|
+
#ifdef AF_SECURITY
|
983
|
+
rb_define_const(rb_cNetworkInterface, "AF_SECURITY", INT2NUM(AF_SECURITY));
|
984
|
+
#endif
|
985
|
+
#ifdef AF_KEY
|
986
|
+
rb_define_const(rb_cNetworkInterface, "AF_KEY", INT2NUM(AF_KEY));
|
987
|
+
#endif
|
988
|
+
#ifdef AF_NETLINK
|
989
|
+
rb_define_const(rb_cNetworkInterface, "AF_NETLINK", INT2NUM(AF_NETLINK));
|
990
|
+
#endif
|
991
|
+
#ifdef AF_ASH
|
992
|
+
rb_define_const(rb_cNetworkInterface, "AF_ASH", INT2NUM(AF_ASH));
|
993
|
+
#endif
|
994
|
+
#ifdef AF_ECONET
|
995
|
+
rb_define_const(rb_cNetworkInterface, "AF_ECONET", INT2NUM(AF_ECONET));
|
996
|
+
#endif
|
997
|
+
#ifdef AF_PPPOX
|
998
|
+
rb_define_const(rb_cNetworkInterface, "AF_PPPOX", INT2NUM(AF_PPPOX));
|
999
|
+
#endif
|
1000
|
+
#ifdef AF_WANPIPE
|
1001
|
+
rb_define_const(rb_cNetworkInterface, "AF_WANPIPE", INT2NUM(AF_WANPIPE));
|
1002
|
+
#endif
|
1003
|
+
#ifdef AF_BLUETOOTH
|
1004
|
+
rb_define_const(rb_cNetworkInterface, "AF_BLUETOOTH", INT2NUM(AF_BLUETOOTH));
|
1005
|
+
#endif
|
1006
|
+
|
1007
|
+
}
|
1008
|
+
|