Make sure packet header structures are correctly packed on Windows.
authorEtienne Dechamps <etienne@edechamps.fr>
Sun, 15 Mar 2015 10:00:56 +0000 (10:00 +0000)
committerEtienne Dechamps <etienne@edechamps.fr>
Sun, 15 Mar 2015 10:12:18 +0000 (10:12 +0000)
Modern versions of GCC handle structure packing differently when
compiling for Windows, as reported in the following GCC bug report:

  http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52991

In practice, this affects tinc because it uses packed structs as a
convenient way to populate packet headers. "struct ip" is especially
affected - on Linux, sizeof(struct ip) returns 20 as expected, while on
Windows, it returns 24 because of the broken alignment.

This in turn completely breaks code that has to populate an IP header.
Specifically, this breaks route_ipv4_unreachable() which is responsible,
among other things, for the generation of ICMP Fragmentation Needed
messages. On Windows, these messages are corrupted beyond hope because
of this alignment issue. For TCP connections that are established
before tinc obtains a fix on the MTU (and thus are not MSS clamped),
this can result in massive disruption.

This commit fixes the issue by forcing GCC to use standard alignment
for all packed structures in the tinc codebase instead of the MSVC
alignment.

src/ethernet.h
src/ipv4.h
src/ipv6.h

index a8b6420..085e96a 100644 (file)
@@ -50,7 +50,7 @@ struct ether_header {
        uint8_t ether_dhost[ETH_ALEN];
        uint8_t ether_shost[ETH_ALEN];
        uint16_t ether_type;
        uint8_t ether_dhost[ETH_ALEN];
        uint8_t ether_shost[ETH_ALEN];
        uint16_t ether_type;
-} __attribute__ ((__packed__));
+} __attribute__ ((__gcc_struct__, __packed__));
 #endif
 
 #ifndef HAVE_STRUCT_ARPHDR
 #endif
 
 #ifndef HAVE_STRUCT_ARPHDR
@@ -60,7 +60,7 @@ struct arphdr {
        uint8_t ar_hln;
        uint8_t ar_pln;
        uint16_t ar_op;
        uint8_t ar_hln;
        uint8_t ar_pln;
        uint16_t ar_op;
-} __attribute__ ((__packed__));
+} __attribute__ ((__gcc_struct__, __packed__));
 
 #define ARPOP_REQUEST 1
 #define ARPOP_REPLY 2
 
 #define ARPOP_REQUEST 1
 #define ARPOP_REPLY 2
@@ -78,7 +78,7 @@ struct  ether_arp {
        uint8_t arp_spa[4];
        uint8_t arp_tha[ETH_ALEN];
        uint8_t arp_tpa[4];
        uint8_t arp_spa[4];
        uint8_t arp_tha[ETH_ALEN];
        uint8_t arp_tpa[4];
-} __attribute__ ((__packed__));
+} __attribute__ ((__gcc_struct__, __packed__));
 #define arp_hrd ea_hdr.ar_hrd
 #define arp_pro ea_hdr.ar_pro
 #define arp_hln ea_hdr.ar_hln
 #define arp_hrd ea_hdr.ar_hrd
 #define arp_pro ea_hdr.ar_pro
 #define arp_hln ea_hdr.ar_hln
index 6cb969b..997b88d 100644 (file)
@@ -81,7 +81,7 @@ struct ip {
        uint8_t ip_p;
        uint16_t ip_sum;
        struct in_addr ip_src, ip_dst;
        uint8_t ip_p;
        uint16_t ip_sum;
        struct in_addr ip_src, ip_dst;
-} __attribute__ ((__packed__));
+} __attribute__ ((__gcc_struct__, __packed__));
 #endif
 
 #ifndef IP_OFFMASK
 #endif
 
 #ifndef IP_OFFMASK
@@ -143,7 +143,7 @@ struct icmp {
 #define icmp_radv icmp_dun.id_radv
 #define icmp_mask icmp_dun.id_mask
 #define icmp_data icmp_dun.id_data
 #define icmp_radv icmp_dun.id_radv
 #define icmp_mask icmp_dun.id_mask
 #define icmp_data icmp_dun.id_data
-} __attribute__ ((__packed__));
+} __attribute__ ((__gcc_struct__, __packed__));
 #endif
 
 #endif /* __TINC_IPV4_H__ */
 #endif
 
 #endif /* __TINC_IPV4_H__ */
