2
* Copyright (C) 2006 Justin Karneges
4
* This library is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU Lesser General Public
6
* License as published by the Free Software Foundation; either
7
* version 2.1 of the License, or (at your option) any later version.
9
* This library is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* Lesser General Public License for more details.
14
* You should have received a copy of the GNU Lesser General Public
15
* License along with this library; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21
// this code assumes the following ioctls work:
22
// SIOCGIFCONF - get list of devices
23
// SIOCGIFFLAGS - get flags about a device
25
// gateway detection currently only works on linux
27
#include "irisnetplugin.h"
30
#include <sys/types.h>
31
#include <sys/socket.h>
32
#include <sys/ioctl.h>
34
#include <net/route.h>
35
#include <netinet/in.h>
39
# include<sys/sockio.h>
57
static QList<UnixIface> get_sioc_ifaces()
61
int tmpsock = socket(AF_INET, SOCK_DGRAM, 0);
67
QByteArray buf(100 * sizeof(struct ifreq), 0); // guess
70
ifc.ifc_len = buf.size();
71
ifc.ifc_buf = buf.data();
72
if(ioctl(tmpsock, SIOCGIFCONF, &ifc) < 0)
74
if(errno != EINVAL || lastlen != 0)
79
// if it didn't grow since last time, then
80
// there's no overflow
81
if(ifc.ifc_len == lastlen)
83
lastlen = ifc.ifc_len;
85
buf.resize(buf.size() + 10 * sizeof(struct ifreq));
90
for(int at = 0; at < buf.size(); at += itemsize)
92
struct ifreq *ifr = (struct ifreq *)(buf.data() + at);
95
if(((struct sockaddr *)&ifr->ifr_addr)->sa_family == AF_INET)
96
sockaddr_len = sizeof(struct sockaddr_in);
97
else if(((struct sockaddr *)&ifr->ifr_addr)->sa_family == AF_INET6)
98
sockaddr_len = sizeof(struct sockaddr_in6);
100
sockaddr_len = sizeof(struct sockaddr);
102
// set this asap so the next iteration is possible
103
itemsize = sizeof(ifr->ifr_name) + sockaddr_len;
105
// skip if the family is 0 (sometimes you get empty entries)
106
if(ifr->ifr_addr.sa_family == 0)
109
// make a copy of this item to do additional ioctls on
110
struct ifreq ifrcopy = *ifr;
113
if(ioctl(tmpsock, SIOCGIFFLAGS, &ifrcopy) < 0)
116
// device must be up and not loopback
117
if(!(ifrcopy.ifr_flags & IFF_UP))
121
i.name = QString::fromLatin1(ifr->ifr_name);
122
i.loopback = (ifrcopy.ifr_flags & IFF_LOOPBACK) ? true : false;
123
i.address.setAddress(&ifr->ifr_addr);
127
// don't need this anymore
133
static QStringList read_proc_as_lines(const char *procfile)
137
FILE *f = fopen(procfile, "r");
144
// max read on a proc is 4K
145
QByteArray block(4096, 0);
146
int ret = fread(block.data(), 1, block.size(), f);
154
QString str = QString::fromLocal8Bit(buf);
155
out = str.split('\n', QString::SkipEmptyParts);
159
static QHostAddress linux_ipv6_to_qaddr(const QString &in)
162
if(in.length() != 32)
165
for(int n = 0; n < 16; ++n)
168
int x = in.mid(n * 2, 2).toInt(&ok, 16);
177
static QHostAddress linux_ipv4_to_qaddr(const QString &in)
183
unsigned char *rawp = (unsigned char *)&raw;
184
for(int n = 0; n < 4; ++n)
187
int x = in.mid(n * 2, 2).toInt(&ok, 16);
190
rawp[n] = (unsigned char )x;
196
static QList<UnixIface> get_linux_ipv6_ifaces()
198
QList<UnixIface> out;
200
QStringList lines = read_proc_as_lines("/proc/net/if_inet6");
201
for(int n = 0; n < lines.count(); ++n)
203
const QString &line = lines[n];
204
QStringList parts = line.simplified().split(' ', QString::SkipEmptyParts);
205
if(parts.count() < 6)
208
QString name = parts[5];
211
QHostAddress addr = linux_ipv6_to_qaddr(parts[0]);
215
QString scopestr = parts[3];
217
unsigned int scope = parts[3].toInt(&ok, 16);
221
// IPV6_ADDR_LOOPBACK 0x0010U
222
// IPV6_ADDR_SCOPE_MASK 0x00f0U
223
bool loopback = false;
224
if((scope & 0x00f0U) == 0x0010U)
229
i.loopback = loopback;
237
static QList<UnixGateway> get_linux_gateways()
239
QList<UnixGateway> out;
241
QStringList lines = read_proc_as_lines("/proc/net/route");
242
// skip the first line, so we start at 1
243
for(int n = 1; n < lines.count(); ++n)
245
const QString &line = lines[n];
246
QStringList parts = line.simplified().split(' ', QString::SkipEmptyParts);
247
if(parts.count() < 10) // net-tools does 10, but why not 11?
250
QHostAddress addr = linux_ipv4_to_qaddr(parts[2]);
254
int iflags = parts[3].toInt(0, 16);
255
if(!(iflags & RTF_UP))
258
if(!(iflags & RTF_GATEWAY))
262
g.ifaceName = parts[0];
267
lines = read_proc_as_lines("/proc/net/ipv6_route");
268
for(int n = 0; n < lines.count(); ++n)
270
const QString &line = lines[n];
271
QStringList parts = line.simplified().split(' ', QString::SkipEmptyParts);
272
if(parts.count() < 10)
275
QHostAddress addr = linux_ipv6_to_qaddr(parts[4]);
279
int iflags = parts[8].toInt(0, 16);
280
if(!(iflags & RTF_UP))
283
if(!(iflags & RTF_GATEWAY))
287
g.ifaceName = parts[9];
295
static QList<UnixIface> get_unix_ifaces()
297
QList<UnixIface> out = get_sioc_ifaces();
299
out += get_linux_ipv6_ifaces();
304
static QList<UnixGateway> get_unix_gateways()
306
// support other platforms here
307
QList<UnixGateway> out;
309
out = get_linux_gateways();
316
class UnixNet : public NetInterfaceProvider
319
Q_INTERFACES(XMPP::NetInterfaceProvider);
326
connect(&t, SIGNAL(timeout()), SLOT(check()));
335
QList<Info> interfaces() const
344
QList<UnixIface> list = get_unix_ifaces();
345
for(int n = 0; n < list.count(); ++n)
347
// see if we have it already
349
for(int k = 0; k < ifaces.count(); ++k)
351
if(ifaces[k].id == list[n].name)
358
// don't have it? make it
363
i.name = list[n].name;
364
i.isLoopback = list[n].loopback;
365
i.addresses += list[n].address;
368
// otherwise, tack on the address
370
ifaces[lookup].addresses += list[n].address;
373
QList<UnixGateway> glist = get_unix_gateways();
374
for(int n = 0; n < glist.count(); ++n)
376
// look up the interface
378
for(int k = 0; k < ifaces.count(); ++k)
380
if(ifaces[k].id == glist[n].ifaceName)
390
ifaces[lookup].gateway = glist[n].address;
407
class UnixNetProvider : public IrisNetProvider
410
Q_INTERFACES(XMPP::IrisNetProvider);
412
virtual NetInterfaceProvider *createNetInterfaceProvider()
418
IrisNetProvider *irisnet_createUnixNetProvider()
420
return new UnixNetProvider;
425
#include "netinterface_unix.moc"