aboutgitcodebugslistschat
path: root/inany.c
diff options
context:
space:
mode:
Diffstat (limited to 'inany.c')
-rw-r--r--inany.c78
1 files changed, 75 insertions, 3 deletions
diff --git a/inany.c b/inany.c
index 7680439..2a586ed 100644
--- a/inany.c
+++ b/inany.c
@@ -11,6 +11,7 @@
#include <assert.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <errno.h>
#include "util.h"
#include "ip.h"
@@ -21,8 +22,27 @@
const union inany_addr inany_loopback4 = INANY_INIT4(IN4ADDR_LOOPBACK_INIT);
const union inany_addr inany_any4 = INANY_INIT4(IN4ADDR_ANY_INIT);
+/** inany_matches - Do two addresses match?
+ * @a, @b: IPv[46] addresses (NULL for 0.0.0.0 & ::)
+ *
+ * Return: true if they match, false otherwise
+ *
+ * Addresses match themselves, but also unspecified addresses of the same
+ * family.
+ */
+bool inany_matches(const union inany_addr *a, const union inany_addr *b)
+{
+ if (!a || !b)
+ return true;
+
+ if (inany_is_unspecified(a) || inany_is_unspecified(b))
+ return !!inany_v4(a) == !!inany_v4(b);
+
+ return inany_equals(a, b);
+}
+
/** inany_ntop - Convert an IPv[46] address to text format
- * @src: IPv[46] address
+ * @src: IPv[46] address (NULL for unspecified)
* @dst: output buffer, minimum INANY_ADDRSTRLEN bytes
* @size: size of buffer at @dst
*
@@ -30,9 +50,12 @@ const union inany_addr inany_any4 = INANY_INIT4(IN4ADDR_ANY_INIT);
*/
const char *inany_ntop(const union inany_addr *src, char *dst, socklen_t size)
{
- const struct in_addr *v4 = inany_v4(src);
+ const struct in_addr *v4;
- if (v4)
+ if (!src)
+ return strncpy(dst, "*", size);
+
+ if ((v4 = inany_v4(src)))
return inet_ntop(AF_INET, v4, dst, size);
return inet_ntop(AF_INET6, &src->a6, dst, size);
@@ -57,3 +80,52 @@ int inany_pton(const char *src, union inany_addr *dst)
return 0;
}
+
+/**
+ * inany_prefix_pton() - Parse an IPv[46] address with prefix length
+ * @src: IPv[46] address and prefix length string in CIDR format
+ * @dst: Output buffer, filled with parsed address
+ * @prefix_len: Prefix length, to be filled in IPv6 format
+ *
+ * Return: 1 on success, 0 if no parseable address or prefix is found
+ */
+int inany_prefix_pton(const char *src, union inany_addr *dst,
+ uint8_t *prefix_len)
+{
+ char astr[INANY_ADDRSTRLEN] = { 0 };
+ size_t alen = strcspn(src, "/");
+ const char *pstr = &src[alen + 1];
+ unsigned long plen;
+ char *end;
+
+ if (alen >= INANY_ADDRSTRLEN)
+ return 0;
+
+ if (src[alen] != '/')
+ return 0;
+
+ strncpy(astr, src, alen);
+
+ /* Read prefix length */
+ errno = 0;
+ plen = strtoul(pstr, &end, 10);
+ if (errno || *end || plen > 128)
+ return 0;
+
+ /* Read address */
+ if (inet_pton(AF_INET6, astr, dst)) {
+ if (inany_v4(dst) && plen < 96)
+ return 0;
+ *prefix_len = plen;
+ return 1;
+ }
+
+ if (inany_pton(astr, dst)) {
+ if (plen > 32)
+ return 0;
+ *prefix_len = plen + 96;
+ return 1;
+ }
+
+ return 0;
+}