summaryrefslogtreecommitdiffstats
path: root/3rdparty/openpgm-svn-r1085/pgm/inet_network.c
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/openpgm-svn-r1085/pgm/inet_network.c')
-rw-r--r--3rdparty/openpgm-svn-r1085/pgm/inet_network.c237
1 files changed, 237 insertions, 0 deletions
diff --git a/3rdparty/openpgm-svn-r1085/pgm/inet_network.c b/3rdparty/openpgm-svn-r1085/pgm/inet_network.c
new file mode 100644
index 0000000..8cac34b
--- /dev/null
+++ b/3rdparty/openpgm-svn-r1085/pgm/inet_network.c
@@ -0,0 +1,237 @@
+/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
+ *
+ * portable implementations of inet_network and inet_network6.
+ *
+ * Copyright (c) 2006-2010 Miru Limited.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <ctype.h>
+#include <impl/framework.h>
+
+
+//#define INET_NETWORK_DEBUG
+
+/* locals */
+
+static uint32_t cidr_to_netmask (const unsigned) PGM_GNUC_CONST;
+
+
+/* calculate IPv4 netmask from network size, returns address in
+ * host byte order.
+ */
+
+static
+uint32_t
+cidr_to_netmask (
+ const unsigned cidr
+ )
+{
+ return (cidr == 0) ? 0 : (0xffffffff - (1 << (32 - cidr)) + 1);
+}
+
+
+/* Converts a numbers-and-dots notation string into a network number in
+ * host order.
+ * Note parameters and return value differs from inet_network(). This
+ * function will not interpret octal numbers, preceeded with a 0, or
+ * hexadecimal numbers, preceeded by 0x.
+ *
+ * 127 => 127.0.0.0
+ * 127.1/8 => 127.0.0.0 -- 127.1.0.0
+ * inet_addr() would be 127.0.0.1
+ * inet_network() would be 0.0.127.1
+ *
+ * returns 0 on success, returns -1 on invalid address.
+ */
+
+int /* return type to match inet_network() */
+pgm_inet_network (
+ const char* restrict s,
+ struct in_addr* restrict in
+ )
+{
+ pgm_return_val_if_fail (NULL != s, -1);
+ pgm_return_val_if_fail (NULL != in, -1);
+
+ pgm_debug ("pgm_inet_network (s:\"%s\" in:%p)",
+ s, (const void*)in);
+
+ const char *p = s;
+ unsigned val = 0;
+ int shift = 24;
+
+ in->s_addr = INADDR_ANY;
+
+ while (*p)
+ {
+ if (isdigit (*p)) {
+ val = 10 * val + (*p - '0');
+ } else if (*p == '.' || *p == 0) {
+ if (val > 0xff) {
+ in->s_addr = INADDR_NONE;
+ return -1;
+ }
+
+//g_trace ("elem %i", val);
+
+ in->s_addr |= val << shift;
+ val = 0;
+ shift -= 8;
+ if (shift < 0 && *p != 0) {
+ in->s_addr = INADDR_NONE;
+ return -1;
+ }
+
+ } else if (*p == '/') {
+ if (val > 0xff) {
+ in->s_addr = INADDR_NONE;
+ return -1;
+ }
+//g_trace ("elem %i", val);
+ in->s_addr |= val << shift;
+ p++; val = 0;
+ while (*p)
+ {
+ if (isdigit (*p)) {
+ val = 10 * val + (*p - '0');
+ } else {
+ in->s_addr = INADDR_NONE;
+ return -1;
+ }
+ p++;
+ }
+ if (val == 0 || val > 32) {
+ in->s_addr = INADDR_NONE;
+ return -1;
+ }
+//g_trace ("bit mask %i", val);
+
+/* zero out host bits */
+ const struct in_addr netaddr = { .s_addr = cidr_to_netmask (val) };
+#ifdef INET_NETWORK_DEBUG
+{
+g_debug ("netaddr %s", inet_ntoa (netaddr));
+}
+#endif
+ in->s_addr &= netaddr.s_addr;
+ return 0;
+
+ } else if (*p == 'x' || *p == 'X') { /* skip number, e.g. 1.x.x.x */
+ if (val > 0) {
+ in->s_addr = INADDR_NONE;
+ return -1;
+ }
+
+ } else {
+ in->s_addr = INADDR_NONE;
+ return -1;
+ }
+ p++;
+ }
+
+ in->s_addr |= val << shift;
+ return 0;
+}
+
+/* Converts a numbers-and-dots notation string into an IPv6 network number.
+ *
+ * ::1/128 => 0:0:0:0:0:0:0:1
+ * ::1 => 0:0:0:0:0:0:0:1
+ * ::1.2.3.4 => 0:0:0:0:1.2.3.4
+ *
+ * returns 0 on success, returns -1 on invalid address.
+ */
+
+int
+pgm_inet6_network (
+ const char* restrict s, /* NULL terminated */
+ struct in6_addr* restrict in6
+ )
+{
+ pgm_return_val_if_fail (NULL != s, -1);
+ pgm_return_val_if_fail (NULL != in6, -1);
+
+ pgm_debug ("pgm_inet6_network (s:\"%s\" in6:%p)",
+ s, (const void*)in6);
+
+/* inet_pton cannot parse IPv6 addresses with subnet declarations, so
+ * chop them off.
+ *
+ * as we are dealing with network addresses IPv6 zone indices are not important
+ * so we can use the inet_xtoy functions.
+ */
+ char s2[INET6_ADDRSTRLEN];
+ const char *p = s;
+ char* p2 = s2;
+ while (*p) {
+ if (*p == '/') break;
+ *p2++ = *p++;
+ }
+ if (*p == 0) {
+ if (pgm_inet_pton (AF_INET6, s, in6)) return 0;
+ pgm_debug ("pgm_inet_pton(AF_INET6) failed on '%s'", s);
+ memcpy (in6, &in6addr_any, sizeof(in6addr_any));
+ return -1;
+ }
+
+ *p2 = 0;
+ pgm_debug ("net part %s", s2);
+ if (!pgm_inet_pton (AF_INET6, s2, in6)) {
+ pgm_debug ("pgm_inet_pton(AF_INET) failed parsing network part '%s'", s2);
+ memcpy (in6, &in6addr_any, sizeof(in6addr_any));
+ return -1;
+ }
+
+#ifdef INET_NETWORK_DEBUG
+ char sdebug[INET6_ADDRSTRLEN];
+ pgm_debug ("IPv6 network address: %s", pgm_inet_ntop(AF_INET6, in6, sdebug, sizeof(sdebug)));
+#endif
+
+ p++;
+ unsigned val = 0;
+ while (*p)
+ {
+ if (isdigit(*p)) {
+ val = 10 * val + (*p - '0');
+ } else {
+ pgm_debug ("failed parsing subnet size due to character '%c'", *p);
+ memcpy (in6, &in6addr_any, sizeof(in6addr_any));
+ return -1;
+ }
+ p++;
+ }
+ if (val == 0 || val > 128) {
+ pgm_debug ("subnet size invalid (%d)", val);
+ memcpy (in6, &in6addr_any, sizeof(in6addr_any));
+ return -1;
+ }
+ pgm_debug ("subnet size %i", val);
+
+/* zero out host bits */
+ const unsigned suffix_length = 128 - val;
+ for (int i = suffix_length, j = 15; i > 0; i -= 8, --j)
+ {
+ in6->s6_addr[ j ] &= i >= 8 ? 0x00 : (unsigned)(( 0xffU << i ) & 0xffU );
+ }
+
+ pgm_debug ("effective IPv6 network address after subnet mask: %s", pgm_inet_ntop(AF_INET6, in6, s2, sizeof(s2)));
+
+ return 0;
+}
+
+/* eof */
+