The Assimilation Monitoring 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 <projectcommon.h>
30 #include <netaddr.h>
31 #include <address_family_numbers.h>
32 #ifdef _MSC_VER
33 # include <ws2tcpip.h>
34 #endif
35 
36 FSTATIC struct sockaddr_in6 _netaddr_ipv6sockaddr(const NetAddr* self);
37 FSTATIC struct sockaddr_in _netaddr_ipv4sockaddr(const NetAddr* self);
39 FSTATIC guint16 _netaddr_port(const NetAddr* self);
40 FSTATIC void _netaddr_setport(NetAddr* self, guint16);
41 FSTATIC guint16 _netaddr_addrtype(const NetAddr* self);
42 FSTATIC gboolean _netaddr_ismcast(const NetAddr* self);
43 FSTATIC gboolean _netaddr_islocal(const NetAddr* self);
44 FSTATIC gconstpointer _netaddr_addrinnetorder(gsize *addrlen);
45 FSTATIC gboolean _netaddr_equal(const NetAddr*, const NetAddr*);
46 FSTATIC guint _netaddr_hash(const NetAddr*);
47 FSTATIC gchar * _netaddr_toStringflex(const NetAddr*, gboolean canonformat);
48 FSTATIC gchar * _netaddr_toString(gconstpointer);
49 FSTATIC gchar * _netaddr_canonStr(const NetAddr*);
51 FSTATIC gchar * _netaddr_toString_ipv6_ipv4(const NetAddr* self, gboolean ipv4format);
52 FSTATIC NetAddr* _netaddr_string_ipv4_new(const char* addrstr);
53 FSTATIC NetAddr* _netaddr_string_ipv6_new(const char* addrstr);
54 
56 
64 
65 static const guchar ipv6loop [16] = CONST_IPV6_LOOPBACK;
66 static const guchar ipv4loopversion2 [16] = {CONST_IPV6_IPV4SPACE, 127, 0, 0, 1};
67 static const guchar ipv4loop [4] = CONST_IPV4_LOOPBACK;
68 
70 FSTATIC gchar *
71 _netaddr_toString_ipv6_ipv4(const NetAddr* self, gboolean ipv4format)
72 {
73  const char * prefix;
74  const char * suffix;
75  if (self->_addrport) {
76  prefix = (ipv4format ? "" : "[::ffff:");
77  suffix = (ipv4format ? ":" : "]:" );
78  }else{
79  prefix = (ipv4format ? "" : "::ffff:");
80  suffix = ""; // Not used
81  }
82 
83  if (self->_addrport) {
84  return g_strdup_printf("%s%d.%d.%d.%d%s%d",
85  prefix,
86  ((const guchar*)self->_addrbody)[12],
87  ((const guchar*)self->_addrbody)[13],
88  ((const guchar*)self->_addrbody)[14],
89  ((const guchar*)self->_addrbody)[15],
90  suffix,
91  self->_addrport);
92  }
93  return g_strdup_printf("%s%d.%d.%d.%d",
94  prefix,
95  ((const guchar*)self->_addrbody)[12],
96  ((const guchar*)self->_addrbody)[13],
97  ((const guchar*)self->_addrbody)[14],
98  ((const guchar*)self->_addrbody)[15]);
99 }
102 FSTATIC gchar *
103 _netaddr_toString(gconstpointer baseobj)
104 {
105  const NetAddr* self = CASTTOCONSTCLASS(NetAddr, baseobj);
106  return _netaddr_toStringflex(self, FALSE);
107 }
108 
109 FSTATIC gchar *
111 {
112  return _netaddr_toStringflex(self, TRUE);
113 }
114 
116 NetAddr*
118 {
119 
120  switch (self->_addrtype) {
121  case ADDR_FAMILY_IPV6:
122  // Return a copy of this IPv6 address
123  return netaddr_ipv6_new(self->_addrbody, self->_addrport);
124 
125  case ADDR_FAMILY_IPV4: {
126  const int ipv4prefixlen = 12;
127  guchar ipv6addr[16] = {CONST_IPV6_IPV4SPACE, 0, 0, 0, 0};
128  // We have an IPv4 address we want to convert to an IPv6 address
129  if (memcmp(self->_addrbody, ipv4loop, sizeof(ipv4loop)) == 0) {
130  // Convert loopback addresses from v4 to v6
131  memcpy(ipv6addr, ipv6loop, sizeof(ipv6loop));
132  }else{
133  memcpy(ipv6addr+ipv4prefixlen, self->_addrbody, 4);
134  }
135  return netaddr_ipv6_new(ipv6addr, self->_addrport);
136  }
137 
138  default: // OOPS!
139  break;
140  }
142  g_return_val_if_reached(NULL);
143 }
144 
145 
147 FSTATIC gchar *
148 _netaddr_toStringflex(const NetAddr* self, gboolean canon_format)
149 {
150  gchar * ret = NULL;
151  GString* gsret = NULL;
152  int nbyte;
153  if (self->_addrtype == ADDR_FAMILY_IPV4) {
154  if (self->_addrport) {
155  return g_strdup_printf("%d.%d.%d.%d:%d",
156  ((const guchar*)self->_addrbody)[0],
157  ((const guchar*)self->_addrbody)[1],
158  ((const guchar*)self->_addrbody)[2],
159  ((const guchar*)self->_addrbody)[3],
160  self->_addrport);
161  }
162  return g_strdup_printf("%d.%d.%d.%d",
163  ((const guchar*)self->_addrbody)[0],
164  ((const guchar*)self->_addrbody)[1],
165  ((const guchar*)self->_addrbody)[2],
166  ((const guchar*)self->_addrbody)[3]);
167  }
168  gsret = g_string_new("");
169  if (self->_addrtype == ADDR_FAMILY_IPV6) {
170  gboolean doublecolonyet = FALSE;
171  gboolean justhaddoublecolon = FALSE;
172  int zerocount = 0;
173  guchar ipv4prefix[] = {0,0,0,0,0,0,0,0,0,0,0xff,0xff};
174  if (self->_addrlen != 16) {
175  g_string_free(gsret, TRUE); gsret = NULL;
176  return g_strdup("{invalid ipv6}");
177  }
178  if (self->_addrport) {
179  g_string_append(gsret, "[");
180  }
181  if (memcmp(self->_addrbody, ipv4prefix, sizeof(ipv4prefix)) == 0) {
182  g_string_free(gsret, TRUE); gsret = NULL;
183  return _netaddr_toString_ipv6_ipv4(self, canon_format);
184  }
185  for (nbyte = 0; nbyte < self->_addrlen; nbyte += 2) {
186  guint16 byte0 = ((const guchar*)self->_addrbody)[nbyte];
187  guint16 byte1 = ((const guchar*)self->_addrbody)[nbyte+1];
188  guint16 word = (byte0 << 8 | byte1);
189  if (!doublecolonyet && word == 0x00) {
190  ++zerocount;
191  continue;
192  }
193  if (zerocount == 1) {
194  g_string_append_printf(gsret, (nbyte == 2 ? "0" : ":0"));
195  zerocount=0;
196  }else if (zerocount > 1) {
197  g_string_append_printf(gsret, "::");
198  zerocount=0;
199  doublecolonyet = TRUE;
200  justhaddoublecolon = TRUE;
201  }
202  g_string_append_printf(gsret
203  , ((nbyte == 0 || justhaddoublecolon) ? "%x" : ":%x"), word);
204  justhaddoublecolon = FALSE;
205  }
206  if (zerocount == 1) {
207  g_string_append_printf(gsret, ":00");
208  }else if (zerocount > 1) {
209  g_string_append_printf(gsret, "::");
210  }
211  if (self->_addrport) {
212  g_string_append_printf(gsret, "]:%d", self->_addrport);
213  }
214 
215  }else{
216  for (nbyte = 0; nbyte < self->_addrlen; ++nbyte) {
217  g_string_append_printf(gsret, (nbyte == 0 ? "%02x" : ":%02x"),
218  ((const guchar*)self->_addrbody)[nbyte]);
219  }
220  }
221  ret = gsret->str;
222  g_string_free(gsret, FALSE);
223  return ret;
224 }
225 
227 FSTATIC gboolean
228 _netaddr_equal(const NetAddr*self, const NetAddr*other)
229 {
231  const guchar ipv6v4 [12] = {CONST_IPV6_IPV4SPACE};// Where IPv4 addrs are found inside IPv6 space
232  gint memcmprc;
233 
234 
235  DEBUGMSG5("%s.%d: Comparing (type %d, length %d) vs (type %d, length %d)"
236  , __FUNCTION__, __LINE__, self->_addrtype, self->_addrlen, other->_addrtype, other->_addrlen)
237  DEBUGMSG5("%s.%d: checking ports for equality (if v4/v6 addresses)", __FUNCTION__, __LINE__)
238  if ((self->_addrtype == ADDR_FAMILY_IPV6 || self->_addrtype == ADDR_FAMILY_IPV4)
239  && (other->_addrtype == ADDR_FAMILY_IPV6 || other->_addrtype == ADDR_FAMILY_IPV4)
240  && self->_addrport != other->_addrport) {
241  DEBUGMSG5("%s.%d: selfport:%d, otherport:%d", __FUNCTION__, __LINE__, self->_addrport, other->_addrport);
242  return FALSE;
243  }
244 
245  if (self->_addrtype == ADDR_FAMILY_IPV6) {
246  DEBUGMSG5("%s.%d: self is IPv6", __FUNCTION__, __LINE__)
247  if (other->_addrtype == ADDR_FAMILY_IPV4) {
248  const guchar *selfabody = self->_addrbody;
249  // Check for equivalent IPv4 and IPv6 addresses
250  DEBUGMSG5("%s.%d: checking equivalent v6/v4 addresses", __FUNCTION__, __LINE__)
251  if (memcmp(selfabody, ipv6v4, sizeof(ipv6v4)) == 0
252  && memcmp(selfabody+12, other->_addrbody, 4) == 0) {
253  DEBUGMSG5("%s.%d: v6/v4 addresses are equivalent", __FUNCTION__, __LINE__)
254  return TRUE;
255  }
256  DEBUGMSG5("%s.%d: checking v6/v4 loopbacks", __FUNCTION__, __LINE__)
257  // Check for the equivalent loopback addresses between IPv4 and IPv6
259  if (memcmp(self->_addrbody, ipv6loop, sizeof(ipv6loop)) == 0
260  && memcmp(other->_addrbody, ipv4loop, sizeof(ipv4loop)) == 0) {
261  DEBUGMSG5("%s.%d: v6/v4 addresses are both loopbacks", __FUNCTION__, __LINE__)
262  return TRUE;
263  }
264  DEBUGMSG5("%s.%d: v6/v4 addresses are not equivalent", __FUNCTION__, __LINE__)
265  return FALSE;
266  }else if (other->_addrtype == ADDR_FAMILY_IPV6) {
267  // Well... Are we cross comparing the two types of ipv6 loopback addresses?
268  // These are: ::1 and ::ff:127.0.0.1 Kinda weird - but seems valid...
269  DEBUGMSG5("%s.%d: other is IPv6 too", __FUNCTION__, __LINE__)
270  if (memcmp(self->_addrbody, ipv6loop, sizeof(ipv6loop)) == 0) {
271  DEBUGMSG5("%s.%d: comparing loopbacks", __FUNCTION__, __LINE__);
272  if (memcmp(other->_addrbody, ipv4loopversion2, sizeof(ipv4loopversion2)) == 0) {
273  return TRUE;
274  }
275  }else if (memcmp(self->_addrbody, ipv4loopversion2, sizeof(ipv4loopversion2)) == 0) {
276  DEBUGMSG5("%s.%d: comparing loopbacks the other way", __FUNCTION__, __LINE__);
277  if (memcmp(other->_addrbody, ipv6loop, sizeof(ipv6loop)) == 0) {
278  return TRUE;
279  }
280  }
281  }
282  }
283 
284  DEBUGMSG5("%s.%d: checking to see if we need to reverse operands...", __FUNCTION__, __LINE__)
285 
286  if (self->_addrtype == ADDR_FAMILY_IPV4 && other->_addrtype == ADDR_FAMILY_IPV6) {
287  gboolean retval;
288  // Switch the operands and try again...
289  DEBUGMSG5("%s.%d: switching operands", __FUNCTION__, __LINE__)
290  retval = _netaddr_equal(other, self);
291  DEBUGMSG5("%s.%d: returning %s after switching operands", __FUNCTION__, __LINE__
292  , (retval ? "True" : "False"));
293  return retval;
294  }
295  DEBUGMSG5("%s.%d: checking type and length...", __FUNCTION__, __LINE__)
296  // Other than ipv4 vs ipv6 (handled above) we require addresses to be of the same type
297  if (self->_addrtype != other->_addrtype || self->_addrlen != other->_addrlen) {
298  DEBUGMSG5("%s.%d: self->addrtype:%d, other->addrtype:%d", __FUNCTION__, __LINE__, self->_addrtype, other->_addrtype);
299  DEBUGMSG5("%s.%d: self->addrlen: %d, other->addrlen: %d", __FUNCTION__, __LINE__, self->_addrlen, other->_addrlen);
300  return FALSE;
301  }
302  memcmprc = memcmp(self->_addrbody, other->_addrbody, self->_addrlen);
303  DEBUGMSG5("%s.%d: memcmp(self, other, %d) returned %d", __FUNCTION__, __LINE__
304  , self->_addrlen, memcmprc);
305  return memcmprc == 0;
306 }
307 
308 #ifndef CHAR_BIT
309 # define CHAR_BIT 8
310 #endif
311 
312 
313 
314 FSTATIC guint
315 _netaddr_hash(const NetAddr* self)
316 {
317  // For an explanation of the random hash seed see https://lwn.net/Articles/474912/
318  const guint shift = 7;
319  static guint hashseed = 0;
320  int j;
321  NetAddr* v6addr = NULL;
322  const NetAddr* addrtouse = self;
323  guint result;
324  const guchar v6loopback[16] = CONST_IPV6_LOOPBACK;
325  while (0 == hashseed) {
326  hashseed = (guint)g_random_int();
327  }
328 
329 
330  DEBUGMSG5("%s.%d: %d/%d:%d NetAddr", __FUNCTION__, __LINE__
331  , self->_addrtype, self->_addrlen, self->_addrport);
332  // Convert v4 addresses into v6 so that we match the compare operation's behavior
333  if (self->_addrtype == ADDR_FAMILY_IPV4) {
334  DEBUGMSG5("%s.%d: Hashing IPv6", __FUNCTION__, __LINE__);
335 
336  // This is kind of high overhead... Could be optimized if need be
337  if (memcmp(self->_addrbody, ipv4loop, sizeof(ipv4loop))== 0) {
338  DEBUGMSG5("%s.%d: Returning an IPv6 loopback value", __FUNCTION__, __LINE__);
339  v6addr = netaddr_ipv6_new(v6loopback, self->_addrport);
340  }else{
341  DEBUGMSG5("%s.%d: Returning an IPv6 replacement value", __FUNCTION__, __LINE__);
342  v6addr = _netaddr_toIPv6(self);
343  }
344  addrtouse = v6addr;
345  }else if (self->_addrtype == ADDR_FAMILY_IPV6) {
346  DEBUGMSG5("%s.%d: Hashing IPv6", __FUNCTION__, __LINE__);
347  if (memcmp(self->_addrbody, ipv4loopversion2, sizeof(ipv4loopversion2)) == 0) {
348  DEBUGMSG5("%s.%d: Returning an IPv6 loopback value", __FUNCTION__, __LINE__);
349  v6addr = netaddr_ipv6_new(v6loopback, self->_addrport);
350  addrtouse = v6addr;
351  }
352  }
353 
354  g_return_val_if_fail(addrtouse != NULL, 0);
355  result = (guint)(addrtouse->_addrtype) ^ hashseed;
356  if (addrtouse->_addrtype == ADDR_FAMILY_IPV6 || addrtouse->_addrtype == ADDR_FAMILY_IPV4) {
357  result ^= addrtouse->_addrport;
358  }
359  for (j=0; j < addrtouse->_addrlen; ++j) {
360  // Circular shift with addrbody xored in...
361  // Addresses are typically either 4 bytes or 16 bytes (6 and 8 bytes are also possible)
362  // So 4 bytes means the first byte gets shifted by 28 bits, and 16 means it
363  // all wraps around a lot ;-)
364  result = ((result << shift) | (result >> (sizeof(result)*CHAR_BIT - shift)))
365  ^ ((guint)((guint8*)addrtouse->_addrbody)[j]);
366  }
367  if (v6addr) {
368  UNREF(v6addr);
369  addrtouse = NULL;
370  }
371  return result;
372 }
373 
375 WINEXPORT gboolean
376 netaddr_g_hash_equal(gconstpointer lhs, gconstpointer rhs)
377 {
378  const NetAddr* a_lhs = CASTTOCONSTCLASS(NetAddr, lhs);
379  const NetAddr* a_rhs = CASTTOCONSTCLASS(NetAddr, rhs);
380  return a_lhs->equal(a_lhs, a_rhs);
381 }
382 
384 WINEXPORT guint
385 netaddr_g_hash_hash(gconstpointer addrptr)
386 {
387  const NetAddr* self = CASTTOCONSTCLASS(NetAddr, addrptr);
388  return self->hash(self);
389 }
390 
392 FSTATIC void
394 {
395  NetAddr* self = CASTTOCLASS(NetAddr, base);
396  if (self->_addrbody) {
397  FREE(self->_addrbody);
398  self->_addrbody = NULL;
399  }
400  FREECLASSOBJ(self);
401  self = NULL;
402 }
403 
404 
406 FSTATIC guint16
407 _netaddr_port(const NetAddr* self)
408 {
409  return self->_addrport;
410 }
411 
412 
414 FSTATIC void
415 _netaddr_setport(NetAddr* self, guint16 port)
416 {
417  self->_addrport = port;
418 }
419 
420 
422 FSTATIC guint16
424 {
425  return self->_addrtype;
426 }
427 
429 FSTATIC gboolean
431 {
432  if (self->_addrbody == NULL) {
433  return FALSE;
434  }
436  switch (self->_addrtype) {
437  case ADDR_FAMILY_IPV4: {
438  guint8 byte0 = ((guint8*)self->_addrbody)[0];
439  return (byte0 >= 224 && byte0 <= 239);
440  }
441  break;;
442  }
443  return FALSE;
444 }
446 FSTATIC gboolean
448 {
449  switch (self->_addrtype) {
450  case ADDR_FAMILY_IPV4: {
451  guint8 byte0 = ((guint8*)self->_addrbody)[0];
452  return byte0 == 127;;
453  }
454  case ADDR_FAMILY_IPV6: {
455  const guint8 ipv6local[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
456  const guint8 ipv4localprefix[13] = {0,0,0,0,0,0,0,0,0,0,0xff,0xff, 127};
457  if (memcmp(self->_addrbody, ipv6local, sizeof(ipv6local)) == 0) {
458  return TRUE;
459  }
460  if (memcmp(self->_addrbody, ipv4localprefix, sizeof(ipv4localprefix)) == 0) {
461  return TRUE;
462  }
463  break;
464  }
465 
466  default:
467  break;
468  }
469  return FALSE;
470 }
471 
473 NetAddr*
474 netaddr_new(gsize objsize,
475  guint16 port,
476  guint16 addrtype,
477  gconstpointer addrbody,
478  guint16 addrlen)
479 {
480  AssimObj* baseobj;
481  NetAddr* self;
482 
483 
485  if (objsize < sizeof(NetAddr)) {
486  objsize = sizeof(NetAddr);
487  }
488  g_return_val_if_fail(addrbody != NULL, NULL);
489  g_return_val_if_fail(addrlen >= 4, NULL);
490 
491 
492 
493  baseobj = assimobj_new(objsize);
494  proj_class_register_subclassed(baseobj, "NetAddr");
495  self = CASTTOCLASS(NetAddr, baseobj);
496  g_return_val_if_fail(self != NULL, NULL);
497 
498  baseobj->_finalize = _netaddr_finalize;
499  baseobj->toString = _netaddr_toString;
500  self->canonStr = _netaddr_canonStr;
501  self->toIPv6 = _netaddr_toIPv6;
502  self->_addrport = port;
503  self->_addrtype = addrtype;
504  self->_addrlen = addrlen;
505  self->ipv6sockaddr = _netaddr_ipv6sockaddr;
506  self->ipv4sockaddr = _netaddr_ipv4sockaddr;
507  self->_addrbody = g_memdup(addrbody, addrlen);
508  self->port = _netaddr_port;
509  self->setport = _netaddr_setport;
510  self->addrtype = _netaddr_addrtype;
511  self->ismcast = _netaddr_ismcast;
512  self->islocal = _netaddr_islocal;
513  self->equal = _netaddr_equal;
514  self->hash = _netaddr_hash;
515 
516  return self;
517 
518 }
519 
522 _netaddr_string_ipv4_new(const char* addrstr)
523 {
524  // Must have four numbers [0-255] in decimal - optionally followed by : port number...
525  int dotpositions[3];
526  int colonpos = -1;
527  guint8 addresses[4];
528  guint8 stack_protector_dummy[8];
529  guint whichdot = 0;
530  int byte;
531  NetAddr* ret;
532  int port = 0;
533 
534  guint j;
535  int debug = FALSE;
536  int lastpos = 0;
537 
538  (void)stack_protector_dummy;
539  //debug = g_ascii_isdigit(addrstr[0]);
540 
541  if (debug) {
542  g_debug("CHECKING [%s]", addrstr);
543  }
544 
545  // Scruffy IPv4 string format verification
546  for (j=0; addrstr[j]; ++j) {
547  if (debug) {
548  g_debug("Looking at '%c'", addrstr[j]);
549  }
550  switch(addrstr[j]) {
551  case '0': case '1': case '2': case '3': case '4':
552  case '5': case '6': case '7': case '8': case '9':
553  continue;
554 
555  case '.':
556  if (whichdot >= DIMOF(dotpositions)
557  || colonpos >= 0) {
558  return NULL;
559  }
560  dotpositions[whichdot] = j;
561  whichdot += 1;
562  continue;
563 
564  case '\0':
565  break;
566  case ':':
567  if (colonpos >= 0) {
568  return NULL;
569  }
570  colonpos = j;
571  break;
572 
573  default:
574  if (debug) {
575  g_debug("Illegal character [%c]", addrstr[j]);
576  }
577 
578  return NULL;
579  }
580  if (j > 21) {
581  return NULL;
582  }
583  }
584  lastpos = j;
585  if (debug) {
586  g_debug("whichdot = %d", whichdot);
587  }
588  if (whichdot != 3) {
589  return NULL;
590  }
591  byte = atoi(addrstr);
592  if (debug) {
593  g_debug("byte %d = %d", 0, byte);
594  }
595  if (byte < 0 || byte > 255) {
596  return NULL;
597  }
598  addresses[0] = byte;
599 
600 
601  for (j=0; j < DIMOF(dotpositions); ++j) {
602  byte = atoi(addrstr+dotpositions[j]+1);
603  if (debug) {
604  g_debug("byte %d = %d", j, byte);
605  }
606  if (byte < 0 || byte > 255) {
607  return NULL;
608  }
609  addresses[j+1] = (guint8)byte;
610  }
611  if (colonpos >= 0) {
612  if (colonpos > (lastpos - 2)) {
613  return NULL;
614  }
615  port = atoi(addrstr+colonpos+1);
616  if (port > 65535) {
617  g_debug("found bad (%s) IPV4 port", addrstr+colonpos+1);
618  return NULL;
619  }
620  if (debug) {
621  g_debug("found good IPV4 port [%d]", port);
622  }
623  }
624  if (debug) {
625  g_debug("Returning good IPV4 address!");
626  }
627  ret = netaddr_ipv4_new(addresses, port);
628  if (debug) {
629  g_debug("Returning good IPV4 address [%p]!", ret);
630  }
631  return ret;
632 }
633 
638 _netaddr_string_ipv6_new(const char* addrstr)
639 {
640 /*
641  * ipv6
642  * OR
643  * [ipv6]:decimal-port
644  *
645  * The 'IPv6' part is described by RFC 4291
646  *
647  *
648  * It consists of a sequence of 0-8 collections of 1-4 hexadecimal digits separated by
649  * colon characters.
650  * If there are fewer than 8 collections of digits, then there must be exactly one :: string
651  * in the address string. This :: tag represents a variable-length sequence of zeros in the address.
652  *
653  * There is also another variant on the format of the IPv6 portion:
654  *
655  * It can be "::ffff:" followed by an IPv4 address in typical IPv4 dotted decimal notation.
656  * @todo make _netaddr_string_ipv6_new() support the special format used for
657  * IPv6-encapsulated IPv4 addresses.
658  *
659  */
660  int len = strlen(addrstr);
661  const char * firstaddrdigit = addrstr;
662  const char * lastaddrdigit = addrstr+len-1;
663  const char * curaddrdigit;
664  unsigned j;
665  long port = 0;
666  guint16 addrchunks[8];
667  guint8 addrbytes[16];
668  guint8* addrptr;
669  guint chunkindex = 0;
670  int coloncolonindex = -1;
671  guint coloncolonlength = 0;
672  char* firstbadhexchar = NULL;
673  NetAddr* retval;
674  const char v4prefix[] = "ffff:";
675  const guint v4prefixlen = sizeof(v4prefix)-1;
676  gboolean v4encapsulated = FALSE;
677  guint conversionbase = 16;
678  char delimchar = ':';
679  guint maxchunkindex = DIMOF(addrchunks);
680  long maxchunkvalue = 65535;
681 
682  DEBUGMSG5("%s.%d(\"%s\")", __FUNCTION__, __LINE__, addrstr);
683  memset(addrchunks, 0, sizeof(addrchunks));
684 
685  if (*addrstr == '[') {
686  // Then we have a port number - look for ']' and ':'
687  char * rbracketpos = strchr(addrstr+1, ']');
688  char * firstbadchar = rbracketpos;
689 
690  if (rbracketpos == NULL || rbracketpos[1] != ':') {
691  return NULL;
692  }
693  firstaddrdigit += 1;
694  lastaddrdigit = rbracketpos - 1;
695  port = strtol(rbracketpos+2, &firstbadchar, 10);
696  if (*firstbadchar != '\0' || port <= 0 || port >= 65536) {
697  DEBUGMSG5("%s.%d: Not IPv6 format due to bad port number syntax"
698  , __FUNCTION__, __LINE__);
699  return NULL;
700  }
701  }
702  // Now, we know where the collection of address characters starts and ends
703  if (firstaddrdigit[0] == ':' && firstaddrdigit[1] == ':') {
704  coloncolonindex = 0;
705  firstaddrdigit += 2;
706  // Let's see if it might be an ipv4 address encapsulated as ipv6...
707  DEBUGMSG5("%s.%d: LOOKING to see if we have an encapsulated IPv4 address. [%s] [%s]"
708  , __FUNCTION__, __LINE__, firstaddrdigit, v4prefix);
709  if (strncmp(firstaddrdigit, v4prefix, v4prefixlen) == 0) {
710  DEBUGMSG5("%s.%d: May have an encapsulated IPv4 address. [%s]"
711  , __FUNCTION__, __LINE__, firstaddrdigit);
712  if (strchr(firstaddrdigit + v4prefixlen, '.') != NULL) {
713  // We have '.'s but no more ':'s...
714  DEBUGMSG5("%s.%d: Appear to have an encapsulated IPv4 address."
715  , __FUNCTION__, __LINE__);
716  v4encapsulated = TRUE;
717  conversionbase = 10; // IPv4 addresses are decimal
718  delimchar = '.'; // IPv4 addresses use . delimiters
719  maxchunkindex = 4; // IPv4 addresses have exactly 4 parts
720  maxchunkvalue = 255; // IPv4 address elements are single bytes
721  firstaddrdigit += v4prefixlen;
722  }
723  }
724  }
725  curaddrdigit = firstaddrdigit;
726  // Loop over the characters, breaking them into a series of hexadecimal (or decimal) chunks
727  for (chunkindex=0; chunkindex < maxchunkindex && curaddrdigit <= lastaddrdigit; ++chunkindex) {
728  long chunk = strtol(curaddrdigit, &firstbadhexchar, conversionbase);
729  DEBUGMSG5("%s.%d: chunk %d begins [%s] converts to 0x%lx", __FUNCTION__, __LINE__
730  , chunkindex, curaddrdigit, (unsigned long)chunk);
731  if (chunk < 0 || chunk > maxchunkvalue) {
732  DEBUGMSG5("%s.%d: Not IPv6 format due to invalid chunk value [%ld]"
733  , __FUNCTION__, __LINE__, chunk);
734  return NULL;
735  }
736  // Remember the value of this chunk...
737  addrchunks[chunkindex] = (guint16)chunk;
738 
739  // Was the ending delimiter what we expected?
740  if (firstbadhexchar <= lastaddrdigit && *firstbadhexchar != delimchar) {
741  DEBUGMSG5("%s.%d: Not IPv6 format due to invalid character [%c]"
742  , __FUNCTION__, __LINE__, *firstbadhexchar);
743  return NULL;
744  }
745  curaddrdigit = firstbadhexchar;
746  if (v4encapsulated && *firstbadhexchar == delimchar) {
747  curaddrdigit += 1;
748  // Is there a :: in this position in the address?
749  }else if (!v4encapsulated && firstbadhexchar[0] == ':') {
750  if (firstbadhexchar[1] == ':') {
751  if (coloncolonindex >= 0) {
752  // :: can only appear once in the address
753  DEBUGMSG5("%s.%d: Not IPv6 format due to multiple ::'s"
754  , __FUNCTION__, __LINE__);
755  return NULL;
756  }
757  coloncolonindex = chunkindex + 1;
758  curaddrdigit += 2;
759  }else{
760  curaddrdigit += 1;
761  }
762  }else if (*firstbadhexchar != ']' && *firstbadhexchar != '\0') {
763  DEBUGMSG5("%s.%d: Not IPv6 format due to illegal char [%c]"
764  , __FUNCTION__, __LINE__, *firstbadhexchar);
765  return NULL;
766  }
767 
768  if (firstbadhexchar >= lastaddrdigit + 1) {
769  break;
770  }
771  }
772  if (firstbadhexchar != NULL && firstbadhexchar != lastaddrdigit + 1) {
773  DEBUGMSG5("%s.%d: Not IPv6 format due to excess length.", __FUNCTION__, __LINE__);
774  DEBUGMSG5("%s.%d: firstbadhexchar = %p, lastaddrdigit = %p, diff=%ld"
775  , __FUNCTION__, __LINE__, firstbadhexchar, lastaddrdigit
776  , (long)(lastaddrdigit-firstbadhexchar));
777  return NULL;
778  }
779  if (coloncolonindex >= 0 && chunkindex == DIMOF(addrchunks)-1) {
780  DEBUGMSG5("%s.%d: Not IPv6 format due to full length with :: present"
781  , __FUNCTION__, __LINE__);
782  return NULL;
783  }
784  if (coloncolonindex < 0 && chunkindex != DIMOF(addrchunks)-1) {
785  DEBUGMSG5("%s.%d: Not IPv6 format due to too few digits."
786  , __FUNCTION__, __LINE__);
787  return NULL;
788  }
789  // OK --- now we have something that looks a lot like a legit IPv6 address.
790  // let's see if we can make a NetAddr out of it...
791  if (coloncolonindex >= 0) {
792  coloncolonlength = (DIMOF(addrchunks)-1) - chunkindex;
793  DEBUGMSG5("%s.%d: coloncolonlength is %d, index is %d", __FUNCTION__, __LINE__
794  , coloncolonlength, coloncolonindex);
795  }
796  DEBUGMSG5("%s.%d: chunkindex is %d", __FUNCTION__, __LINE__, chunkindex);
797 
798  addrptr = addrbytes;
799 
800 
801  if (v4encapsulated) {
802  // Take care of the encapsulated IPv4 special case...
803  const guint8 v4prefix[] = {CONST_IPV6_IPV4SPACE};
804  const guint offset = sizeof(v4prefix);
805  if (chunkindex != 3) {
806  DEBUGMSG5("%s.%d: Not IPv4 encapsulated as IPv6 format due to too few digits."
807  , __FUNCTION__, __LINE__);
808  return NULL;
809  }
810  memcpy(addrbytes, v4prefix, sizeof(v4prefix));
811  addrbytes[offset+0] = (guint8)addrchunks[0];
812  addrbytes[offset+1] = (guint8)addrchunks[1];
813  addrbytes[offset+2] = (guint8)addrchunks[2];
814  addrbytes[offset+3] = (guint8)addrchunks[3];
815  }else{
816  // Otherwise we have a more normal IPv6 address
817  memset(addrbytes, 0, DIMOF(addrbytes));
818  // Make our set of chunks into an IPv6 address in binary
819  for (j=0; j <= chunkindex; ++j) {
820  // Is this where the :: goes?
821  if (((gint)j) == coloncolonindex) {
822  // Insert the right number of zeros
823  memset(addrptr, 0, coloncolonlength*2);
824  addrptr += 2*coloncolonlength;
825  }
826  // Copy the next bit of data
827  addrptr[0] = (((addrchunks[j]) >> 8) & 0xff);
828  addrptr[1] = addrchunks[j] & 0xff;
829  addrptr += 2;
830  }
831  // Did the :: appear at the end of the address - weird but legal...
832  if (coloncolonindex == (gint)chunkindex + 1) {
833  DEBUGMSG5("%s.%d: Appending %d zeros to the end of the address"
834  , __FUNCTION__, __LINE__, coloncolonlength*2);
835  memset(addrptr, 0, coloncolonlength*2);
836  addrptr += 2*coloncolonlength;
837  }
838  DEBUGMSG5("%s.%d: addrptr == addrbytes+%ld", __FUNCTION__, __LINE__
839  , (long)(addrptr-addrbytes));
840  g_return_val_if_fail(addrptr == addrbytes+DIMOF(addrbytes), NULL);
841  }
842  retval = netaddr_ipv6_new(addrbytes, port);
843  DUMP5(addrstr, &retval->baseclass, " Converted the former into the latter...(ignore the extra ':')");
844  return retval;
845 }
846 
847 NetAddr*
848 netaddr_string_new(const char* addrstr)
849 {
850  NetAddr* retval;
851  if (addrstr[0] == '[' || addrstr[0] == ':') {
852  retval = _netaddr_string_ipv6_new(addrstr);
853  }else{
854  retval = _netaddr_string_ipv4_new(addrstr);
855  if (!retval) {
856  retval = _netaddr_string_ipv6_new(addrstr);
857  }
858  }
859  return retval;
860 }
861 
862 
864 NetAddr*
865 netaddr_macaddr_new(gconstpointer macbuf,
866  guint16 maclen)
867 {
868 
869  g_return_val_if_fail(maclen == 6 || maclen == 8, NULL);
870  return netaddr_new(0, 0, ADDR_FAMILY_802, macbuf, maclen);
871 }
872 
874 NetAddr*
875 netaddr_mac48_new(gconstpointer macbuf)
876 {
877  return netaddr_macaddr_new(macbuf, 6);
878 }
879 
881 NetAddr*
882 netaddr_mac64_new(gconstpointer macbuf)
883 {
884  return netaddr_macaddr_new(macbuf, 8);
885 }
886 
888 NetAddr*
889 netaddr_ipv4_new(gconstpointer ipbuf,
890  guint16 port)
891 {
892  return netaddr_new(0, port, ADDR_FAMILY_IPV4, ipbuf, 4);
893 }
894 
896 NetAddr*
897 netaddr_ipv6_new(gconstpointer ipbuf,
898  guint16 port)
899 {
900  return netaddr_new(0, port, ADDR_FAMILY_IPV6, ipbuf, 16);
901 }
902 
903 
904 
905 
907 NetAddr*
908 netaddr_sockaddr_new(const struct sockaddr_in6 *sa_in6,
909  socklen_t length)
910 {
911  const struct sockaddr_in* sa_in = (const struct sockaddr_in*)sa_in6;
912 
913  (void)length;
914  switch(sa_in->sin_family) {
915  case AF_INET:
916  return netaddr_new(0, ntohs(sa_in->sin_port),
917  ADDR_FAMILY_IPV4, &sa_in->sin_addr, 4);
918  break;
919 
920  case AF_INET6:
922  return netaddr_new(0, ntohs(sa_in6->sin6_port),
923  ADDR_FAMILY_IPV6, &sa_in6->sin6_addr, 16);
924  break;
925  }
926  g_return_val_if_reached(NULL);
927 }
928 
929 FSTATIC struct sockaddr_in6
930 _netaddr_ipv6sockaddr(const NetAddr* self) //<[in] NetAddr object to convert to IPv6 sockaddr
931 {
932  struct sockaddr_in6 saddr;
933 
934  memset(&saddr, 0x00, sizeof(saddr));
935 
936  switch (self->_addrtype) {
937  case ADDR_FAMILY_IPV4:
938  g_return_val_if_fail(4 == self->_addrlen, saddr);
939  saddr.sin6_family = AF_INET6;
940  saddr.sin6_port = htons(self->_addrport);
943  // (this works because saddr is initialized to zero)
944  saddr.sin6_addr.s6_addr[10] = 0xff;
945  saddr.sin6_addr.s6_addr[11] = 0xff;
946  memcpy(saddr.sin6_addr.s6_addr+12, self->_addrbody, self->_addrlen);
947  DEBUGMSG3("%s:%s: sin6_family 0x%x, sin6_port %d"
948  , __FILE__, __FUNCTION__
949  , saddr.sin6_family, ntohs(saddr.sin6_port));
950  DEBUGMSG3("%s:%s:s6_addr(v4): %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x"
951  , __FILE__, __FUNCTION__
952  , saddr.sin6_addr.s6_addr[0],saddr.sin6_addr.s6_addr[1]
953  , saddr.sin6_addr.s6_addr[2],saddr.sin6_addr.s6_addr[3]
954  , saddr.sin6_addr.s6_addr[4],saddr.sin6_addr.s6_addr[5]
955  , saddr.sin6_addr.s6_addr[6],saddr.sin6_addr.s6_addr[7]
956  , saddr.sin6_addr.s6_addr[8],saddr.sin6_addr.s6_addr[8]
957  , saddr.sin6_addr.s6_addr[10],saddr.sin6_addr.s6_addr[11]
958  , saddr.sin6_addr.s6_addr[12],saddr.sin6_addr.s6_addr[13]
959  , saddr.sin6_addr.s6_addr[14],saddr.sin6_addr.s6_addr[15]);
960 
961  break;
962 
963  case ADDR_FAMILY_IPV6:
964  g_return_val_if_fail(16 == self->_addrlen, saddr);
965  saddr.sin6_family = AF_INET6;
966  saddr.sin6_port = htons(self->_addrport);
967  memcpy(&saddr.sin6_addr, self->_addrbody, self->_addrlen);
968  break;
969 
970  default:
971  g_return_val_if_reached(saddr);
972  }
973  return saddr;
974 }
975 
976 FSTATIC struct sockaddr_in
977 _netaddr_ipv4sockaddr(const NetAddr* self) //<[in] NetAddr object to convert to IPv4 sockaddr
978 {
979  struct sockaddr_in saddr;
980 
981  memset(&saddr, 0x00, sizeof(saddr));
982 
983  switch (self->_addrtype) {
984  case ADDR_FAMILY_IPV4:
985  g_return_val_if_fail(4 == self->_addrlen, saddr);
986  saddr.sin_family = AF_INET;
987  saddr.sin_port = htons(self->_addrport);
988  memcpy(&saddr.sin_addr, self->_addrbody, 4);
989  break;
990 
991  default:
992  g_return_val_if_reached(saddr);
993  }
994  return saddr;
995 }