WvStreams
wvipaliaser.cc
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  * 
00005  * WvIPAliaser handles IP aliasing in the Linux kernel.  See wvipaliaser.h.
00006  */
00007 #include "wvipaliaser.h"
00008 #include "wvinterface.h"
00009 #include <assert.h>
00010 
00011 
00012 WvIPAliaser::AliasList WvIPAliaser::all_aliases;
00013 
00014 
00015 
00017 
00018 
00019 
00020 WvIPAliaser::Alias::Alias(const WvIPAddr &_ip) : ip(_ip)
00021 {
00022     WvIPAddr noip;
00023     WvIPNet nonet(noip, noip);
00024     link_count = 0;
00025     
00026     for (index = 0; index < 256; index++)
00027     {
00028         WvInterface i(WvString("lo:wv%s", index));
00029         
00030         if (!i.isup() || i.ipaddr() == nonet) // not in use yet!
00031         {
00032             i.setipaddr(ip);
00033             i.up(true);
00034             if (WvIPAddr(i.ipaddr()) != ip)
00035             {
00036                 // no permission, most likely.
00037                 index = -1;
00038                 i.up(false);
00039             }
00040             return;
00041         }
00042         
00043         if (i.isup() && WvIPNet(i.ipaddr(),32) == ip)
00044         {
00045             // a bit weird... this alias already has the right address.
00046             // Keep it.
00047             return; 
00048         }
00049     }
00050     
00051     // got through all possible names without a free one?  Weird!
00052     index = -1;
00053 }
00054 
00055 
00056 WvIPAliaser::Alias::~Alias()
00057 {
00058     if (index >= 0)
00059     {
00060         WvInterface i(WvString("lo:wv%s", index));
00061         // i.setipaddr(WvIPAddr()); // not necessary in recent kernels
00062         i.up(false);
00063     }
00064 }
00065 
00066 
00067 
00069 
00070 
00071 
00072 WvIPAliaser::WvIPAliaser() : interfaces()
00073 {
00074     // nothing to do
00075 }
00076 
00077 
00078 WvIPAliaser::~WvIPAliaser()
00079 {
00080     // clear the alias list
00081     start_edit();
00082     done_edit();
00083 }
00084 
00085 
00086 void WvIPAliaser::start_edit()
00087 {
00088     AliasList::Iter i(aliases);
00089     
00090     #ifndef NDEBUG
00091     AliasList::Iter i_all(all_aliases);
00092     #endif
00093     
00094     interfaces.update();
00095     
00096     for (i.rewind(); i.next(); )
00097     {
00098         assert(i_all.find(i.ptr()));
00099         
00100         // the global alias entry goes down by one
00101         i().link_count--;
00102     }
00103     
00104     // empty out the local list
00105     aliases.zap();
00106 }
00107 
00108 
00109 WvIPAliaser::Alias *WvIPAliaser::ipsearch(WvIPAliaser::AliasList &l,
00110                                           const WvIPAddr &ip)
00111 {
00112     AliasList::Iter i(l);
00113     
00114     for (i.rewind(); i.next(); )
00115     {
00116         if (i->ip == WvIPAddr(ip))
00117             return i.ptr();
00118     }
00119     
00120     return NULL;
00121 }
00122 
00123 
00124 bool WvIPAliaser::add(const WvIPAddr &ip)
00125 {
00126     Alias *a;
00127 
00128     if (WvIPAddr(ip) == WvIPAddr() || ipsearch(aliases, ip))
00129         return false;     // already done.
00130 
00131     // If the alias is already a local address, there is no need for an alias.
00132     // We have to be careful that we don't find an existing alias as the
00133     // local interface.  Otherwise, we'll toggle that alias on and off.
00134     WvString ifc(interfaces.islocal(WvIPAddr(ip)));
00135     if (!!ifc && !strchr(ifc, ':')) // Make sure it is a real interface
00136         return false;
00137 
00138     a = ipsearch(all_aliases, ip);
00139     if (a)
00140     {
00141         // It's already in the global list, so we add its entry to
00142         // our list and increase the link count.
00143         aliases.append(a, false);
00144         a->link_count++;
00145         return false;
00146     }
00147     else
00148     {
00149         // It's not there, so we add a new alias to the global list and
00150         // our local list.
00151         a = new Alias(ip);
00152         aliases.append(a, false);
00153         all_aliases.append(a, true);
00154         a->link_count++;
00155         return true;
00156     }
00157 }
00158 
00159 
00160 bool WvIPAliaser::done_edit()
00161 {
00162     bool any_change=false;
00163     AliasList::Iter i(all_aliases);
00164     
00165     i.rewind(); i.next();
00166     while (i.cur())
00167     {
00168         Alias &a = *i;
00169         if (!a.link_count) {
00170             i.unlink();
00171             any_change = true;
00172         } else
00173             i.next();
00174     } 
00175 
00176     return any_change;
00177 }
00178 
00179 
00180 void WvIPAliaser::dump()
00181 {
00182     {
00183         WvLog log("local aliases");
00184         AliasList::Iter i(aliases);
00185         for (i.rewind(); i.next(); )
00186         {
00187             Alias &a = *i;
00188             log("#%s = lo:wv%s: %s (%s links)\n",
00189                 a.index, a.index, a.ip, a.link_count);
00190         }
00191         log(".\n");
00192     }
00193 
00194     {
00195         WvLog log("global aliases");
00196         AliasList::Iter i(all_aliases);
00197         for (i.rewind(); i.next(); )
00198         {
00199             Alias &a = *i;
00200             log("#%s = lo:wv%s: %s (%s links)\n",
00201                 a.index, a.index, a.ip, a.link_count);
00202         }
00203         log(".\n.\n");
00204     }
00205 }