00001
00002
00003
00004
00005
00006
00007
00008
#include "wvinterface.h"
00009
#if 1
00010
00011
00012
#include "wvsubproc.h"
00013
#include "wvfile.h"
00014
00015
#include <sys/ioctl.h>
00016
#include <sys/socket.h>
00017
#include <sys/wait.h>
00018
#include <net/if_arp.h>
00019
#include <net/route.h>
00020
#include <unistd.h>
00021
#include <errno.h>
00022
#include <linux/sockios.h>
00023
#include <linux/wireless.h>
00024
00025 #define min(x,y) ((x) < (y) ? (x) : (y))
00026
00027 WvInterfaceDictBase WvInterfaceDict::slist(15);
00028 int WvInterfaceDict::links = 0;
00029
00030
00031 WvInterface::WvInterface(
WvStringParm _name) :
00032 err("Net Interface",
WvLog::Error), name(_name)
00033 {
00034 my_hwaddr = my_ipaddr = NULL;
00035
valid =
true;
00036 }
00037
00038
00039 WvInterface::~WvInterface()
00040 {
00041
rescan();
00042 }
00043
00044
00045 int WvInterface::req(
int ioctl_num,
struct ifreq *ifr)
00046 {
00047
int sock, retval;
00048
00049 sock = socket(AF_INET, SOCK_STREAM, 0);
00050 strncpy(ifr->ifr_name,
name, IFNAMSIZ-1);
00051 ifr->ifr_name[IFNAMSIZ-1] = 0;
00052
00053 retval = ioctl(sock, ioctl_num, ifr);
00054
if (retval)
00055 retval = errno;
00056 close(sock);
00057
return retval;
00058 }
00059
00060
00061 int WvInterface::req(
int ioctl_num,
struct iwreq *ifr)
00062 {
00063
int sock, retval;
00064
00065 sock = socket(AF_INET, SOCK_STREAM, 0);
00066 strncpy(ifr->ifr_name,
name, IFNAMSIZ-1);
00067 ifr->ifr_name[IFNAMSIZ-1] = 0;
00068
00069 retval = ioctl(sock, ioctl_num, ifr);
00070
if (retval)
00071 retval = errno;
00072 close(sock);
00073
return retval;
00074 }
00075
00076
00077
00078 void WvInterface::rescan()
00079 {
00080
if (my_hwaddr)
00081 {
00082
delete my_hwaddr;
00083 my_hwaddr = NULL;
00084 }
00085
00086
if (my_ipaddr)
00087 {
00088
delete my_ipaddr;
00089 my_ipaddr = NULL;
00090 }
00091 }
00092
00093
00094
00095 const WvAddr &
WvInterface::hwaddr()
00096 {
00097
struct ifreq ifr;
00098
00099
if (!my_hwaddr)
00100 {
00101
if (
req(SIOCGIFHWADDR, &ifr))
00102 my_hwaddr =
new WvStringAddr(
"Unknown", WvEncap::Unknown);
00103
else
00104 my_hwaddr = WvAddr::gen(&ifr.ifr_hwaddr);
00105 }
00106
return *my_hwaddr;
00107 }
00108
00109
00110
00111 const WvIPNet &
WvInterface::ipaddr()
00112 {
00113
struct ifreq ifr, ifr2;
00114
00115
if (!my_ipaddr)
00116 {
00117 ifr.ifr_addr.sa_family = AF_INET;
00118 ifr2.ifr_netmask.sa_family = AF_INET;
00119
if (
req(SIOCGIFADDR, &ifr) ||
req(SIOCGIFNETMASK, &ifr2))
00120 my_ipaddr =
new WvIPNet();
00121
else
00122 my_ipaddr =
new WvIPNet(&ifr.ifr_addr, &ifr2.ifr_netmask);
00123 }
00124
00125
return *my_ipaddr;
00126 }
00127
00128
00129
00130 const WvIPAddr WvInterface::dstaddr()
00131 {
00132
struct ifreq ifr;
00133 ifr.ifr_dstaddr.sa_family = AF_INET;
00134
if (!(
getflags() & IFF_POINTOPOINT) ||
req(SIOCGIFDSTADDR, &ifr))
00135
return WvIPAddr();
00136
else
00137
return WvIPAddr(&ifr.ifr_dstaddr);
00138 }
00139
00140
00141 int WvInterface::getflags()
00142 {
00143
struct ifreq ifr;
00144
int retval =
req(SIOCGIFFLAGS, &ifr);
00145
if (retval)
00146
valid =
false;
00147
return ifr.ifr_flags;
00148 }
00149
00150
00151 int WvInterface::setflags(
int clear,
int set)
00152 {
00153
struct ifreq ifr;
00154
00155
int retval =
req(SIOCGIFFLAGS, &ifr);
00156
if (retval)
00157
return retval;
00158
int newflags = (ifr.ifr_flags & ~clear) | set;
00159
if (newflags != ifr.ifr_flags)
00160 {
00161 ifr.ifr_flags = newflags;
00162 retval = req(SIOCSIFFLAGS, &ifr);
00163
if (retval && retval != EACCES && retval != EPERM)
00164 err.
perror(
WvString(
"SetFlags %s",
name));
00165 }
00166
return retval;
00167 }
00168
00169
00170 void WvInterface::up(
bool enable)
00171 {
00172
setflags(IFF_UP, enable ? IFF_UP : 0);
00173
rescan();
00174 }
00175
00176
00177 bool WvInterface::isup()
00178 {
00179
return (
valid && (
getflags() & IFF_UP)) ? 1 : 0;
00180 }
00181
00182
00183 void WvInterface::promisc(
bool enable)
00184 {
00185
setflags(IFF_PROMISC, enable ? IFF_PROMISC : 0);
00186 }
00187
00188
00189 bool WvInterface::ispromisc()
00190 {
00191
return (
getflags() & IFF_PROMISC) ? 1 : 0;
00192 }
00193
00194
00195 int WvInterface::setipaddr(
const WvIPNet &addr)
00196 {
00197
struct ifreq ifr;
00198
struct sockaddr *sa;
00199 size_t len;
00200
int sock;
00201
WvIPAddr none;
00202
00203
if (addr !=
ipaddr())
00204 err(WvLog::Info,
"Changing %s address to %s (%s bits)\n",
name,
00205 addr.
base(), addr.
bits());
00206
00207 sock = socket(AF_INET, SOCK_STREAM, 0);
00208 strncpy(ifr.ifr_name,
name, IFNAMSIZ-1);
00209 ifr.ifr_name[IFNAMSIZ-1] = 0;
00210 ifr.ifr_addr.sa_family = AF_INET;
00211
00212 len =
min(
sizeof(sockaddr), addr.
sockaddr_len());
00213
00214 sa = addr.
sockaddr();
00215 memcpy(&ifr.ifr_addr, sa, len);
00216
delete sa;
00217
if (ioctl(sock, SIOCSIFADDR, &ifr))
00218 {
00219
if (errno != EACCES && errno != EPERM)
00220 err.
perror(
WvString(
"SetIfAddress %s",
name));
00221 close(sock);
00222
return -1;
00223 }
00224
00225
00226
00227
if (addr.
base() != none)
00228 {
00229 sa = addr.
netmask().
sockaddr();
00230 memcpy(&ifr.ifr_netmask, sa, len);
00231
delete sa;
00232
if (ioctl(sock, SIOCSIFNETMASK, &ifr))
00233 {
00234
if (errno != EACCES && errno != EPERM)
00235 err.
perror(
WvString(
"SetNetmask %s",
name));
00236 close(sock);
00237
return -1;
00238 }
00239
00240
if (!strchr(
name,
':'))
00241 {
00242 sa = addr.
broadcast().
sockaddr();
00243 memcpy(&ifr.ifr_broadaddr, sa, len);
00244
delete sa;
00245
if (ioctl(sock, SIOCSIFBRDADDR, &ifr))
00246 {
00247
if (errno != EACCES && errno != EPERM)
00248 err.
perror(
WvString(
"SetBroadcast %s",
name));
00249 close(sock);
00250
return -1;
00251 }
00252 }
00253 }
00254
00255
00256 close(sock);
00257
00258
rescan();
00259
return 0;
00260 }
00261
00262
00263 int WvInterface::setmtu(
int mtu)
00264 {
00265
struct ifreq ifr;
00266 ifr.ifr_mtu = mtu;
00267
int retval =
req(SIOCSIFMTU, &ifr);
00268
if (retval && retval != EACCES && retval != EPERM)
00269 err.
perror(
WvString(
"SetMTU %s",
name));
00270
return retval;
00271 }
00272
00273
00274 int WvInterface::sethwaddr(
const WvAddr &addr)
00275 {
00276
struct ifreq ifr;
00277 sockaddr *saddr = addr.
sockaddr();
00278 memcpy(& ifr.ifr_hwaddr, saddr, addr.
sockaddr_len());
00279
delete saddr;
00280
00281
bool wasup =
isup();
00282
if (wasup)
00283
up(
false);
00284
00285
int retval =
req(SIOCSIFHWADDR, &ifr);
00286
if (retval && retval != EACCES && retval != EPERM)
00287 err.
perror(
WvString(
"SetHWAddr %s",
name));
00288
00289
if (wasup)
00290
up(
true);
00291
00292
rescan();
00293
return retval;
00294 }
00295
00296
00297
00298
void WvInterface::fill_rte(
struct rtentry *rte,
char ifname[17],
00299
const WvIPNet &dest,
const WvIPAddr &gw,
00300
int metric)
00301 {
00302
struct sockaddr *net, *mask, *gwaddr;
00303 size_t len;
00304
bool is_direct = (gw ==
WvIPAddr());
00305
bool is_host = dest.
is_host();
00306
00307 memset(rte, 0,
sizeof(
struct rtentry));
00308 rte->rt_metric = metric + 1;
00309
00310 strncpy(ifname, name, 17);
00311 ifname[17-1] = 0;
00312 rte->rt_dev = ifname;
00313
00314 len =
min(
sizeof(sockaddr), dest.
sockaddr_len());
00315
00316 net = dest.
network().
sockaddr();
00317 memcpy(&rte->rt_dst, net, len);
00318
delete net;
00319
00320
if (!is_host)
00321 {
00322 mask = dest.
netmask().
sockaddr();
00323 memcpy(&rte->rt_genmask, mask, len);
00324
delete mask;
00325 }
00326
00327
if (!is_direct)
00328 {
00329 gwaddr = gw.sockaddr();
00330 memcpy(&rte->rt_gateway, gwaddr, len);
00331
delete gwaddr;
00332 }
00333
00334 rte->rt_flags = (RTF_UP
00335 | (is_host ? RTF_HOST : 0)
00336 | (is_direct ? 0 : RTF_GATEWAY));
00337 }
00338
00339
00340
int WvInterface::really_addroute(
const WvIPNet &dest,
const WvIPAddr &gw,
00341
const WvIPAddr &src,
int metric,
WvStringParm table,
00342
bool shutup)
00343 {
00344
struct rtentry rte;
00345
char ifname[17];
00346
int sock;
00347
WvString deststr(dest), gwstr(gw), metr(metric), srcstr(src);
00348
00349
00350
const char *
const argvnosrc[] = {
00351
"ip",
"route",
"add",
00352 deststr,
00353
"table", table,
00354
"dev",
name,
00355
"via", gwstr,
00356
"metric", metr,
00357 NULL
00358 };
00359
00360
const char *
const argvsrc[] = {
00361
"ip",
"route",
"add",
00362 deststr,
00363
"table", table,
00364
"dev",
name,
00365
"via", gwstr,
00366
"src", srcstr,
00367
"metric", metr,
00368 NULL
00369 };
00370
00371 WvIPAddr zero;
00372
const char *
const * argv;
00373
if (src != zero)
00374 argv = argvsrc;
00375
else
00376 argv = argvnosrc;
00377
00378
if (dest.
is_default() || table !=
"default")
00379 {
00380 err(WvLog::Debug2,
"addroute: ");
00381
for (
int i = 0; argv[i]; i++)
00382 err(WvLog::Debug2,
"%s ", argv[i]);
00383 err(WvLog::Debug2,
"\n");
00384
00385
WvSubProc checkProc;
00386 checkProc.
startv(*argv, argv);
00387 checkProc.
wait(-1);
00388
00389
00390
if (checkProc.
estatus != 242)
00391 {
00392
00393
00394
return 0;
00395 }
00396 }
00397
00398
00399
00400
00401 fill_rte(&rte, ifname, dest, gw, metric);
00402
00403 sock = socket(AF_INET, SOCK_STREAM, 0);
00404
if (ioctl(sock, SIOCADDRT, &rte))
00405 {
00406
if (errno != EACCES && errno != EPERM && errno != EEXIST
00407 && errno != ENOENT)
00408 {
00409
if (!shutup)
00410 err.
perror(
WvString(
"AddRoute '%s' %s (up=%s)",
00411 name, dest,
isup()));
00412 }
00413 close(sock);
00414
return -1;
00415 }
00416
00417 close(sock);
00418
return 0;
00419 }
00420
00421
00422 int WvInterface::addroute(
const WvIPNet &dest,
const WvIPAddr &gw,
00423
const WvIPAddr &src,
int metric,
WvStringParm table)
00424 {
00425 WvIPAddr zero;
00426
int ret;
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
if (gw != zero)
00439 really_addroute(gw, zero, zero, 255,
"default",
true);
00440 ret = really_addroute(dest, gw, src, metric, table,
false);
00441
if (gw != zero)
00442
delroute(gw, zero, 255,
"default");
00443
00444
return ret;
00445 }
00446
00447
00448
00449 int WvInterface::addroute(
const WvIPNet &dest,
int metric,
00450
WvStringParm table)
00451 {
00452
return addroute(dest, WvIPAddr(), WvIPAddr(), metric, table);
00453 }
00454
00455
00456 int WvInterface::delroute(
const WvIPNet &dest,
const WvIPAddr &gw,
00457
int metric,
WvStringParm table)
00458 {
00459
struct rtentry rte;
00460
char ifname[17];
00461
int sock;
00462
WvString deststr(dest), gwstr(gw), metr(metric);
00463
const char *argv[] = {
00464
"ip",
"route",
"del",
00465 deststr,
00466
"table", table,
00467
"dev",
name,
00468
"via", gwstr,
00469
"metric", metr,
00470 NULL
00471 };
00472
00473
if (dest.
is_default() || table !=
"default")
00474 {
00475 err(WvLog::Debug2,
"addroute: ");
00476
for (
int i = 0; argv[i]; i++)
00477 err(WvLog::Debug2,
"%s ", argv[i]);
00478 err(WvLog::Debug2,
"\n");
00479
00480
WvSubProc checkProc;
00481 checkProc.
startv(*argv, (
char *
const *)argv);
00482 checkProc.
wait(-1);
00483
00484
00485
if (!WEXITSTATUS(checkProc.
estatus))
00486 {
00487
00488
return 0;
00489 }
00490 }
00491
00492 fill_rte(&rte, ifname, dest, gw, metric);
00493
00494 sock = socket(AF_INET, SOCK_STREAM, 0);
00495
if (ioctl(sock, SIOCDELRT, &rte))
00496 {
00497
if (errno != EACCES && errno != EPERM && errno != EEXIST)
00498 err.
perror(
WvString(
"DelRoute %s",
name));
00499 close(sock);
00500
return -1;
00501 }
00502
00503 close(sock);
00504
return 0;
00505 }
00506
00507
00508
00509 int WvInterface::delroute(
const WvIPNet &dest,
int metric,
WvStringParm table)
00510 {
00511
return delroute(dest, WvIPAddr(), metric, table);
00512 }
00513
00514
00515
00516 int WvInterface::addarp(
const WvIPNet &dest,
const WvAddr &hw,
bool proxy)
00517 {
00518
int sock;
00519
struct arpreq ar;
00520
struct sockaddr *sa;
00521 size_t len;
00522
00523 sa = dest.
network().
sockaddr();
00524 len =
min(dest.
sockaddr_len(),
sizeof(ar.arp_pa));
00525 memcpy(&ar.arp_pa, sa, len);
00526
delete sa;
00527
00528 sa = hw.
sockaddr();
00529 len =
min(hw.
sockaddr_len(),
sizeof(ar.arp_ha));
00530 memcpy(&ar.arp_ha, sa, len);
00531
delete sa;
00532
00533 sa = dest.
netmask().
sockaddr();
00534 len =
min(dest.
sockaddr_len(),
sizeof(ar.arp_netmask));
00535 memcpy(&ar.arp_netmask, sa, len);
00536
delete sa;
00537
00538 strncpy(ar.arp_dev,
name,
sizeof(ar.arp_dev));
00539
00540 ar.arp_flags = (
ATF_COM |
ATF_PERM
00541 | (proxy ?
ATF_PUBL : 0)
00542 | (proxy && dest.
is_host() ?
ATF_NETMASK : 0));
00543
00544 sock = socket(AF_INET, SOCK_STREAM, 0);
00545
if (ioctl(sock, SIOCSARP, &ar))
00546 {
00547
if (errno != EACCES && errno != EPERM)
00548 err.
perror(
WvString(
"AddARP %s",
name));
00549 close(sock);
00550
return -1;
00551 }
00552
00553 close(sock);
00554
return 0;
00555 }
00556
00557
00558 bool WvInterface::isarp()
00559 {
00560
int f =
getflags();
00561
return !(f & (IFF_NOARP | IFF_LOOPBACK)) && (f & IFF_BROADCAST);
00562 }
00563
00564
00565 static char *
find_ifname(
char *line)
00566 {
00567
if (!line)
return NULL;
00568
00569
00570
while (*line==
' ') line++;
00571
00572
00573
char *cptr = strrchr(line,
':');
00574
if (!cptr)
00575
return NULL;
00576 *cptr = 0;
00577
return line;
00578 }
00579
00580
00581
00582
00583
00584 WvInterfaceDict::WvInterfaceDict() :
log("Net Interface",
WvLog::Info)
00585 {
00586
links++;
00587
update();
00588 }
00589
00590
00591 WvInterfaceDict::~WvInterfaceDict()
00592 {
00593
links--;
00594
00595
if (!
links)
00596
slist.zap();
00597 }
00598
00599
00600
00601
00602
00603
00604
00605 void WvInterfaceDict::update()
00606 {
00607
int sock;
00608
struct ifconf ifconf;
00609
char buf[
sizeof(ifconf.ifc_req) * 100];
00610
WvLog err(
log.
split(WvLog::Error));
00611
WvFile procdev(
"/proc/net/dev", O_RDONLY);
00612
char *ifname;
00613
00614
00615
00616
Iter i(*
this);
00617
for (i.rewind(); i.next(); )
00618 i().valid =
false;
00619
00620
00621
00622
00623
00624
00625 procdev.
getline(-1); procdev.
getline(-1);
00626
00627
00628
while ((ifname =
find_ifname(procdev.
getline(-1))) != NULL)
00629 {
00630
WvString s(ifname);
00631
WvInterface *ifc = (*this)[s];
00632
00633
if (!ifc)
00634 {
00635 ifc =
new WvInterface(ifname);
00636
slist.add(ifc,
true);
00637
log(WvLog::Debug3,
"Found %-16s [%s]\n", ifname, ifc->
hwaddr());
00638 }
00639
else
00640 ifc->
rescan();
00641 ifc->
valid =
true;
00642 }
00643
00644
00645
00646
00647
00648 ifconf.ifc_buf = buf;
00649 ifconf.ifc_len =
sizeof(buf);
00650
00651 sock = socket(AF_INET, SOCK_STREAM, 0);
00652
if (! ioctl(sock, SIOCGIFCONF, &ifconf))
00653 {
00654
int count, max = ifconf.ifc_len /
sizeof(ifconf.ifc_req[0]);
00655
00656
for (count = 0; count < max; count++)
00657 {
00658
struct ifreq &ifr = ifconf.ifc_req[count];
00659
WvInterface *ifc = (*this)[ifr.ifr_name];
00660
00661
if (!ifc)
00662 {
00663 ifc =
new WvInterface(ifr.ifr_name);
00664
slist.add(ifc,
true);
00665 }
00666
else
00667 ifc->
rescan();
00668 ifc->
valid =
true;
00669 }
00670 }
00671 close(sock);
00672 }
00673
00674
00675
00676 bool WvInterfaceDict::islocal(
const WvAddr &addr)
00677 {
00678
static WvIPAddr bcast(
"255.255.255.255");
00679
00680
if (addr == bcast)
00681
return true;
00682
00683
Iter i(*
this);
00684
for (i.rewind(); i.next(); )
00685 {
00686
WvInterface &ifc(*i);
00687
if (!ifc.
valid)
continue;
00688
00689
if (ifc.
ipaddr() == addr || ifc.
ipaddr().
base() == addr
00690 || ifc.
ipaddr().
broadcast() == addr)
00691
return true;
00692
00693
if (ifc.
hwaddr() == addr)
00694
return true;
00695 }
00696
00697
return false;
00698 }
00699
00700
00701 bool WvInterfaceDict::on_local_net(
const WvIPNet &addr)
00702 {
00703 WvIPAddr zero;
00704
00705
if (
islocal(addr))
00706
return true;
00707
00708
Iter i(*
this);
00709
for (i.rewind(); i.next(); )
00710 {
00711
WvInterface &ifc = *i;
00712
if (!ifc.
valid)
continue;
00713
00714
if (ifc.
isup() && WvIPAddr(ifc.
ipaddr()) != zero
00715 && ifc.
ipaddr().
includes(addr))
00716
return true;
00717 }
00718
00719
return false;
00720 }
00721
00722
#else
00723
00724 WvInterfaceDictBase WvInterfaceDict::slist(15);
00725
00726
int WvInterface::getinfo(
struct ifreq *ifr,
int ioctl_num) {
return 0; }
00727
void WvInterface::fill_rte(
struct rtentry *rte,
char *ifname,
00728
const WvIPNet &dest,
const WvIPAddr &gw,
00729
int metric) {}
00730
00731
WvInterface::WvInterface(
WvStringParm _name) :err("fake") {}
00732
WvInterface::~WvInterface() {}
00733
00734
void WvInterface::rescan() {}
00735
const WvIPNet &
WvInterface::ipaddr() {
return *(
new WvIPNet()); }
00736
const WvIPAddr
WvInterface::dstaddr() {
return *(
new WvIPAddr()); }
00737
int WvInterface::getflags() {
return 0; }
00738
int WvInterface::setflags(
int clear,
int set) {
return 0; }
00739
bool WvInterface::isup() {
return true; }
00740
void WvInterface::up(
bool enable) {}
00741
bool WvInterface::ispromisc() {
return true; }
00742
void WvInterface::promisc(
bool enable) {}
00743
int WvInterface::setipaddr(
const WvIPNet &addr) {
return 0; }
00744
int WvInterface::setmtu(
int mtu) {
return 0; }
00745
int WvInterface::addroute(
const WvIPNet &dest,
int metric = 0,
00746
WvStringParm table =
"default") {
return 0; }
00747
int WvInterface::addroute(
const WvIPNet &dest,
const WvIPAddr &gw,
00748
int metric = 0,
WvStringParm table =
"default") {
return 0; }
00749
int WvInterface::delroute(
const WvIPNet &dest,
int metric = 0,
00750
WvStringParm table =
"default") {
return 0; }
00751
int WvInterface::delroute(
const WvIPNet &dest,
const WvIPAddr &gw,
00752
int metric = 0,
WvStringParm table =
"default") {
return 0; }
00753
bool WvInterface::isarp() {
return true; }
00754
int WvInterface::addarp(
const WvIPNet &proto,
const WvAddr &hw,
bool proxy)
00755 {
return 0; }
00756
00757
WvInterfaceDict::WvInterfaceDict() :
log("fake") {}
00758
WvInterfaceDict::~WvInterfaceDict() {}
00759
00760
void WvInterfaceDict::update() {}
00761
bool WvInterfaceDict::islocal(
const WvAddr &addr) {
return true; }
00762
bool WvInterfaceDict::on_local_net(
const WvIPNet &addr) {
return true; }
00763
00764
#endif