This is a backport of commit cb8a0f6f5741d102b667d98370ab4d553503d0b5,
which introduces float support for DCO linux, Windows, and the
OS-independent parts.
DCO linux/windows in 2.6 has no float support kernel-side, so this
ignores all OS dependent parts, backporting just enough to add
FreeBSD support in the next patch.
One notable difference in the backport is that 2.6 has no multi-socket
support, so all the "link_sockets[0]" occurances need to be changed back
to "link_socket".
See https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=289303 for all
the epic details...
Change-Id: Ib748e726eb84dcbe8a48b297d165dec80c0e578d
Signed-off-by: Ralf Lici <ralf@mandelbit.com>
Signed-off-by: Gert Doering <gert@greenie.muc.de>
Acked-by: Ralf Lici <ralf@mandelbit.com>
(cherry picked from commit cb8a0f6f5741d102b667d98370ab4d553503d0b5)
Message-Id: <20250908081124.17933-1-gert@greenie.muc.de>
URL: https://sourceforge.net/p/openvpn/mailman/message/59230454/
Signed-off-by: Gert Doering <gert@greenie.muc.de>
| ... | ... |
@@ -1234,6 +1234,41 @@ process_incoming_link(struct context *c) |
| 1234 | 1234 |
perf_pop(); |
| 1235 | 1235 |
} |
| 1236 | 1236 |
|
| 1237 |
+void |
|
| 1238 |
+extract_dco_float_peer_addr(const sa_family_t socket_family, |
|
| 1239 |
+ struct openvpn_sockaddr *out_osaddr, |
|
| 1240 |
+ const struct sockaddr *float_sa) |
|
| 1241 |
+{
|
|
| 1242 |
+ if (float_sa->sa_family == AF_INET) |
|
| 1243 |
+ {
|
|
| 1244 |
+ struct sockaddr_in *float4 = (struct sockaddr_in *)float_sa; |
|
| 1245 |
+ /* DCO treats IPv4-mapped IPv6 addresses as pure IPv4. However, on a |
|
| 1246 |
+ * dual-stack socket, we need to preserve the mapping otherwise openvpn |
|
| 1247 |
+ * will not be able to find the peer by its transport address. |
|
| 1248 |
+ */ |
|
| 1249 |
+ if (socket_family == AF_INET6) |
|
| 1250 |
+ {
|
|
| 1251 |
+ out_osaddr->addr.in6.sin6_family = AF_INET6; |
|
| 1252 |
+ out_osaddr->addr.in6.sin6_port = float4->sin_port; |
|
| 1253 |
+ |
|
| 1254 |
+ memset(&out_osaddr->addr.in6.sin6_addr.s6_addr, 0, 10); |
|
| 1255 |
+ out_osaddr->addr.in6.sin6_addr.s6_addr[10] = 0xff; |
|
| 1256 |
+ out_osaddr->addr.in6.sin6_addr.s6_addr[11] = 0xff; |
|
| 1257 |
+ memcpy(&out_osaddr->addr.in6.sin6_addr.s6_addr[12], |
|
| 1258 |
+ &float4->sin_addr.s_addr, sizeof(in_addr_t)); |
|
| 1259 |
+ } |
|
| 1260 |
+ else |
|
| 1261 |
+ {
|
|
| 1262 |
+ memcpy(&out_osaddr->addr.in4, float4, sizeof(struct sockaddr_in)); |
|
| 1263 |
+ } |
|
| 1264 |
+ } |
|
| 1265 |
+ else |
|
| 1266 |
+ {
|
|
| 1267 |
+ struct sockaddr_in6 *float6 = (struct sockaddr_in6 *)float_sa; |
|
| 1268 |
+ memcpy(&out_osaddr->addr.in6, float6, sizeof(struct sockaddr_in6)); |
|
| 1269 |
+ } |
|
| 1270 |
+} |
|
| 1271 |
+ |
|
| 1237 | 1272 |
static void |
| 1238 | 1273 |
process_incoming_dco(struct context *c) |
| 1239 | 1274 |
{
|
| ... | ... |
@@ -189,6 +189,21 @@ bool process_incoming_link_part1(struct context *c, struct link_socket_info *lsi |
| 189 | 189 |
void process_incoming_link_part2(struct context *c, struct link_socket_info *lsi, const uint8_t *orig_buf); |
| 190 | 190 |
|
| 191 | 191 |
/** |
| 192 |
+ * Transfers \c float_sa data extracted from an incoming DCO |
|
| 193 |
+ * PEER_FLOAT_NTF to \c out_osaddr for later processing. |
|
| 194 |
+ * |
|
| 195 |
+ * @param socket_family - The address family of the socket |
|
| 196 |
+ * @param out_osaddr - openvpn_sockaddr struct that will be filled the new |
|
| 197 |
+ * address data |
|
| 198 |
+ * @param float_sa - The sockaddr struct containing the data received from the |
|
| 199 |
+ * DCO notification |
|
| 200 |
+ */ |
|
| 201 |
+void |
|
| 202 |
+extract_dco_float_peer_addr(sa_family_t socket_family, |
|
| 203 |
+ struct openvpn_sockaddr *out_osaddr, |
|
| 204 |
+ const struct sockaddr *float_sa); |
|
| 205 |
+ |
|
| 206 |
+/** |
|
| 192 | 207 |
* Write a packet to the external network interface. |
| 193 | 208 |
* @ingroup external_multiplexer |
| 194 | 209 |
* |
| ... | ... |
@@ -3169,6 +3169,18 @@ multi_process_float(struct multi_context *m, struct multi_instance *mi) |
| 3169 | 3169 |
goto done; |
| 3170 | 3170 |
} |
| 3171 | 3171 |
|
| 3172 |
+ /* It doesn't make sense to let a peer float to the address it already |
|
| 3173 |
+ * has, so we disallow it. This can happen if a DCO netlink notification |
|
| 3174 |
+ * gets lost and we miss a floating step. |
|
| 3175 |
+ */ |
|
| 3176 |
+ if (m1->peer_id == m2->peer_id) |
|
| 3177 |
+ {
|
|
| 3178 |
+ msg(M_WARN, "disallowing peer %" PRIu32 " (%s) from floating to " |
|
| 3179 |
+ "its own address (%s)", |
|
| 3180 |
+ m1->peer_id, tls_common_name(mi->context.c2.tls_multi, false), |
|
| 3181 |
+ mroute_addr_print(&mi->real, &gc)); |
|
| 3182 |
+ goto done; |
|
| 3183 |
+ } |
|
| 3172 | 3184 |
msg(D_MULTI_MEDIUM, "closing instance %s", multi_instance_string(ex_mi, false, &gc)); |
| 3173 | 3185 |
multi_close_instance(m, ex_mi, false); |
| 3174 | 3186 |
} |
| ... | ... |
@@ -3301,6 +3313,17 @@ multi_process_incoming_dco(struct multi_context *m) |
| 3301 | 3301 |
{
|
| 3302 | 3302 |
process_incoming_del_peer(m, mi, dco); |
| 3303 | 3303 |
} |
| 3304 |
+#if 0 |
|
| 3305 |
+ else if (dco->dco_message_type == OVPN_CMD_FLOAT_PEER) |
|
| 3306 |
+ {
|
|
| 3307 |
+ ASSERT(mi->context.c2.link_socket); |
|
| 3308 |
+ extract_dco_float_peer_addr(mi->context.c2.link_socket->info.af, |
|
| 3309 |
+ &m->top.c2.from.dest, |
|
| 3310 |
+ (struct sockaddr *)&dco->dco_float_peer_ss); |
|
| 3311 |
+ multi_process_float(m, mi); |
|
| 3312 |
+ CLEAR(dco->dco_float_peer_ss); |
|
| 3313 |
+ } |
|
| 3314 |
+#endif /* if defined(TARGET_LINUX) || defined(TARGET_WIN32) */ |
|
| 3304 | 3315 |
else if (dco->dco_message_type == OVPN_CMD_SWAP_KEYS) |
| 3305 | 3316 |
{
|
| 3306 | 3317 |
tls_session_soft_reset(mi->context.c2.tls_multi); |