WvStreams
wvaddr.cc
1/*
2 * Worldvisions Weaver Software:
3 * Copyright (C) 1997-2002 Net Integration Technologies, Inc.
4 *
5 * Device-independent and device-specific hardware/protocol address
6 * classes that can store themselves efficiently as well as create a
7 * printable string version of themselves.
8 */
9#ifndef _WIN32
10#include <netdb.h>
11#include <sys/socket.h>
12#include <sys/un.h>
13#ifdef MACOS
14#include <sys/types.h>
15#endif
16#include <net/if_arp.h>
17#endif
18
19#include "wvaddr.h"
20#include <assert.h>
21
22#ifndef ARPHRD_IPSEC
23// From ipsec_tunnel
24#define ARPHRD_IPSEC 31
25#endif
26
27// workaround for functions called sockaddr() -- oops.
28typedef struct sockaddr sockaddr_bin;
29
30/* A list of Linux ARPHRD_* types, one for each element of CapType. */
31int WvEncap::extypes[] = {
32#ifdef _WIN32
33 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
34#else
35 // hardware encapsulation
36 0, // Unknown
37 ARPHRD_LOOPBACK,
38 0, // Ethertap
39 ARPHRD_ETHER,
40 ARPHRD_ARCNET,
41 ARPHRD_SLIP,
42 ARPHRD_CSLIP,
43 ARPHRD_PPP,
44 ARPHRD_IPSEC,
45
46 // protocol encapsulation
47 AF_INET, // IPv4
48 AF_UNIX // Unix domain socket
49#endif
50};
51
52
53/* Printable strings corresponding to each element of CapType */
54const char WvEncap::strings[][20] = {
55 // hardware encapsulation
56 "Unknown",
57 "Loopback",
58 "Ethertap",
59 "Ethernet",
60 "ARCnet",
61 "SLIP",
62 "CSLIP",
63 "PPP",
64 "IPsec",
65
66 // protocol encapsulation
67 "IP", // IPv4
68 "Unix", // Unix domain socket
69};
70
71
72/* Figure out the CapType corresponding to a Linux ARPHRD_* type or
73 * sockaddr sa_family type.
74 */
75WvEncap::WvEncap(int extype)
76{
77 for (int count=0; count < NUM_ENCAP_TYPES; count++)
78 {
79 if (extype == extypes[count])
80 {
81 cap = (CapType)count;
82 return;
83 }
84 }
85 cap = Unknown;
86}
87
88
89/* Find the hash value of a WvAddr, for use with WvHashTable */
90unsigned WvHash(const WvAddr &addr)
91{
92 return addr.WvHash();
93}
94
95
96/* Create an object of the appropriate WvAddr-derived class based on the
97 * address and type stored in 'addr'.
98 */
99WvAddr *WvAddr::gen(struct sockaddr *addr)
100{
101 WvEncap encap(addr->sa_family);
102
103 switch (encap.cap)
104 {
105 case WvEncap::Loopback:
106 return new WvStringAddr("Loopback", WvEncap::Loopback);
107
108 case WvEncap::IPv4:
109 return new WvIPPortAddr((sockaddr_in *)addr);
110#ifndef _WIN32
111 case WvEncap::ARCnet:
112 return new WvARCnetAddr(addr);
113
114 case WvEncap::Ethertap:
115 case WvEncap::Ethernet:
116 return new WvEtherAddr(addr);
117
118 case WvEncap::IPsec:
119 return new WvStringAddr("IPsec", WvEncap::IPsec);
120#endif
121 default:
122 return new WvStringAddr("Unknown", WvEncap::Unknown);
123 }
124}
125
126
127bool WvAddr::isbroadcast() const
128{
129 return false; // default is no support for broadcasts
130}
131
132
133const unsigned char *WvAddr::rawdata() const
134{
135 return NULL;
136}
137
138
139size_t WvAddr::rawdata_len() const
140{
141 return 0;
142}
143
144
145unsigned WvAddr::WvHash() const
146{
147 unsigned hash = 0;
148 const unsigned char *cptr, *raw = rawdata();
149 int len = rawdata_len(), width;
150
151 if (!raw || !len) return 0;
152 width = (sizeof(hash)*8 / len) + 1;
153
154 for (cptr = raw; len; len--)
155 hash = (hash << width) ^ *(cptr++);
156 return hash;
157}
158
159
160bool WvAddr::comparator(const WvAddr *a2, bool first_pass) const
161{
162 if (type() != a2->type()) return false;
163
164 const unsigned char *raw1, *raw2;
165 size_t len;
166
167 len = rawdata_len();
168 if (len != a2->rawdata_len())
169 return false;
170
171 raw1 = rawdata();
172 raw2 = a2->rawdata();
173
174 if (!raw1 && !raw2) return true;
175 if (!raw1 || !raw2) return false;
176
177 return !memcmp(raw1, raw2, len);
178}
179
180
181WvStringAddr::WvStringAddr(WvStringParm s, const WvEncap &_cap)
182 : addr(s), cap(_cap)
183{
184}
185
186
187WvStringAddr::WvStringAddr(const struct sockaddr *_addr)
188 : addr((char *)_addr->sa_data), cap(_addr->sa_family)
189{
190}
191
192
193WvStringAddr::~WvStringAddr()
194{
195 // nothing to do
196}
197
198
199WvEncap WvStringAddr::encap() const
200{
201 return cap;
202}
203
204
205const unsigned char *WvStringAddr::rawdata() const
206{
207 return (const unsigned char *)(const char *)addr;
208}
209
210
211size_t WvStringAddr::rawdata_len() const
212{
213 return strlen(addr);
214}
215
216
217sockaddr_bin *WvStringAddr::sockaddr() const
218{
219 sockaddr_bin *sa = new sockaddr_bin;
220 memset(sa, 0, sizeof(*sa));
221 strncpy(sa->sa_data, addr, sizeof(sa->sa_data));
222 return sa;
223}
224
225
226size_t WvStringAddr::sockaddr_len() const
227{
228 return sizeof(sockaddr_bin);
229}
230
231
232WvString WvStringAddr::printable() const
233{
234 return addr;
235}
236
237
238#ifndef _WIN32
239/* create a WvEtherAddr from a printable string in the format:
240 * AA:BB:CC:DD:EE:FF (six hex numbers, separated by colons)
241 */
242void WvEtherAddr::string_init(char const string[])
243{
244 char *endptr = NULL;
245 unsigned char *cptr = binaddr;
246
247 memset(binaddr, 0, ETHER_ADDR_LEN);
248 for (unsigned int count=0; count < ETHER_ADDR_LEN; count++)
249 {
250 *cptr++ = strtoul(endptr ? endptr : string, &endptr, 16);
251 if (!endptr || !*endptr || endptr==string) break;
252 endptr++;
253 }
254}
255
256
257WvEtherAddr::~WvEtherAddr()
258{
259 // nothing to do
260}
261
262
263/* Generate a printable version of an ethernet address. */
264WvString WvEtherAddr::printable() const
265{
266 char s[ETHER_ADDR_LEN*3], *cptr = s;
267
268 for (unsigned int count = 0; count < ETHER_ADDR_LEN; count++)
269 {
270 if (cptr > s)
271 *cptr++ = ':';
272 sprintf(cptr, "%02X", binaddr[count]);
273 cptr += 2;
274 }
275 *cptr = 0;
276
277 return WvString("%s", s); // create a dynamic WvString
278}
279
280
281WvEncap WvEtherAddr::encap() const
282{
283 return WvEncap(WvEncap::Ethernet);
284}
285
286
287// FF:FF:FF:FF:FF:FF is the ethernet broadcast address.
288bool WvEtherAddr::isbroadcast() const
289{
290 for (unsigned int count = 0; count < ETHER_ADDR_LEN; count++)
291 if (binaddr[count] != 0xFF)
292 return false;
293 return true;
294}
295
296
297const unsigned char *WvEtherAddr::rawdata() const
298{
299 return binaddr;
300}
301
302
303size_t WvEtherAddr::rawdata_len() const
304{
305 return ETHER_ADDR_LEN;
306}
307
308
309sockaddr_bin *WvEtherAddr::sockaddr() const
310{
311 sockaddr_bin *sa = new sockaddr_bin;
312 memset(sa, 0, sizeof(*sa));
313 sa->sa_family = ARPHRD_ETHER;
314 memcpy(sa->sa_data, binaddr, ETHER_ADDR_LEN);
315 return sa;
316}
317
318
319size_t WvEtherAddr::sockaddr_len() const
320{
321 return sizeof(sockaddr_bin);
322}
323
324
325WvARCnetAddr::~WvARCnetAddr()
326{
327 // nothing to do
328}
329
330
331WvString WvARCnetAddr::printable() const
332{
333 WvString s(" ");
334 sprintf(s.edit(), "%02X", binaddr);
335 return s;
336}
337
338
339WvEncap WvARCnetAddr::encap() const
340{
341 return WvEncap(WvEncap::ARCnet);
342}
343
344
345const unsigned char *WvARCnetAddr::rawdata() const
346{
347 return &binaddr;
348}
349
350
351size_t WvARCnetAddr::rawdata_len() const
352{
353 return 1;
354}
355
356
357sockaddr_bin *WvARCnetAddr::sockaddr() const
358{
359 sockaddr_bin *sa = new sockaddr_bin;
360 memset(sa, 0, sizeof(*sa));
361 sa->sa_family = ARPHRD_ARCNET;
362 sa->sa_data[0] = binaddr;
363 return sa;
364}
365
366
367size_t WvARCnetAddr::sockaddr_len() const
368{
369 return sizeof(sockaddr_bin);
370}
371
372#endif //_WIN32
373
374/* create an IP address from a dotted-quad string. We don't support
375 * gethostname()-style lookups here, because they happen only synchronously.
376 * Streams that need hostname lookups will have to do it themselves.
377 */
378void WvIPAddr::string_init(const char string[])
379{
380 const char *iptr, *nptr;
381 unsigned char *cptr = binaddr;
382
383 memset(binaddr, 0, 4);
384 nptr = string;
385 for (int count=0; count < 4 && nptr; count++)
386 {
387 iptr = nptr;
388 nptr = strchr(iptr, '.');
389 if (nptr) nptr++;
390 *cptr++ = strtol(iptr, NULL, 10);
391 if (!nptr) break;
392 }
393}
394
395WvIPAddr::~WvIPAddr()
396{
397 // nothing to do
398}
399
400bool WvIPAddr::comparator(const WvAddr *a2, bool first_pass) const
401{
402 if (a2->type() == WVIPADDR)
403 return !memcmp(binaddr, ((WvIPAddr *)a2)->binaddr, sizeof(binaddr));
404 else if (first_pass)
405 return a2->comparator(this, false);
406 else
407 {
408 const unsigned char *raw1, *raw2;
409 size_t len;
410
411 len = rawdata_len();
412 if (len != a2->rawdata_len())
413 return false;
414
415 raw1 = rawdata();
416 raw2 = a2->rawdata();
417
418 if (!raw1 && !raw2) return true;
419 if (!raw1 || !raw2) return false;
420
421 return !memcmp(raw1, raw2, len);
422 }
423}
424
425
426/* Generate a printable version of an IP address. */
427WvString WvIPAddr::printable() const
428{
429 return WvString("%s.%s.%s.%s",
430 binaddr[0], binaddr[1], binaddr[2], binaddr[3]);
431}
432
433
434/* AND two IP addresses together (handle netmasks) */
435WvIPAddr WvIPAddr::operator& (const WvIPAddr &a2) const
436{
437 unsigned char obin[4];
438
439 for (int count=0; count<4; count++)
440 obin[count] = binaddr[count] & a2.binaddr[count];
441 return WvIPAddr(obin);
442}
443
444
445/* OR two IP addresses together (for broadcasts, etc) */
446WvIPAddr WvIPAddr::operator| (const WvIPAddr &a2) const
447{
448 unsigned char obin[4];
449
450 for (int count=0; count<4; count++)
451 obin[count] = binaddr[count] | a2.binaddr[count];
452 return WvIPAddr(obin);
453}
454
455
456/* XOR two IP addresses together (for binary operations) */
457WvIPAddr WvIPAddr::operator^ (const WvIPAddr &a2) const
458{
459 unsigned char obin[4];
460
461 for (int count=0; count<4; count++)
462 obin[count] = binaddr[count] ^ a2.binaddr[count];
463 return WvIPAddr(obin);
464}
465
466
467/* invert all the bits of an IP address (for useful binary operations) */
468WvIPAddr WvIPAddr::operator~ () const
469{
470 unsigned char obin[4];
471
472 for (int count=0; count<4; count++)
473 obin[count] = ~binaddr[count];
474 return WvIPAddr(obin);
475}
476
477
478/* add an integer value to an IP address:
479 * eg. 192.168.42.255 + 1 == 192.168.43.0
480 */
481WvIPAddr WvIPAddr::operator+ (int n) const
482{
483 uint32_t newad = htonl(ntohl(addr()) + n);
484 return WvIPAddr((unsigned char *)&newad);
485}
486
487
488WvIPAddr WvIPAddr::operator- (int n) const
489{
490 uint32_t newad = htonl(ntohl(addr()) - n);
491 return WvIPAddr((unsigned char *)&newad);
492}
493
494
495WvEncap WvIPAddr::encap() const
496{
497 return WvEncap(WvEncap::IPv4);
498}
499
500
501const unsigned char *WvIPAddr::rawdata() const
502{
503 return binaddr;
504}
505
506
507size_t WvIPAddr::rawdata_len() const
508{
509 return 4;
510}
511
512
513/* Generate a struct sockaddr (suitable for sendto()) from this IP
514 * address. Don't forget to delete it after you're done!
515 */
516sockaddr_bin *WvIPAddr::sockaddr() const
517{
518 sockaddr_in *sin = new sockaddr_in;
519
520 memset(sin, 0, sizeof(*sin));
521 sin->sin_family = AF_INET;
522 sin->sin_addr.s_addr = addr();
523 sin->sin_port = 0;
524 return (sockaddr_bin *)sin;
525}
526
527
528size_t WvIPAddr::sockaddr_len() const
529{
530 return sizeof(sockaddr_in);
531}
532
533
535
536
537WvIPNet::WvIPNet(const WvIPNet &_net)
538 : WvIPAddr(_net), mask(_net.netmask()) { }
539
540
541// If the netmask is not specified, it will default to all 1's.
542void WvIPNet::string_init(const char string[])
543{
544 const char *maskptr;
545 int bits;
546 uint32_t imask;
547
548 maskptr = strchr(string, '/');
549 if (!maskptr)
550 {
551 mask = WvIPAddr("255.255.255.255");
552 return;
553 }
554
555 maskptr++;
556
557 if (strchr(maskptr, '.'))
558 mask = WvIPAddr(maskptr);
559 else
560 {
561 bits = atoi(maskptr);
562 if (bits > 0)
563 imask = htonl(~(((uint32_t)1 << (32-bits)) - 1)); // see below
564 else
565 imask = 0;
566 mask = WvIPAddr((unsigned char *)&imask);
567 }
568}
569
570
571WvIPNet::WvIPNet(const WvIPAddr &base, const WvIPAddr &_mask)
572 : WvIPAddr(base), mask(_mask) { }
573
574
575WvIPNet::WvIPNet(const WvIPAddr &base, int bits)
576 : WvIPAddr(base)
577{
578 uint32_t imask;
579 if (bits > 0) // <<32 is a bad idea!
580 imask = htonl(~(((uint32_t)1 << (32-bits)) - 1));
581 else
582 imask = 0;
583 mask = WvIPAddr((unsigned char *)&imask);
584}
585
586WvIPNet::~WvIPNet()
587{
588 // nothing to do
589}
590
591
592WvString WvIPNet::printable() const
593{
594 if (bits() < 32)
595 return WvString("%s/%s", network(), bits());
596 else
597 return WvIPAddr::printable();
598}
599
600
601unsigned WvIPNet::WvHash() const
602{
603 return WvIPAddr::WvHash() + mask.WvHash();
604}
605
606
607bool WvIPNet::comparator(const WvAddr *a2, bool first_pass) const
608{
609 if (a2->type() == WVIPNET)
610 return WvIPAddr::comparator(a2, false) && mask == ((WvIPNet *)a2)->mask;
611 else if (first_pass)
612 return a2->comparator(this, false);
613 else
614 return WvIPAddr::comparator(a2, false);
615
616}
617
618
619void WvIPNet::include(const WvIPNet &addr)
620{
621 mask = mask & addr.mask & ~(*this ^ addr);
622}
623
624
625bool WvIPNet::includes(const WvIPNet &addr) const
626{
627 return (addr.base() & netmask()) == network() &&
628 (addr.netmask() & netmask()) == netmask();
629}
630
631
632int WvIPNet::bits() const
633{
634 int bits = 0;
635 uint32_t val = ntohl(mask.addr());
636
637 do
638 {
639 bits += val >> 31;
640 } while ((val <<= 1) & (1 << 31));
641
642 return bits;
643}
644
645
646void WvIPNet::normalize()
647{
648 if (bits() > 0)
649 {
650 uint32_t val = htonl(~(((uint32_t)1 << (32-bits())) - 1));
651 mask = WvIPAddr((unsigned char *)&val);
652 }
653 else
654 mask = WvIPAddr(); // empty netmask
655}
656
657
658WvIPPortAddr::WvIPPortAddr()
659{
660 port = 0;
661}
662
663
664WvIPPortAddr::WvIPPortAddr(const WvIPAddr &_ipaddr, uint16_t _port)
665 : WvIPAddr(_ipaddr)
666{
667 port = _port;
668}
669
670
671static bool all_digits(const char *s)
672{
673 for (; *s; s++)
674 if (!isdigit((unsigned char)*s))
675 return false;
676 return true;
677}
678
679
680// If no port is specified (after a ':' or a space or a tab) it defaults to 0.
681void WvIPPortAddr::string_init(const char string[])
682{
683 // special case for an all-numeric string: it must be just a port,
684 // with default address 0.0.0.0.
685 if (all_digits(string))
686 {
687 *this = WvIPAddr();
688 port = atoi(string);
689 return;
690 }
691
692 const char *cptr = strchr(string, ':');
693 if (!cptr)
694 cptr = strchr(string, ' ');
695 if (!cptr)
696 cptr = strchr(string, '\t');
697
698 // avoid calling getservbyname() if we can avoid it, since it's really
699 // slow and people like to create WvIPPortAddr objects really often.
700 if (cptr && strcmp(cptr+1, "0"))
701 {
702 port = atoi(cptr+1);
703 if (!port)
704 {
705 struct servent *serv = getservbyname(cptr+1, NULL);
706 if (serv)
707 port = ntohs(serv->s_port);
708 }
709 }
710 else
711 port = 0;
712}
713
714
715WvIPPortAddr::WvIPPortAddr(uint16_t _port)
716 : WvIPAddr("0.0.0.0")
717{
718 port = _port;
719}
720
721
722WvIPPortAddr::WvIPPortAddr(const char string[], uint16_t _port)
723 : WvIPAddr(string)
724{
725 port = _port;
726}
727
728
729WvIPPortAddr::~WvIPPortAddr()
730{
731 // nothing to do
732}
733
734
735/* Generate a printable version of an IP+Port Address. */
736WvString WvIPPortAddr::printable() const
737{
738 return WvString("%s:%s", WvIPAddr::printable(), WvString(port));
739}
740
741
742/* Generate a struct sockaddr (suitable for sendto()) from this IP+Port
743 * address. Don't forget to delete it after you're done!
744 */
745sockaddr_bin *WvIPPortAddr::sockaddr() const
746{
747 sockaddr_in *sin = (sockaddr_in *)WvIPAddr::sockaddr();
748 sin->sin_port = htons(port);
749 return (sockaddr_bin *)sin;
750}
751
752
753unsigned WvIPPortAddr::WvHash() const
754{
755 return WvIPAddr::WvHash() + port;
756}
757
758bool WvIPPortAddr::comparator(const WvAddr *a2, bool first_pass) const
759{
760 if (a2->type() == WVIPPORTADDR)
761 return WvIPAddr::comparator(a2, false)
762 && port == ((WvIPPortAddr *)a2)->port;
763 else if (first_pass)
764 return a2->comparator(this, false);
765 else
766 return WvIPAddr::comparator(a2, false);
767
768}
769
770#ifndef _WIN32
771WvUnixAddr::WvUnixAddr(const char *_sockname)
772 : sockname(_sockname)
773{
774 if (!sockname)
775 sockname = "/";
776}
777
778
779WvUnixAddr::WvUnixAddr(WvStringParm _sockname)
780 : sockname(_sockname)
781{
782 if (!sockname)
783 sockname = "/";
784}
785
786
787WvUnixAddr::WvUnixAddr(const WvUnixAddr &_addr)
788 : sockname(_addr.sockname)
789{
790 // nothing else needed
791}
792
793
794WvUnixAddr::~WvUnixAddr()
795{
796 // nothing special
797}
798
799
800WvString WvUnixAddr::printable() const
801{
802 return sockname;
803}
804
805
806WvEncap WvUnixAddr::encap() const
807{
808 return WvEncap::Unix;
809}
810
811
812/* don't forget to delete the returned object when you're done! */
813sockaddr_bin *WvUnixAddr::sockaddr() const
814{
815 sockaddr_un *addr = new sockaddr_un;
816
817 memset(addr, 0, sizeof(*addr));
818 addr->sun_family = AF_UNIX;
819 size_t max = strlen(sockname);
820 if (max > sizeof(addr->sun_path) - 2) // appease valgrind
821 max = sizeof(addr->sun_path) - 2;
822 strncpy(addr->sun_path, sockname, max);
823 if (addr->sun_path[0] == '@') // user wants an "abstract" socket
824 addr->sun_path[0] = 0; // leading byte should be nul
825 return (sockaddr_bin *)addr;
826}
827
828
829size_t WvUnixAddr::sockaddr_len() const
830{
831 sockaddr_un *fake;
832 size_t max = sizeof(fake->sun_path);
833 size_t val = strlen(sockname);
834 if (val > max)
835 val = max;
836 return sizeof(fake->sun_family) + val;
837}
838
839
840const unsigned char *WvUnixAddr::rawdata() const
841{
842 return (const unsigned char *)(const char *)sockname;
843}
844
845
846size_t WvUnixAddr::rawdata_len() const
847{
848 return strlen(sockname);
849}
850#endif // _WIN32
An ARCnet address is made up of a single hex number.
Definition: wvaddr.h:216
Base class for different address types, each of which will have the ability to convert itself to/from...
Definition: wvaddr.h:119
Common packet encapsulation types, with the ability to convert a Linux ARPHRD_* value or (struct sock...
Definition: wvaddr.h:73
An ethernet address is made up of a string of hex numbers, in the form AA:BB:CC:DD:EE:FF.
Definition: wvaddr.h:187
A WvFastString acts exactly like a WvString, but can take (const char *) strings without needing to a...
Definition: wvstring.h:94
An IP address is made up of a "dotted quad" – four decimal numbers in the form www....
Definition: wvaddr.h:250
An IP network comprises two WvIPAddr structures: an address and a netmask.
Definition: wvaddr.h:313
bool includes(const WvIPNet &addr) const
determine whether the given address is already included in this net
Definition: wvaddr.cc:625
void include(const WvIPNet &addr)
adjust the netmask so that 'addr' would be included in this network
Definition: wvaddr.cc:619
WvIPNet()
construct an empty IPNet for later copying (probably by operator=)
Definition: wvaddr.cc:534
int bits() const
weird netmasks such as 255.0.255.0 (easy example) are almost never used – they have '0' bits in the m...
Definition: wvaddr.cc:632
virtual unsigned WvHash() const
Override the hash and comparison functions.
Definition: wvaddr.cc:601
WvIPAddr base() const
Get the 'base IP address' component, netmask, network, and broadcast.
Definition: wvaddr.h:347
An IP+Port address also includes a port number, with the resulting form www.xxx.yyy....
Definition: wvaddr.h:394
A WvAddr that simply contains a printable string with a user-defined encapsulation type.
Definition: wvaddr.h:162
WvString is an implementation of a simple and efficient printable-string class.
Definition: wvstring.h:330
A Unix domain socket address is really just a filename.
Definition: wvaddr.h:430