+
+/**
+ * Parse an IPv6 network policy. The argument specifies a list of
+ * subnets. The format is <tt>(network[/netmask[:SPORT[-DPORT]]];)*</tt>
+ * (no whitespace, must be terminated with a semicolon). The network
+ * must be given in colon-hex notation. The netmask must be given in
+ * CIDR notation (/16) or can be omitted to specify a single host.
+ * Note that the netmask is mandatory if ports are specified.
+ *
+ * @param routeListX a string specifying the policy
+ * @return the converted list, 0-terminated, NULL if the synatx is flawed
+ */
+struct GNUNET_STRINGS_IPv6NetworkPolicy *
+GNUNET_STRINGS_parse_ipv6_policy (const char *routeListX)
+{
+ unsigned int count;
+ unsigned int i;
+ unsigned int len;
+ unsigned int pos;
+ int start;
+ int slash;
+ int ret;
+ char *routeList;
+ struct GNUNET_STRINGS_IPv6NetworkPolicy *result;
+ unsigned int bits;
+ unsigned int off;
+ int save;
+ int colon;
+
+ if (NULL == routeListX)
+ return NULL;
+ len = strlen (routeListX);
+ if (0 == len)
+ return NULL;
+ routeList = GNUNET_strdup (routeListX);
+ count = 0;
+ for (i = 0; i < len; i++)
+ if (';' == routeList[i])
+ count++;
+ if (';' != routeList[len - 1])
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("Invalid network notation (does not end with ';': `%s')\n"),
+ routeList);
+ GNUNET_free (routeList);
+ return NULL;
+ }
+
+ result = GNUNET_malloc (sizeof (struct GNUNET_STRINGS_IPv6NetworkPolicy) * (count + 1));
+ i = 0;
+ pos = 0;
+ while (i < count)
+ {
+ start = pos;
+ while (';' != routeList[pos])
+ pos++;
+ slash = pos;
+ while ((slash >= start) && (routeList[slash] != '/'))
+ slash--;
+
+ if (slash < start)
+ {
+ memset (&result[i].netmask,
+ 0xFF,
+ sizeof (struct in6_addr));
+ slash = pos;
+ }
+ else
+ {
+ routeList[pos] = '\0';
+ for (colon = pos; ':' != routeList[colon]; colon--)
+ if ('/' == routeList[colon])
+ break;
+ if (':' == routeList[colon])
+ {
+ routeList[colon] = '\0';
+ if (GNUNET_OK != parse_port_policy (&routeList[colon + 1],
+ &result[i].pp))
+ {
+ GNUNET_free (result);
+ GNUNET_free (routeList);
+ return NULL;
+ }
+ }
+ ret = inet_pton (AF_INET6, &routeList[slash + 1], &result[i].netmask);
+ if (ret <= 0)
+ {
+ save = errno;
+ if ((1 != SSCANF (&routeList[slash + 1], "%u", &bits)) || (bits > 128))
+ {
+ if (0 == ret)
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("Wrong format `%s' for netmask\n"),
+ &routeList[slash + 1]);
+ else
+ {
+ errno = save;
+ LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "inet_pton");
+ }
+ GNUNET_free (result);
+ GNUNET_free (routeList);
+ return NULL;
+ }
+ off = 0;
+ while (bits > 8)
+ {
+ result[i].netmask.s6_addr[off++] = 0xFF;
+ bits -= 8;
+ }
+ while (bits > 0)
+ {
+ result[i].netmask.s6_addr[off] =
+ (result[i].netmask.s6_addr[off] >> 1) + 0x80;
+ bits--;
+ }
+ }
+ }
+ routeList[slash] = '\0';
+ ret = inet_pton (AF_INET6, &routeList[start], &result[i].network);
+ if (ret <= 0)
+ {
+ if (0 == ret)
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("Wrong format `%s' for network\n"),
+ &routeList[slash + 1]);
+ else
+ LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
+ "inet_pton");
+ GNUNET_free (result);
+ GNUNET_free (routeList);
+ return NULL;
+ }
+ pos++;
+ i++;
+ }
+ GNUNET_free (routeList);
+ return result;
+}
+
+
+
+/** ******************** Base64 encoding ***********/
+
+#define FILLCHAR '='
+static char *cvt =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789+/";
+
+
+/**
+ * Encode into Base64.
+ *
+ * @param data the data to encode
+ * @param len the length of the input
+ * @param output where to write the output (*output should be NULL,
+ * is allocated)
+ * @return the size of the output
+ */
+size_t
+GNUNET_STRINGS_base64_encode (const char *data,
+ size_t len,
+ char **output)
+{
+ size_t i;
+ char c;
+ size_t ret;
+ char *opt;
+
+ ret = 0;
+ opt = GNUNET_malloc (2 + (len * 4 / 3) + 8);
+ *output = opt;
+ for (i = 0; i < len; ++i)
+ {
+ c = (data[i] >> 2) & 0x3f;
+ opt[ret++] = cvt[(int) c];
+ c = (data[i] << 4) & 0x3f;
+ if (++i < len)
+ c |= (data[i] >> 4) & 0x0f;
+ opt[ret++] = cvt[(int) c];
+ if (i < len)
+ {
+ c = (data[i] << 2) & 0x3f;
+ if (++i < len)
+ c |= (data[i] >> 6) & 0x03;
+ opt[ret++] = cvt[(int) c];
+ }
+ else
+ {
+ ++i;
+ opt[ret++] = FILLCHAR;
+ }
+ if (i < len)
+ {
+ c = data[i] & 0x3f;
+ opt[ret++] = cvt[(int) c];
+ }
+ else
+ {
+ opt[ret++] = FILLCHAR;
+ }
+ }
+ opt[ret++] = FILLCHAR;
+ return ret;
+}
+
+#define cvtfind(a)( (((a) >= 'A')&&((a) <= 'Z'))? (a)-'A'\
+ :(((a)>='a')&&((a)<='z')) ? (a)-'a'+26\
+ :(((a)>='0')&&((a)<='9')) ? (a)-'0'+52\
+ :((a) == '+') ? 62\
+ :((a) == '/') ? 63 : -1)
+
+
+/**
+ * Decode from Base64.
+ *
+ * @param data the data to encode
+ * @param len the length of the input
+ * @param output where to write the output (*output should be NULL,
+ * is allocated)
+ * @return the size of the output
+ */
+size_t
+GNUNET_STRINGS_base64_decode (const char *data,
+ size_t len, char **output)
+{
+ size_t i;
+ char c;
+ char c1;
+ size_t ret = 0;
+
+#define CHECK_CRLF while (data[i] == '\r' || data[i] == '\n') {\
+ GNUNET_log(GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, "ignoring CR/LF\n"); \
+ i++; \
+ if (i >= len) goto END; \
+ }
+
+ *output = GNUNET_malloc ((len * 3 / 4) + 8);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "base64_decode decoding len=%d\n",
+ (int) len);
+ for (i = 0; i < len; ++i)
+ {
+ CHECK_CRLF;
+ if (FILLCHAR == data[i])
+ break;
+ c = (char) cvtfind (data[i]);
+ ++i;
+ CHECK_CRLF;
+ c1 = (char) cvtfind (data[i]);
+ c = (c << 2) | ((c1 >> 4) & 0x3);
+ (*output)[ret++] = c;
+ if (++i < len)
+ {
+ CHECK_CRLF;
+ c = data[i];
+ if (FILLCHAR == c)
+ break;
+ c = (char) cvtfind (c);
+ c1 = ((c1 << 4) & 0xf0) | ((c >> 2) & 0xf);
+ (*output)[ret++] = c1;
+ }
+ if (++i < len)
+ {
+ CHECK_CRLF;
+ c1 = data[i];
+ if (FILLCHAR == c1)
+ break;
+
+ c1 = (char) cvtfind (c1);
+ c = ((c << 6) & 0xc0) | c1;
+ (*output)[ret++] = c;
+ }
+ }
+END:
+ return ret;
+}
+
+
+
+
+