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