diff --git a/configure.ac b/configure.ac index e19bd4a5..8188f1cd 100644 --- a/configure.ac +++ b/configure.ac @@ -1,406 +1,405 @@ # # Copyright (C) 2010-2015 Red Hat, Inc. All rights reserved. # # Authors: Fabio M. Di Nitto # Federico Simoncelli # # This software licensed under GPL-2.0+, LGPL-2.0+ # # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. # AC_PREREQ([2.63]) AC_INIT([kronosnet], m4_esyscmd([build-aux/git-version-gen .tarball-version]), [devel@lists.kronosnet.org]) AC_USE_SYSTEM_EXTENSIONS AM_INIT_AUTOMAKE([1.11.1 dist-bzip2 dist-xz color-tests -Wno-portability subdir-objects]) LT_PREREQ([2.2.6]) LT_INIT AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([kronosnetd/main.c]) AC_CONFIG_HEADERS([config.h]) AC_CANONICAL_HOST AC_PROG_LIBTOOL AC_LANG([C]) systemddir=${prefix}/lib/systemd/system if test "$prefix" = "NONE"; then prefix="/usr" if test "$localstatedir" = "\${prefix}/var"; then localstatedir="/var" fi if test "$sysconfdir" = "\${prefix}/etc"; then sysconfdir="/etc" fi if test "$systemddir" = "NONE/lib/systemd/system"; then systemddir=/lib/systemd/system fi if test "$libdir" = "\${exec_prefix}/lib"; then if test -e /usr/lib64; then libdir="/usr/lib64" else libdir="/usr/lib" fi fi fi # Checks for programs. if ! ${MAKE-make} --version /cannot/make/this >/dev/null 2>&1; then AC_MSG_ERROR(["you don't seem to have GNU make; it is required"]) fi AC_PROG_AWK AC_PROG_GREP AC_PROG_SED AC_PROG_CPP AC_PROG_CC AM_PROG_CC_C_O AC_PROG_LN_S AC_PROG_INSTALL AC_PROG_MAKE_SET AC_PROG_CXX AC_PROG_RANLIB AC_CHECK_PROGS([PUBLICAN], [publican], [:]) AC_CHECK_PROGS([PKGCONFIG], [pkg-config]) AC_ARG_ENABLE([poc], [ --enable-poc : build poc code ],, [ enable_poc="yes" ]) AM_CONDITIONAL([BUILD_POC], test x$enable_poc = xyes) AC_ARG_ENABLE([kronosnetd], [ --enable-kronosnetd : Kronosnetd support ],, [ enable_kronosnetd="no" ]) AM_CONDITIONAL([BUILD_KRONOSNETD], test x$enable_kronosnetd = xyes) AC_ARG_ENABLE([libtap], [ --enable-libtap : libtap support ],, [ enable_libtap="no" ]) if test "x$enable_kronosnetd" = xyes; then enable_libtap=yes fi AM_CONDITIONAL([BUILD_LIBTAP], test x$enable_libtap = xyes) AC_ARG_ENABLE([libknet-sctp], [ --enable-libknet-sctp : libknet SCTP support ],, [ enable_libknet_sctp="yes" ]) ## local helper functions # this function checks if CC support options passed as # args. Global CFLAGS are ignored during this test. cc_supports_flag() { saveCPPFLAGS="$CPPFLAGS" CPPFLAGS="$@" if echo $CC | grep -q clang; then CPPFLAGS="-Werror $CPPFLAGS" fi AC_MSG_CHECKING([whether $CC supports "$@"]) AC_PREPROC_IFELSE([AC_LANG_PROGRAM([])], [RC=0; AC_MSG_RESULT([yes])], [RC=1; AC_MSG_RESULT([no])]) CPPFLAGS="$saveCPPFLAGS" return $RC } # helper macro to check libs without adding them to LIBS check_lib_no_libs() { lib_no_libs_arg1=$1 shift lib_no_libs_arg2=$1 shift lib_no_libs_args=$@ AC_CHECK_LIB([$lib_no_libs_arg1], [$lib_no_libs_arg2],,, [$lib_no_libs_args]) LIBS=$ac_check_lib_save_LIBS } # Checks for C features AC_C_INLINE # Checks for libraries. AC_CHECK_LIB([pthread], [pthread_create]) AC_CHECK_LIB([m], [ceil]) AC_CHECK_LIB([rt], [clock_gettime]) PKG_CHECK_MODULES([nss],[nss]) # Checks for header files. AC_CHECK_HEADERS([fcntl.h]) AC_CHECK_HEADERS([stdlib.h]) AC_CHECK_HEADERS([string.h]) AC_CHECK_HEADERS([strings.h]) AC_CHECK_HEADERS([sys/ioctl.h]) AC_CHECK_HEADERS([syslog.h]) AC_CHECK_HEADERS([unistd.h]) AC_CHECK_HEADERS([netinet/in.h]) AC_CHECK_HEADERS([sys/socket.h]) AC_CHECK_HEADERS([arpa/inet.h]) AC_CHECK_HEADERS([netdb.h]) AC_CHECK_HEADERS([limits.h]) AC_CHECK_HEADERS([stdint.h]) AC_CHECK_HEADERS([sys/epoll.h]) if test "x$enable_libknet_sctp" = xyes; then AC_CHECK_HEADERS([netinet/sctp.h],, AC_MSG_ERROR(["missing required SCTP headers"])) fi # Checks for typedefs, structures, and compiler characteristics. AC_C_INLINE AC_TYPE_SIZE_T AC_TYPE_PID_T AC_TYPE_SSIZE_T AC_TYPE_UINT8_T AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_TYPE_INT32_T # Checks for library functions. AC_FUNC_ALLOCA AC_FUNC_FORK AC_FUNC_MALLOC AC_FUNC_REALLOC AC_CHECK_FUNCS([memset]) AC_CHECK_FUNCS([strdup]) AC_CHECK_FUNCS([strerror]) AC_CHECK_FUNCS([dup2]) AC_CHECK_FUNCS([select]) AC_CHECK_FUNCS([socket]) AC_CHECK_FUNCS([inet_ntoa]) AC_CHECK_FUNCS([memmove]) AC_CHECK_FUNCS([strchr]) AC_CHECK_FUNCS([atexit]) AC_CHECK_FUNCS([ftruncate]) AC_CHECK_FUNCS([strrchr]) AC_CHECK_FUNCS([strstr]) AC_CHECK_FUNCS([clock_gettime]) AC_CHECK_FUNCS([strcasecmp]) AC_CHECK_FUNCS([sendmmsg]) AC_CHECK_FUNCS([recvmmsg]) AC_CHECK_FUNCS([kevent]) # if neither sys/epoll.h nor kevent are present, we should fail. if test "x$ac_cv_header_sys_epoll_h" = xno && test "x$ac_cv_func_kevent" = xno; then AC_MSG_ERROR([Both epoll and kevent unavailable on this OS]) fi if test "x$ac_cv_header_sys_epoll_h" = xyes && test "x$ac_cv_func_kevent" = xyes; then AC_MSG_ERROR([Both epoll and kevent available on this OS, please contact the maintainers to fix the code]) fi # Check entries in specific structs AC_CHECK_MEMBER([struct mmsghdr.msg_hdr], [AC_DEFINE_UNQUOTED([HAVE_MMSGHDR], [1], [struct mmsghdr exists])], [], [[#include ]]) # checks (for kronosnetd) if test "x$enable_kronosnetd" = xyes; then AC_CHECK_HEADERS([security/pam_appl.h], [AC_CHECK_LIB([pam], [pam_start])], [AC_MSG_ERROR([Unable to find LinuxPAM devel files])]) AC_CHECK_HEADERS([security/pam_misc.h], [AC_CHECK_LIB([pam_misc], [misc_conv])], [AC_MSG_ERROR([Unable to find LinuxPAM MISC devel files])]) PKG_CHECK_MODULES([libqb], [libqb]) AC_CHECK_LIB([qb], [qb_log_thread_priority_set], [have_qb_log_thread_priority_set="yes"], [have_qb_log_thread_priority_set="no"]) if test "x${have_qb_log_thread_priority_set}" = xyes; then AC_DEFINE_UNQUOTED([HAVE_QB_LOG_THREAD_PRIORITY_SET], 1, [have qb_log_thread_priority_set]) fi fi # local options AC_ARG_ENABLE([debug], [ --enable-debug enable debug build. ], [ default="no" ]) AC_ARG_ENABLE([publicandocs], [ --enable-publicandocs enable docs build. ], [ default="no" ]) AC_ARG_WITH([initdefaultdir], [ --with-initdefaultdir : path to /etc/sysconfig/.. or /etc/default dir. ], [ INITDEFAULTDIR="$withval" ], [ INITDEFAULTDIR="$sysconfdir/default" ]) AC_ARG_WITH([initddir], [ --with-initddir=DIR : path to init script directory. ], [ INITDDIR="$withval" ], [ INITDDIR="$sysconfdir/init.d" ]) AC_ARG_WITH([systemddir], [ --with-systemddir=DIR : path to systemd unit files directory. ], [ SYSTEMDDIR="$withval" ], [ SYSTEMDDIR="$systemddir" ]) AC_ARG_WITH([syslogfacility], [ --with-syslogfacility=FACILITY default syslog facility. ], [ SYSLOGFACILITY="$withval" ], [ SYSLOGFACILITY="LOG_DAEMON" ]) AC_ARG_WITH([sysloglevel], [ --with-sysloglevel=LEVEL default syslog level. ], [ SYSLOGLEVEL="$withval" ], [ SYSLOGLEVEL="LOG_INFO" ]) AC_ARG_WITH([defaultadmgroup], [ --with-defaultadmgroup=GROUP define PAM group. Users part of this group will be allowed to configure kronosnet. Others will only receive read-only rights. ], [ DEFAULTADMGROUP="$withval" ], [ DEFAULTADMGROUP="kronosnetadm" ]) ## random vars LOGDIR=${localstatedir}/log/ RUNDIR=${localstatedir}/run/ DEFAULT_CONFIG_DIR=${sysconfdir}/kronosnet ## do subst AM_CONDITIONAL([BUILD_DOCS], [test "x${enable_publicandocs}" = xyes]) AM_CONDITIONAL([DEBUG], [test "x${enable_debug}" = xyes]) AC_SUBST([DEFAULT_CONFIG_DIR]) AC_SUBST([INITDEFAULTDIR]) AC_SUBST([INITDDIR]) AC_SUBST([SYSTEMDDIR]) AC_SUBST([LOGDIR]) AC_SUBST([DEFAULTADMGROUP]) AC_DEFINE_UNQUOTED([DEFAULT_CONFIG_DIR], ["$(eval echo ${DEFAULT_CONFIG_DIR})"], [Default config directory]) AC_DEFINE_UNQUOTED([DEFAULT_CONFIG_FILE], ["$(eval echo ${DEFAULT_CONFIG_DIR}/kronosnetd.conf)"], [Default config file]) AC_DEFINE_UNQUOTED([LOGDIR], ["$(eval echo ${LOGDIR})"], [Default logging directory]) AC_DEFINE_UNQUOTED([DEFAULT_LOG_FILE], ["$(eval echo ${LOGDIR}/kronosnetd.log)"], [Default log file]) AC_DEFINE_UNQUOTED([RUNDIR], ["$(eval echo ${RUNDIR})"], [Default run directory]) AC_DEFINE_UNQUOTED([SYSLOGFACILITY], [$(eval echo ${SYSLOGFACILITY})], [Default syslog facility]) AC_DEFINE_UNQUOTED([SYSLOGLEVEL], [$(eval echo ${SYSLOGLEVEL})], [Default syslog level]) AC_DEFINE_UNQUOTED([DEFAULTADMGROUP], ["$(eval echo ${DEFAULTADMGROUP})"], [Default admin group]) ## *FLAGS handling ENV_CFLAGS="$CFLAGS" ENV_CPPFLAGS="$CPPFLAGS" ENV_LDFLAGS="$LDFLAGS" # debug build stuff if test "x${enable_debug}" = xyes; then AC_DEFINE_UNQUOTED([DEBUG], [1], [Compiling Debugging code]) OPT_CFLAGS="-O0" else OPT_CFLAGS="-O3" fi # gdb flags if test "x${GCC}" = xyes; then GDB_FLAGS="-ggdb3" else GDB_FLAGS="-g" fi # extra warnings EXTRA_WARNINGS="" WARNLIST=" all shadow missing-prototypes missing-declarations strict-prototypes declaration-after-statement pointer-arith write-strings cast-align bad-function-cast missing-format-attribute format=2 format-security format-nonliteral no-long-long unsigned-char gnu89-inline no-strict-aliasing error address cpp overflow parentheses sequence-point switch uninitialized unused-but-set-variable unused-function unused-result unused-value unused-variable " for j in $WARNLIST; do if cc_supports_flag -W$j; then EXTRA_WARNINGS="$EXTRA_WARNINGS -W$j"; fi done CFLAGS="$ENV_CFLAGS $lt_prog_compiler_pic $OPT_CFLAGS $GDB_FLAGS \ $EXTRA_WARNINGS $WERROR_CFLAGS" CPPFLAGS="$ENV_CPPFLAGS" LDFLAGS="$ENV_LDFLAGS $lt_prog_compiler_pic -Wl,--as-needed" AC_CONFIG_FILES([ Makefile init/Makefile libtap/Makefile libtap/libtap.pc kronosnetd/Makefile kronosnetd/kronosnetd.logrotate libknet/Makefile libknet/libknet.pc libknet/tests/Makefile docs/Makefile poc-code/Makefile poc-code/iov-hash/Makefile poc-code/access-list/Makefile - poc-code/sctp-defrag-bug/Makefile ]) AC_OUTPUT diff --git a/poc-code/Makefile.am b/poc-code/Makefile.am index e0986523..4b12510e 100644 --- a/poc-code/Makefile.am +++ b/poc-code/Makefile.am @@ -1,13 +1,13 @@ # # Copyright (C) 2016 Red Hat, Inc. All rights reserved. # # Author: Fabio M. Di Nitto # # This software licensed under GPL-2.0+, LGPL-2.0+ # MAINTAINERCLEANFILES = Makefile.in include $(top_srcdir)/build-aux/check.mk -SUBDIRS = access-list iov-hash sctp-defrag-bug +SUBDIRS = access-list iov-hash diff --git a/poc-code/sctp-defrag-bug/Makefile.am b/poc-code/sctp-defrag-bug/Makefile.am deleted file mode 100644 index 0635e562..00000000 --- a/poc-code/sctp-defrag-bug/Makefile.am +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright (C) 2017 Red Hat, Inc. All rights reserved. -# -# Author: Fabio M. Di Nitto -# -# This software licensed under GPL-2.0+, LGPL-2.0+ -# - -MAINTAINERCLEANFILES = Makefile.in - -include $(top_srcdir)/build-aux/check.mk - -AM_CPPFLAGS = -I$(top_srcdir)/libknet - -# override global LIBS that pulls in lots of craft we don't need here -LIBS = -lz - -noinst_PROGRAMS = client server - -noinst_HEADERS = common.h - -server_SOURCES = server.c \ - common.c - -client_SOURCES = client.c \ - common.c diff --git a/poc-code/sctp-defrag-bug/client.c b/poc-code/sctp-defrag-bug/client.c deleted file mode 100644 index ecb4ced2..00000000 --- a/poc-code/sctp-defrag-bug/client.c +++ /dev/null @@ -1,215 +0,0 @@ -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_NETINET_SCTP_H -#include -#include "common.h" - -int main(int argc, char **argv) -{ - int err = 0; - int rv; - int enable_crc = 0; - char defport[8] = "50000"; - char *address = NULL, *port = NULL; - - struct sockaddr_storage ss; - int sock; - - int rx_epoll; - struct epoll_event ev; - struct epoll_event events[32]; - int i, nev; - - struct mmsghdr msg_in[256]; - - struct mmsghdr msg_out[256]; - struct iovec iov_out[256]; - - int sent_msgs; - - while ((rv = getopt(argc, argv, "a:p:c")) != EOF) { - switch(rv) { - case 'a': - address = optarg; - break; - case 'p': - port = optarg; - break; - case 'c': - enable_crc = 1; - break; - default: - fprintf(stderr, "Unknown option\n"); - return -1; - break; - } - } - - /* - * Setup RX buffers - */ - memset(&msg_in, 0, sizeof(struct mmsghdr)); - if (setup_rx_buffers(msg_in) < 0) { - return -1; - } - - /* - * setup TX buffers - */ - for (i = 0; i < 256; i++) { - iov_out[i].iov_base = (void *)malloc(65536); - if (!iov_out[i].iov_base) { - fprintf(stderr, "Unable to malloc RX buffers(%d): %s\n", - errno, strerror(errno)); - return -1; - } - if (enable_crc) { - unsigned int *dataint = (unsigned int *)iov_out[i].iov_base; - unsigned int crc; - int j; - - for (j=1; j<65536/sizeof(int); j++) { - dataint[j] = rand(); - } - crc = crc32(0, NULL, 0); - dataint[0] = crc32(crc, (Bytef*)&dataint[1], 65536-sizeof(int)); - } else { - memset(iov_out[i].iov_base, 0, 65536); - } - iov_out[i].iov_len = 65536; - } - - rx_epoll = epoll_create(32); - if (rx_epoll < 0) { - fprintf(stderr, "Unable to create rx_epoll (%d): %s\n", - errno, strerror(errno)); - return -1; - } - - /* - * setup SCTP client socket - */ - - if (!address) { - fprintf(stderr, "No server address specified (use -a ).\n"); - fprintf(stderr, "Scanning the internet for SCTP servers (this might take a while).\n"); - while (1) { - fprintf(stderr, "..."); - sleep(1); - } - } - - if (!port) { - port = defport; - } - - if (strtoaddr(address, port, &ss, sizeof(struct sockaddr_storage)) < 0) { - return -1; - } - - sock = socket(ss.ss_family, SOCK_STREAM, IPPROTO_SCTP); - if (sock < 0) { - fprintf(stderr, "unable to create socket (%d): %s\n", - errno, strerror(errno)); - return -1; - } - - if (setup_sctp_common_sock_opts(sock, &ss) < 0) { - fprintf(stderr, "Unable to set socket options\n"); - goto out; - } - - if (connect(sock, (struct sockaddr *)&ss, sizeof(struct sockaddr_storage)) < 0) { - if ((errno != EALREADY) && (errno != EINPROGRESS) && (errno != EISCONN)) { - fprintf(stderr, "Unable to connect to server: (%d): %s\n", - errno, strerror(errno)); - return -1; - } - } - - /* - * i am supposed to check SO_ERROR to see if it's connected, but this is a PoC - * and I am lazy - */ - - sleep(1); - - memset(&ev, 0, sizeof(struct epoll_event)); - ev.events = EPOLLIN; - ev.data.fd = sock; - if (epoll_ctl(rx_epoll, EPOLL_CTL_ADD, sock, &ev) < 0) { - fprintf(stderr, "Unable to add listen socket to epoll (%d): %s\n", - errno, strerror(errno)); - goto out; - } - - /* - * main loop - */ - - while(1) { - nev = epoll_wait(rx_epoll, events, 32, 0); - if (nev < 0) { - fprintf(stderr, "SCTP listen handler EPOLL ERROR (%d): %s\n", - errno, strerror(errno)); - } else { - for (i = 0; i < nev; i++) { - if (events[i].data.fd == sock) { - get_incoming_data(events[i].data.fd, msg_in, enable_crc); - } - } - } - - sleep(1); - - memset(&msg_out, 0, sizeof(msg_out)); - for (i = 0; i < 256; i++) { - memset(&msg_out[i].msg_hdr, 0, sizeof(struct msghdr)); - msg_out[i].msg_hdr.msg_name = &ss; - msg_out[i].msg_hdr.msg_namelen = sizeof(struct sockaddr_storage); - msg_out[i].msg_hdr.msg_iov = &iov_out[i]; - msg_out[i].msg_hdr.msg_iovlen = 1; - } - - sent_msgs = sendmmsg(sock, msg_out, 256, MSG_DONTWAIT | MSG_NOSIGNAL); - if (sent_msgs <= 0) { - fprintf(stderr, "Error sending msgs (%d): %s\n", - errno, strerror(errno)); - } - if (sent_msgs != 256) { - fprintf(stderr, "Unable to send all 256 messages at once (sent: %d)\n", - sent_msgs); - } - fprintf(stderr, "sent %d messages\n", sent_msgs); - } - -out: - if (sock >= 0) { - close(sock); - } - if (rx_epoll >= 0) { - close(rx_epoll); - } - - return err; -} -#else -int main(void) -{ - printf("SCTP unsupported in this build\n"); - errno = EINVAL; - return -1; -} -#endif diff --git a/poc-code/sctp-defrag-bug/common.c b/poc-code/sctp-defrag-bug/common.c deleted file mode 100644 index 432d53f0..00000000 --- a/poc-code/sctp-defrag-bug/common.c +++ /dev/null @@ -1,340 +0,0 @@ -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_NETINET_SCTP_H -#include -#include "common.h" - -int strtoaddr(const char *host, const char *port, struct sockaddr_storage *ss, socklen_t sslen) -{ - int err; - struct addrinfo hints; - struct addrinfo *result = NULL; - - if (!host) { - errno = EINVAL; - return -1; - } - - if (!port) { - errno = EINVAL; - return -1; - } - - if (!ss) { - errno = EINVAL; - return -1; - } - - if (!sslen) { - errno = EINVAL; - return -1; - } - - memset(&hints, 0, sizeof(struct addrinfo)); - - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV; - - err = getaddrinfo(host, port, &hints, &result); - - if (!err) { - memmove(ss, result->ai_addr, - (sslen < result->ai_addrlen) ? sslen : result->ai_addrlen); - - freeaddrinfo(result); - } - - return err; -} - -int _fdset_cloexec(int fd) -{ - int fdflags; - - fdflags = fcntl(fd, F_GETFD, 0); - if (fdflags < 0) - return -1; - - fdflags |= FD_CLOEXEC; - - if (fcntl(fd, F_SETFD, fdflags) < 0) - return -1; - - return 0; -} - -int _fdset_nonblock(int fd) -{ - int fdflags; - - fdflags = fcntl(fd, F_GETFL, 0); - if (fdflags < 0) - return -1; - - fdflags |= O_NONBLOCK; - - if (fcntl(fd, F_SETFL, fdflags) < 0) - return -1; - - return 0; -} - -int setup_sctp_common_sock_opts(int sock, struct sockaddr_storage *ss) -{ - struct sctp_event_subscribe events; - int value; - - if (_fdset_cloexec(sock)) { - fprintf(stderr, "unable to set CLOEXEC socket opts (%d): %s\n", - errno, strerror(errno)); - return -1; - } - - if (_fdset_nonblock(sock)) { - fprintf(stderr, "unable to set NONBLOCK socket opts (%d): %s\n", - errno, strerror(errno)); - return -1; - } - - value = 8388608; - if (setsockopt(sock, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0) { - fprintf(stderr, "Unable to set receive buffer (%d): %s\n", - errno, strerror(errno)); - return -1; - } - - value = 8388608; - if (setsockopt(sock, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0) { - fprintf(stderr, "Unable to set send buffer (%d): %s\n", - errno, strerror(errno)); - return -1; - } - - if (ss->ss_family == AF_INET6) { - value = IPV6_PMTUDISC_PROBE; - if (setsockopt(sock, SOL_IPV6, IPV6_MTU_DISCOVER, &value, sizeof(value)) <0) { - fprintf(stderr, "Unable to set PMTUDISC (%d): %s\n", - errno, strerror(errno)); - return -1; - } - } else { - value = IP_PMTUDISC_PROBE; - if (setsockopt(sock, SOL_IP, IP_MTU_DISCOVER, &value, sizeof(value)) <0) { - fprintf(stderr, "Unable to set PMTUDISC (%d): %s\n", - errno, strerror(errno)); - return -1; - } - } - - value = 1; - if (setsockopt(sock, SOL_SCTP, SCTP_NODELAY, &value, sizeof(value)) < 0) { - fprintf(stderr, "Unable to set SCTP_NODELAY (%d): %s\n", - errno, strerror(errno)); - return -1; - } - -#if 0 /* workaround */ - value = 1; - if (setsockopt(sock, SOL_SCTP, SCTP_DISABLE_FRAGMENTS, &value, sizeof(value)) < 0) { - fprintf(stderr, "Unable to set SCTP_DISABLE_FRAGMENTS (%d): %s\n", - errno, strerror(errno)); - return -1; - } -#endif - - memset(&events, 0, sizeof (events)); - events.sctp_data_io_event = 1; - events.sctp_association_event = 1; - events.sctp_send_failure_event = 1; - events.sctp_address_event = 1; - events.sctp_peer_error_event = 1; - events.sctp_shutdown_event = 1; - if (setsockopt(sock, IPPROTO_SCTP, SCTP_EVENTS, &events, sizeof (events)) < 0) { - fprintf(stderr, "Unable to configure SCTP notifications (%d): %s\n", - errno, strerror(errno)); - return -1; - } - - return 0; -} - -int setup_sctp_server_sock_opts(int sock, struct sockaddr_storage *ss) -{ - int value; - - if (setup_sctp_common_sock_opts(sock, ss) < 0) { - return -1; - } - - value = 1; - if (setsockopt(sock, SOL_IP, IP_FREEBIND, &value, sizeof(value)) <0) { - fprintf(stderr, "Unable to set FREEBIND (%d): %s\n", - errno, strerror(errno)); - return -1; - } - - if (ss->ss_family == AF_INET6) { - value = 1; - if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, - &value, sizeof(value)) < 0) { - fprintf(stderr, "Unable to set IPv6 only (%d): %s\n", - errno, strerror(errno)); - return -1; - } - } - - value = 1; - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value)) < 0) { - fprintf(stderr, "Unable to set REUSEADDR (%d): %s\n", - errno, strerror(errno)); - return -1; - } - - return 0; -} - -static int fragsize = 0; - -static void parse_incoming_data(struct mmsghdr msg, int check_crc) -{ - int i; - struct iovec *iov = msg.msg_hdr.msg_iov; - size_t iovlen = msg.msg_hdr.msg_iovlen; - unsigned int crc; - unsigned int *data = msg.msg_hdr.msg_iov->iov_base; - size_t datalen = msg.msg_len; - union sctp_notification *snp; - - if (!(msg.msg_hdr.msg_flags & MSG_NOTIFICATION)) { - if (msg.msg_len == 0) { - fprintf(stderr, "Received 0bytes packet\n"); - exit(-1); - } - if (!(msg.msg_hdr.msg_flags & MSG_EOR)) { - fprintf(stderr, "got a fragment size: %d\n", msg.msg_len); - fragsize = fragsize + msg.msg_len; - return; - } - if (fragsize) { - fragsize = fragsize + msg.msg_len; - fprintf(stderr, "Received all packets from frags: %d\n", fragsize); - if (fragsize != 65536) { - fprintf(stderr, "KABOOM: %d\n", msg.msg_len); - exit(-1); - } - fragsize = 0; - } else { - /* check pckt len here */ - if (msg.msg_len != 65536) { - fprintf(stderr, "KABOOM: %d\n", msg.msg_len); - exit(-1); - } - if (check_crc) { - crc = crc32(0, NULL, 0); - crc = crc32(crc, (Bytef *)&data[1], datalen - sizeof(unsigned int)) & 0xFFFFFFFF; - if (crc != data[0]) { - fprintf(stderr, "KABOOM - CRCs do not match\n"); - exit(-1); - } - } - } - return; - } - - if (!(msg.msg_hdr.msg_flags & MSG_EOR)) { - fprintf(stderr, "[event] end of notifications\n"); - return; - } - - /* got a notification */ - for (i=0; i< iovlen; i++) { - snp = iov[i].iov_base; - - switch (snp->sn_header.sn_type) { - case SCTP_ASSOC_CHANGE: - fprintf(stderr, "[event] sctp assoc change\n"); - break; - case SCTP_SHUTDOWN_EVENT: - fprintf(stderr, "[event] sctp shutdown event\n"); - break; - case SCTP_SEND_FAILED: - fprintf(stderr, "[event] sctp send failed\n"); - break; - case SCTP_PEER_ADDR_CHANGE: - fprintf(stderr, "[event] sctp peer addr change\n"); - break; - case SCTP_REMOTE_ERROR: - fprintf(stderr, "[event] sctp remote error\n"); - break; - default: - fprintf(stderr, "[event] unknown sctp event type: %hu\n", snp->sn_header.sn_type); - exit(-1); - break; - } - } - return; -} - -void get_incoming_data(int sock, struct mmsghdr *msg, int check_crc) -{ - int i, msg_recv; - - msg_recv = recvmmsg(sock, msg, 256, MSG_DONTWAIT | MSG_NOSIGNAL, NULL); - - if (msg_recv <= 0) { - fprintf(stderr, "Error message received from recvmmsg (%d): %s\n", - errno, strerror(errno)); - exit(-1); - } - - fprintf(stderr, "Received: %d messages\n", msg_recv); - - for (i = 0; i < msg_recv; i++) { - parse_incoming_data(msg[i], check_crc); - } -} - -int setup_rx_buffers(struct mmsghdr *msg) -{ - int i; - struct sockaddr_storage addr[256]; - struct iovec iov_in[256]; - - if (!msg) { - return -1; - } - - /* - * Setup buffers - */ - for (i = 0; i < 256; i++) { - iov_in[i].iov_base = (void *)malloc(65536); - if (!iov_in[i].iov_base) { - fprintf(stderr, "Unable to malloc RX buffers(%d): %s\n", - errno, strerror(errno)); - return -1; - } - memset(iov_in[i].iov_base, 0, 65536); - iov_in[i].iov_len = 65536; - memset(&msg[i].msg_hdr, 0, sizeof(struct msghdr)); - msg[i].msg_hdr.msg_name = &addr[i]; - msg[i].msg_hdr.msg_namelen = sizeof(struct sockaddr_storage); - msg[i].msg_hdr.msg_iov = &iov_in[i]; - msg[i].msg_hdr.msg_iovlen = 1; - } - return 0; -} -#endif diff --git a/poc-code/sctp-defrag-bug/common.h b/poc-code/sctp-defrag-bug/common.h deleted file mode 100644 index a82299f4..00000000 --- a/poc-code/sctp-defrag-bug/common.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2017 Red Hat, Inc. All rights reserved. - * - * Authors: Fabio M. Di Nitto - * - * This software licensed under GPL-2.0+, LGPL-2.0+ - */ - -#ifndef __COMMON_H__ -#define __COMMON_H__ - -int strtoaddr(const char *host, const char *port, struct sockaddr_storage *ss, socklen_t sslen); -int _fdset_cloexec(int fd); -int _fdset_nonblock(int fd); -int setup_sctp_common_sock_opts(int sock, struct sockaddr_storage *ss); -int setup_sctp_server_sock_opts(int sock, struct sockaddr_storage *ss); -void get_incoming_data(int sock, struct mmsghdr *msg, int check_crc); -int setup_rx_buffers(struct mmsghdr *msg); - -#endif diff --git a/poc-code/sctp-defrag-bug/server.c b/poc-code/sctp-defrag-bug/server.c deleted file mode 100644 index 7918f3e1..00000000 --- a/poc-code/sctp-defrag-bug/server.c +++ /dev/null @@ -1,172 +0,0 @@ -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_NETINET_SCTP_H -#include -#include "common.h" - -int main(int argc, char **argv) -{ - int err = 0; - int rv; - int check_crc = 0; - char defaddr[8] = "0.0.0.0"; - char defport[8] = "50000"; - char *address = NULL, *port = NULL; - - struct sockaddr_storage ss, newss; - int sock, newsock; - socklen_t sock_len = sizeof(ss); - - int rx_epoll; - struct epoll_event ev; - struct epoll_event events[32]; - int i, nev; - - struct mmsghdr msg[256]; - - while ((rv = getopt(argc, argv, "a:p:c")) != EOF) { - switch(rv) { - case 'a': - address = optarg; - break; - case 'p': - port = optarg; - break; - case 'c': - check_crc = 1; - break; - default: - fprintf(stderr, "Unknown option\n"); - return -1; - break; - } - } - - memset(&msg, 0, sizeof(msg)); - if (setup_rx_buffers(msg) < 0) { - return -1; - } - - rx_epoll = epoll_create(32); - if (rx_epoll < 0) { - fprintf(stderr, "Unable to create rx_epoll (%d): %s\n", - errno, strerror(errno)); - return -1; - } - - /* - * setup SCTP server socket - */ - - if (!address) { - address = defaddr; - } - if (!port) { - port = defport; - } - - if (strtoaddr(address, port, &ss, sizeof(struct sockaddr_storage)) < 0) { - return -1; - } - - sock = socket(ss.ss_family, SOCK_STREAM, IPPROTO_SCTP); - if (sock < 0) { - fprintf(stderr, "unable to create socket (%d): %s\n", - errno, strerror(errno)); - return -1; - } - - if (setup_sctp_server_sock_opts(sock, &ss) < 0) { - fprintf(stderr, "Unable to set socket options\n"); - goto out; - } - - if (bind(sock, (struct sockaddr *)&ss, sizeof(struct sockaddr_storage)) < 0) { - fprintf(stderr, "Unable to bind socket (%d): %s\n", - errno, strerror(errno)); - goto out; - } - - if (listen(sock, 5) < 0) { - fprintf(stderr, "Unable to listen socket (%d): %s\n", - errno, strerror(errno)); - goto out; - } - - memset(&ev, 0, sizeof(struct epoll_event)); - ev.events = EPOLLIN; - ev.data.fd = sock; - if (epoll_ctl(rx_epoll, EPOLL_CTL_ADD, sock, &ev) < 0) { - fprintf(stderr, "Unable to add listen socket to epoll (%d): %s\n", - errno, strerror(errno)); - goto out; - } - - /* - * main loop - */ - - while(1) { - nev = epoll_wait(rx_epoll, events, 32, -1); - if (nev < 0) { - fprintf(stderr, "SCTP listen handler EPOLL ERROR (%d): %s\n", - errno, strerror(errno)); - } - - for (i = 0; i < nev; i++) { - if (events[i].data.fd == sock) { - newsock = accept(sock, (struct sockaddr *)&newss, &sock_len); - if (newsock < 0) { - fprintf(stderr, "Error accepting connection (%d): %s\n", - errno, strerror(errno)); - continue; - } - if (setup_sctp_common_sock_opts(newsock, &newss) < 0) { - fprintf(stderr, "Error setting sockopts\n"); - close(newsock); - continue; - } - memset(&ev, 0, sizeof(struct epoll_event)); - ev.events = EPOLLIN; - ev.data.fd = newsock; - if (epoll_ctl(rx_epoll, EPOLL_CTL_ADD, newsock, &ev) < 0) { - fprintf(stderr, "Unable to add accept new connection (%d): %s\n", - errno, strerror(errno)); - close(newsock); - } - fprintf(stderr, "Accepted socket: %d\n", newsock); - } else { - get_incoming_data(events[i].data.fd, msg, check_crc); - } - } - } - -out: - if (sock >= 0) { - close(sock); - } - if (rx_epoll >= 0) { - close(rx_epoll); - } - - return err; -} -#else -int main(void) -{ - printf("SCTP unsupported in this build\n"); - errno = EINVAL; - return -1; -} -#endif