Read ECN marks on IPv4 packets on dual-stack sockets.

Fixes the problem in cloudtop testing. Will have to confirm in the canary cluster.

Tried to do a unit test, but QuicListenerTest infrastructure does not support dual-stack.

Protected by quic_restart_flag_quic_dual_stack_ecn.

PiperOrigin-RevId: 572564123
diff --git a/quiche/quic/core/quic_udp_socket_posix.inc b/quiche/quic/core/quic_udp_socket_posix.inc
index 169119f..26aed73 100644
--- a/quiche/quic/core/quic_udp_socket_posix.inc
+++ b/quiche/quic/core/quic_udp_socket_posix.inc
@@ -204,16 +204,26 @@
   if (address_family == AF_INET &&
       setsockopt(fd, IPPROTO_IP, IP_RECVTOS, &set, sizeof(set)) != 0) {
     QUIC_LOG_FIRST_N(ERROR, 100) << "Failed to request to receive ECN on "
-                                 << "socket";
+                                 << "IPv4 socket";
     return false;
   }
-  if (address_family == AF_INET6 &&
-      setsockopt(fd, IPPROTO_IPV6, IPV6_RECVTCLASS, &set, sizeof(set)) != 0) {
-    QUIC_LOG_FIRST_N(ERROR, 100) << "Failed to request to receive ECN on "
-                                 << "socket";
-    return false;
+  if (address_family == AF_INET6) {
+    if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVTCLASS, &set, sizeof(set)) != 0) {
+      QUIC_LOG_FIRST_N(ERROR, 100) << "Failed to request to receive ECN on "
+                                   << "IPv6 socket";
+      return false;
+    }
+    int ipv6_only;
+    socklen_t len;
+    if (getsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6_only, &len) != 0) {
+      QUIC_LOG_FIRST_N(ERROR, 100) << "Could not query IPV6_V6ONLY";
+    } else if (ipv6_only != 1 &&
+               setsockopt(fd, IPPROTO_IP, IP_RECVTOS, &set, sizeof(set)) != 0) {
+      QUIC_LOG_FIRST_N(ERROR, 100) << "Could not receive IPv4 ECN on "
+                                   << "dual-stack socket";
+      return false;
+    }
   }
-
   if (!(address_family == AF_INET6 && ipv6_only)) {
     if (!EnableReceiveSelfIpAddressForV4(fd)) {
       QUIC_LOG_FIRST_N(ERROR, 100)