Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

host_addr.h

Go to the documentation of this file.
00001 /*
00002  * $Id: host_addr.h 13879 2007-06-18 22:41:05Z cbiere $
00003  *
00004  * Copyright (c) 2001-2003, Raphael Manfredi
00005  * Copyright (c) 2005, Christian Biere
00006  *
00007  *----------------------------------------------------------------------
00008  * This file is part of gtk-gnutella.
00009  *
00010  *  gtk-gnutella is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  gtk-gnutella is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU General Public License for more details.
00019  *
00020  *  You should have received a copy of the GNU General Public License
00021  *  along with gtk-gnutella; if not, write to the Free Software
00022  *  Foundation, Inc.:
00023  *      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024  *----------------------------------------------------------------------
00025  */
00026 
00037 #ifndef _host_addr_h_
00038 #define _host_addr_h_
00039 
00040 #include "common.h"
00041 
00042 #include "lib/endian.h"
00043 #include "lib/misc.h"
00044 
00051 enum net_type {
00052     NET_TYPE_NONE   = 0,
00053     NET_TYPE_LOCAL  = 1,
00054     NET_TYPE_IPV4   = 4,
00055     NET_TYPE_IPV6   = 6
00056 };
00057 
00058 static inline gint
00059 net_type_to_pf(enum net_type net)
00060 {
00061     switch (net) {
00062     case NET_TYPE_NONE:  return PF_UNSPEC;
00063     case NET_TYPE_LOCAL: return PF_LOCAL;
00064     case NET_TYPE_IPV4:  return PF_INET;
00065     case NET_TYPE_IPV6:
00066 #ifdef HAS_IPV6
00067         return PF_INET6;
00068 #else
00069         return PF_UNSPEC;
00070 #endif /* HAS_IPV6 */
00071     }
00072     g_assert_not_reached();
00073     return PF_UNSPEC;
00074 }
00075 
00076 static inline gint
00077 net_type_to_af(enum net_type net)
00078 {
00079     switch (net) {
00080     case NET_TYPE_NONE:  return AF_UNSPEC;
00081     case NET_TYPE_LOCAL: return AF_LOCAL;
00082     case NET_TYPE_IPV4:  return AF_INET;
00083     case NET_TYPE_IPV6:
00084 #ifdef HAS_IPV6
00085         return AF_INET6;
00086 #else
00087         return AF_UNSPEC;
00088 #endif /* HAS_IPV6 */
00089     }
00090     g_assert_not_reached();
00091     return AF_UNSPEC;
00092 }
00093 
00094 
00095 typedef struct host_addr {
00096     guint32 net;    
00097     union {
00098         guint8  ipv6[16];   
00099         guint32 ipv4;   
00100     } addr;
00101 } host_addr_t;
00102 
00103 struct packed_host_addr {
00104     guchar net;
00105     guchar addr[sizeof ((host_addr_t *) 0)->addr];
00106 };
00107 
00108 struct packed_host {
00109     guchar port[sizeof (guint16)];
00110     struct packed_host_addr ha;
00111 };
00112 
00113 typedef union socket_addr {
00114     guint8 len;
00115     struct sockaddr_in inet4;
00116 #ifdef HAS_IPV6
00117     struct sockaddr_in6 inet6;
00118 #endif /* HAS_IPV6 */
00119 } socket_addr_t;
00120 
00121 static const host_addr_t ipv4_unspecified = {   /* 0.0.0.0/32 */
00122     NET_TYPE_IPV4,
00123     { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
00124 };
00125 
00126 static const host_addr_t ipv4_loopback = {  /* 0.0.0.0/32 */
00127     NET_TYPE_IPV4,
00128     { { 0x7f, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
00129 };
00130 
00131 static const host_addr_t ipv6_unspecified = {   /* ::/128 */
00132     NET_TYPE_IPV6,
00133     { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
00134 };
00135 
00136 static const host_addr_t ipv6_loopback = {  /* ::1/128 */
00137     NET_TYPE_IPV6,
00138     { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } },
00139 };
00140 
00141 static const host_addr_t ipv6_ipv4_mapped = {   /* ::ffff:0:0/96 */
00142     NET_TYPE_IPV6,
00143     { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 0, 0, 0 } },
00144 };
00145 
00146 static const host_addr_t ipv6_multicast = {     /* ff00::/8 */
00147     NET_TYPE_IPV6,
00148     { { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
00149 };
00150 
00151 static const host_addr_t ipv6_link_local = {    /* fe80::/10 */
00152     NET_TYPE_IPV6,
00153     { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
00154 };
00155 
00156 static const host_addr_t ipv6_site_local = {    /* fec0::/10 */
00157     NET_TYPE_IPV6,
00158     { { 0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
00159 };
00160 
00161 static const host_addr_t ipv6_6to4 = {          /* 2002::/16 */
00162     NET_TYPE_IPV6,
00163     { { 0x20, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
00164 };
00165 
00166 
00167 static const host_addr_t local_host_addr = {
00168     NET_TYPE_LOCAL,
00169     { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
00170 };
00171 
00172 static const host_addr_t zero_host_addr;
00173 
00174 gboolean host_addr_convert(const host_addr_t from, host_addr_t *to,
00175     enum net_type to_net);
00176 gboolean host_addr_can_convert(const host_addr_t from, enum net_type to_net);
00177 gboolean host_addr_6to4_to_ipv4(const host_addr_t from, host_addr_t *to);
00178 
00179 
00180 static inline gboolean
00181 host_addr_initialized(const host_addr_t ha)
00182 {
00183     switch (ha.net) {
00184     case NET_TYPE_IPV4:
00185     case NET_TYPE_IPV6:
00186     case NET_TYPE_LOCAL:
00187         return TRUE;
00188     case NET_TYPE_NONE:
00189         return FALSE;
00190     }
00191     g_assert_not_reached();
00192     return FALSE;
00193 }
00194 
00195 static inline const gchar *
00196 net_type_to_string(enum net_type net)
00197 {
00198     switch (net) {
00199     case NET_TYPE_IPV4:  return "IPv4";
00200     case NET_TYPE_IPV6:  return "IPv6";
00201     case NET_TYPE_LOCAL: return "<local>";
00202     case NET_TYPE_NONE:  return "<none>";
00203     }
00204     g_assert_not_reached();
00205     return NULL;
00206 }
00207 
00208 static inline enum net_type 
00209 host_addr_net(const host_addr_t ha)
00210 {
00211     return ha.net;
00212 }
00213 
00214 static inline guint32
00215 host_addr_ipv4(const host_addr_t ha)
00216 {
00217     return NET_TYPE_IPV4 == ha.net ? ha.addr.ipv4 : 0;
00218 }
00219 
00220 static inline const guint8 *
00221 host_addr_ipv6(const host_addr_t *ha)
00222 {
00223     return NET_TYPE_IPV6 == ha->net ? ha->addr.ipv6 : NULL;
00224 }
00225 
00226 static inline host_addr_t
00227 host_addr_get_ipv4(guint32 ip)
00228 {
00229     host_addr_t ha;
00230 
00231     ha.net = NET_TYPE_IPV4;
00232     ha.addr.ipv4 = ip;
00233     return ha;
00234 }
00235 
00236 static inline host_addr_t
00237 host_addr_peek_ipv4(const void *ipv4)
00238 {
00239     return host_addr_get_ipv4(peek_be32(ipv4));
00240 }
00241 
00242 static inline host_addr_t
00243 host_addr_peek_ipv6(const guint8 *ipv6)
00244 {
00245     host_addr_t ha;
00246     
00247     ha.net = NET_TYPE_IPV6;
00248     memcpy(ha.addr.ipv6, ipv6, 16);
00249     return ha;
00250 }
00251 
00252 static inline gboolean
00253 host_addr_equal(const host_addr_t a, const host_addr_t b)
00254 {
00255     if (a.net == b.net) {
00256         switch (a.net) {
00257         case NET_TYPE_IPV4:
00258             return host_addr_ipv4(a) == host_addr_ipv4(b);
00259         case NET_TYPE_IPV6:
00260             if (0 != memcmp(a.addr.ipv6, b.addr.ipv6, sizeof a.addr.ipv6)) {
00261                 host_addr_t a_ipv4, b_ipv4;
00262 
00263                 return host_addr_convert(a, &a_ipv4, NET_TYPE_IPV4) &&
00264                     host_addr_convert(b, &b_ipv4, NET_TYPE_IPV4) &&
00265                     host_addr_ipv4(a_ipv4) == host_addr_ipv4(b_ipv4);
00266             }
00267             return TRUE;
00268 
00269         case NET_TYPE_LOCAL:
00270         case NET_TYPE_NONE:
00271             return TRUE;
00272         }
00273         g_assert_not_reached();
00274     } else {
00275         host_addr_t to;
00276 
00277         return host_addr_convert(a, &to, b.net) && host_addr_equal(to, b);
00278     }
00279     return FALSE;
00280 }
00281 
00282 static inline gint
00283 host_addr_cmp(host_addr_t a, host_addr_t b)
00284 {
00285     gint r;
00286 
00287     r = CMP(a.net, b.net);
00288     if (0 != r) {
00289         host_addr_t to;
00290 
00291         if (!host_addr_convert(b, &to, a.net))
00292             return r;
00293         b = to;
00294     }
00295 
00296     switch (a.net) {
00297     case NET_TYPE_IPV4:
00298         return CMP(host_addr_ipv4(a), host_addr_ipv4(b));
00299     case NET_TYPE_IPV6:
00300         {
00301             guint i;
00302 
00303             for (i = 0; i < G_N_ELEMENTS(a.addr.ipv6); i++) {
00304                 r = CMP(a.addr.ipv6[i], b.addr.ipv6[i]);
00305                 if (0 != r)
00306                     break;
00307             }
00308         }
00309         return r;
00310     case NET_TYPE_LOCAL:
00311     case NET_TYPE_NONE:
00312         return 0;
00313     }
00314     g_assert_not_reached();
00315     return 0;
00316 }
00317 
00318 static inline gboolean
00319 host_addr_matches(const host_addr_t a, const host_addr_t b, guint8 bits)
00320 {
00321     host_addr_t to;
00322     guint8 shift;
00323 
00324     if (!host_addr_convert(b, &to, a.net))
00325         return FALSE;
00326 
00327     switch (a.net) {
00328     case NET_TYPE_IPV4:
00329         shift = bits < 32 ? 32 - bits : 0;
00330         return host_addr_ipv4(a) >> shift == host_addr_ipv4(to) >> shift;
00331 
00332     case NET_TYPE_IPV6:
00333         {
00334             gint i;
00335 
00336             bits = MIN(128, bits);
00337             for (i = 0; bits >= 8; i++, bits -= 8) {
00338                 if (a.addr.ipv6[i] != to.addr.ipv6[i])
00339                     return FALSE;
00340             }
00341 
00342             if (bits > 0) {
00343                 shift = 8 - bits;
00344                 return (a.addr.ipv6[i] >> shift) == (to.addr.ipv6[i] >> shift);
00345             }
00346 
00347         }
00348         return TRUE;
00349 
00350     case NET_TYPE_LOCAL:
00351     case NET_TYPE_NONE:
00352         return TRUE;
00353     }
00354 
00355     g_assert_not_reached();
00356     return FALSE;
00357 }
00358 
00359 
00360 static inline gboolean
00361 is_host_addr(const host_addr_t ha)
00362 {
00363     switch (host_addr_net(ha)) {
00364     case NET_TYPE_IPV4:
00365         return 0 != host_addr_ipv4(ha);
00366     case NET_TYPE_IPV6:
00367         return 0 != memcmp(ha.addr.ipv6, zero_host_addr.addr.ipv6,
00368                         sizeof ha.addr.ipv6);
00369     case NET_TYPE_LOCAL:
00370     case NET_TYPE_NONE:
00371         return FALSE;
00372     }
00373     g_assert_not_reached();
00374     return FALSE;
00375 }
00376 
00377 static inline guint32
00378 host_addr_hash(host_addr_t ha)
00379 {
00380     switch (ha.net) {
00381     case NET_TYPE_IPV6:
00382         {
00383             host_addr_t ha_ipv4;
00384 
00385             if (!host_addr_convert(ha, &ha_ipv4, NET_TYPE_IPV4)) {
00386                 guint32 h = ha.net ^ ha.addr.ipv6[15];
00387                 guint i;
00388 
00389                 for (i = 0; i < sizeof ha.addr.ipv6; i++)
00390                     h ^= (guint32) ha.addr.ipv6[i] << (i * 2);
00391 
00392                 return h;
00393             }
00394             ha = ha_ipv4;
00395         }
00396         /* FALL THROUGH */
00397     case NET_TYPE_IPV4:
00398         return ha.net ^ host_addr_ipv4(ha);
00399     case NET_TYPE_LOCAL:
00400     case NET_TYPE_NONE:
00401         return ha.net;
00402     }
00403     g_assert_not_reached();
00404     return -1;
00405 }
00406 
00413 static inline host_addr_t
00414 socket_addr_get_addr(const socket_addr_t *addr)
00415 {
00416     host_addr_t ha;
00417 
00418     g_assert(addr);
00419 
00420     if (AF_INET == addr->inet4.sin_family) {
00421         ha = host_addr_peek_ipv4(&addr->inet4.sin_addr.s_addr);
00422 #if defined(HAS_IPV6)
00423     } else if (AF_INET6 == addr->inet6.sin6_family) {
00424         ha = host_addr_peek_ipv6(addr->inet6.sin6_addr.s6_addr);
00425 #endif /* HAS_IPV6 */
00426     } else {
00427         ha = zero_host_addr;
00428     }
00429 
00430     return ha;
00431 }
00432 
00439 static inline guint16
00440 socket_addr_get_port(const socket_addr_t *addr)
00441 {
00442     g_assert(addr != NULL);
00443 
00444     if (AF_INET == addr->inet4.sin_family) {
00445         return ntohs(addr->inet4.sin_port);
00446 #if defined(HAS_IPV6)
00447     } else if (AF_INET6 == addr->inet6.sin6_family) {
00448         return ntohs(addr->inet6.sin6_port);
00449 #endif /* HAS_IPV6 */
00450     }
00451 
00452     return 0;
00453 }
00454 
00455 static inline socklen_t
00456 socket_addr_get_len(const socket_addr_t *addr)
00457 {
00458     g_assert(addr != NULL);
00459 
00460     if (AF_INET == addr->inet4.sin_family) {
00461         return sizeof addr->inet4;
00462 #if defined(HAS_IPV6)
00463     } else if (AF_INET6 == addr->inet6.sin6_family) {
00464         return sizeof addr->inet6;
00465 #endif /* HAS_IPV6 */
00466     }
00467 
00468     return 0;
00469 }
00470 
00471 static inline const struct sockaddr *
00472 socket_addr_get_const_sockaddr(const socket_addr_t *addr)
00473 {
00474     g_assert(addr != NULL);
00475 
00476     if (AF_INET == addr->inet4.sin_family) {
00477         return cast_to_gconstpointer(&addr->inet4);
00478 #if defined(HAS_IPV6)
00479     } else if (AF_INET6 == addr->inet6.sin6_family) {
00480         return cast_to_gconstpointer(&addr->inet6);
00481 #endif /* HAS_IPV6 */
00482     }
00483 
00484     return NULL;
00485 }
00486 
00487 static inline struct sockaddr *
00488 socket_addr_get_sockaddr(socket_addr_t *addr)
00489 {
00490     return (struct sockaddr *) socket_addr_get_const_sockaddr(addr);
00491 }
00492 
00493 static inline gint
00494 socket_addr_get_family(const socket_addr_t *addr)
00495 {
00496     g_assert(addr != NULL);
00497 
00498     if (AF_INET == addr->inet4.sin_family) {
00499         return AF_INET;
00500 #if defined(HAS_IPV6)
00501     } else if (AF_INET6 == addr->inet6.sin6_family) {
00502         return AF_INET6;
00503 #endif /* HAS_IPV6 */
00504     }
00505 
00506     return 0;
00507 }
00508 
00509 socklen_t socket_addr_set(socket_addr_t *sa_ptr,
00510             const host_addr_t addr, guint16 port);
00511 socklen_t socket_addr_init(socket_addr_t *sa_ptr, enum net_type net);
00512 
00513 guint host_addr_hash_func(gconstpointer key);
00514 gboolean host_addr_eq_func(gconstpointer p, gconstpointer q);
00515 void wfree_host_addr(gpointer key, gpointer unused_data);
00516 
00517 int host_addr_family(const host_addr_t ha);
00518 gboolean is_private_addr(const host_addr_t addr);
00519 gboolean host_addr_is_routable(const host_addr_t addr);
00520 gboolean host_addr_is_loopback(const host_addr_t addr);
00521 
00522 static inline gboolean
00523 host_addr_is_ipv4_mapped(const host_addr_t addr)
00524 {
00525     return NET_TYPE_IPV6 == host_addr_net(addr) && 
00526         host_addr_matches(addr, ipv6_ipv4_mapped, 96);
00527 }
00528 
00529 const gchar *host_addr_to_string(const host_addr_t addr);
00530 size_t host_addr_to_string_buf(const host_addr_t addr, gchar *, size_t);
00531 gboolean string_to_host_addr(const gchar *s, const gchar **endptr, host_addr_t *addr_ptr);
00532 const gchar *host_addr_port_to_string(const host_addr_t addr, guint16 port);
00533 const gchar *host_addr_port_to_string2(const host_addr_t addr, guint16 port);
00534 size_t host_addr_port_to_string_buf(const host_addr_t addr,
00535                 guint16 port, gchar *, size_t);
00536 gboolean string_to_host_addr_port(const gchar *str, const gchar **endptr,
00537     host_addr_t *addr_ptr, guint16 *port_ptr);
00538 const gchar *host_port_to_string(const gchar *hostname,
00539                 host_addr_t addr, guint16 port);
00540 
00541 GSList *name_to_host_addr(const gchar *host, enum net_type net);
00542 void host_addr_free_list(GSList **sl_ptr);
00543 
00544 host_addr_t name_to_single_host_addr(const gchar *host, enum net_type net);
00545 
00546 const gchar *host_addr_to_name(const host_addr_t addr);
00547 gboolean string_to_host_or_addr(const char *s, const gchar **endptr,
00548         host_addr_t *ha);
00549 
00550 GSList *host_addr_get_interface_addrs(enum net_type net);
00551 void host_addr_free_interface_addrs(GSList **sl_ptr);
00552 
00553 guint packed_host_addr_size(const struct packed_host_addr paddr);
00554 struct packed_host_addr host_addr_pack(const host_addr_t addr);
00555 host_addr_t packed_host_addr_unpack(const struct packed_host_addr paddr);
00556 
00557 guint packed_host_size(const struct packed_host paddr);
00558 struct packed_host host_pack(const host_addr_t addr, guint16 port);
00559 gboolean packed_host_unpack(const struct packed_host phost,
00560         host_addr_t *addr_ptr, guint16 *port_ptr);
00561 
00562 guint packed_host_hash_func(gconstpointer key);
00563 gboolean packed_host_eq_func(gconstpointer p, gconstpointer q);
00564 gpointer walloc_packed_host(const host_addr_t addr, guint16 port);
00565 void wfree_packed_host(gpointer key, gpointer unused_data);
00566 
00567 #endif /* _host_addr_h_ */
00568 /* vi: set ts=4 sw=4 cindent: */

Generated on Sat Jun 30 17:53:23 2007 for gtk-gnutella by  doxygen 1.3.9.1