diff --git a/security/openvpn/Makefile b/security/openvpn/Makefile index 7c44e64f7dba..44f30253b5b2 100644 --- a/security/openvpn/Makefile +++ b/security/openvpn/Makefile @@ -1,172 +1,172 @@ PORTNAME= openvpn DISTVERSION= 2.6.14 -PORTREVISION?= 1 +PORTREVISION?= 2 CATEGORIES= security net net-vpn MASTER_SITES= https://swupdate.openvpn.org/community/releases/ \ https://build.openvpn.net/downloads/releases/ \ LOCAL/mandree MAINTAINER= mandree@FreeBSD.org COMMENT?= Secure IP/Ethernet tunnel daemon WWW= https://openvpn.net/community/ LICENSE= GPLv2 LICENSE_FILE= ${WRKSRC}/COPYRIGHT.GPL BUILD_DEPENDS+= cmocka>=0:sysutils/cmocka \ rst2man:textproc/py-docutils@${PY_FLAVOR} USES= cpe libtool localbase:ldflags pkgconfig python:build shebangfix ssl USE_RC_SUBR= openvpn SHEBANG_FILES= sample/sample-scripts/auth-pam.pl \ sample/sample-scripts/totpauth.py \ sample/sample-scripts/ucn.pl \ sample/sample-scripts/verify-cn GNU_CONFIGURE= yes GNU_CONFIGURE_MANPREFIX= ${PREFIX}/share CONFIGURE_ARGS+= --enable-strict --with-crypto-library=openssl # set PLUGIN_LIBDIR so that unqualified plugin paths are found: CONFIGURE_ENV+= PLUGINDIR="${PREFIX}/lib/openvpn/plugins" CONFLICTS_INSTALL?= openvpn-devel SUB_FILES= pkg-message openvpn-client USERS= openvpn GROUPS= openvpn PORTDOCS= * PORTEXAMPLES= * OPTIONS_DEFINE= ASYNC_PUSH DCO DOCS EASYRSA EXAMPLES LZ4 LZO PKCS11 SMALL \ TEST UNITTESTS X509ALTUSERNAME OPTIONS_DEFAULT= DCO EASYRSA LZ4 LZO PKCS11 TEST OPTIONS_EXCLUDE_FreeBSD_13= DCO # FreeBSD 14 only ASYNC_PUSH_DESC= Enable async-push support DCO_DESC= Data Channel Offload/ovpn(4) support->README.dco.md EASYRSA_DESC= Install security/easy-rsa RSA helper package LZO_DESC= LZO compression (incompatible with LibreSSL) PKCS11_DESC= Use security/pkcs11-helper, needs same SSL lib! SMALL_DESC= Build a smaller executable with fewer features UNITTESTS_DESC= Enable unit tests X509ALTUSERNAME_DESC= Enable --x509-username-field ASYNC_PUSH_LIB_DEPENDS= libinotify.so:devel/libinotify ASYNC_PUSH_CONFIGURE_ENABLE= async-push DCO_CONFIGURE_ENABLE= dco EASYRSA_RUN_DEPENDS= easy-rsa>=0:security/easy-rsa LZ4_LIB_DEPENDS+= liblz4.so:archivers/liblz4 LZ4_CONFIGURE_ENABLE= lz4 LZO_LIB_DEPENDS+= liblzo2.so:archivers/lzo2 LZO_CONFIGURE_ENABLE= lzo PKCS11_LIB_DEPENDS= libpkcs11-helper.so:security/pkcs11-helper PKCS11_CONFIGURE_ENABLE= pkcs11 SMALL_CONFIGURE_ENABLE= small TEST_ALL_TARGET= check TEST_TEST_TARGET_OFF= check UNITTESTS_BUILD_DEPENDS= cmocka>=0:sysutils/cmocka UNITTESTS_CONFIGURE_ENABLE= unit-tests X509ALTUSERNAME_CONFIGURE_ENABLE= x509-alt-username .ifdef (LOG_OPENVPN) CFLAGS+= -DLOG_OPENVPN=${LOG_OPENVPN} .endif .include .if ${PORT_OPTIONS:MLZO} IGNORE_SSL=libressl libressl-devel IGNORE_SSL_REASON=OpenVPN does not have permission to include LZO with LibreSSL. Compile against OpenSSL, or if your setups support it, disable LZO support .endif .if ! ${PORT_OPTIONS:MLZ4} && ! ${PORT_OPTIONS:MLZO} CONFIGURE_ARGS+= --enable-comp-stub .endif .include .if !empty(PORT_OPTIONS:MLZO) && !empty(SSL_DEFAULT:Nbase:Nopenssl*) # in-depth security net if Mk/Uses/ssl.mk changes pre-everything:: @${ECHO_CMD} >&2 "ERROR: OpenVPN is not licensed to combine LZO with other OpenSSL-licensed libraries than OpenSSL. Compile against OpenSSL, or if your setups support it, disable LZO support." @${SHELL} -c 'exit 1' .endif post-patch: ${RM} sample/sample-keys/dh2048.pem # no longer needed ${REINPLACE_CMD} -E -i '' -e 's/(user|group) nobody/\1 openvpn/' \ -e 's/"nobody"( after init)/"openvpn" \1/' \ ${WRKSRC}/sample/sample-config-files/*.conf \ ${WRKSRC}/doc/man-sections/generic-options.rst pre-configure: # just too many of sign-compare; bitwise-instead-of-logical was audited and is intentional, # and unused-function affects test---these are developer-side warnings, not relevant on end systems ${REINPLACE_CMD} 's/-Wsign-compare/-Wno-unknown-warning-option -Wno-sign-compare -Wno-bitwise-instead-of-logical -Wno-unused-function/' ${WRKSRC}/configure .ifdef (LOG_OPENVPN) @${ECHO} "Building with LOG_OPENVPN=${LOG_OPENVPN}" .else @${ECHO} "" @${ECHO} "You may use the following build options:" @${ECHO} "" @${ECHO} " LOG_OPENVPN={Valid syslog facility, default LOG_DAEMON}" @${ECHO} " EXAMPLE: make LOG_OPENVPN=LOG_LOCAL6" @${ECHO} "" .endif .if !empty(SSL_DEFAULT:Mlibressl*) @${ECHO} "### --------------------------------------------------------- ###" @${ECHO} "### NOTE that libressl is not primarily supported by OpenVPN ###" @${ECHO} "### Do not report bugs without fixes/patches unless the issue ###" @${ECHO} "### can be reproduced with a released OpenSSL version. ###" @${ECHO} "### --------------------------------------------------------- ###" @sleep 10 .endif post-configure: ${REINPLACE_CMD} '/^CFLAGS =/s/$$/ -fPIC/' \ ${WRKSRC}/src/plugins/auth-pam/Makefile \ ${WRKSRC}/src/plugins/down-root/Makefile # sanity check that we don't inherit incompatible SSL libs through, # for instance, pkcs11-helper: _tlslibs=libssl libcrypto post-build: @a=$$(LC_ALL=C ldd -f '%o\n' ${WRKSRC}/src/openvpn/openvpn \ | ${SORT} -u) ; set -- $$(for i in ${_tlslibs} ; do ${PRINTF} '%s\n' "$$a" | ${GREP} $${i}.so | wc -l ; done | ${SORT} -u) ;\ if test "$$*" != "1" ; then ( set -x ; ldd -a ${WRKSRC}/src/openvpn/openvpn ) ; ${PRINTF} '%s\n' "$$a" ; ${ECHO_CMD} >&2 "${.CURDIR} FAILED: either of ${_tlslibs} libraries linked multiple times" ; ${RM} ${BUILD_COOKIE} ; exit 1 ; fi post-install: ${STRIP_CMD} ${STAGEDIR}${PREFIX}/lib/openvpn/plugins/openvpn-plugin-auth-pam.so ${STRIP_CMD} ${STAGEDIR}${PREFIX}/lib/openvpn/plugins/openvpn-plugin-down-root.so ${INSTALL_SCRIPT} ${WRKSRC}/contrib/pull-resolv-conf/client.up ${STAGEDIR}${PREFIX}/libexec/openvpn-client.up ${INSTALL_SCRIPT} ${WRKSRC}/contrib/pull-resolv-conf/client.down ${STAGEDIR}${PREFIX}/libexec/openvpn-client.down ${INSTALL_SCRIPT} ${WRKDIR}/openvpn-client ${STAGEDIR}${PREFIX}/sbin/openvpn-client ${MKDIR} ${STAGEDIR}${PREFIX}/include post-install-DOCS-on: ${MKDIR} ${STAGEDIR}${DOCSDIR}/ .for i in AUTHORS ChangeLog Changes.rst CONTRIBUTING.rst PORTS README README.ec ${INSTALL_MAN} ${WRKSRC}/${i} ${STAGEDIR}${DOCSDIR}/ .endfor .if !empty(PORT_OPTIONS:MDCO) ${INSTALL_MAN} ${WRKSRC}/README.dco.md ${STAGEDIR}${DOCSDIR}/ .endif post-install-EXAMPLES-on: (cd ${WRKSRC}/sample && ${COPYTREE_SHARE} \* ${STAGEDIR}${EXAMPLESDIR}/) ${CHMOD} ${BINMODE} ${STAGEDIR}${EXAMPLESDIR}/sample-scripts/* ${RM} ${STAGEDIR}${EXAMPLESDIR}/sample-config-files/*.orig .include diff --git a/security/openvpn/files/patch-src_openvpn_dco__freebsd.c b/security/openvpn/files/patch-src_openvpn_dco__freebsd.c new file mode 100644 index 000000000000..22c24baa9ec3 --- /dev/null +++ b/security/openvpn/files/patch-src_openvpn_dco__freebsd.c @@ -0,0 +1,96 @@ +--- src/openvpn/dco_freebsd.c.orig 2025-04-02 06:53:10 UTC ++++ src/openvpn/dco_freebsd.c +@@ -72,6 +72,67 @@ sockaddr_to_nvlist(const struct sockaddr *sa) + return (nvl); + } + ++static bool ++nvlist_to_sockaddr(const nvlist_t *nvl, struct sockaddr_storage *ss) ++{ ++ if (!nvlist_exists_number(nvl, "af")) ++ { ++ return (false); ++ } ++ if (!nvlist_exists_binary(nvl, "address")) ++ { ++ return (false); ++ } ++ if (!nvlist_exists_number(nvl, "port")) ++ { ++ return (false); ++ } ++ ++ ss->ss_family = nvlist_get_number(nvl, "af"); ++ ++ switch (ss->ss_family) ++ { ++ case AF_INET: ++ { ++ struct sockaddr_in *in = (struct sockaddr_in *)ss; ++ const void *data; ++ size_t len; ++ ++ in->sin_len = sizeof(*in); ++ data = nvlist_get_binary(nvl, "address", &len); ++ if (len != sizeof(in->sin_addr)) ++ { ++ return (false); ++ } ++ memcpy(&in->sin_addr, data, sizeof(in->sin_addr)); ++ in->sin_port = nvlist_get_number(nvl, "port"); ++ break; ++ } ++ ++ case AF_INET6: ++ { ++ struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)ss; ++ const void *data; ++ size_t len; ++ ++ in6->sin6_len = sizeof(*in6); ++ data = nvlist_get_binary(nvl, "address", &len); ++ if (len != sizeof(in6->sin6_addr)) ++ { ++ return (false); ++ } ++ memcpy(&in6->sin6_addr, data, sizeof(in6->sin6_addr)); ++ in6->sin6_port = nvlist_get_number(nvl, "port"); ++ break; ++ } ++ ++ default: ++ return (false); ++ } ++ ++ return (true); ++} ++ + int + dco_new_peer(dco_context_t *dco, unsigned int peerid, int sd, + struct sockaddr *localaddr, struct sockaddr *remoteaddr, +@@ -570,6 +631,25 @@ dco_do_read(dco_context_t *dco) + case OVPN_NOTIF_ROTATE_KEY: + dco->dco_message_type = OVPN_CMD_SWAP_KEYS; + break; ++ ++ case OVPN_NOTIF_FLOAT: { ++ const nvlist_t *address; ++ ++ if (!nvlist_exists_nvlist(nvl, "address")) ++ { ++ msg(M_WARN, "Float notification without address"); ++ break; ++ } ++ ++ address = nvlist_get_nvlist(nvl, "address"); ++ if (!nvlist_to_sockaddr(address, &dco->dco_float_peer_ss)) ++ { ++ msg(M_WARN, "Failed to parse float notification"); ++ break; ++ } ++ dco->dco_message_type = OVPN_CMD_FLOAT_PEER; ++ break; ++ } + + default: + msg(M_WARN, "Unknown kernel notification %d", type); diff --git a/security/openvpn/files/patch-src_openvpn_dco__freebsd.h b/security/openvpn/files/patch-src_openvpn_dco__freebsd.h new file mode 100644 index 000000000000..32dd08563f27 --- /dev/null +++ b/security/openvpn/files/patch-src_openvpn_dco__freebsd.h @@ -0,0 +1,18 @@ +--- src/openvpn/dco_freebsd.h.orig 2025-04-02 06:53:10 UTC ++++ src/openvpn/dco_freebsd.h +@@ -36,6 +36,7 @@ enum ovpn_message_type_t { + OVPN_CMD_DEL_PEER, + OVPN_CMD_PACKET, + OVPN_CMD_SWAP_KEYS, ++ OVPN_CMD_FLOAT_PEER, + }; + + enum ovpn_del_reason_t { +@@ -55,6 +56,7 @@ typedef struct dco_context { + int dco_message_type; + int dco_message_peer_id; + int dco_del_peer_reason; ++ struct sockaddr_storage dco_float_peer_ss; + uint64_t dco_read_bytes; + uint64_t dco_write_bytes; + } dco_context_t; diff --git a/security/openvpn/files/patch-src_openvpn_forward.c b/security/openvpn/files/patch-src_openvpn_forward.c new file mode 100644 index 000000000000..0734167f6636 --- /dev/null +++ b/security/openvpn/files/patch-src_openvpn_forward.c @@ -0,0 +1,44 @@ +--- src/openvpn/forward.c.orig 2025-04-02 06:53:10 UTC ++++ src/openvpn/forward.c +@@ -1234,6 +1234,41 @@ process_incoming_link(struct context *c) + perf_pop(); + } + ++void ++extract_dco_float_peer_addr(const sa_family_t socket_family, ++ struct openvpn_sockaddr *out_osaddr, ++ const struct sockaddr *float_sa) ++{ ++ if (float_sa->sa_family == AF_INET) ++ { ++ struct sockaddr_in *float4 = (struct sockaddr_in *)float_sa; ++ /* DCO treats IPv4-mapped IPv6 addresses as pure IPv4. However, on a ++ * dual-stack socket, we need to preserve the mapping otherwise openvpn ++ * will not be able to find the peer by its transport address. ++ */ ++ if (socket_family == AF_INET6) ++ { ++ out_osaddr->addr.in6.sin6_family = AF_INET6; ++ out_osaddr->addr.in6.sin6_port = float4->sin_port; ++ ++ memset(&out_osaddr->addr.in6.sin6_addr.s6_addr, 0, 10); ++ out_osaddr->addr.in6.sin6_addr.s6_addr[10] = 0xff; ++ out_osaddr->addr.in6.sin6_addr.s6_addr[11] = 0xff; ++ memcpy(&out_osaddr->addr.in6.sin6_addr.s6_addr[12], ++ &float4->sin_addr.s_addr, sizeof(in_addr_t)); ++ } ++ else ++ { ++ memcpy(&out_osaddr->addr.in4, float4, sizeof(struct sockaddr_in)); ++ } ++ } ++ else ++ { ++ struct sockaddr_in6 *float6 = (struct sockaddr_in6 *)float_sa; ++ memcpy(&out_osaddr->addr.in6, float6, sizeof(struct sockaddr_in6)); ++ } ++} ++ + static void + process_incoming_dco(struct context *c) + { diff --git a/security/openvpn/files/patch-src_openvpn_forward.h b/security/openvpn/files/patch-src_openvpn_forward.h new file mode 100644 index 000000000000..050343949c03 --- /dev/null +++ b/security/openvpn/files/patch-src_openvpn_forward.h @@ -0,0 +1,24 @@ +--- src/openvpn/forward.h.orig 2025-04-02 06:53:10 UTC ++++ src/openvpn/forward.h +@@ -189,6 +189,21 @@ void process_incoming_link_part2(struct context *c, st + void process_incoming_link_part2(struct context *c, struct link_socket_info *lsi, const uint8_t *orig_buf); + + /** ++ * Transfers \c float_sa data extracted from an incoming DCO ++ * PEER_FLOAT_NTF to \c out_osaddr for later processing. ++ * ++ * @param socket_family - The address family of the socket ++ * @param out_osaddr - openvpn_sockaddr struct that will be filled the new ++ * address data ++ * @param float_sa - The sockaddr struct containing the data received from the ++ * DCO notification ++ */ ++void ++extract_dco_float_peer_addr(sa_family_t socket_family, ++ struct openvpn_sockaddr *out_osaddr, ++ const struct sockaddr *float_sa); ++ ++/** + * Write a packet to the external network interface. + * @ingroup external_multiplexer + * diff --git a/security/openvpn/files/patch-src_openvpn_multi.c b/security/openvpn/files/patch-src_openvpn_multi.c new file mode 100644 index 000000000000..22995fb45caf --- /dev/null +++ b/security/openvpn/files/patch-src_openvpn_multi.c @@ -0,0 +1,39 @@ +--- src/openvpn/multi.c.orig 2025-04-02 06:53:10 UTC ++++ src/openvpn/multi.c +@@ -3169,6 +3169,18 @@ multi_process_float(struct multi_context *m, struct mu + goto done; + } + ++ /* It doesn't make sense to let a peer float to the address it already ++ * has, so we disallow it. This can happen if a DCO netlink notification ++ * gets lost and we miss a floating step. ++ */ ++ if (m1->peer_id == m2->peer_id) ++ { ++ msg(M_WARN, "disallowing peer %" PRIu32 " (%s) from floating to " ++ "its own address (%s)", ++ m1->peer_id, tls_common_name(mi->context.c2.tls_multi, false), ++ mroute_addr_print(&mi->real, &gc)); ++ goto done; ++ } + msg(D_MULTI_MEDIUM, "closing instance %s", multi_instance_string(ex_mi, false, &gc)); + multi_close_instance(m, ex_mi, false); + } +@@ -3301,6 +3313,17 @@ multi_process_incoming_dco(struct multi_context *m) + { + process_incoming_del_peer(m, mi, dco); + } ++#if defined(TARGET_FREEBSD) ++ else if (dco->dco_message_type == OVPN_CMD_FLOAT_PEER) ++ { ++ ASSERT(mi->context.c2.link_socket); ++ extract_dco_float_peer_addr(mi->context.c2.link_socket->info.af, ++ &m->top.c2.from.dest, ++ (struct sockaddr *)&dco->dco_float_peer_ss); ++ multi_process_float(m, mi); ++ CLEAR(dco->dco_float_peer_ss); ++ } ++#endif /* if defined(TARGET_LINUX) || defined(TARGET_WIN32) */ + else if (dco->dco_message_type == OVPN_CMD_SWAP_KEYS) + { + tls_session_soft_reset(mi->context.c2.tls_multi); diff --git a/security/openvpn/files/patch-src_openvpn_ovpn__dco__freebsd.h b/security/openvpn/files/patch-src_openvpn_ovpn__dco__freebsd.h new file mode 100644 index 000000000000..1d1ff16e5d8e --- /dev/null +++ b/security/openvpn/files/patch-src_openvpn_ovpn__dco__freebsd.h @@ -0,0 +1,10 @@ +--- src/openvpn/ovpn_dco_freebsd.h.orig 2025-04-02 06:53:10 UTC ++++ src/openvpn/ovpn_dco_freebsd.h +@@ -37,6 +37,7 @@ enum ovpn_notif_type { + enum ovpn_notif_type { + OVPN_NOTIF_DEL_PEER, + OVPN_NOTIF_ROTATE_KEY, ++ OVPN_NOTIF_FLOAT, + }; + + enum ovpn_del_reason {