wvaddr.cc

00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  * 
00005  * Device-independent and device-specific hardware/protocol address
00006  * classes that can store themselves efficiently as well as create a
00007  * printable string version of themselves.
00008  */
00009 #ifndef _WIN32
00010 #include <netdb.h>
00011 #include <sys/socket.h>
00012 #include <sys/un.h>
00013 #include <net/if_arp.h>
00014 #endif
00015 
00016 #include "wvaddr.h"
00017 #include <assert.h>
00018 
00019 #ifndef ARPHRD_IPSEC
00020 // From ipsec_tunnel
00021 #define ARPHRD_IPSEC 31
00022 #endif
00023 
00024 // workaround for functions called sockaddr() -- oops.
00025 typedef struct sockaddr sockaddr_bin;
00026 
00027 /* A list of Linux ARPHRD_* types, one for each element of CapType. */
00028 int WvEncap::extypes[] = {
00029 #ifdef _WIN32
00030     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
00031 #else
00032     // hardware encapsulation
00033     0, // Unknown
00034     ARPHRD_LOOPBACK,
00035     0, // Ethertap
00036     ARPHRD_ETHER,
00037     ARPHRD_ARCNET,
00038     ARPHRD_SLIP,
00039     ARPHRD_CSLIP,
00040     ARPHRD_PPP,
00041     ARPHRD_IPSEC,
00042     
00043     // protocol encapsulation
00044     AF_INET, // IPv4
00045     AF_UNIX  // Unix domain socket
00046 #endif
00047 };
00048 
00049 
00050 /* Printable strings corresponding to each element of CapType */
00051 const char WvEncap::strings[][20] = {
00052     // hardware encapsulation
00053     "Unknown",
00054     "Loopback",
00055     "Ethertap",
00056     "Ethernet",
00057     "ARCnet",
00058     "SLIP",
00059     "CSLIP",
00060     "PPP",
00061     "IPsec",
00062     
00063     // protocol encapsulation
00064     "IP", // IPv4
00065     "Unix", // Unix domain socket
00066 };
00067 
00068 
00069 /* Figure out the CapType corresponding to a Linux ARPHRD_* type or
00070  * sockaddr sa_family type.
00071  */
00072 WvEncap::WvEncap(int extype)
00073 {
00074     for (int count=0; count < NUM_ENCAP_TYPES; count++)
00075     {
00076         if (extype == extypes[count])
00077         {
00078             cap = (CapType)count;
00079             return;
00080         }
00081     }
00082     cap = Unknown;
00083 }
00084 
00085 
00086 /* Find the hash value of a WvAddr, for use with WvHashTable */
00087 unsigned WvHash(const WvAddr &addr)
00088 {
00089     return addr.WvHash();
00090 }
00091 
00092 
00093 /* Create an object of the appropriate WvAddr-derived class based on the
00094  * address and type stored in 'addr'.
00095  */
00096 WvAddr *WvAddr::gen(struct sockaddr *addr)
00097 {
00098     WvEncap encap(addr->sa_family);
00099     
00100     switch (encap.cap)
00101     {
00102     case WvEncap::Loopback:
00103         return new WvStringAddr("Loopback", WvEncap::Loopback);
00104         
00105     case WvEncap::IPv4:
00106         return new WvIPPortAddr((sockaddr_in *)addr);
00107 #ifndef _WIN32
00108     case WvEncap::ARCnet:
00109         return new WvARCnetAddr(addr);
00110         
00111     case WvEncap::Ethertap:
00112     case WvEncap::Ethernet:
00113         return new WvEtherAddr(addr);
00114 
00115     case WvEncap::IPsec:
00116         return new WvStringAddr("IPsec", WvEncap::IPsec);
00117 #endif
00118     default:
00119         return new WvStringAddr("Unknown", WvEncap::Unknown);
00120     }
00121 }
00122 
00123 
00124 bool WvAddr::isbroadcast() const
00125 {
00126     return false; // default is no support for broadcasts
00127 }
00128 
00129 
00130 const unsigned char *WvAddr::rawdata() const
00131 {
00132     return NULL;
00133 }
00134 
00135 
00136 size_t WvAddr::rawdata_len() const
00137 {
00138     return 0;
00139 }
00140 
00141 
00142 unsigned WvAddr::WvHash() const
00143 {
00144     unsigned hash = 0;
00145     const unsigned char *cptr, *raw = rawdata();
00146     int len = rawdata_len(), width;
00147    
00148     if (!raw || !len) return 0;
00149     width = (sizeof(hash)*8 / len) + 1;
00150     
00151     for (cptr = raw; len; len--)
00152         hash = (hash << width) ^ *(cptr++);
00153     return hash;
00154 }
00155 
00156 
00157 bool WvAddr::comparator(const WvAddr *a2, bool first_pass) const
00158 {
00159     if (type() != a2->type()) return false;    
00160 
00161     const unsigned char *raw1, *raw2;
00162     size_t len;
00163     
00164     len = rawdata_len();
00165     if (len != a2->rawdata_len())
00166         return false;
00167     
00168     raw1 = rawdata();
00169     raw2 = a2->rawdata();
00170     
00171     if (!raw1 && !raw2) return true;
00172     if (!raw1 || !raw2) return false;
00173     
00174     return !memcmp(raw1, raw2, len);
00175 }
00176 
00177 
00178 WvStringAddr::WvStringAddr(WvStringParm s, const WvEncap &_cap)
00179         : addr(s), cap(_cap)
00180 {
00181 }
00182 
00183 
00184 WvStringAddr::WvStringAddr(const struct sockaddr *_addr)
00185         : addr((char *)_addr->sa_data), cap(_addr->sa_family)
00186 {
00187 }
00188 
00189 
00190 WvStringAddr::~WvStringAddr()
00191 {
00192     // nothing to do
00193 }
00194 
00195 
00196 WvEncap WvStringAddr::encap() const
00197 {
00198     return cap;
00199 }
00200 
00201 
00202 const unsigned char *WvStringAddr::rawdata() const
00203 {
00204     return (const unsigned char *)(const char *)addr;
00205 }
00206 
00207 
00208 size_t WvStringAddr::rawdata_len() const
00209 {
00210     return strlen(addr);
00211 }
00212 
00213 
00214 sockaddr_bin *WvStringAddr::sockaddr() const
00215 {
00216     sockaddr_bin *sa = new sockaddr_bin;
00217     memset(sa, 0, sizeof(*sa));
00218     strncpy(sa->sa_data, addr, sizeof(sa->sa_data));
00219     return sa;
00220 }
00221 
00222 
00223 size_t WvStringAddr::sockaddr_len() const
00224 {
00225     return sizeof(sockaddr_bin);
00226 }
00227 
00228 
00229 WvString WvStringAddr::printable() const
00230 {
00231     return addr;
00232 }
00233 
00234 
00235 #ifndef _WIN32
00236 /* create a WvEtherAddr from a printable string in the format:
00237  *      AA:BB:CC:DD:EE:FF  (six hex numbers, separated by colons)
00238  */
00239 void WvEtherAddr::string_init(char const string[])
00240 {
00241     char *endptr = NULL;
00242     unsigned char *cptr = binaddr;
00243     
00244     memset(binaddr, 0, ETHER_ADDR_LEN);
00245     for (unsigned int count=0; count < ETHER_ADDR_LEN; count++)
00246     {
00247         *cptr++ = strtoul(endptr ? endptr : string, &endptr, 16);
00248         if (!endptr || !*endptr || endptr==string) break;
00249         endptr++;
00250     }
00251 }
00252 
00253 
00254 WvEtherAddr::~WvEtherAddr()
00255 {
00256     // nothing to do
00257 }
00258 
00259 
00260 /* Generate a printable version of an ethernet address. */
00261 WvString WvEtherAddr::printable() const
00262 {
00263     char s[ETHER_ADDR_LEN*3], *cptr = s;
00264     
00265     for (unsigned int count = 0; count < ETHER_ADDR_LEN; count++)
00266     {
00267         if (cptr > s)
00268             *cptr++ = ':';
00269         sprintf(cptr, "%02X", binaddr[count]);
00270         cptr += 2;
00271     }
00272     *cptr = 0;
00273 
00274     return WvString("%s", s); // create a dynamic WvString
00275 }
00276 
00277 
00278 WvEncap WvEtherAddr::encap() const
00279 {
00280     return WvEncap(WvEncap::Ethernet);
00281 }
00282 
00283 
00284 // FF:FF:FF:FF:FF:FF is the ethernet broadcast address.
00285 bool WvEtherAddr::isbroadcast() const
00286 {
00287     for (unsigned int count = 0; count < ETHER_ADDR_LEN; count++)
00288         if (binaddr[count] != 0xFF)
00289             return false;
00290     return true;
00291 }
00292 
00293 
00294 const unsigned char *WvEtherAddr::rawdata() const
00295 {
00296     return binaddr;
00297 }
00298 
00299 
00300 size_t WvEtherAddr::rawdata_len() const
00301 {
00302     return ETHER_ADDR_LEN;
00303 }
00304 
00305 
00306 sockaddr_bin *WvEtherAddr::sockaddr() const
00307 {
00308     sockaddr_bin *sa = new sockaddr_bin;
00309     memset(sa, 0, sizeof(*sa));
00310     sa->sa_family = ARPHRD_ETHER;
00311     memcpy(sa->sa_data, binaddr, ETHER_ADDR_LEN);
00312     return sa;
00313 }
00314 
00315 
00316 size_t WvEtherAddr::sockaddr_len() const
00317 {
00318     return sizeof(sockaddr_bin);
00319 }
00320 
00321 
00322 WvARCnetAddr::~WvARCnetAddr()
00323 {
00324     // nothing to do
00325 }
00326 
00327 
00328 WvString WvARCnetAddr::printable() const
00329 {
00330     WvString s("  ");
00331     sprintf(s.edit(), "%02X", binaddr);
00332     return s;
00333 }
00334 
00335 
00336 WvEncap WvARCnetAddr::encap() const
00337 {
00338     return WvEncap(WvEncap::ARCnet);
00339 }
00340 
00341 
00342 const unsigned char *WvARCnetAddr::rawdata() const
00343 {
00344     return &binaddr;
00345 }
00346 
00347 
00348 size_t WvARCnetAddr::rawdata_len() const
00349 {
00350     return 1;
00351 }
00352 
00353 
00354 sockaddr_bin *WvARCnetAddr::sockaddr() const
00355 {
00356     sockaddr_bin *sa = new sockaddr_bin;
00357     memset(sa, 0, sizeof(*sa));
00358     sa->sa_family = ARPHRD_ARCNET;
00359     sa->sa_data[0] = binaddr;
00360     return sa;
00361 }
00362 
00363 
00364 size_t WvARCnetAddr::sockaddr_len() const
00365 {
00366     return sizeof(sockaddr_bin);
00367 }
00368 
00369 #endif //_WIN32
00370 
00371 /* create an IP address from a dotted-quad string.  Maybe someday we'll
00372  * support hostnames too with gethostbyname, but not yet.
00373  */
00374 void WvIPAddr::string_init(const char string[])
00375 {
00376     const char *iptr, *nptr;
00377     unsigned char *cptr = binaddr;
00378 
00379     memset(binaddr, 0, 4);
00380     nptr = string;
00381     for (int count=0; count < 4 && nptr; count++)
00382     {
00383         iptr = nptr;
00384         nptr = strchr(iptr, '.');
00385         if (nptr) nptr++;
00386         *cptr++ = strtol(iptr, NULL, 10);
00387         if (!nptr) break;
00388     }
00389 }
00390 
00391 WvIPAddr::~WvIPAddr()
00392 {
00393     // nothing to do
00394 }
00395 
00396 bool WvIPAddr::comparator(const WvAddr *a2, bool first_pass) const
00397 {
00398     if (a2->type() == WVIPADDR)
00399         return !memcmp(binaddr, ((WvIPAddr *)a2)->binaddr, sizeof(binaddr));
00400     else if (first_pass)
00401         return a2->comparator(this, false);
00402     else 
00403     {
00404         const unsigned char *raw1, *raw2;
00405         size_t len;
00406 
00407         len = rawdata_len();
00408         if (len != a2->rawdata_len())
00409             return false;
00410 
00411         raw1 = rawdata();
00412         raw2 = a2->rawdata();
00413 
00414         if (!raw1 && !raw2) return true;
00415         if (!raw1 || !raw2) return false;
00416 
00417         return !memcmp(raw1, raw2, len);
00418     }
00419 } 
00420 
00421 
00422 /* Generate a printable version of an IP address. */
00423 WvString WvIPAddr::printable() const
00424 {
00425     return WvString("%s.%s.%s.%s",
00426                     binaddr[0], binaddr[1], binaddr[2], binaddr[3]);
00427 }
00428 
00429 
00430 /* AND two IP addresses together (handle netmasks) */
00431 WvIPAddr WvIPAddr::operator& (const WvIPAddr &a2) const
00432 {
00433     unsigned char obin[4];
00434     
00435     for (int count=0; count<4; count++)
00436         obin[count] = binaddr[count] & a2.binaddr[count];
00437     return WvIPAddr(obin);
00438 }
00439 
00440 
00441 /* OR two IP addresses together (for broadcasts, etc) */
00442 WvIPAddr WvIPAddr::operator| (const WvIPAddr &a2) const
00443 {
00444     unsigned char obin[4];
00445     
00446     for (int count=0; count<4; count++)
00447         obin[count] = binaddr[count] | a2.binaddr[count];
00448     return WvIPAddr(obin);
00449 }
00450 
00451 
00452 /* XOR two IP addresses together (for binary operations) */
00453 WvIPAddr WvIPAddr::operator^ (const WvIPAddr &a2) const
00454 {
00455     unsigned char obin[4];
00456     
00457     for (int count=0; count<4; count++)
00458         obin[count] = binaddr[count] ^ a2.binaddr[count];
00459     return WvIPAddr(obin);
00460 }
00461 
00462 
00463 /* invert all the bits of an IP address (for useful binary operations) */
00464 WvIPAddr WvIPAddr::operator~ () const
00465 {
00466     unsigned char obin[4];
00467     
00468     for (int count=0; count<4; count++)
00469         obin[count] = ~binaddr[count];
00470     return WvIPAddr(obin);
00471 }
00472 
00473 
00474 /* add an integer value to an IP address:
00475  *   eg. 192.168.42.255 + 1 == 192.168.43.0
00476  */
00477 WvIPAddr WvIPAddr::operator+ (int n) const
00478 {
00479     uint32_t newad = htonl(ntohl(addr()) + n);
00480     return WvIPAddr((unsigned char *)&newad);
00481 }
00482 
00483 
00484 WvIPAddr WvIPAddr::operator- (int n) const
00485 {
00486     uint32_t newad = htonl(ntohl(addr()) - n);
00487     return WvIPAddr((unsigned char *)&newad);
00488 }
00489 
00490 
00491 WvEncap WvIPAddr::encap() const
00492 {
00493     return WvEncap(WvEncap::IPv4);
00494 }
00495 
00496 
00497 const unsigned char *WvIPAddr::rawdata() const
00498 {
00499     return binaddr;
00500 }
00501 
00502 
00503 size_t WvIPAddr::rawdata_len() const
00504 {
00505     return 4;
00506 }
00507 
00508 
00509 /* Generate a struct sockaddr (suitable for sendto()) from this IP
00510  * address.  Don't forget to delete it after you're done!
00511  */
00512 sockaddr_bin *WvIPAddr::sockaddr() const
00513 {
00514     sockaddr_in *sin = new sockaddr_in;
00515     
00516     memset(sin, 0, sizeof(*sin));
00517     sin->sin_family = AF_INET;
00518     sin->sin_addr.s_addr = addr();
00519     sin->sin_port = 0;
00520     return (sockaddr_bin *)sin;
00521 }
00522 
00523 
00524 size_t WvIPAddr::sockaddr_len() const
00525 {
00526     return sizeof(sockaddr_in);
00527 }
00528 
00529 
00530 WvIPNet::WvIPNet() { }
00531 
00532 
00533 WvIPNet::WvIPNet(const WvIPNet &_net)
00534         : WvIPAddr(_net), mask(_net.netmask()) { }
00535 
00536 
00537 // If the netmask is not specified, it will default to all 1's.
00538 void WvIPNet::string_init(const char string[])
00539 {
00540     char *maskptr;
00541     int bits;
00542     uint32_t imask;
00543 
00544     maskptr = strchr(string, '/');
00545     if (!maskptr)
00546     {
00547         mask = WvIPAddr("255.255.255.255");
00548         return;
00549     }
00550     
00551     maskptr++;
00552     
00553     if (strchr(maskptr, '.'))
00554         mask = WvIPAddr(maskptr);
00555     else
00556     {
00557         bits = atoi(maskptr);
00558         if (bits > 0)
00559             imask = htonl(~(((uint32_t)1 << (32-bits)) - 1)); // see below
00560         else
00561             imask = 0;
00562         mask = WvIPAddr((unsigned char *)&imask);
00563     }
00564 }
00565 
00566 
00567 WvIPNet::WvIPNet(const WvIPAddr &base, const WvIPAddr &_mask)
00568         : WvIPAddr(base), mask(_mask) { }
00569 
00570 
00571 WvIPNet::WvIPNet(const WvIPAddr &base, int bits)
00572         : WvIPAddr(base)
00573 {
00574     uint32_t imask;
00575     if (bits > 0) // <<32 is a bad idea!
00576         imask = htonl(~(((uint32_t)1 << (32-bits)) - 1));
00577     else
00578         imask = 0;
00579     mask = WvIPAddr((unsigned char *)&imask);
00580 }
00581 
00582 WvIPNet::~WvIPNet()
00583 {
00584     // nothing to do
00585 }
00586 
00587 
00588 WvString WvIPNet::printable() const
00589 {
00590     if (bits() < 32)
00591         return WvString("%s/%s", network(), bits());
00592     else
00593         return WvIPAddr::printable();
00594 }
00595 
00596 
00597 unsigned WvIPNet::WvHash() const
00598 {
00599     return WvIPAddr::WvHash() + mask.WvHash();
00600 }
00601 
00602 
00603 bool WvIPNet::comparator(const WvAddr *a2, bool first_pass) const
00604 {
00605     if (a2->type() == WVIPNET)
00606         return WvIPAddr::comparator(a2, false) && mask == ((WvIPNet *)a2)->mask;
00607     else if (first_pass)
00608         return a2->comparator(this, false);
00609     else
00610         return WvIPAddr::comparator(a2, false);
00611     
00612 }
00613 
00614 
00615 void WvIPNet::include(const WvIPNet &addr)
00616 {
00617     mask = mask & addr.mask & ~(*this ^ addr);
00618 }
00619 
00620 
00621 bool WvIPNet::includes(const WvIPNet &addr) const
00622 {
00623     return (addr.base() & netmask()) == network() &&
00624         (addr.netmask() & netmask()) == netmask();
00625 }
00626 
00627 
00628 int WvIPNet::bits() const
00629 {
00630     int bits = 0;
00631     uint32_t val = ntohl(mask.addr());
00632     
00633     do
00634     {
00635         bits += val >> 31;
00636     } while ((val <<= 1) & (1 << 31));
00637     
00638     return bits;
00639 }
00640 
00641 
00642 void WvIPNet::normalize()
00643 {
00644     if (bits() > 0)
00645     {
00646         uint32_t val = htonl(~(((uint32_t)1 << (32-bits())) - 1));
00647         mask = WvIPAddr((unsigned char *)&val);
00648     }
00649     else
00650         mask = WvIPAddr(); // empty netmask
00651 }
00652 
00653 
00654 WvIPPortAddr::WvIPPortAddr()
00655 {
00656     port = 0;
00657 }
00658 
00659 
00660 WvIPPortAddr::WvIPPortAddr(const WvIPAddr &_ipaddr, uint16_t _port)
00661                         : WvIPAddr(_ipaddr)
00662 {
00663     port = _port;
00664 }
00665 
00666 
00667 // If no port is specified (after a ':' or a space or a tab) it defaults to 0.
00668 void WvIPPortAddr::string_init(const char string[]) 
00669 {
00670     struct servent* serv;
00671 
00672     const char *cptr = strchr(string, ':');
00673     if (!cptr)
00674         cptr = strchr(string, ' ');
00675     if (!cptr)
00676         cptr = strchr(string, '\t');
00677 
00678     // avoid calling getservbyname() if we can avoid it, since it's really
00679     // slow and people like to create WvIPPortAddr objects really often.
00680     if (cptr && strcmp(cptr+1, "0"))
00681     {
00682         port = atoi(cptr+1);
00683         if (!port)
00684         {
00685             serv = getservbyname(cptr+1, NULL);
00686             if (serv)
00687                 port = ntohs(serv->s_port);
00688         }
00689     }
00690     else
00691         port = 0;
00692 }
00693 
00694 
00695 WvIPPortAddr::WvIPPortAddr(uint16_t _port)
00696                               : WvIPAddr("0.0.0.0")
00697 {
00698     port = _port;
00699 }
00700 
00701 
00702 WvIPPortAddr::WvIPPortAddr(const char string[], uint16_t _port)
00703                               : WvIPAddr(string)
00704 {
00705     port = _port;
00706 }
00707 
00708  
00709 WvIPPortAddr::~WvIPPortAddr()
00710 {
00711     // nothing to do
00712 }
00713 
00714 
00715 /* Generate a printable version of an IP+Port Address. */
00716 WvString WvIPPortAddr::printable() const
00717 {
00718     return WvString("%s:%s", WvIPAddr::printable(), WvString(port));
00719 }
00720 
00721 
00722 /* Generate a struct sockaddr (suitable for sendto()) from this IP+Port
00723  * address.  Don't forget to delete it after you're done!
00724  */
00725 sockaddr_bin *WvIPPortAddr::sockaddr() const
00726 {
00727     sockaddr_in *sin = (sockaddr_in *)WvIPAddr::sockaddr();
00728     sin->sin_port = htons(port);
00729     return (sockaddr_bin *)sin;
00730 }
00731 
00732 
00733 unsigned WvIPPortAddr::WvHash() const
00734 {
00735     return WvIPAddr::WvHash() + port;
00736 }
00737 
00738 bool WvIPPortAddr::comparator(const WvAddr *a2, bool first_pass) const
00739 {
00740     if (a2->type() == WVIPPORTADDR)
00741         return WvIPAddr::comparator(a2, false)
00742              && port == ((WvIPPortAddr *)a2)->port;
00743     else if (first_pass)
00744         return a2->comparator(this, false);
00745     else
00746         return WvIPAddr::comparator(a2, false);
00747 
00748 }  
00749 
00750 #ifndef _WIN32
00751 WvUnixAddr::WvUnixAddr(const char *_sockname)
00752     : sockname(_sockname)
00753 {
00754     assert(!!sockname);
00755 }
00756 
00757 
00758 WvUnixAddr::WvUnixAddr(WvStringParm _sockname)
00759     : sockname(_sockname)
00760 {
00761     assert(!!sockname);
00762 }
00763 
00764 
00765 WvUnixAddr::WvUnixAddr(const WvUnixAddr &_addr)
00766     : sockname(_addr.sockname)
00767 {
00768     // nothing else needed
00769 }
00770 
00771 
00772 WvUnixAddr::~WvUnixAddr()
00773 {
00774     // nothing special
00775 }
00776 
00777 
00778 WvString WvUnixAddr::printable() const
00779 {
00780     return sockname;
00781 }
00782 
00783 
00784 WvEncap WvUnixAddr::encap() const
00785 {
00786     return WvEncap::Unix;
00787 }
00788 
00789 
00790 /* don't forget to delete the returned object when you're done! */
00791 sockaddr_bin *WvUnixAddr::sockaddr() const
00792 {
00793     sockaddr_un *addr = new sockaddr_un;
00794     
00795     memset(addr, 0, sizeof(*addr));
00796     addr->sun_family = AF_UNIX;
00797     size_t max = strlen(sockname);
00798     if (max > sizeof(addr->sun_path) - 2) // appease valgrind
00799         max = sizeof(addr->sun_path) - 2;
00800     strncpy(addr->sun_path, sockname, max);
00801     return (sockaddr_bin *)addr;
00802 }
00803 
00804 
00805 size_t WvUnixAddr::sockaddr_len() const
00806 {
00807     return sizeof(sockaddr_un);
00808 }
00809 
00810 
00811 const unsigned char *WvUnixAddr::rawdata() const
00812 {
00813     return (const unsigned char *)(const char *)sockname;
00814 }
00815 
00816 
00817 size_t WvUnixAddr::rawdata_len() const
00818 {
00819     return strlen(sockname);
00820 }
00821 #endif // _WIN32

Generated on Thu May 25 21:51:02 2006 for WvStreams by  doxygen 1.4.6