From patchwork Sun Dec 11 03:22:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "wushaohua@chinatelecom.cn" X-Patchwork-Id: 1715076 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=openvswitch.org (client-ip=2605:bc80:3010::136; helo=smtp3.osuosl.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4NW65S0pdtz23pD for ; Tue, 13 Dec 2022 03:09:32 +1100 (AEDT) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id 7674A600CB; Mon, 12 Dec 2022 16:09:30 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 7674A600CB X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id UfbYyXvoTN0e; Mon, 12 Dec 2022 16:09:29 +0000 (UTC) Received: from lists.linuxfoundation.org (lf-lists.osuosl.org [IPv6:2605:bc80:3010:104::8cd3:938]) by smtp3.osuosl.org (Postfix) with ESMTPS id 73AF2600C6; Mon, 12 Dec 2022 16:09:28 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org 73AF2600C6 Received: from lf-lists.osuosl.org (localhost [127.0.0.1]) by lists.linuxfoundation.org (Postfix) with ESMTP id 4F6D8C0033; Mon, 12 Dec 2022 16:09:28 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@lists.linuxfoundation.org Received: from smtp3.osuosl.org (smtp3.osuosl.org [IPv6:2605:bc80:3010::136]) by lists.linuxfoundation.org (Postfix) with ESMTP id E55E9C002D for ; Sun, 11 Dec 2022 03:23:06 +0000 (UTC) Received: from localhost (localhost [127.0.0.1]) by smtp3.osuosl.org (Postfix) with ESMTP id AA91160A89 for ; Sun, 11 Dec 2022 03:23:06 +0000 (UTC) DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org AA91160A89 X-Virus-Scanned: amavisd-new at osuosl.org Received: from smtp3.osuosl.org ([127.0.0.1]) by localhost (smtp3.osuosl.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id rGaq1N82Dyzu for ; Sun, 11 Dec 2022 03:23:05 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.8.0 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp3.osuosl.org CD0F260A70 Received: from chinatelecom.cn (prt-mail.chinatelecom.cn [42.123.76.219]) by smtp3.osuosl.org (Postfix) with ESMTP id CD0F260A70 for ; Sun, 11 Dec 2022 03:23:04 +0000 (UTC) HMM_SOURCE_IP: 172.18.0.188:53480.1106066994 HMM_ATTACHE_NUM: 0000 HMM_SOURCE_TYPE: SMTP Received: from clientip-101.43.140.16 (unknown [172.18.0.188]) by chinatelecom.cn (HERMES) with SMTP id A7F2A2800B5; Sun, 11 Dec 2022 11:22:58 +0800 (CST) X-189-SAVE-TO-SEND: wushaohua@chinatelecom.cn Received: from ([101.43.140.16]) by app0023 with ESMTP id c2e2c5ff219a49eebe506aaa01282502 for dev@openvswitch.org; Sun, 11 Dec 2022 11:23:00 CST X-Transaction-ID: c2e2c5ff219a49eebe506aaa01282502 X-Real-From: wushaohua@chinatelecom.cn X-Receive-IP: 101.43.140.16 X-MEDUSA-Status: 0 From: wushaohua@chinatelecom.cn To: dev@openvswitch.org Date: Sun, 11 Dec 2022 11:22:57 +0800 Message-Id: <20221211032257.822854-1-wushaohua@chinatelecom.cn> X-Mailer: git-send-email 2.30.2 MIME-Version: 1.0 X-Mailman-Approved-At: Mon, 12 Dec 2022 16:09:26 +0000 Cc: zoum2@chinatelecom.cn, wenxu@chinatelecom.cn Subject: [ovs-dev] [PATCH] conntrack: Fix icmp_id conflicts in snat X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: ovs-dev-bounces@openvswitch.org Sender: "dev" From: wushaohua The icmp_id maybe conflicts in snat Description: If multiple devices send icmp packets with the same icmp_id, the sip of the packets changes to the same source ip address after the snat operation, and the packets are sent to the same destination ip address. Only one ct entry is created.The data packets sent by other devices cannot be sent to the peer device ovs-appctl dpctl/dump-conntrack icmp,orig=(src=10.0.0.4,dst=10.0.0.2,id=500,type=8,code=0),reply=(src=10.0.0.2,dst=10.0.0.201,id=500,type=0,code=0) After fixing the problem: ovs-appctl dpctl/dump-conntrack icmp,orig=(src=10.0.0.3,dst=10.0.0.2,id=500,type=8,code=0),reply=(src=10.0.0.2,dst=10.0.0.201,id=501,type=0,code=0) icmp,orig=(src=10.0.0.1,dst=10.0.0.2,id=500,type=8,code=0),reply=(src=10.0.0.2,dst=10.0.0.201,id=500,type=0,code=0) icmp,orig=(src=10.0.0.7,dst=10.0.0.2,id=500,type=8,code=0),reply=(src=10.0.0.2,dst=10.0.0.201,id=505,type=0,code=0) icmp,orig=(src=10.0.0.4,dst=10.0.0.2,id=500,type=8,code=0),reply=(src=10.0.0.2,dst=10.0.0.201,id=502,type=0,code=0) icmp,orig=(src=10.0.0.5,dst=10.0.0.2,id=500,type=8,code=0),reply=(src=10.0.0.2,dst=10.0.0.201,id=503,type=0,code=0) icmp,orig=(src=10.0.0.6,dst=10.0.0.2,id=500,type=8,code=0),reply=(src=10.0.0.2,dst=10.0.0.201,id=504,type=0,code=0) Signed-off-by: wushaohua --- lib/conntrack.c | 63 ++++++++++++++++++++++++++++++++++++++++++++----- lib/packets.c | 22 +++++++++++++++++ lib/packets.h | 2 ++ 3 files changed, 81 insertions(+), 6 deletions(-) diff --git a/lib/conntrack.c b/lib/conntrack.c index 550b2be9b..16182d232 100644 --- a/lib/conntrack.c +++ b/lib/conntrack.c @@ -697,6 +697,36 @@ get_ip_proto(const struct dp_packet *pkt) return ip_proto; } +static bool _is_icmpv4_info_message(uint8_t nw_proto,uint8_t icmp_type) +{ + if (nw_proto != IPPROTO_ICMP) { + return false; + } + switch (icmp_type) { + case ICMP4_ECHO_REQUEST: + case ICMP4_TIMESTAMP: + case ICMP4_INFOREQUEST: + case ICMP4_ECHO_REPLY: + case ICMP4_TIMESTAMPREPLY: + case ICMP4_INFOREPLY: + return true; + default: + return false; + } +} + +static bool packet_is_icmpv4_info_message(const struct dp_packet *pkt) +{ + uint8_t ip_proto,icmp_type; + ip_proto = get_ip_proto(pkt); + if (ip_proto != IPPROTO_ICMP) { + return false; + } else { + icmp_type = packet_get_icmp_type(pkt); + } + return _is_icmpv4_info_message(ip_proto,icmp_type); +} + static bool is_ftp_ctl(const enum ct_alg_ctl_type ct_alg_ctl) { @@ -773,6 +803,9 @@ pat_packet(struct dp_packet *pkt, const struct conn *conn) } else if (conn->key.nw_proto == IPPROTO_UDP) { struct udp_header *uh = dp_packet_l4(pkt); packet_set_udp_port(pkt, conn->rev_key.dst.port, uh->udp_dst); + } else if (packet_is_icmpv4_info_message(pkt) && + conn->key.nw_proto == IPPROTO_ICMP) { + packet_set_icmp_id(pkt, conn->rev_key.dst.icmp_id); } } else if (conn->nat_action & NAT_ACTION_DST) { if (conn->key.nw_proto == IPPROTO_TCP) { @@ -781,6 +814,9 @@ pat_packet(struct dp_packet *pkt, const struct conn *conn) } else if (conn->key.nw_proto == IPPROTO_UDP) { packet_set_udp_port(pkt, conn->rev_key.dst.port, conn->rev_key.src.port); + } else if (packet_is_icmpv4_info_message(pkt) && + conn->key.nw_proto == IPPROTO_ICMP) { + packet_set_icmp_id(pkt, conn->rev_key.src.icmp_id); } } } @@ -831,13 +867,19 @@ un_pat_packet(struct dp_packet *pkt, const struct conn *conn) } else if (conn->key.nw_proto == IPPROTO_UDP) { struct udp_header *uh = dp_packet_l4(pkt); packet_set_udp_port(pkt, uh->udp_src, conn->key.src.port); - } + } else if (packet_is_icmpv4_info_message(pkt) && + conn->key.nw_proto == IPPROTO_ICMP) { + packet_set_icmp_id(pkt, conn->key.src.icmp_id); + } } else if (conn->nat_action & NAT_ACTION_DST) { if (conn->key.nw_proto == IPPROTO_TCP) { packet_set_tcp_port(pkt, conn->key.dst.port, conn->key.src.port); } else if (conn->key.nw_proto == IPPROTO_UDP) { packet_set_udp_port(pkt, conn->key.dst.port, conn->key.src.port); - } + } else if (packet_is_icmpv4_info_message(pkt) && + conn->key.nw_proto == IPPROTO_ICMP) { + packet_set_icmp_id(pkt, conn->key.dst.icmp_id); + } } } @@ -2366,8 +2408,8 @@ store_addr_to_key(union ct_addr *addr, struct conn_key *key, static bool nat_get_unique_l4(struct conntrack *ct, struct conn *nat_conn, - ovs_be16 *port, uint16_t curr, uint16_t min, - uint16_t max) + ovs_be16 *port, ovs_be16 *peer_port, + uint16_t curr, uint16_t min, uint16_t max) { static const unsigned int max_attempts = 128; uint16_t range = max - min + 1; @@ -2388,6 +2430,9 @@ another_round: } *port = htons(curr); + if (peer_port) { + *peer_port = htons(curr); + } if (!conn_lookup(ct, &nat_conn->rev_key, time_msec(), NULL, NULL)) { return true; @@ -2401,6 +2446,9 @@ another_round: } *port = htons(orig); + if (peer_port) { + *peer_port = htons(orig); + } return false; } @@ -2434,7 +2482,8 @@ nat_get_unique_tuple(struct conntrack *ct, const struct conn *conn, uint32_t hash = nat_range_hash(conn, ct->hash_basis, nat_info); union ct_addr min_addr = {0}, max_addr = {0}, addr = {0}; bool pat_proto = conn->key.nw_proto == IPPROTO_TCP || - conn->key.nw_proto == IPPROTO_UDP; + conn->key.nw_proto == IPPROTO_UDP || + conn->key.nw_proto == IPPROTO_ICMP; uint16_t min_dport, max_dport, curr_dport; uint16_t min_sport, max_sport, curr_sport; @@ -2469,11 +2518,13 @@ nat_get_unique_tuple(struct conntrack *ct, const struct conn *conn, bool found = false; if (nat_info->nat_action & NAT_ACTION_DST_PORT) { found = nat_get_unique_l4(ct, nat_conn, &nat_conn->rev_key.src.port, - curr_dport, min_dport, max_dport); + NULL,curr_dport, min_dport, max_dport); } if (!found) { found = nat_get_unique_l4(ct, nat_conn, &nat_conn->rev_key.dst.port, + nat_conn->rev_key.nw_proto == IPPROTO_ICMP ? + &nat_conn->rev_key.src.port : NULL, curr_sport, min_sport, max_sport); } diff --git a/lib/packets.c b/lib/packets.c index 1dcd4a6fc..11d21d8c3 100644 --- a/lib/packets.c +++ b/lib/packets.c @@ -1441,6 +1441,28 @@ packet_set_icmp(struct dp_packet *packet, uint8_t type, uint8_t code) pkt_metadata_init_conn(&packet->md); } +/* Sets the ICMP id of the ICMP header contained in 'packet'. + * 'packet' must be a valid ICMP packet with its l4 offset properly + * populated. */ +void +packet_set_icmp_id(struct dp_packet *packet, ovs_be16 icmp_id) +{ + struct icmp_header *ih = dp_packet_l4(packet); + ovs_be16 orig_ic = ih->icmp_fields.echo.id; + + if (icmp_id != orig_ic) { + ih->icmp_fields.echo.id = icmp_id; + ih->icmp_csum = recalc_csum16(ih->icmp_csum, orig_ic, icmp_id); + } + pkt_metadata_init_conn(&packet->md); +} + +uint8_t +packet_get_icmp_type(const struct dp_packet *packet) +{ + struct icmp_header *ih = dp_packet_l4(packet); + return ih->icmp_type; +} /* Sets the IGMP type to IGMP_HOST_MEMBERSHIP_QUERY and populates the * v3 query header fields in 'packet'. 'packet' must be a valid IGMPv3 * query packet with its l4 offset properly populated. diff --git a/lib/packets.h b/lib/packets.h index 5bdf6e4bb..a3ddbd8b2 100644 --- a/lib/packets.h +++ b/lib/packets.h @@ -1602,6 +1602,8 @@ void packet_set_tcp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst); void packet_set_udp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst); void packet_set_sctp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst); void packet_set_icmp(struct dp_packet *, uint8_t type, uint8_t code); +void packet_set_icmp_id(struct dp_packet *, uint16_t icmp_id); +uint8_t packet_get_icmp_type(const struct dp_packet *packet); void packet_set_nd(struct dp_packet *, const struct in6_addr *target, const struct eth_addr sll, const struct eth_addr tll); void packet_set_nd_ext(struct dp_packet *packet,