This patch brings the following improvements: * check that ETH proto and version in IP header are consistent; * check that length of the packet is enough to store the expected IP header (it may be an IPv4 or an IPv6 header) * restyle a bit to improve readability; * remove spaces before ')' in invocations.
Signed-off-by: Antonio Quartulli <a...@unstable.cc> --- src/openvpn/proto.c | 91 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 69 insertions(+), 22 deletions(-) diff --git a/src/openvpn/proto.c b/src/openvpn/proto.c index 88abd199..345df341 100644 --- a/src/openvpn/proto.c +++ b/src/openvpn/proto.c @@ -41,31 +41,40 @@ static bool is_ipv_X(int tunnel_type, struct buffer *buf, int ip_ver) { + uint16_t eth_ip_proto; int offset; - uint16_t proto; - const struct openvpn_iphdr *ih; + + switch (ip_ver) + { + case 4: + eth_ip_proto = OPENVPN_ETH_P_IPV4; + break; + + case 6: + eth_ip_proto = OPENVPN_ETH_P_IPV6; + break; + + default: + /* invalid input provided */ + return false; + } verify_align_4(buf); if (tunnel_type == DEV_TYPE_TUN) { - if (BLEN(buf) < sizeof(struct openvpn_iphdr)) - { - return false; - } offset = 0; } else if (tunnel_type == DEV_TYPE_TAP) { - const struct openvpn_ethhdr *eh; - if (BLEN(buf) < (sizeof(struct openvpn_ethhdr) - + sizeof(struct openvpn_iphdr))) + if (BLEN(buf) < sizeof(struct openvpn_ethhdr)) { return false; } - eh = (const struct openvpn_ethhdr *)BPTR(buf); - /* start by assuming this is a standard Eth fram */ - proto = eh->proto; + /* start by assuming this is a standard Eth frame */ + const struct openvpn_ethhdr *eh; + eh = (const struct openvpn_ethhdr *)BPTR(buf); + uint16_t proto = eh->proto; offset = sizeof(struct openvpn_ethhdr); /* if this is a 802.1q frame, parse the header using the according @@ -74,19 +83,17 @@ is_ipv_X(int tunnel_type, struct buffer *buf, int ip_ver) if (proto == htons(OPENVPN_ETH_P_8021Q)) { const struct openvpn_8021qhdr *evh; - if (BLEN(buf) < (sizeof(struct openvpn_ethhdr) - + sizeof(struct openvpn_iphdr))) + if (BLEN(buf) < sizeof(struct openvpn_8021qhdr)) { return false; } evh = (const struct openvpn_8021qhdr *)BPTR(buf); - proto = evh->proto; offset = sizeof(struct openvpn_8021qhdr); } - if (ntohs(proto) != (ip_ver == 6 ? OPENVPN_ETH_P_IPV6 : OPENVPN_ETH_P_IPV4)) + if (ntohs(proto) != eth_ip_proto) { return false; } @@ -96,28 +103,68 @@ is_ipv_X(int tunnel_type, struct buffer *buf, int ip_ver) return false; } - ih = (const struct openvpn_iphdr *)(BPTR(buf) + offset); + /* ensure that there is enough room for a header of the expected version */ + size_t ih_len = 0; + switch (eth_ip_proto) + { + case OPENVPN_ETH_P_IPV4: + ih_len = sizeof(struct openvpn_iphdr); + break; + + case OPENVPN_ETH_P_IPV6: + ih_len = sizeof(struct openvpn_ipv6hdr); + break; + } + if (BLEN(buf) < (offset + ih_len)) + { + return false; + } /* IP version is stored in the same bits for IPv4 or IPv6 header */ - if (OPENVPN_IPH_GET_VER(ih->version_len) == ip_ver) + const struct openvpn_iphdr *ih; + ih = (const struct openvpn_iphdr *)(BPTR(buf) + offset); + uint8_t hdr_ip_ver = OPENVPN_IPH_GET_VER(ih->version_len); + + if (tunnel_type == DEV_TYPE_TAP) { - return buf_advance(buf, offset); + /* ensure consistency between the version in the IP header and + * the Eth proto that was retrieved previously + */ + switch (eth_ip_proto) + { + case OPENVPN_ETH_P_IPV4: + if (hdr_ip_ver != 4) + { + return false; + } + break; + + case OPENVPN_ETH_P_IPV6: + if (hdr_ip_ver != 6) + { + return false; + } + break; + } } - else + + if (hdr_ip_ver != ip_ver) { return false; } + + return buf_advance(buf, offset); } bool is_ipv4(int tunnel_type, struct buffer *buf) { - return is_ipv_X( tunnel_type, buf, 4 ); + return is_ipv_X(tunnel_type, buf, 4); } bool is_ipv6(int tunnel_type, struct buffer *buf) { - return is_ipv_X( tunnel_type, buf, 6 ); + return is_ipv_X(tunnel_type, buf, 6); } -- 2.35.1 _______________________________________________ Openvpn-devel mailing list Openvpn-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/openvpn-devel