From 47b4e499e25f89ff69aeb8bfa0134ff289c676b3 Mon Sep 17 00:00:00 2001
From: Jan Vcelak <jan.vcelak@nic.cz>
Date: Tue, 9 Feb 2016 18:26:34 +0100
Subject: [PATCH] sockaddr: add sockaddr_is_any() interface

---
 Knot.files             |  1 +
 src/contrib/sockaddr.c | 19 +++++++++++++++
 src/contrib/sockaddr.h |  8 ++++++-
 tests/.gitignore       |  1 +
 tests/Makefile.am      |  1 +
 tests/sockaddr.c       | 54 ++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 83 insertions(+), 1 deletion(-)
 create mode 100644 tests/sockaddr.c

diff --git a/Knot.files b/Knot.files
index 65b4712014..dd77c651d5 100644
--- a/Knot.files
+++ b/Knot.files
@@ -526,6 +526,7 @@ tests/rrl.c
 tests/rrset.c
 tests/rrset_wire.c
 tests/server.c
+tests/sockaddr.c
 tests/test_conf.h
 tests/tsig_key.c
 tests/wire.c
diff --git a/src/contrib/sockaddr.c b/src/contrib/sockaddr.c
index a571e0c7a0..f6ecd59af8 100644
--- a/src/contrib/sockaddr.c
+++ b/src/contrib/sockaddr.c
@@ -240,3 +240,22 @@ char *sockaddr_hostname(void)
 	freeaddrinfo(info);
 	return hname;
 }
+
+bool sockaddr_is_any(const struct sockaddr_storage *ss)
+{
+	if (ss == NULL) {
+		return false;
+	}
+
+	if (ss->ss_family == AF_INET) {
+		const struct sockaddr_in *sa = (struct sockaddr_in *)ss;
+		return sa->sin_addr.s_addr == INADDR_ANY;
+	}
+
+	if (ss->ss_family == AF_INET6) {
+		const struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)ss;
+		return memcmp(&sa6->sin6_addr, &in6addr_any, sizeof(sa6->sin6_addr)) == 0;
+	}
+
+	return false;
+}
diff --git a/src/contrib/sockaddr.h b/src/contrib/sockaddr.h
index 9a2c0ea678..ede9a58382 100644
--- a/src/contrib/sockaddr.h
+++ b/src/contrib/sockaddr.h
@@ -29,8 +29,9 @@
 #define __POSIX_VISIBLE = 200112
 #endif
 
-#include <sys/types.h>
+#include <stdbool.h>
 #include <sys/socket.h>
+#include <sys/types.h>
 #include <sys/un.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
@@ -132,4 +133,9 @@ void sockaddr_port_set(struct sockaddr_storage *ss, uint16_t port);
  */
 char *sockaddr_hostname(void);
 
+/*!
+ * \brief Check if address is ANY address.
+ */
+bool sockaddr_is_any(const struct sockaddr_storage *ss);
+
 /*! @} */
diff --git a/tests/.gitignore b/tests/.gitignore
index 3f188dfb72..a45978541b 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -43,6 +43,7 @@ rrl
 rrset
 rrset_wire
 server
+sockaddr
 tsig_key
 wire
 wire_ctx
diff --git a/tests/Makefile.am b/tests/Makefile.am
index df890a1ec1..0147745fe6 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -46,6 +46,7 @@ check_PROGRAMS = \
 	rrset				\
 	rrset_wire			\
 	server				\
+	sockaddr			\
 	tsig_key			\
 	wire				\
 	wire_ctx			\
diff --git a/tests/sockaddr.c b/tests/sockaddr.c
new file mode 100644
index 0000000000..665a922567
--- /dev/null
+++ b/tests/sockaddr.c
@@ -0,0 +1,54 @@
+/*  Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program 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 General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <tap/basic.h>
+
+#include "contrib/sockaddr.h"
+
+static void test_sockaddr_is_any(void)
+{
+	struct sockaddr_storage invalid = { 0 };
+	ok(!sockaddr_is_any(&invalid), "sockaddr_is_any: invalid");
+
+	struct sockaddr_storage path = { 0 };
+	path.ss_family = AF_UNIX;
+	ok(!sockaddr_is_any(&path), "sockaddr_is_any: unix");
+
+	struct sockaddr_storage ipv4_local = { 0 };
+	sockaddr_set(&ipv4_local, AF_INET, "127.0.0.1", 0);
+	ok(!sockaddr_is_any(&ipv4_local), "sockaddr_is_any: IPv4 local");
+
+	struct sockaddr_storage ipv4_any = { 0 };
+	sockaddr_set(&ipv4_any, AF_INET, "0.0.0.0", 0);
+	ok(sockaddr_is_any(&ipv4_any), "sockaddr_is_any: IPv4 any");
+
+	struct sockaddr_storage ipv6_local = { 0 };
+	sockaddr_set(&ipv6_local, AF_INET6, "::1", 0);
+	ok(!sockaddr_is_any(&ipv6_local), "sockaddr_is_any: IPv6 local");
+
+	struct sockaddr_storage ipv6_any = { 0 };
+	sockaddr_set(&ipv6_any, AF_INET6, "::", 0);
+	ok(sockaddr_is_any(&ipv6_any), "sockaddr_is_any: IPv6 any");
+}
+
+int main(int argc, char *argv[])
+{
+	plan_lazy();
+
+	test_sockaddr_is_any();
+
+	return 0;
+}
-- 
GitLab