WvStreams
wvinterface.cc
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  * 
00005  * A WvInterface stores information about a particular network interface.
00006  */
00007 
00008 #include "wvinterface.h"
00009 #if 1
00010 // FIXME: this file doesn't compile on anything other than Linux
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 /* Hack to prevent loading 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 // For Wireless Interfaces...
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 // forget all stored information about the address(es) of this interface
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 // get the hardware address of this interface
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 // get the local IP net of this interface
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 // get the point-to-point IP address of this interface
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     // 2.1 kernels error when we try to change netmask/broadcast for
00249     // a 0.0.0.0 address.
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, ':')) // otherwise, an alias, and no broadcast addr!
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     // addroute(addr); // not necessary on 2.1 and higher kernels
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 // Fill a routing table entry with the given information.
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     // FIXME: There has got to be a better way to do this.
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         //if (WvPipe(argv[0], argv, false, false, false).finish() != 242)
00413         if (checkProc.estatus != 242)
00414         {
00415             // added a default route via the subprogram
00416             // 242 is the magic "WvPipe could not exec program..." exit code.
00417             return 0;
00418         }
00419     }
00420     
00421     // if we get here, it is not a default route or the 'ip' command is
00422     // broken somehow.
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     // The kernel (2.4.19) sometimes tries to protect us from ourselves by
00452     // not letting us create a route via 'x' if 'x' isn't directly reachable
00453     // on the same interface.  This is non-helpful to us in some cases,
00454     // particularly with FreeSwan's screwy lying kernel routes.  Anyway,
00455     // the kernel people weren't clever enough to check that the routing
00456     // table *stays* self-consistent, so we add an extra route, then we
00457     // create our real route, and then we delete the extra route again.
00458     // Blah.
00459     // 
00460     // Using metric 255 should make it not the same as any other route.
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 // add a route with no gateway, ie. direct to interface
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         //if (WvPipe(argv[0], argv, false, false, false).finish() == 0)
00508         if (!WEXITSTATUS(checkProc.estatus))
00509         {
00510             // successfully deleted a default route via the subprogram
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 // delete a route with no gateway, ie. direct to interface
00532 int WvInterface::delroute(const WvIPNet &dest, int metric, WvStringParm table)
00533 {
00534     return delroute(dest, WvIPAddr(), metric, table);
00535 }
00536 
00537 
00538 // add an ARP or proxy ARP entry on this interface
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     // skip leading whitespace
00593     while (*line==' ') line++;
00594 
00595     // everything before the last colon is the device name
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 // auto-fill the list of interfaces using the list from /proc/net/dev.
00624 //
00625 // I wish there was a better way to do this, but the SIOCGIFCONF ioctl
00626 // ignores 'down' interfaces, which is not what we want.
00627 //
00628 void WvInterfaceDict::update()
00629 {
00630     int sock;
00631     struct ifconf ifconf;
00632     char buf[sizeof(ifconf.ifc_req) * 100]; // room for 100 interfaces
00633     WvLog err(log.split(WvLog::Error));
00634     WvFile procdev("/proc/net/dev", O_RDONLY);
00635     char *ifname;
00636 
00637         
00638     // mark all interfaces in list invalid for now
00639     Iter i(*this);
00640     for (i.rewind(); i.next(); )
00641         i().valid = false;
00642     
00643 
00644     // get list of all non-aliased interfaces from /proc/net/dev
00645     
00646     
00647     // skip the two header lines
00648     procdev.blocking_getline(-1); procdev.blocking_getline(-1);
00649     
00650     // add/validate existing interfaces
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     // get list of "up" and aliased interfaces with SIOCGIFCONF ioctl
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 // determine if the given address belongs to the local system
00699 WvString WvInterfaceDict::islocal(const WvAddr &addr)
00700 {
00701     static WvIPAddr bcast("255.255.255.255"); // always a local address!
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