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