From 176ee015267d87ff4fd4d2615e9f5ac978116171 Mon Sep 17 00:00:00 2001 From: Etienne Dechamps Date: Sun, 15 Mar 2015 10:00:56 +0000 Subject: [PATCH] Make sure packet header structures are correctly packed on Windows. 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 | 6 +++--- src/ipv4.h | 4 ++-- src/ipv6.h | 12 ++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/ethernet.h b/src/ethernet.h index a8b64203..085e96ad 100644 --- a/src/ethernet.h +++ b/src/ethernet.h @@ -50,7 +50,7 @@ struct ether_header { 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 @@ -60,7 +60,7 @@ struct arphdr { 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 @@ -78,7 +78,7 @@ struct ether_arp { 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 diff --git a/src/ipv4.h b/src/ipv4.h index 6cb969bd..997b88d8 100644 --- a/src/ipv4.h +++ b/src/ipv4.h @@ -81,7 +81,7 @@ struct ip { 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 @@ -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 -} __attribute__ ((__packed__)); +} __attribute__ ((__gcc_struct__, __packed__)); #endif #endif /* __TINC_IPV4_H__ */ diff --git a/src/ipv6.h b/src/ipv6.h index 37d999a1..46cf62df 100644 --- a/src/ipv6.h +++ b/src/ipv6.h @@ -36,7 +36,7 @@ struct in6_addr { 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 @@ -49,7 +49,7 @@ struct sockaddr_in6 { 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 @@ -72,7 +72,7 @@ struct ip6_hdr { } 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 @@ -91,7 +91,7 @@ struct icmp6_hdr { 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 @@ -111,7 +111,7 @@ struct icmp6_hdr { 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 @@ -124,7 +124,7 @@ struct nd_neighbor_solicit { 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__ */ -- 2.20.1