ip/prefix to regex
[oweals/gnunet.git] / src / regex / regex.c
index a4126e02dd955c62d770735fd15881cd1a315ba9..19b55fca38f29505d0d6fdae45acc1b27cec20bd 100644 (file)
@@ -2816,7 +2816,9 @@ iterate_initial_edge (const unsigned int min_len, const unsigned int max_len,
   struct GNUNET_REGEX_Transition *t;
   unsigned int num_edges = state->transition_count;
   struct GNUNET_REGEX_Edge edges[num_edges];
+  struct GNUNET_REGEX_Edge edge[1];
   struct GNUNET_HashCode hash;
+  struct GNUNET_HashCode hash_new;
 
   unsigned int cur_len;
 
@@ -2825,9 +2827,8 @@ iterate_initial_edge (const unsigned int min_len, const unsigned int max_len,
   else
     cur_len = 0;
 
-  if (cur_len > min_len && NULL != consumed_string)
+  if (cur_len >= min_len && cur_len > 0 && NULL != consumed_string)
   {
-
     if (cur_len <= max_len)
     {
       for (i = 0, t = state->transitions_head; NULL != t && i < num_edges;
@@ -2841,27 +2842,28 @@ iterate_initial_edge (const unsigned int min_len, const unsigned int max_len,
       iterator (iterator_cls, &hash, consumed_string, state->accepting,
                 num_edges, edges);
 
-      // Special case for regex consisting of just a string that is shorter than max_len
+      // Special case for regex consisting of just a string that is shorter than
+      // max_len
       if (GNUNET_YES == state->accepting && cur_len > 1 &&
-          state->transition_count < 1)
+          state->transition_count < 1 && cur_len < max_len)
       {
-        edges[0].label = &consumed_string[cur_len - 1];
-        edges[0].destination = state->hash;
+        edge[0].label = &consumed_string[cur_len - 1];
+        edge[0].destination = state->hash;
         temp = GNUNET_strdup (consumed_string);
         temp[cur_len - 1] = '\0';
-        GNUNET_CRYPTO_hash (temp, cur_len - 1, &hash);
-        iterator (iterator_cls, &hash, temp, GNUNET_NO, 1, edges);
+        GNUNET_CRYPTO_hash (temp, cur_len - 1, &hash_new);
+        iterator (iterator_cls, &hash_new, temp, GNUNET_NO, 1, edge);
         GNUNET_free (temp);
       }
     }
-    else
+    else if (max_len < cur_len)
     {
-      edges[0].label = &consumed_string[max_len];
-      edges[0].destination = state->hash;
+      edge[0].label = &consumed_string[max_len];
+      edge[0].destination = state->hash;
       temp = GNUNET_strdup (consumed_string);
       temp[max_len] = '\0';
       GNUNET_CRYPTO_hash (temp, max_len, &hash);
-      iterator (iterator_cls, &hash, temp, GNUNET_NO, 1, edges);
+      iterator (iterator_cls, &hash, temp, GNUNET_NO, 1, edge);
       GNUNET_free (temp);
     }
   }
@@ -2937,3 +2939,111 @@ GNUNET_REGEX_iterate_all_edges (struct GNUNET_REGEX_Automaton *a,
                         iterator_cls);
   iterate_edge (a->start, iterator, iterator_cls);
 }
+
+
+/**
+ * Create a string with binary IP notation for the given 'addr' in 'str'.
+ *
+ * @param af address family of the given 'addr'.
+ * @param addr address that should be converted to a string.
+ *             struct in_addr * for IPv4 and struct in6_addr * for IPv6.
+ * @param str string that will contain binary notation of 'addr'. Expected
+ *            to be at least 33 bytes long for IPv4 and 129 bytes long for IPv6.
+ */
+static void
+iptobinstr (const int af, const void *addr, char *str)
+{
+  unsigned int i;
+
+  switch (af)
+  {
+  case AF_INET:
+  {
+    uint32_t b = htonl (((struct in_addr *) addr)->s_addr);
+
+    str[32] = '\0';
+    str += 31;
+    for (i = 31; i >= 0; i--)
+    {
+      *str-- = (b & 1) + '0';
+      b >>= 1;
+    }
+    break;
+  }
+  case AF_INET6:
+  {
+    struct in6_addr b = *(struct in6_addr *) addr;
+
+    str[128] = '\0';
+    str += 127;
+    for (i = 127; i >= 0; i--)
+    {
+      *str-- = (b.s6_addr[i / 8] & 1) + '0';
+      b.s6_addr[i / 8] >>= 1;
+    }
+    break;
+  }
+  }
+}
+
+
+/**
+ * Get the ipv4 network prefix from the given 'netmask'.
+ *
+ * @param netmask netmask for which to get the prefix len.
+ *
+ * @return length of ipv4 prefix for 'netmask'.
+ */
+static unsigned int
+ipv4netmasktoprefixlen (const char *netmask)
+{
+  struct in_addr a;
+  unsigned int len;
+  uint32_t t;
+
+  if (1 != inet_pton (AF_INET, netmask, &a))
+    return 0;
+
+  for (len = 32, t = htonl (~a.s_addr); t & 1; t >>= 1, len--) ;
+
+  return len;
+}
+
+
+/**
+ * Create a regex in 'rxstr' from the given 'ip' and 'netmask'.
+ *
+ * @param ip IPv4 representation.
+ * @param netmask netmask for the ip.
+ * @param rxstr generated regex, must be at least GNUNET_REGEX_IPV4_REGEXLEN
+ *              bytes long.
+ */
+void
+GNUNET_REGEX_ipv4toregex (const struct in_addr *ip, const char *netmask,
+                          char *rxstr)
+{
+  unsigned int pfxlen;
+
+  pfxlen = ipv4netmasktoprefixlen (netmask);
+  iptobinstr (AF_INET, ip, rxstr);
+  rxstr[pfxlen] = '\0';
+  strcat (rxstr, "(0|1)*");
+}
+
+
+/**
+ * Create a regex in 'rxstr' from the given 'ipv6' and 'prefixlen'.
+ *
+ * @param ipv6 IPv6 representation.
+ * @param prefixlen length of the ipv6 prefix.
+ * @param rxstr generated regex, must be at least GNUNET_REGEX_IPV6_REGEXLEN
+ *              bytes long.
+ */
+void
+GNUNET_REGEX_ipv6toregex (const struct in6_addr *ipv6,
+                          const unsigned int prefixlen, char *rxstr)
+{
+  iptobinstr (AF_INET6, ipv6, rxstr);
+  rxstr[prefixlen] = '\0';
+  strcat (rxstr, "(0|1)*");
+}