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