MINOR: sock: introduce sock_inet and sock_unix
These files will regroup everything specific to AF_INET, AF_INET6 and
AF_UNIX socket definitions and address management. Some code there might
be agnostic to the socket type and could later move to af_xxxx.c but for
now we only support regular sockets so no need to go too far.
The files are quite poor at this step, they only contain the address
comparison function for each address family.
diff --git a/Makefile b/Makefile
index 7649998..48c5955 100644
--- a/Makefile
+++ b/Makefile
@@ -820,7 +820,7 @@
src/eb64tree.o src/dict.o src/shctx.o src/ebimtree.o \
src/eb32tree.o src/ebtree.o src/dgram.o src/proto_udp.o \
src/hpack-huff.o src/cfgparse-tcp.o src/base64.o src/version.o \
- src/cfgparse-unix.o src/sock.o
+ src/cfgparse-unix.o src/sock.o src/sock_inet.o src/sock_unix.o
ifneq ($(TRACE),)
OBJS += src/calltrace.o
diff --git a/include/haproxy/sock_inet.h b/include/haproxy/sock_inet.h
new file mode 100644
index 0000000..814ae58
--- /dev/null
+++ b/include/haproxy/sock_inet.h
@@ -0,0 +1,33 @@
+/*
+ * include/haproxy/sock_inet.h
+ * This file contains declarations for AF_INET & AF_INET6 sockets.
+ *
+ * Copyright (C) 2000-2020 Willy Tarreau - w@1wt.eu
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, version 2.1
+ * exclusively.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _HAPROXY_SOCK_INET_H
+#define _HAPROXY_SOCK_INET_H
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <haproxy/api.h>
+
+int sock_inet4_addrcmp(const struct sockaddr_storage *a, const struct sockaddr_storage *b);
+int sock_inet6_addrcmp(const struct sockaddr_storage *a, const struct sockaddr_storage *b);
+
+#endif /* _HAPROXY_SOCK_INET_H */
diff --git a/include/haproxy/sock_unix.h b/include/haproxy/sock_unix.h
new file mode 100644
index 0000000..867ea25
--- /dev/null
+++ b/include/haproxy/sock_unix.h
@@ -0,0 +1,32 @@
+/*
+ * include/haproxy/sock_unix.h
+ * This file contains declarations for AF_UNIX sockets.
+ *
+ * Copyright (C) 2000-2020 Willy Tarreau - w@1wt.eu
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, version 2.1
+ * exclusively.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _HAPROXY_SOCK_UNIX_H
+#define _HAPROXY_SOCK_UNIX_H
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <haproxy/api.h>
+
+int sock_unix_addrcmp(const struct sockaddr_storage *a, const struct sockaddr_storage *b);
+
+#endif /* _HAPROXY_SOCK_UNIX_H */
diff --git a/src/sock_inet.c b/src/sock_inet.c
new file mode 100644
index 0000000..21a024a
--- /dev/null
+++ b/src/sock_inet.c
@@ -0,0 +1,77 @@
+/*
+ * AF_INET/AF_INET6 socket management
+ *
+ * Copyright 2000-2020 Willy Tarreau <w@1wt.eu>
+ *
+ * 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
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <string.h>
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <netinet/tcp.h>
+#include <netinet/in.h>
+
+#include <haproxy/api.h>
+#include <haproxy/sock_inet.h>
+#include <haproxy/tools.h>
+
+
+/* PLEASE NOTE for function below:
+ * - sock_inet4_* is solely for AF_INET (IPv4)
+ * - sock_inet6_* is solely for AF_INET6 (IPv6)
+ * - sock_inet_* is for either
+ *
+ * The address family SHOULD always be checked. In some cases a function will
+ * be used in a situation where the address family is guaranteed (e.g. protocol
+ * definitions), so the test may be avoided. This special case must then be
+ * mentioned in the comment before the function definition.
+ */
+
+
+/* Compares two AF_INET sockaddr addresses. Returns 0 if they match or non-zero
+ * if they do not match.
+ */
+int sock_inet4_addrcmp(const struct sockaddr_storage *a, const struct sockaddr_storage *b)
+{
+ const struct sockaddr_in *a4 = (const struct sockaddr_in *)a;
+ const struct sockaddr_in *b4 = (const struct sockaddr_in *)b;
+
+ if (a->ss_family != b->ss_family)
+ return -1;
+
+ if (a->ss_family != AF_INET)
+ return -1;
+
+ if (a4->sin_port != b4->sin_port)
+ return -1;
+
+ return memcmp(&a4->sin_addr, &b4->sin_addr, sizeof(a4->sin_addr));
+}
+
+/* Compares two AF_INET6 sockaddr addresses. Returns 0 if they match or
+ * non-zero if they do not match.
+ */
+int sock_inet6_addrcmp(const struct sockaddr_storage *a, const struct sockaddr_storage *b)
+{
+ const struct sockaddr_in6 *a6 = (const struct sockaddr_in6 *)a;
+ const struct sockaddr_in6 *b6 = (const struct sockaddr_in6 *)b;
+
+ if (a->ss_family != b->ss_family)
+ return -1;
+
+ if (a->ss_family != AF_INET6)
+ return -1;
+
+ if (a6->sin6_port != b6->sin6_port)
+ return -1;
+
+ return memcmp(&a6->sin6_addr, &b6->sin6_addr, sizeof(a6->sin6_addr));
+}
diff --git a/src/sock_unix.c b/src/sock_unix.c
new file mode 100644
index 0000000..c4314d2
--- /dev/null
+++ b/src/sock_unix.c
@@ -0,0 +1,99 @@
+/*
+ * SOCK_UNIX socket management
+ *
+ * Copyright 2000-2020 Willy Tarreau <w@1wt.eu>
+ *
+ * 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
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <ctype.h>
+#include <string.h>
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+
+#include <haproxy/api.h>
+#include <haproxy/listener.h>
+#include <haproxy/namespace.h>
+#include <haproxy/sock_unix.h>
+#include <haproxy/tools.h>
+
+
+/* PLEASE NOTE for functions below:
+ *
+ * The address family SHOULD always be checked. In some cases a function will
+ * be used in a situation where the address family is guaranteed (e.g. protocol
+ * definitions), so the test may be avoided. This special case must then be
+ * mentioned in the comment before the function definition.
+ */
+
+
+/* Compares two AF_UNIX sockaddr addresses. Returns 0 if they match or non-zero
+ * if they do not match. It also supports ABNS socket addresses (those starting
+ * with \0). For regular UNIX sockets however, this does explicitly support
+ * matching names ending exactly with .XXXXX.tmp which are newly bound sockets
+ * about to be replaced; this suffix is then ignored. Note that our UNIX socket
+ * paths are always zero-terminated.
+ */
+int sock_unix_addrcmp(const struct sockaddr_storage *a, const struct sockaddr_storage *b)
+{
+ const struct sockaddr_un *au = (const struct sockaddr_un *)a;
+ const struct sockaddr_un *bu = (const struct sockaddr_un *)b;
+ int idx, dot, idx2;
+
+ if (a->ss_family != b->ss_family)
+ return -1;
+
+ if (a->ss_family != AF_UNIX)
+ return -1;
+
+ if (au->sun_path[0] != bu->sun_path[0])
+ return -1;
+
+ if (au->sun_path[0] == 0)
+ return memcmp(au->sun_path, bu->sun_path, sizeof(au->sun_path));
+
+ idx = 1; dot = 0;
+ while (au->sun_path[idx] == bu->sun_path[idx]) {
+ if (au->sun_path[idx] == 0)
+ return 0;
+ if (au->sun_path[idx] == '.')
+ dot = idx;
+ idx++;
+ }
+
+ /* Now we have a difference. It's OK if they are within or after a
+ * sequence of digits following a dot, and are followed by ".tmp".
+ */
+ if (!dot)
+ return -1;
+
+ /* First, check in path "a" */
+ if (au->sun_path[idx] != 0) {
+ for (idx2 = dot + 1; idx2 && isdigit(au->sun_path[idx2]);)
+ idx2++;
+ if (strcmp(au->sun_path + idx2, ".tmp") != 0)
+ return -1;
+ }
+
+ /* Then check in path "b" */
+ if (bu->sun_path[idx] != 0) {
+ for (idx2 = dot + 1; idx2 && isdigit(bu->sun_path[idx2]); idx2++)
+ ;
+ if (strcmp(bu->sun_path + idx2, ".tmp") != 0)
+ return -1;
+ }
+
+ /* OK that's a match */
+ return 0;
+}