The Assimilation Project
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
netaddr.c
Go to the documentation of this file.
1 
27 #include <stdlib.h>
28 #include <memory.h>
29 #include <ctype.h>
30 #include <projectcommon.h>
31 #include <netaddr.h>
32 #include <address_family_numbers.h>
33 #ifdef _MSC_VER
34 # include <ws2tcpip.h>
35 #endif
36 #ifdef HAVE_SYS_TYPES_H
37 # include <sys/types.h>
38 #endif
39 #ifdef HAVE_SYS_SOCKET_H
40 # include <sys/socket.h>
41 #endif
42 #ifdef HAVE_NETDB_H
43 # include <netdb.h>
44 #endif
45 
46 FSTATIC struct sockaddr_in6 _netaddr_ipv6sockaddr(const NetAddr* self);
47 FSTATIC struct sockaddr_in _netaddr_ipv4sockaddr(const NetAddr* self);
49 FSTATIC guint16 _netaddr_port(const NetAddr* self);
50 FSTATIC void _netaddr_setport(NetAddr* self, guint16);
51 FSTATIC guint16 _netaddr_addrtype(const NetAddr* self);
52 FSTATIC gboolean _netaddr_ismcast(const NetAddr* self);
53 FSTATIC gboolean _netaddr_islocal(const NetAddr* self);
54 FSTATIC gboolean _netaddr_isanyaddr(const NetAddr* self);
55 FSTATIC gconstpointer _netaddr_addrinnetorder(gsize *addrlen);
56 FSTATIC gboolean _netaddr_equal(const NetAddr*, const NetAddr*);
57 FSTATIC guint _netaddr_hash(const NetAddr*);
58 FSTATIC gchar * _netaddr_toStringflex(const NetAddr*, gboolean canonformat);
59 FSTATIC gchar * _netaddr_toString(gconstpointer);
60 FSTATIC gchar * _netaddr_canonStr(const NetAddr*);
62 FSTATIC gchar * _netaddr_toString_ipv6_ipv4(const NetAddr* self, gboolean ipv4format);
63 FSTATIC NetAddr* _netaddr_string_ipv4_new(const char* addrstr);
64 FSTATIC NetAddr* _netaddr_string_ipv6_new(const char* addrstr);
65 FSTATIC NetAddr* _netaddr_string_macaddr_new(const char* addrstr);
66 
68 
76 
77 static const guchar ipv6loop [16] = CONST_IPV6_LOOPBACK;
78 static const guchar ipv4loopversion2 [16] = {CONST_IPV6_IPV4SPACE, 127, 0, 0, 1};
79 static const guchar ipv4loop [4] = CONST_IPV4_LOOPBACK;
80 
82 FSTATIC gchar *
83 _netaddr_toString_ipv6_ipv4(const NetAddr* self, gboolean ipv4format)
84 {
85  const char * prefix;
86  const char * suffix;
87  if (self->_addrport) {
88  prefix = (ipv4format ? "" : "[::ffff:");
89  suffix = (ipv4format ? ":" : "]:" );
90  }else{
91  prefix = (ipv4format ? "" : "::ffff:");
92  suffix = ""; // Not used
93  }
94 
95  if (self->_addrport) {
96  return g_strdup_printf("%s%d.%d.%d.%d%s%d",
97  prefix,
98  ((const guchar*)self->_addrbody)[12],
99  ((const guchar*)self->_addrbody)[13],
100  ((const guchar*)self->_addrbody)[14],
101  ((const guchar*)self->_addrbody)[15],
102  suffix,
103  self->_addrport);
104  }
105  return g_strdup_printf("%s%d.%d.%d.%d",
106  prefix,
107  ((const guchar*)self->_addrbody)[12],
108  ((const guchar*)self->_addrbody)[13],
109  ((const guchar*)self->_addrbody)[14],
110  ((const guchar*)self->_addrbody)[15]);
111 }
114 FSTATIC gchar *
115 _netaddr_toString(gconstpointer baseobj)
116 {
117  const NetAddr* self = CASTTOCONSTCLASS(NetAddr, baseobj);
118  return _netaddr_toStringflex(self, FALSE);
119 }
120 
121 FSTATIC gchar *
123 {
124  return _netaddr_toStringflex(self, TRUE);
125 }
126 
128 NetAddr*
130 {
131 
132  switch (self->_addrtype) {
133  case ADDR_FAMILY_IPV6:
134  // Return a copy of this IPv6 address
135  return netaddr_ipv6_new(self->_addrbody, self->_addrport);
136 
137  case ADDR_FAMILY_IPV4: {
138  const int ipv4prefixlen = 12;
139  guchar ipv6addr[16] = {CONST_IPV6_IPV4SPACE, 0, 0, 0, 0};
140  // We have an IPv4 address we want to convert to an IPv6 address
141  if (memcmp(self->_addrbody, ipv4loop, sizeof(ipv4loop)) == 0) {
142  // Convert loopback addresses from v4 to v6
143  memcpy(ipv6addr, ipv6loop, sizeof(ipv6loop));
144  }else{
145  memcpy(ipv6addr+ipv4prefixlen, self->_addrbody, 4);
146  }
147  return netaddr_ipv6_new(ipv6addr, self->_addrport);
148  }
149 
150  default: // OOPS!
151  break;
152  }
154  g_return_val_if_reached(NULL);
155 }
156 
157 
159 FSTATIC gchar *
160 _netaddr_toStringflex(const NetAddr* self, gboolean canon_format)
161 {
162  gchar * ret = NULL;
163  GString* gsret = NULL;
164  int nbyte;
165  if (self->_addrtype == ADDR_FAMILY_IPV4) {
166  if (self->_addrport) {
167  return g_strdup_printf("%d.%d.%d.%d:%d",
168  ((const guchar*)self->_addrbody)[0],
169  ((const guchar*)self->_addrbody)[1],
170  ((const guchar*)self->_addrbody)[2],
171  ((const guchar*)self->_addrbody)[3],
172  self->_addrport);
173  }
174  return g_strdup_printf("%d.%d.%d.%d",
175  ((const guchar*)self->_addrbody)[0],
176  ((const guchar*)self->_addrbody)[1],
177  ((const guchar*)self->_addrbody)[2],
178  ((const guchar*)self->_addrbody)[3]);
179  }
180  gsret = g_string_new("");
181  if (self->_addrtype == ADDR_FAMILY_IPV6) {
182  gboolean doublecolonyet = FALSE;
183  gboolean justhaddoublecolon = FALSE;
184  int zerocount = 0;
185  guchar ipv4prefix[] = {0,0,0,0,0,0,0,0,0,0,0xff,0xff};
186  if (self->_addrlen != 16) {
187  g_string_free(gsret, TRUE); gsret = NULL;
188  return g_strdup("{invalid ipv6}");
189  }
190  if (self->_addrport) {
191  g_string_append(gsret, "[");
192  }
193  if (memcmp(self->_addrbody, ipv4prefix, sizeof(ipv4prefix)) == 0) {
194  g_string_free(gsret, TRUE); gsret = NULL;
195  return _netaddr_toString_ipv6_ipv4(self, canon_format);
196  }
197  for (nbyte = 0; nbyte < self->_addrlen; nbyte += 2) {
198  guint16 byte0 = ((const guchar*)self->_addrbody)[nbyte];
199  guint16 byte1 = ((const guchar*)self->_addrbody)[nbyte+1];
200  guint16 word = (byte0 << 8 | byte1);
201  if (!doublecolonyet && word == 0x00) {
202  ++zerocount;
203  continue;
204  }
205  if (zerocount == 1) {
206  g_string_append_printf(gsret, (nbyte == 2 ? "0" : ":0"));
207  zerocount=0;
208  }else if (zerocount > 1) {
209  g_string_append_printf(gsret, "::");
210  zerocount=0;
211  doublecolonyet = TRUE;
212  justhaddoublecolon = TRUE;
213  }
214  g_string_append_printf(gsret
215  , ((nbyte == 0 || justhaddoublecolon) ? "%x" : ":%x"), word);
216  justhaddoublecolon = FALSE;
217  }
218  if (zerocount == 1) {
219  g_string_append_printf(gsret, ":00");
220  }else if (zerocount > 1) {
221  g_string_append_printf(gsret, "::");
222  }
223  if (self->_addrport) {
224  g_string_append_printf(gsret, "]:%d", self->_addrport);
225  }
226 
227  }else{
228  for (nbyte = 0; nbyte < self->_addrlen; ++nbyte) {
229  g_string_append_printf(gsret, (nbyte == 0 ? "%02x" : "-%02x"),
230  ((const guchar*)self->_addrbody)[nbyte]);
231  }
232  }
233  ret = gsret->str;
234  g_string_free(gsret, FALSE);
235  return ret;
236 }
237 
239 FSTATIC gboolean
240 _netaddr_equal(const NetAddr*self, const NetAddr*other)
241 {
243  const guchar ipv6v4 [12] = {CONST_IPV6_IPV4SPACE};// Where IPv4 addrs are found inside IPv6 space
244  gint memcmprc;
245 
246 
247  DEBUGMSG5("%s.%d: Comparing (type %d, length %d) vs (type %d, length %d)"
248  , __FUNCTION__, __LINE__, self->_addrtype, self->_addrlen, other->_addrtype, other->_addrlen)
249  DEBUGMSG5("%s.%d: checking ports for equality (if v4/v6 addresses)", __FUNCTION__, __LINE__)
250  if ((self->_addrtype == ADDR_FAMILY_IPV6 || self->_addrtype == ADDR_FAMILY_IPV4)
251  && (other->_addrtype == ADDR_FAMILY_IPV6 || other->_addrtype == ADDR_FAMILY_IPV4)
252  && self->_addrport != other->_addrport) {
253  DEBUGMSG5("%s.%d: selfport:%d, otherport:%d", __FUNCTION__, __LINE__, self->_addrport, other->_addrport);
254  return FALSE;
255  }
256 
257  if (self->_addrtype == ADDR_FAMILY_IPV6) {
258  DEBUGMSG5("%s.%d: self is IPv6", __FUNCTION__, __LINE__)
259  if (other->_addrtype == ADDR_FAMILY_IPV4) {
260  const guchar *selfabody = self->_addrbody;
261  // Check for equivalent IPv4 and IPv6 addresses
262  DEBUGMSG5("%s.%d: checking equivalent v6/v4 addresses", __FUNCTION__, __LINE__)
263  if (memcmp(selfabody, ipv6v4, sizeof(ipv6v4)) == 0
264  && memcmp(selfabody+12, other->_addrbody, 4) == 0) {
265  DEBUGMSG5("%s.%d: v6/v4 addresses are equivalent", __FUNCTION__, __LINE__)
266  return TRUE;
267  }
268  DEBUGMSG5("%s.%d: checking v6/v4 loopbacks", __FUNCTION__, __LINE__)
269  // Check for the equivalent loopback addresses between IPv4 and IPv6
271  if (memcmp(self->_addrbody, ipv6loop, sizeof(ipv6loop)) == 0
272  && memcmp(other->_addrbody, ipv4loop, sizeof(ipv4loop)) == 0) {
273  DEBUGMSG5("%s.%d: v6/v4 addresses are both loopbacks", __FUNCTION__, __LINE__)
274  return TRUE;
275  }
276  DEBUGMSG5("%s.%d: v6/v4 addresses are not equivalent", __FUNCTION__, __LINE__)
277  return FALSE;
278  }else if (other->_addrtype == ADDR_FAMILY_IPV6) {
279  // Well... Are we cross comparing the two types of ipv6 loopback addresses?
280  // These are: ::1 and ::ff:127.0.0.1 Kinda weird - but seems valid...
281  DEBUGMSG5("%s.%d: other is IPv6 too", __FUNCTION__, __LINE__)
282  if (memcmp(self->_addrbody, ipv6loop, sizeof(ipv6loop)) == 0) {
283  DEBUGMSG5("%s.%d: comparing loopbacks", __FUNCTION__, __LINE__);
284  if (memcmp(other->_addrbody, ipv4loopversion2, sizeof(ipv4loopversion2)) == 0) {
285  return TRUE;
286  }
287  }else if (memcmp(self->_addrbody, ipv4loopversion2, sizeof(ipv4loopversion2)) == 0) {
288  DEBUGMSG5("%s.%d: comparing loopbacks the other way", __FUNCTION__, __LINE__);
289  if (memcmp(other->_addrbody, ipv6loop, sizeof(ipv6loop)) == 0) {
290  return TRUE;
291  }
292  }
293  }
294  }
295 
296  DEBUGMSG5("%s.%d: checking to see if we need to reverse operands...", __FUNCTION__, __LINE__)
297 
298  if (self->_addrtype == ADDR_FAMILY_IPV4 && other->_addrtype == ADDR_FAMILY_IPV6) {
299  gboolean retval;
300  // Switch the operands and try again...
301  DEBUGMSG5("%s.%d: switching operands", __FUNCTION__, __LINE__)
302  retval = _netaddr_equal(other, self);
303  DEBUGMSG5("%s.%d: returning %s after switching operands", __FUNCTION__, __LINE__
304  , (retval ? "True" : "False"));
305  return retval;
306  }
307  DEBUGMSG5("%s.%d: checking type and length...", __FUNCTION__, __LINE__)
308  // Other than ipv4 vs ipv6 (handled above) we require addresses to be of the same type
309  if (self->_addrtype != other->_addrtype || self->_addrlen != other->_addrlen) {
310  DEBUGMSG5("%s.%d: self->addrtype:%d, other->addrtype:%d", __FUNCTION__, __LINE__, self->_addrtype, other->_addrtype);
311  DEBUGMSG5("%s.%d: self->addrlen: %d, other->addrlen: %d", __FUNCTION__, __LINE__, self->_addrlen, other->_addrlen);
312  return FALSE;
313  }
314  memcmprc = memcmp(self->_addrbody, other->_addrbody, self->_addrlen);
315  DEBUGMSG5("%s.%d: memcmp(self, other, %d) returned %d", __FUNCTION__, __LINE__
316  , self->_addrlen, memcmprc);
317  return memcmprc == 0;
318 }
319 
320 #ifndef CHAR_BIT
321 # define CHAR_BIT 8
322 #endif
323 FSTATIC guint
327 _netaddr_hash(const NetAddr* self)
328 {
329  // For an explanation of the random hash seed see https://lwn.net/Articles/474912/
330  const guint shift = 7;
331  static guint hashseed = 0;
332  int j;
333  NetAddr* v6addr = NULL;
334  const NetAddr* addrtouse = self;
335  guint result;
336  const guchar v6loopback[16] = CONST_IPV6_LOOPBACK;
337  while (0 == hashseed) {
338  hashseed = (guint)g_random_int();
339  }
340 
341 
342  DEBUGMSG5("%s.%d: %d/%d:%d NetAddr", __FUNCTION__, __LINE__
343  , self->_addrtype, self->_addrlen, self->_addrport);
344  // Convert v4 addresses into v6 so that we match the compare operation's behavior
345  if (self->_addrtype == ADDR_FAMILY_IPV4) {
346  DEBUGMSG5("%s.%d: Hashing IPv6", __FUNCTION__, __LINE__);
347 
348  // This is kind of high overhead... Could be optimized if need be
349  if (memcmp(self->_addrbody, ipv4loop, sizeof(ipv4loop))== 0) {
350  DEBUGMSG5("%s.%d: Returning an IPv6 loopback value", __FUNCTION__, __LINE__);
351  v6addr = netaddr_ipv6_new(v6loopback, self->_addrport);
352  }else{
353  DEBUGMSG5("%s.%d: Returning an IPv6 replacement value", __FUNCTION__, __LINE__);
354  v6addr = _netaddr_toIPv6(self);
355  }
356  addrtouse = v6addr;
357  }else if (self->_addrtype == ADDR_FAMILY_IPV6) {
358  DEBUGMSG5("%s.%d: Hashing IPv6", __FUNCTION__, __LINE__);
359  if (memcmp(self->_addrbody, ipv4loopversion2, sizeof(ipv4loopversion2)) == 0) {
360  DEBUGMSG5("%s.%d: Returning an IPv6 loopback value", __FUNCTION__, __LINE__);
361  v6addr = netaddr_ipv6_new(v6loopback, self->_addrport);
362  addrtouse = v6addr;
363  }
364  }
365 
366  g_return_val_if_fail(addrtouse != NULL, 0);
367  result = (guint)(addrtouse->_addrtype) ^ hashseed;
368  if (addrtouse->_addrtype == ADDR_FAMILY_IPV6 || addrtouse->_addrtype == ADDR_FAMILY_IPV4) {
369  result ^= addrtouse->_addrport;
370  }
371  for (j=0; j < addrtouse->_addrlen; ++j) {
372  // Circular shift with addrbody xored in...
373  // Addresses are typically either 4 bytes or 16 bytes (6 and 8 bytes are also possible)
374  // So 4 bytes means the first byte gets shifted by 28 bits, and 16 means it
375  // all wraps around a lot ;-)
376  result = ((result << shift) | (result >> (sizeof(result)*CHAR_BIT - shift)))
377  ^ ((guint)((guint8*)addrtouse->_addrbody)[j]);
378  }
379  if (v6addr) {
380  UNREF(v6addr);
381  addrtouse = NULL;
382  }
383  return result;
384 }
385 
387 WINEXPORT gboolean
388 netaddr_g_hash_equal(gconstpointer lhs, gconstpointer rhs)
389 {
390  const NetAddr* a_lhs = CASTTOCONSTCLASS(NetAddr, lhs);
391  const NetAddr* a_rhs = CASTTOCONSTCLASS(NetAddr, rhs);
392  return a_lhs->equal(a_lhs, a_rhs);
393 }
394 
396 WINEXPORT guint
397 netaddr_g_hash_hash(gconstpointer addrptr)
398 {
399  const NetAddr* self = CASTTOCONSTCLASS(NetAddr, addrptr);
400  return self->hash(self);
401 }
402 
404 FSTATIC void
406 {
407  NetAddr* self = CASTTOCLASS(NetAddr, base);
408  if (self->_addrbody) {
409  FREE(self->_addrbody);
410  self->_addrbody = NULL;
411  }
412  FREECLASSOBJ(self);
413  self = NULL;
414 }
415 
416 
418 FSTATIC guint16
419 _netaddr_port(const NetAddr* self)
420 {
421  return self->_addrport;
422 }
423 
424 
426 FSTATIC void
427 _netaddr_setport(NetAddr* self, guint16 port)
428 {
429  self->_addrport = port;
430 }
431 
432 
434 FSTATIC guint16
436 {
437  return self->_addrtype;
438 }
439 
441 FSTATIC gboolean
443 {
444  if (self->_addrbody == NULL) {
445  return FALSE;
446  }
448  switch (self->_addrtype) {
449  case ADDR_FAMILY_IPV4: {
450  guint8 byte0 = ((guint8*)self->_addrbody)[0];
451  return (byte0 >= 224 && byte0 <= 239);
452  }
453  break;;
454  }
455  return FALSE;
456 }
458 FSTATIC gboolean
460 {
461  switch (self->_addrtype) {
462  case ADDR_FAMILY_IPV4: {
463  guint8 byte0 = ((guint8*)self->_addrbody)[0];
464  return byte0 == 127;;
465  }
466  case ADDR_FAMILY_IPV6: {
467  const guint8 ipv6local[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
468  const guint8 ipv4localprefix[13] = {0,0,0,0,0,0,0,0,0,0,0xff,0xff, 127};
469  if (memcmp(self->_addrbody, ipv6local, sizeof(ipv6local)) == 0) {
470  return TRUE;
471  }
472  if (memcmp(self->_addrbody, ipv4localprefix, sizeof(ipv4localprefix)) == 0) {
473  return TRUE;
474  }
475  break;
476  }
477 
478  default:
479  break;
480  }
481  return FALSE;
482 }
483 
484 FSTATIC gboolean
486 {
487  const guint8 anyaddr[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
488  const guint8 v6v4anyaddr[16] = {CONST_IPV6_IPV4SPACE, 0, 0, 0, 0};
489  if (self->_addrtype != ADDR_FAMILY_IPV4 && self->_addrtype != ADDR_FAMILY_IPV6) {
490  return FALSE;
491  }
492  if (memcmp(self->_addrbody, anyaddr, self->_addrlen) == 0) {
493  return TRUE;
494  }
495  return memcmp(self->_addrbody, v6v4anyaddr, self->_addrlen) == 0;
496 }
497 
498 
500 NetAddr*
501 netaddr_new(gsize objsize,
502  guint16 port,
503  guint16 addrtype,
504  gconstpointer addrbody,
505  guint16 addrlen)
506 {
507  AssimObj* baseobj;
508  NetAddr* self;
509 
510 
512  if (objsize < sizeof(NetAddr)) {
513  objsize = sizeof(NetAddr);
514  }
515  g_return_val_if_fail(addrbody != NULL, NULL);
516  g_return_val_if_fail(addrlen >= 4, NULL);
517 
518 
519 
520  baseobj = assimobj_new(objsize);
521  proj_class_register_subclassed(baseobj, "NetAddr");
522  self = CASTTOCLASS(NetAddr, baseobj);
523  g_return_val_if_fail(self != NULL, NULL);
524 
525  baseobj->_finalize = _netaddr_finalize;
526  baseobj->toString = _netaddr_toString;
527  self->canonStr = _netaddr_canonStr;
528  self->toIPv6 = _netaddr_toIPv6;
529  self->_addrport = port;
530  self->_addrtype = addrtype;
531  self->_addrlen = addrlen;
532  self->ipv6sockaddr = _netaddr_ipv6sockaddr;
533  self->ipv4sockaddr = _netaddr_ipv4sockaddr;
534  self->_addrbody = g_memdup(addrbody, addrlen);
535  self->port = _netaddr_port;
536  self->setport = _netaddr_setport;
537  self->addrtype = _netaddr_addrtype;
538  self->ismcast = _netaddr_ismcast;
539  self->islocal = _netaddr_islocal;
540  self->isanyaddr = _netaddr_isanyaddr;
541  self->equal = _netaddr_equal;
542  self->hash = _netaddr_hash;
543 
544  return self;
545 
546 }
547 
550 _netaddr_string_ipv4_new(const char* addrstr)
551 {
552  // Must have four numbers [0-255] in decimal - optionally followed by : port number...
553  int dotpositions[3];
554  int colonpos = -1;
555  guint8 addresses[4];
556  guint8 stack_protector_dummy[8];
557  guint whichdot = 0;
558  int byte;
559  NetAddr* ret;
560  int port = 0;
561 
562  guint j;
563  int debug = FALSE;
564  int lastpos = 0;
565 
566  (void)stack_protector_dummy;
567  //debug = g_ascii_isdigit(addrstr[0]);
568 
569  if (debug) {
570  g_debug("CHECKING [%s]", addrstr);
571  }
572 
573  // Scruffy IPv4 string format verification
574  for (j=0; addrstr[j]; ++j) {
575  if (debug) {
576  g_debug("Looking at '%c'", addrstr[j]);
577  }
578  switch(addrstr[j]) {
579  case '0': case '1': case '2': case '3': case '4':
580  case '5': case '6': case '7': case '8': case '9':
581  continue;
582 
583  case '.':
584  if (whichdot >= DIMOF(dotpositions)
585  || colonpos >= 0) {
586  return NULL;
587  }
588  dotpositions[whichdot] = j;
589  whichdot += 1;
590  continue;
591 
592  case '\0':
593  break;
594  case ':':
595  if (colonpos >= 0) {
596  return NULL;
597  }
598  colonpos = j;
599  break;
600 
601  default:
602  if (debug) {
603  g_debug("Illegal character [%c]", addrstr[j]);
604  }
605 
606  return NULL;
607  }
608  if (j > 21) {
609  return NULL;
610  }
611  }
612  lastpos = j;
613  if (debug) {
614  g_debug("whichdot = %d", whichdot);
615  }
616  if (whichdot != 3) {
617  return NULL;
618  }
619  byte = atoi(addrstr);
620  if (debug) {
621  g_debug("byte %d = %d", 0, byte);
622  }
623  if (byte < 0 || byte > 255) {
624  return NULL;
625  }
626  addresses[0] = byte;
627 
628 
629  for (j=0; j < DIMOF(dotpositions); ++j) {
630  byte = atoi(addrstr+dotpositions[j]+1);
631  if (debug) {
632  g_debug("byte %d = %d", j, byte);
633  }
634  if (byte < 0 || byte > 255) {
635  return NULL;
636  }
637  addresses[j+1] = (guint8)byte;
638  }
639  if (colonpos >= 0) {
640  if (colonpos > (lastpos - 2)) {
641  return NULL;
642  }
643  port = atoi(addrstr+colonpos+1);
644  if (port > 65535) {
645  g_debug("found bad (%s) IPV4 port", addrstr+colonpos+1);
646  return NULL;
647  }
648  if (debug) {
649  g_debug("found good IPV4 port [%d]", port);
650  }
651  }
652  if (debug) {
653  g_debug("Returning good IPV4 address!");
654  }
655  ret = netaddr_ipv4_new(addresses, port);
656  if (debug) {
657  g_debug("Returning good IPV4 address [%p]!", ret);
658  }
659  return ret;
660 }
661 
666 _netaddr_string_ipv6_new(const char* addrstr)
667 {
668 /*
669  * ipv6
670  * OR
671  * [ipv6]:decimal-port
672  *
673  * The 'IPv6' part is described by RFC 4291
674  *
675  *
676  * It consists of a sequence of 0-8 collections of 1-4 hexadecimal digits separated by
677  * colon characters.
678  * If there are fewer than 8 collections of digits, then there must be exactly one :: string
679  * in the address string. This :: tag represents a variable-length sequence of zeros in the address.
680  *
681  * There is also another variant on the format of the IPv6 portion:
682  *
683  * It can be "::ffff:" followed by an IPv4 address in typical IPv4 dotted decimal notation.
684  * @todo make _netaddr_string_ipv6_new() support the special format used for
685  * IPv6-encapsulated IPv4 addresses.
686  *
687  */
688  int len = strlen(addrstr);
689  const char * firstaddrdigit = addrstr;
690  const char * lastaddrdigit = addrstr+len-1;
691  const char * curaddrdigit;
692  unsigned j;
693  long port = 0;
694  guint16 addrchunks[8];
695  guint8 addrbytes[16];
696  guint8* addrptr;
697  guint chunkindex = 0;
698  int coloncolonindex = -1;
699  guint coloncolonlength = 0;
700  char* firstbadhexchar = NULL;
701  NetAddr* retval;
702  const char v4prefix[] = "ffff:";
703  const guint v4prefixlen = sizeof(v4prefix)-1;
704  gboolean v4encapsulated = FALSE;
705  guint conversionbase = 16;
706  char delimchar = ':';
707  guint maxchunkindex = DIMOF(addrchunks);
708  long maxchunkvalue = 65535;
709 
710  DEBUGMSG5("%s.%d(\"%s\")", __FUNCTION__, __LINE__, addrstr);
711  memset(addrchunks, 0, sizeof(addrchunks));
712 
713  if (*addrstr == '[') {
714  // Then we have a port number - look for ']' and ':'
715  char * rbracketpos = strchr(addrstr+1, ']');
716  char * firstbadchar = rbracketpos;
717 
718  if (rbracketpos == NULL || rbracketpos[1] != ':') {
719  return NULL;
720  }
721  firstaddrdigit += 1;
722  lastaddrdigit = rbracketpos - 1;
723  port = strtol(rbracketpos+2, &firstbadchar, 10);
724  if (*firstbadchar != '\0' || port <= 0 || port >= 65536) {
725  DEBUGMSG5("%s.%d: Not IPv6 format due to bad port number syntax"
726  , __FUNCTION__, __LINE__);
727  return NULL;
728  }
729  }
730  // Now, we know where the collection of address characters starts and ends
731  if (firstaddrdigit[0] == ':' && firstaddrdigit[1] == ':') {
732  coloncolonindex = 0;
733  firstaddrdigit += 2;
734  // Let's see if it might be an ipv4 address encapsulated as ipv6...
735  DEBUGMSG5("%s.%d: LOOKING to see if we have an encapsulated IPv4 address. [%s] [%s]"
736  , __FUNCTION__, __LINE__, firstaddrdigit, v4prefix);
737  if (strncmp(firstaddrdigit, v4prefix, v4prefixlen) == 0) {
738  DEBUGMSG5("%s.%d: May have an encapsulated IPv4 address. [%s]"
739  , __FUNCTION__, __LINE__, firstaddrdigit);
740  if (strchr(firstaddrdigit + v4prefixlen, '.') != NULL) {
741  // We have '.'s but no more ':'s...
742  DEBUGMSG5("%s.%d: Appear to have an encapsulated IPv4 address."
743  , __FUNCTION__, __LINE__);
744  v4encapsulated = TRUE;
745  conversionbase = 10; // IPv4 addresses are decimal
746  delimchar = '.'; // IPv4 addresses use . delimiters
747  maxchunkindex = 4; // IPv4 addresses have exactly 4 parts
748  maxchunkvalue = 255; // IPv4 address elements are single bytes
749  firstaddrdigit += v4prefixlen;
750  }
751  }
752  }
753  curaddrdigit = firstaddrdigit;
754  // Loop over the characters, breaking them into a series of hexadecimal (or decimal) chunks
755  for (chunkindex=0; chunkindex < maxchunkindex && curaddrdigit <= lastaddrdigit; ++chunkindex) {
756  long chunk = strtol(curaddrdigit, &firstbadhexchar, conversionbase);
757  DEBUGMSG5("%s.%d: chunk %d begins [%s] converts to 0x%lx", __FUNCTION__, __LINE__
758  , chunkindex, curaddrdigit, (unsigned long)chunk);
759  if (chunk < 0 || chunk > maxchunkvalue) {
760  DEBUGMSG5("%s.%d: Not IPv6 format due to invalid chunk value [%ld]"
761  , __FUNCTION__, __LINE__, chunk);
762  return NULL;
763  }
764  // Remember the value of this chunk...
765  addrchunks[chunkindex] = (guint16)chunk;
766 
767  // Was the ending delimiter what we expected?
768  if (firstbadhexchar <= lastaddrdigit && *firstbadhexchar != delimchar) {
769  DEBUGMSG5("%s.%d: Not IPv6 format due to invalid character [%c]"
770  , __FUNCTION__, __LINE__, *firstbadhexchar);
771  return NULL;
772  }
773  curaddrdigit = firstbadhexchar;
774  if (v4encapsulated && *firstbadhexchar == delimchar) {
775  curaddrdigit += 1;
776  // Is there a :: in this position in the address?
777  }else if (!v4encapsulated && firstbadhexchar[0] == ':') {
778  if (firstbadhexchar[1] == ':') {
779  if (coloncolonindex >= 0) {
780  // :: can only appear once in the address
781  DEBUGMSG5("%s.%d: Not IPv6 format due to multiple ::'s"
782  , __FUNCTION__, __LINE__);
783  return NULL;
784  }
785  coloncolonindex = chunkindex + 1;
786  curaddrdigit += 2;
787  }else{
788  curaddrdigit += 1;
789  }
790  }else if (*firstbadhexchar != ']' && *firstbadhexchar != '\0') {
791  DEBUGMSG5("%s.%d: Not IPv6 format due to illegal char [%c]"
792  , __FUNCTION__, __LINE__, *firstbadhexchar);
793  return NULL;
794  }
795 
796  if (firstbadhexchar >= lastaddrdigit + 1) {
797  break;
798  }
799  }
800  if (firstbadhexchar != NULL && firstbadhexchar != lastaddrdigit + 1) {
801  DEBUGMSG5("%s.%d: Not IPv6 format due to excess length.", __FUNCTION__, __LINE__);
802  DEBUGMSG5("%s.%d: firstbadhexchar = %p, lastaddrdigit = %p, diff=%ld"
803  , __FUNCTION__, __LINE__, firstbadhexchar, lastaddrdigit
804  , (long)(lastaddrdigit-firstbadhexchar));
805  return NULL;
806  }
807  if (coloncolonindex >= 0 && chunkindex == DIMOF(addrchunks)-1) {
808  DEBUGMSG5("%s.%d: Not IPv6 format due to full length with :: present"
809  , __FUNCTION__, __LINE__);
810  return NULL;
811  }
812  if (coloncolonindex < 0 && chunkindex != DIMOF(addrchunks)-1) {
813  DEBUGMSG5("%s.%d: Not IPv6 format due to too few digits."
814  , __FUNCTION__, __LINE__);
815  return NULL;
816  }
817  // OK --- now we have something that looks a lot like a legit IPv6 address.
818  // let's see if we can make a NetAddr out of it...
819  if (coloncolonindex >= 0) {
820  coloncolonlength = (DIMOF(addrchunks)-1) - chunkindex;
821  DEBUGMSG5("%s.%d: coloncolonlength is %d, index is %d", __FUNCTION__, __LINE__
822  , coloncolonlength, coloncolonindex);
823  }
824  DEBUGMSG5("%s.%d: chunkindex is %d", __FUNCTION__, __LINE__, chunkindex);
825 
826  addrptr = addrbytes;
827 
828 
829  if (v4encapsulated) {
830  // Take care of the encapsulated IPv4 special case...
831  const guint8 v4prefix[] = {CONST_IPV6_IPV4SPACE};
832  const guint offset = sizeof(v4prefix);
833  if (chunkindex != 3) {
834  DEBUGMSG5("%s.%d: Not IPv4 encapsulated as IPv6 format due to too few digits."
835  , __FUNCTION__, __LINE__);
836  return NULL;
837  }
838  memcpy(addrbytes, v4prefix, sizeof(v4prefix));
839  addrbytes[offset+0] = (guint8)addrchunks[0];
840  addrbytes[offset+1] = (guint8)addrchunks[1];
841  addrbytes[offset+2] = (guint8)addrchunks[2];
842  addrbytes[offset+3] = (guint8)addrchunks[3];
843  }else{
844  // Otherwise we have a more normal IPv6 address
845  memset(addrbytes, 0, DIMOF(addrbytes));
846  // Make our set of chunks into an IPv6 address in binary
847  for (j=0; j <= chunkindex; ++j) {
848  // Is this where the :: goes?
849  if (((gint)j) == coloncolonindex) {
850  // Insert the right number of zeros
851  memset(addrptr, 0, coloncolonlength*2);
852  addrptr += 2*coloncolonlength;
853  }
854  // Copy the next bit of data
855  addrptr[0] = (((addrchunks[j]) >> 8) & 0xff);
856  addrptr[1] = addrchunks[j] & 0xff;
857  addrptr += 2;
858  }
859  // Did the :: appear at the end of the address - weird but legal...
860  if (coloncolonindex == (gint)chunkindex + 1) {
861  DEBUGMSG5("%s.%d: Appending %d zeros to the end of the address"
862  , __FUNCTION__, __LINE__, coloncolonlength*2);
863  memset(addrptr, 0, coloncolonlength*2);
864  addrptr += 2*coloncolonlength;
865  }
866  DEBUGMSG5("%s.%d: addrptr == addrbytes+%ld", __FUNCTION__, __LINE__
867  , (long)(addrptr-addrbytes));
868  g_return_val_if_fail(addrptr == addrbytes+DIMOF(addrbytes), NULL);
869  }
870  retval = netaddr_ipv6_new(addrbytes, port);
871  DUMP5(addrstr, &retval->baseclass, " Converted the former into the latter...(ignore the extra ':')");
872  return retval;
873 }
874 
877 NetAddr*
878 _netaddr_string_macaddr_new(const char *addrstr)
879 {
880  guint8 hexvals[8];
881  unsigned hexindex = 0;
882 
883  const char * cp;
884  char * nextcp;
885 
886  for (cp = addrstr; *cp; hexindex++, cp=nextcp) {
887  long hexvalue;
888  if (hexindex >= DIMOF(hexvals)) {
889  return NULL;
890  }
891  hexvalue = strtol(cp, &nextcp, 16);
892  if (hexvalue < 0 || hexvalue > 255 || nextcp == cp) {
893  return NULL;
894  }
895  hexvals[hexindex] = hexvalue;
896  if (*nextcp == '-' || *nextcp == ':') {
897  nextcp++;
898  // Disallow a final : or -
899  if (*nextcp == '\0') {
900  return NULL;
901  }
902  }
903  }
904  if (hexindex == 6) {
905  return netaddr_mac48_new(hexvals);
906  }
907  if (hexindex == 8) {
908  return netaddr_mac64_new(hexvals);
909  }
910  return NULL;
911 }
912 
914 NetAddr*
915 netaddr_string_new(const char* addrstr)
916 {
917  NetAddr* retval = NULL;
918  char addr0 = addrstr[0];
919 
920  if (addr0 == '[' || addr0 == ':') {
921  return _netaddr_string_ipv6_new(addrstr);
922  }
923 
924  if (isdigit(addr0)) {
925  retval = _netaddr_string_ipv4_new(addrstr);
926  if (!retval) {
927  retval = _netaddr_string_ipv6_new(addrstr);
928  if (!retval) {
929  retval = _netaddr_string_macaddr_new(addrstr);
930  }
931  }
932  }else if (isxdigit(addr0)) {
933  retval = _netaddr_string_ipv6_new(addrstr);
934  if (!retval) {
935  retval = _netaddr_string_macaddr_new(addrstr);
936  }
937  }
938  return retval;
939 }
940 
942 NetAddr*
943 netaddr_dns_new(const char * sysname_or_addr) //< System name/address
944 {
945 #ifdef HAVE_GETADDRINFO
946  NetAddr* ret = NULL;
947  const char* digits = ":[0123456789ABCDEFabcdef";
948  const char * colonpos;
949  char* sysname;
950  int rc;
951  const char* service = NULL;
952  struct addrinfo hints;
953  struct addrinfo*sysinfo;
954 
955  // See if it _could_ be a numeric address...
956  if (strchr(digits, sysname_or_addr[0]) != NULL) {
957  ret = netaddr_string_new(sysname_or_addr);
958  if (NULL != ret) {
959  return ret;
960  }
961  // Who knows, maybe they gave a symbolic port and a constant IP address...
962  // In any case, give it another shot...
963  }
964 
965  // See if they specified a port...
966  colonpos = strchr(sysname_or_addr, ':');
967 
968  if (NULL == colonpos) {
969  service = "0";
970  sysname = g_strdup(sysname_or_addr);
971  }else{
972  service = colonpos + 1;
973  if (strlen(service) < 1 || atol(service) < 0 || atol(service) > 65535) {
974  return NULL;
975  }
976  sysname = g_strndup(sysname_or_addr, colonpos-sysname_or_addr);
977  }
978  memset(&hints, 0, sizeof(hints));
979  hints.ai_family = AF_UNSPEC;
980  hints.ai_socktype = SOCK_DGRAM;
981  rc = getaddrinfo(sysname, service, &hints, &sysinfo);
982  if (0 != rc) {
983  DEBUGMSG("%s.%d: Could not resolve %s - reason: %s"
984  , __FUNCTION__, __LINE__, sysname, gai_strerror(rc));
985  }else{
986  ret = netaddr_sockaddr_new((struct sockaddr_in6*)sysinfo[0].ai_addr
987  , sysinfo[0].ai_addrlen);
988  freeaddrinfo(sysinfo);
989  }
990  g_free(sysname); sysname = NULL;
991 #else
992 # error "Must have a replacement for getaddrinfo(3)"
993 #endif
994  return ret;
995 }
996 
997 
999 NetAddr*
1000 netaddr_macaddr_new(gconstpointer macbuf,
1001  guint16 maclen)
1002 {
1003 
1004  g_return_val_if_fail(maclen == 6 || maclen == 8, NULL);
1005  return netaddr_new(0, 0, ADDR_FAMILY_802, macbuf, maclen);
1006 }
1007 
1009 NetAddr*
1010 netaddr_mac48_new(gconstpointer macbuf)
1011 {
1012  return netaddr_macaddr_new(macbuf, 6);
1013 }
1014 
1016 NetAddr*
1017 netaddr_mac64_new(gconstpointer macbuf)
1018 {
1019  return netaddr_macaddr_new(macbuf, 8);
1020 }
1021 
1023 NetAddr*
1024 netaddr_ipv4_new(gconstpointer ipbuf,
1025  guint16 port)
1026 {
1027  return netaddr_new(0, port, ADDR_FAMILY_IPV4, ipbuf, 4);
1028 }
1029 
1031 NetAddr*
1032 netaddr_ipv6_new(gconstpointer ipbuf,
1033  guint16 port)
1034 {
1035  return netaddr_new(0, port, ADDR_FAMILY_IPV6, ipbuf, 16);
1036 }
1037 
1038 
1039 
1040 
1042 NetAddr*
1043 netaddr_sockaddr_new(const struct sockaddr_in6 *sa_in6,
1044  socklen_t length)
1045 {
1046  const struct sockaddr_in* sa_in = (const struct sockaddr_in*)sa_in6;
1047 
1048  (void)length;
1049  switch(sa_in->sin_family) {
1050  case AF_INET:
1051  return netaddr_new(0, ntohs(sa_in->sin_port),
1052  ADDR_FAMILY_IPV4, &sa_in->sin_addr, 4);
1053  break;
1054 
1055  case AF_INET6:
1057  return netaddr_new(0, ntohs(sa_in6->sin6_port),
1058  ADDR_FAMILY_IPV6, &sa_in6->sin6_addr, 16);
1059  break;
1060  }
1061  g_return_val_if_reached(NULL);
1062 }
1063 
1064 FSTATIC struct sockaddr_in6
1065 _netaddr_ipv6sockaddr(const NetAddr* self) //<[in] NetAddr object to convert to IPv6 sockaddr
1066 {
1067  struct sockaddr_in6 saddr;
1068 
1069  memset(&saddr, 0x00, sizeof(saddr));
1070 
1071  switch (self->_addrtype) {
1072  case ADDR_FAMILY_IPV4:
1073  g_return_val_if_fail(4 == self->_addrlen, saddr);
1074  saddr.sin6_family = AF_INET6;
1075  saddr.sin6_port = htons(self->_addrport);
1078  // (this works because saddr is initialized to zero)
1079  saddr.sin6_addr.s6_addr[10] = 0xff;
1080  saddr.sin6_addr.s6_addr[11] = 0xff;
1081  memcpy(saddr.sin6_addr.s6_addr+12, self->_addrbody, self->_addrlen);
1082  DEBUGMSG3("%s:%s: sin6_family 0x%x, sin6_port %d"
1083  , __FILE__, __FUNCTION__
1084  , saddr.sin6_family, ntohs(saddr.sin6_port));
1085  DEBUGMSG3("%s:%s:s6_addr(v4): %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
1086  , __FILE__, __FUNCTION__
1087  , saddr.sin6_addr.s6_addr[0],saddr.sin6_addr.s6_addr[1]
1088  , saddr.sin6_addr.s6_addr[2],saddr.sin6_addr.s6_addr[3]
1089  , saddr.sin6_addr.s6_addr[4],saddr.sin6_addr.s6_addr[5]
1090  , saddr.sin6_addr.s6_addr[6],saddr.sin6_addr.s6_addr[7]
1091  , saddr.sin6_addr.s6_addr[8],saddr.sin6_addr.s6_addr[8]
1092  , saddr.sin6_addr.s6_addr[10],saddr.sin6_addr.s6_addr[11]
1093  , saddr.sin6_addr.s6_addr[12],saddr.sin6_addr.s6_addr[13]
1094  , saddr.sin6_addr.s6_addr[14],saddr.sin6_addr.s6_addr[15]);
1095 
1096  break;
1097 
1098  case ADDR_FAMILY_IPV6:
1099  g_return_val_if_fail(16 == self->_addrlen, saddr);
1100  saddr.sin6_family = AF_INET6;
1101  saddr.sin6_port = htons(self->_addrport);
1102  memcpy(&saddr.sin6_addr, self->_addrbody, self->_addrlen);
1103  break;
1104 
1105  default:
1106  g_return_val_if_reached(saddr);
1107  }
1108  return saddr;
1109 }
1110 
1111 FSTATIC struct sockaddr_in
1112 _netaddr_ipv4sockaddr(const NetAddr* self) //<[in] NetAddr object to convert to IPv4 sockaddr
1113 {
1114  struct sockaddr_in saddr;
1115 
1116  memset(&saddr, 0x00, sizeof(saddr));
1117 
1118  switch (self->_addrtype) {
1119  case ADDR_FAMILY_IPV4:
1120  g_return_val_if_fail(4 == self->_addrlen, saddr);
1121  saddr.sin_family = AF_INET;
1122  saddr.sin_port = htons(self->_addrport);
1123  memcpy(&saddr.sin_addr, self->_addrbody, 4);
1124  break;
1125 
1126  default:
1127  g_return_val_if_reached(saddr);
1128  }
1129  return saddr;
1130 }
IETF/IANA Address family assignments.
FSTATIC gboolean _netaddr_equal(const NetAddr *, const NetAddr *)
Return TRUE if these two addresses are "equal" (equivalent)
Definition: netaddr.c:240
#define CHAR_BIT
Definition: netaddr.c:321
FSTATIC struct sockaddr_in6 _netaddr_ipv6sockaddr(const NetAddr *self)
Definition: netaddr.c:1065
FSTATIC gchar * _netaddr_toString_ipv6_ipv4(const NetAddr *self, gboolean ipv4format)
Convert this IPv6-encapsulated IPv4 NetAddr to a string.
Definition: netaddr.c:83
FSTATIC guint16 _netaddr_addrtype(const NetAddr *self)
Return the address type of this NetAddr.
Definition: netaddr.c:435
FSTATIC void _netaddr_setport(NetAddr *self, guint16)
Set the port of this NetAddr.
Definition: netaddr.c:427
FSTATIC gboolean _netaddr_islocal(const NetAddr *self)
Return TRUE if this is a multicast address.
Definition: netaddr.c:459
FSTATIC gchar * _netaddr_toString(gconstpointer)
Convert this IPv6-encapsulated IPv4 NetAddr to an IPv4 representation Convert this NetAddr to a strin...
Definition: netaddr.c:115
FSTATIC gchar * _netaddr_canonStr(const NetAddr *)
Definition: netaddr.c:122
NetAddr * netaddr_macaddr_new(gconstpointer macbuf, guint16 maclen)
Create new NetAddr from a MAC address.
Definition: netaddr.c:1000
#define DEBUGMSG(...)
Definition: proj_classes.h:87
NetAddr * netaddr_dns_new(const char *sysname_or_addr)
Create a NetAddr from a DNS name or an ipv4 or ipv6 constant string.
Definition: netaddr.c:943
NetAddr * netaddr_mac64_new(gconstpointer macbuf)
Create new NetAddr from a MAC64 address.
Definition: netaddr.c:1017
#define DEBUGMSG5(...)
Definition: proj_classes.h:93
FSTATIC void _netaddr_finalize(AssimObj *self)
Finalize (free) this object.
Definition: netaddr.c:405
AssimObj baseclass
Definition: netaddr.h:44
guint16 _addrport
private: Address port (if applicable)
Definition: netaddr.h:61
FSTATIC gboolean _netaddr_isanyaddr(const NetAddr *self)
Definition: netaddr.c:485
FSTATIC NetAddr * _netaddr_string_macaddr_new(const char *addrstr)
Create a NetAddr from a 48-bit or 64-bit-format MAC address string.
Definition: netaddr.c:878
NetAddr * netaddr_ipv4_new(gconstpointer ipbuf, guint16 port)
Create new NetAddr from a IPv4 address.
Definition: netaddr.c:1024
#define WINEXPORT
Definition: projectcommon.h:45
#define FSTATIC
Definition: projectcommon.h:31
#define DEBUGMSG3(...)
Definition: proj_classes.h:91
NetAddr * netaddr_sockaddr_new(const struct sockaddr_in6 *sa_in6, socklen_t length)
Create new NetAddr from a struct sockaddr
Definition: netaddr.c:1043
FSTATIC gchar * _netaddr_toStringflex(const NetAddr *, gboolean canonformat)
Convert this NetAddr to a string.
Definition: netaddr.c:160
#define FREECLASSOBJ(obj)
Free a C-class object.
Definition: proj_classes.h:76
#define BINDDEBUG(Cclass)
BINDDEBUG is for telling the class system where the debug variable for this class is - put it in the ...
Definition: proj_classes.h:82
NetAddr * netaddr_mac48_new(gconstpointer macbuf)
Create new NetAddr from a MAC48 address.
Definition: netaddr.c:1010
FSTATIC gboolean _netaddr_ismcast(const NetAddr *self)
Return TRUE if this is a multicast address.
Definition: netaddr.c:442
#define __FUNCTION__
FSTATIC gconstpointer _netaddr_addrinnetorder(gsize *addrlen)
gpointer proj_class_register_subclassed(gpointer object, const char *static_subclassname)
Log the creation of a subclassed object from a superclassed object.
Definition: proj_classes.c:192
#define CONST_IPV6_LOOPBACK
Definition: netaddr.h:76
NetAddr * netaddr_ipv6_new(gconstpointer ipbuf, guint16 port)
Create new NetAddr from a IPv6 address.
Definition: netaddr.c:1032
#define FREE(m)
Our interface to free.
Definition: projectcommon.h:29
WINEXPORT gboolean netaddr_g_hash_equal(gconstpointer lhs, gconstpointer rhs)
g_hash_table equal comparator for a NetAddr
Definition: netaddr.c:388
#define ADDR_FAMILY_IPV6
IPv6.
#define CASTTOCONSTCLASS(Cclass, obj)
Safely cast 'obj' to const C-class 'class' - verifying that it was registered as being of type class ...
Definition: proj_classes.h:71
Project common header file.
#define DIMOF(a)
Definition: lldp_min.c:30
NetAddr * anyaddr
Definition: pcap+mainloop.c:84
#define CONST_IPV6_IPV4SPACE
Definition: netaddr.h:78
struct _NetAddr NetAddr
Definition: netaddr.h:36
AssimObj * assimobj_new(guint objsize)
Definition: assimobj.c:74
#define DUMP5(prefix, obj, suffix)
Definition: proj_classes.h:99
FSTATIC NetAddr * _netaddr_toIPv6(const NetAddr *)
Convert this IPv6-encapsulated IPv4 NetAddr to an IPv4 representation.
Definition: netaddr.c:129
void(* _finalize)(AssimObj *)
Free object (private)
Definition: assimobj.h:55
gboolean(* equal)(const NetAddr *, const NetAddr *)
Compare NetAddrs.
Definition: netaddr.h:53
The NetAddr class class represents a general network address - whether IP, MAC, or any other type of ...
Definition: netaddr.h:43
FSTATIC guint _netaddr_hash(const NetAddr *)
NetAddr hash function which worries about denial of service via hash collisions.
Definition: netaddr.c:327
Defines interfaces for the NetAddr (network address) object.
FSTATIC NetAddr * _netaddr_string_ipv6_new(const char *addrstr)
Convert a string into an IPv6 address - possibly including a port as per RFC 4291.
Definition: netaddr.c:666
NetAddr * netaddr_new(gsize objsize, guint16 port, guint16 addrtype, gconstpointer addrbody, guint16 addrlen)
Generic NetAddr constructor.
Definition: netaddr.c:501
guint16 _addrlen
private: Length of _addrbody
Definition: netaddr.h:60
FSTATIC guint16 _netaddr_port(const NetAddr *self)
Return the port of this NetAddr.
Definition: netaddr.c:419
gchar *(* toString)(gconstpointer)
Produce malloc-ed string representation.
Definition: assimobj.h:58
WINEXPORT guint netaddr_g_hash_hash(gconstpointer addrptr)
g_hash_table hash function for a NetAddr
Definition: netaddr.c:397
#define DEBUGDECLARATIONS
Definition: proj_classes.h:79
#define ADDR_FAMILY_802
Level 2 physical (MAC) addresses.
guint16 _addrtype
private: Address type
Definition: netaddr.h:59
FSTATIC NetAddr * _netaddr_string_ipv4_new(const char *addrstr)
Convert a string to an IPv4 NetAddr.
Definition: netaddr.c:550
NetAddr * netaddr_string_new(const char *addrstr)
Create a NetAddr from an ipv4, ipv6 or MAC address string.
Definition: netaddr.c:915
#define ADDR_FAMILY_IPV4
IPv4.
#define CASTTOCLASS(Cclass, obj)
Safely cast 'obj' to C-class 'class' - verifying that it was registerd as being of type class ...
Definition: proj_classes.h:66
#define UNREF(obj)
Definition: assimobj.h:35
FSTATIC struct sockaddr_in _netaddr_ipv4sockaddr(const NetAddr *self)
Definition: netaddr.c:1112
#define CONST_IPV4_LOOPBACK
Definition: netaddr.h:77
gpointer _addrbody
private: Address body
Definition: netaddr.h:58