index 37d999a..46cf62d 100644 (file)
@@ -36,7 +36,7 @@ struct in6_addr {
                uint16_t u6_addr16[8];
                uint32_t u6_addr32[4];
        } in6_u;
                uint16_t u6_addr16[8];
                uint32_t u6_addr32[4];
        } in6_u;
-} __attribute__ ((__packed__));
+} __attribute__ ((__gcc_struct__, __packed__));
 #define s6_addr in6_u.u6_addr8
 #define s6_addr16 in6_u.u6_addr16
 #define s6_addr32 in6_u.u6_addr32
 #define s6_addr in6_u.u6_addr8
 #define s6_addr16 in6_u.u6_addr16
 #define s6_addr32 in6_u.u6_addr32
@@ -49,7 +49,7 @@ struct sockaddr_in6 {
        uint32_t sin6_flowinfo;
        struct in6_addr sin6_addr;
        uint32_t sin6_scope_id;
        uint32_t sin6_flowinfo;
        struct in6_addr sin6_addr;
        uint32_t sin6_scope_id;
-} __attribute__ ((__packed__));
+} __attribute__ ((__gcc_struct__, __packed__));
 #endif
 
 #ifndef IN6_IS_ADDR_V4MAPPED
 #endif
 
 #ifndef IN6_IS_ADDR_V4MAPPED
@@ -72,7 +72,7 @@ struct ip6_hdr {
        } ip6_ctlun;
        struct in6_addr ip6_src;
        struct in6_addr ip6_dst;
        } ip6_ctlun;
        struct in6_addr ip6_src;
        struct in6_addr ip6_dst;
-} __attribute__ ((__packed__));
+} __attribute__ ((__gcc_struct__, __packed__));
 #define ip6_vfc ip6_ctlun.ip6_un2_vfc
 #define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
 #define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
 #define ip6_vfc ip6_ctlun.ip6_un2_vfc
 #define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow
 #define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen
@@ -91,7 +91,7 @@ struct icmp6_hdr {
                uint16_t icmp6_un_data16[2];
                uint8_t icmp6_un_data8[4];
        } icmp6_dataun;
                uint16_t icmp6_un_data16[2];
                uint8_t icmp6_un_data8[4];
        } icmp6_dataun;
-} __attribute__ ((__packed__));
+} __attribute__ ((__gcc_struct__, __packed__));
 #define ICMP6_DST_UNREACH_NOROUTE 0
 #define ICMP6_DST_UNREACH 1
 #define ICMP6_PACKET_TOO_BIG 2
 #define ICMP6_DST_UNREACH_NOROUTE 0
 #define ICMP6_DST_UNREACH 1
 #define ICMP6_PACKET_TOO_BIG 2
@@ -111,7 +111,7 @@ struct icmp6_hdr {
 struct nd_neighbor_solicit {
        struct icmp6_hdr nd_ns_hdr;
        struct in6_addr nd_ns_target;
 struct nd_neighbor_solicit {
        struct icmp6_hdr nd_ns_hdr;
        struct in6_addr nd_ns_target;
-} __attribute__ ((__packed__));
+} __attribute__ ((__gcc_struct__, __packed__));
 #define ND_OPT_SOURCE_LINKADDR 1
 #define ND_OPT_TARGET_LINKADDR 2
 #define nd_ns_type nd_ns_hdr.icmp6_type
 #define ND_OPT_SOURCE_LINKADDR 1
 #define ND_OPT_TARGET_LINKADDR 2
 #define nd_ns_type nd_ns_hdr.icmp6_type
@@ -124,7 +124,7 @@ struct nd_neighbor_solicit {
 struct nd_opt_hdr {
        uint8_t nd_opt_type;
        uint8_t nd_opt_len;
 struct nd_opt_hdr {
        uint8_t nd_opt_type;
        uint8_t nd_opt_len;
-} __attribute__ ((__packed__));
+} __attribute__ ((__gcc_struct__, __packed__));
 #endif
 
 #endif /* __TINC_IPV6_H__ */
 #endif
 
 #endif /* __TINC_IPV6_H__ */