+
+/**
+ * Parse the given port policy. The format is
+ * "[!]SPORT[-DPORT]".
+ *
+ * @param port_policy string to parse
+ * @param pp policy to fill in
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR if the
+ * @a port_policy is malformed
+ */
+static int
+parse_port_policy (const char *port_policy,
+ struct GNUNET_STRINGS_PortPolicy *pp)
+{
+ const char *pos;
+ int s;
+ int e;
+ char eol[2];
+
+ pos = port_policy;
+ if ('!' == *pos)
+ {
+ pp->negate_portrange = GNUNET_YES;
+ pos++;
+ }
+ if (2 == sscanf (pos,
+ "%u-%u%1s",
+ &s, &e, eol))
+ {
+ if ( (0 == s) ||
+ (s > 0xFFFF) ||
+ (e < s) ||
+ (e > 0xFFFF) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Port not in range\n"));
+ return GNUNET_SYSERR;
+ }
+ pp->start_port = (uint16_t) s;
+ pp->end_port = (uint16_t) e;
+ return GNUNET_OK;
+ }
+ if (1 == sscanf (pos,
+ "%u%1s",
+ &s,
+ eol))
+ {
+ if ( (0 == s) ||
+ (s > 0xFFFF) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Port not in range\n"));
+ return GNUNET_SYSERR;
+ }
+
+ pp->start_port = (uint16_t) s;
+ pp->end_port = (uint16_t) s;
+ return GNUNET_OK;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Malformed port policy `%s'\n"),
+ port_policy);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Parse an IPv4 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
+ * dotted-decimal notation. The netmask can be given in CIDR notation
+ * (/16) or in dotted-decimal (/255.255.0.0).
+ *
+ * @param routeListX a string specifying the IPv4 subnets
+ * @return the converted list, terminated with all zeros;
+ * NULL if the synatx is flawed
+ */
+struct GNUNET_STRINGS_IPv4NetworkPolicy *
+GNUNET_STRINGS_parse_ipv4_policy (const char *routeListX)
+{
+ unsigned int count;
+ unsigned int i;
+ unsigned int j;
+ unsigned int len;
+ int cnt;
+ unsigned int pos;
+ unsigned int temps[8];
+ int slash;
+ struct GNUNET_STRINGS_IPv4NetworkPolicy *result;
+ int colon;
+ int end;
+ char *routeList;
+
+ 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++;
+ result = GNUNET_malloc (sizeof (struct GNUNET_STRINGS_IPv4NetworkPolicy) * (count + 1));
+ i = 0;
+ pos = 0;
+ while (i < count)
+ {
+ for (colon = pos; ':' != routeList[colon]; colon++)
+ if ( (';' == routeList[colon]) ||
+ ('\0' == routeList[colon]) )
+ break;
+ for (end = colon; ';' != routeList[end]; end++)
+ if ('\0' == routeList[end])
+ break;
+ if ('\0' == routeList[end])
+ break;
+ routeList[end] = '\0';
+ if (':' == routeList[colon])
+ {
+ routeList[colon] = '\0';
+ if (GNUNET_OK != parse_port_policy (&routeList[colon + 1],
+ &result[i].pp))
+ break;
+ }
+ cnt =
+ SSCANF (&routeList[pos],
+ "%u.%u.%u.%u/%u.%u.%u.%u",
+ &temps[0],
+ &temps[1],
+ &temps[2],
+ &temps[3],
+ &temps[4],
+ &temps[5],
+ &temps[6],
+ &temps[7]);
+ if (8 == cnt)
+ {
+ for (j = 0; j < 8; j++)
+ if (temps[j] > 0xFF)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("Invalid format for IP: `%s'\n"),
+ &routeList[pos]);
+ GNUNET_free (result);
+ GNUNET_free (routeList);
+ return NULL;
+ }
+ result[i].network.s_addr =
+ htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) +
+ temps[3]);
+ result[i].netmask.s_addr =
+ htonl ((temps[4] << 24) + (temps[5] << 16) + (temps[6] << 8) +
+ temps[7]);
+ pos = end + 1;
+ i++;
+ continue;
+ }
+ /* try second notation */
+ cnt =
+ SSCANF (&routeList[pos],
+ "%u.%u.%u.%u/%u",
+ &temps[0],
+ &temps[1],
+ &temps[2],
+ &temps[3],
+ &slash);
+ if (5 == cnt)
+ {
+ for (j = 0; j < 4; j++)
+ if (temps[j] > 0xFF)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("Invalid format for IP: `%s'\n"),
+ &routeList[pos]);
+ GNUNET_free (result);
+ GNUNET_free (routeList);
+ return NULL;
+ }
+ result[i].network.s_addr =
+ htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) +
+ temps[3]);
+ if ((slash <= 32) && (slash >= 0))
+ {
+ result[i].netmask.s_addr = 0;
+ while (slash > 0)
+ {
+ result[i].netmask.s_addr =
+ (result[i].netmask.s_addr >> 1) + 0x80000000;
+ slash--;
+ }
+ result[i].netmask.s_addr = htonl (result[i].netmask.s_addr);
+ pos = end + 1;
+ i++;
+ continue;
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("Invalid network notation ('/%d' is not legal in IPv4 CIDR)."),
+ slash);
+ GNUNET_free (result);
+ GNUNET_free (routeList);
+ return NULL; /* error */
+ }
+ }
+ /* try third notation */
+ slash = 32;
+ cnt =
+ SSCANF (&routeList[pos],
+ "%u.%u.%u.%u",
+ &temps[0],
+ &temps[1],
+ &temps[2],
+ &temps[3]);
+ if (4 == cnt)
+ {
+ for (j = 0; j < 4; j++)
+ if (temps[j] > 0xFF)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("Invalid format for IP: `%s'\n"),
+ &routeList[pos]);
+ GNUNET_free (result);
+ GNUNET_free (routeList);
+ return NULL;
+ }
+ result[i].network.s_addr =
+ htonl ((temps[0] << 24) + (temps[1] << 16) + (temps[2] << 8) +
+ temps[3]);
+ result[i].netmask.s_addr = 0;
+ while (slash > 0)
+ {
+ result[i].netmask.s_addr = (result[i].netmask.s_addr >> 1) + 0x80000000;
+ slash--;
+ }
+ result[i].netmask.s_addr = htonl (result[i].netmask.s_addr);
+ pos = end + 1;
+ i++;
+ continue;
+ }
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("Invalid format for IP: `%s'\n"),
+ &routeList[pos]);
+ GNUNET_free (result);
+ GNUNET_free (routeList);
+ return NULL; /* error */
+ }
+ if (pos < strlen (routeList))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("Invalid format: `%s'\n"),
+ &routeListX[pos]);
+ GNUNET_free (result);
+ GNUNET_free (routeList);
+ return NULL; /* oops */
+ }
+ GNUNET_free (routeList);
+ return result; /* ok */
+}
+
+
+/**
+ * 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;
+}
+
+
+
+
+