diff --git a/Makefile b/Makefile index 7649998df..48c595511 100644 --- a/Makefile +++ b/Makefile @@ -820,7 +820,7 @@ OBJS = src/mux_fcgi.o src/mux_h1.o src/mux_h2.o src/backend.o \ 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 000000000..814ae5839 --- /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 +#include + +#include + +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 000000000..867ea256a --- /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 +#include + +#include + +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 000000000..21a024ab4 --- /dev/null +++ b/src/sock_inet.c @@ -0,0 +1,77 @@ +/* + * AF_INET/AF_INET6 socket management + * + * Copyright 2000-2020 Willy Tarreau + * + * 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 + +#include +#include +#include + +#include +#include + +#include +#include +#include + + +/* 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 000000000..c4314d2e7 --- /dev/null +++ b/src/sock_unix.c @@ -0,0 +1,99 @@ +/* + * SOCK_UNIX socket management + * + * Copyright 2000-2020 Willy Tarreau + * + * 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 +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +/* 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; +}