No functional change, just fixing coding style. Signed-off-by: Flavio Leitner <f...@sysclose.org> --- lib/conntrack.c | 335 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 188 insertions(+), 147 deletions(-)
diff --git a/lib/conntrack.c b/lib/conntrack.c index f5a3aa9fa..022a0737b 100644 --- a/lib/conntrack.c +++ b/lib/conntrack.c @@ -320,6 +320,8 @@ void conntrack_destroy(struct conntrack *ct) { unsigned i; + struct nat_conn_key_node *nat_conn_key_node; + struct alg_exp_node *alg_exp_node; latch_set(&ct->clean_thread_exit); pthread_join(ct->clean_thread, NULL); @@ -341,13 +343,11 @@ conntrack_destroy(struct conntrack *ct) ct_lock_destroy(&ctb->lock); } ct_rwlock_wrlock(&ct->resources_lock); - struct nat_conn_key_node *nat_conn_key_node; HMAP_FOR_EACH_POP (nat_conn_key_node, node, &ct->nat_conn_keys) { free(nat_conn_key_node); } hmap_destroy(&ct->nat_conn_keys); - struct alg_exp_node *alg_exp_node; HMAP_FOR_EACH_POP (alg_exp_node, node, &ct->alg_expectations) { free(alg_exp_node); } @@ -444,9 +444,9 @@ is_ftp_ctl(const struct dp_packet *pkt) * the external dependency. */ #define CT_IPPORT_FTP 21 - return (ip_proto == IPPROTO_TCP && - (th->tcp_src == htons(CT_IPPORT_FTP) || - th->tcp_dst == htons(CT_IPPORT_FTP))); + return (ip_proto == IPPROTO_TCP + && (th->tcp_src == htons(CT_IPPORT_FTP) + || th->tcp_dst == htons(CT_IPPORT_FTP))); } @@ -460,8 +460,8 @@ is_tftp_ctl(const struct dp_packet *pkt) * at least in in.h. Since this value will never change, remove * the external dependency. */ #define CT_IPPORT_TFTP 69 - return (ip_proto == IPPROTO_UDP && - uh->udp_dst == htons(CT_IPPORT_TFTP)); + return (ip_proto == IPPROTO_UDP + && uh->udp_dst == htons(CT_IPPORT_TFTP)); } @@ -696,10 +696,12 @@ static struct conn * conn_lookup(struct conntrack *ct, const struct conn_key *key, long long now) { struct conn_lookup_ctx ctx; + unsigned bucket; + ctx.conn = NULL; ctx.key = *key; ctx.hash = conn_key_hash(key, ct->hash_basis); - unsigned bucket = hash_to_bucket(ctx.hash); + bucket = hash_to_bucket(ctx.hash); conn_key_lookup(&ct->buckets[bucket], &ctx, now); return ctx.conn; } @@ -710,8 +712,10 @@ conn_seq_skew_set(struct conntrack *ct, const struct conn_key *key, { uint32_t hash = conn_key_hash(key, ct->hash_basis); unsigned bucket = hash_to_bucket(hash); + struct conn *conn; + ct_lock_lock(&ct->buckets[bucket].lock); - struct conn *conn = conn_lookup(ct, key, now); + conn = conn_lookup(ct, key, now); if (conn && seq_skew) { conn->seq_skew = seq_skew; conn->seq_skew_dir = seq_skew_dir; @@ -724,23 +728,26 @@ nat_clean(struct conntrack *ct, struct conn *conn, struct conntrack_bucket *ctb) OVS_REQUIRES(ctb->lock) { + struct nat_conn_key_node *nat_conn_key_node; + struct conn *rev_conn; long long now = time_msec(); + uint32_t hash_rev_conn; + unsigned bucket_rev_conn; + ct_rwlock_wrlock(&ct->resources_lock); nat_conn_keys_remove(&ct->nat_conn_keys, &conn->rev_key, ct->hash_basis); ct_rwlock_unlock(&ct->resources_lock); ct_lock_unlock(&ctb->lock); - uint32_t hash_rev_conn = conn_key_hash(&conn->rev_key, ct->hash_basis); - unsigned bucket_rev_conn = hash_to_bucket(hash_rev_conn); + hash_rev_conn = conn_key_hash(&conn->rev_key, ct->hash_basis); + bucket_rev_conn = hash_to_bucket(hash_rev_conn); ct_lock_lock(&ct->buckets[bucket_rev_conn].lock); ct_rwlock_wrlock(&ct->resources_lock); - struct conn *rev_conn = conn_lookup(ct, &conn->rev_key, now); - - struct nat_conn_key_node *nat_conn_key_node = - nat_conn_keys_lookup(&ct->nat_conn_keys, &conn->rev_key, - ct->hash_basis); + rev_conn = conn_lookup(ct, &conn->rev_key, now); + nat_conn_key_node = nat_conn_keys_lookup(&ct->nat_conn_keys, + &conn->rev_key, ct->hash_basis); /* In the unlikely event, rev conn was recreated, then skip * rev_conn cleanup. */ @@ -784,6 +791,7 @@ conn_not_found(struct conntrack *ct, struct dp_packet *pkt, { unsigned bucket = hash_to_bucket(ctx->hash); struct conn *nc = NULL; + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); if (!valid_new(pkt, &ctx->key)) { pkt->md.ct_state = CS_INVALID; @@ -824,6 +832,8 @@ conn_not_found(struct conntrack *ct, struct dp_packet *pkt, nc->nat_info = xmemdup(nat_action_info, sizeof *nc->nat_info); if (alg_exp) { + bool new_insert; + if (alg_exp->passive_mode) { nc->rev_key.dst.addr = alg_exp->alg_nat_repl_addr; nc->nat_info->nat_action = NAT_ACTION_SRC; @@ -833,9 +843,9 @@ conn_not_found(struct conntrack *ct, struct dp_packet *pkt, } *conn_for_un_nat_copy = *nc; ct_rwlock_wrlock(&ct->resources_lock); - bool new_insert = nat_conn_keys_insert(&ct->nat_conn_keys, - conn_for_un_nat_copy, - ct->hash_basis); + new_insert = nat_conn_keys_insert(&ct->nat_conn_keys, + conn_for_un_nat_copy, + ct->hash_basis); ct_rwlock_unlock(&ct->resources_lock); if (!new_insert) { char *log_msg = xasprintf("Pre-existing alg " @@ -845,11 +855,11 @@ conn_not_found(struct conntrack *ct, struct dp_packet *pkt, free(log_msg); } } else { + bool nat_res; + *conn_for_un_nat_copy = *nc; ct_rwlock_wrlock(&ct->resources_lock); - bool nat_res = nat_select_range_tuple( - ct, nc, conn_for_un_nat_copy); - + nat_res = nat_select_range_tuple(ct, nc, conn_for_un_nat_copy); if (!nat_res) { goto nat_res_exhaustion; } @@ -884,7 +894,6 @@ nat_res_exhaustion: * this point on unused. */ memset(conn_for_un_nat_copy, 0, sizeof *conn_for_un_nat_copy); ct_rwlock_unlock(&ct->resources_lock); - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); VLOG_WARN_RL(&rl, "Unable to NAT due to tuple space exhaustion - " "if DoS attack, use firewalling and/or zone partitioning."); return NULL; @@ -904,11 +913,12 @@ conn_update_state(struct conntrack *ct, struct dp_packet *pkt, pkt->md.ct_state |= CS_REPLY_DIR; } } else { + enum ct_update_res res; + if ((*conn)->alg_related) { pkt->md.ct_state |= CS_RELATED; } - enum ct_update_res res = conn_update(*conn, &ct->buckets[bucket], - pkt, ctx->reply, now); + res = conn_update(*conn, &ct->buckets[bucket], pkt, ctx->reply, now); switch (res) { case CT_UPDATE_VALID: @@ -956,10 +966,11 @@ create_un_nat_conn(struct conntrack *ct, struct conn *conn_for_un_nat_copy, free(nc); } } else { - ct_rwlock_rdlock(&ct->resources_lock); + struct nat_conn_key_node *nat_conn_key_node; - struct nat_conn_key_node *nat_conn_key_node = - nat_conn_keys_lookup(&ct->nat_conn_keys, &nc->key, ct->hash_basis); + ct_rwlock_rdlock(&ct->resources_lock); + nat_conn_key_node = nat_conn_keys_lookup(&ct->nat_conn_keys, &nc->key, + ct->hash_basis); if (nat_conn_key_node && !conn_key_cmp(&nat_conn_key_node->value, &nc->rev_key) && !rev_conn) { @@ -983,9 +994,9 @@ handle_nat(struct dp_packet *pkt, struct conn *conn, uint16_t zone, bool reply, bool related) { if (conn->nat_info && - (!(pkt->md.ct_state & (CS_SRC_NAT | CS_DST_NAT)) || - (pkt->md.ct_state & (CS_SRC_NAT | CS_DST_NAT) && - zone != pkt->md.ct_zone))) { + (!(pkt->md.ct_state & (CS_SRC_NAT | CS_DST_NAT)) + || (pkt->md.ct_state & (CS_SRC_NAT | CS_DST_NAT) + && zone != pkt->md.ct_zone))) { if (pkt->md.ct_state & (CS_SRC_NAT | CS_DST_NAT)) { pkt->md.ct_state &= ~(CS_SRC_NAT | CS_DST_NAT); @@ -1005,17 +1016,25 @@ check_orig_tuple(struct conntrack *ct, struct dp_packet *pkt, const struct nat_action_info_t *nat_action_info) OVS_REQUIRES(ct->buckets[*bucket].lock) { - if ((ctx_in->key.dl_type == htons(ETH_TYPE_IP) && - !pkt->md.ct_orig_tuple.ipv4.ipv4_proto) || - (ctx_in->key.dl_type == htons(ETH_TYPE_IPV6) && - !pkt->md.ct_orig_tuple.ipv6.ipv6_proto) || - !(pkt->md.ct_state & (CS_SRC_NAT | CS_DST_NAT)) || - nat_action_info) { + struct conn_lookup_ctx ctx; + uint16_t src_port; + + if (ctx_in->key.dl_type == htons(ETH_TYPE_IP) + && !pkt->md.ct_orig_tuple.ipv4.ipv4_proto) { + return false; + } + if (ctx_in->key.dl_type == htons(ETH_TYPE_IPV6) + && !pkt->md.ct_orig_tuple.ipv6.ipv6_proto) { + return false; + } + if (!(pkt->md.ct_state & (CS_SRC_NAT | CS_DST_NAT))) { + return false; + } + if (nat_action_info) { return false; } ct_lock_unlock(&ct->buckets[*bucket].lock); - struct conn_lookup_ctx ctx; memset(&ctx, 0 , sizeof ctx); ctx.conn = NULL; @@ -1026,7 +1045,7 @@ check_orig_tuple(struct conntrack *ct, struct dp_packet *pkt, if (ctx_in->key.nw_proto == IPPROTO_ICMP) { ctx.key.src.icmp_id = ctx_in->key.src.icmp_id; ctx.key.dst.icmp_id = ctx_in->key.dst.icmp_id; - uint16_t src_port = ntohs(pkt->md.ct_orig_tuple.ipv4.src_port); + src_port = ntohs(pkt->md.ct_orig_tuple.ipv4.src_port); ctx.key.src.icmp_type = (uint8_t) src_port; ctx.key.dst.icmp_type = reverse_icmp_type(ctx.key.src.icmp_type); } else { @@ -1041,7 +1060,7 @@ check_orig_tuple(struct conntrack *ct, struct dp_packet *pkt, if (ctx_in->key.nw_proto == IPPROTO_ICMPV6) { ctx.key.src.icmp_id = ctx_in->key.src.icmp_id; ctx.key.dst.icmp_id = ctx_in->key.dst.icmp_id; - uint16_t src_port = ntohs(pkt->md.ct_orig_tuple.ipv6.src_port); + src_port = ntohs(pkt->md.ct_orig_tuple.ipv6.src_port); ctx.key.src.icmp_type = (uint8_t) src_port; ctx.key.dst.icmp_type = reverse_icmp6_type(ctx.key.src.icmp_type); } else { @@ -1053,7 +1072,6 @@ check_orig_tuple(struct conntrack *ct, struct dp_packet *pkt, ctx.key.dl_type = ctx_in->key.dl_type; ctx.key.zone = pkt->md.ct_zone; - ctx.hash = conn_key_hash(&ctx.key, ct->hash_basis); *bucket = hash_to_bucket(ctx.hash); ct_lock_lock(&ct->buckets[*bucket].lock); @@ -1077,8 +1095,17 @@ process_one(struct conntrack *ct, struct dp_packet *pkt, const struct nat_action_info_t *nat_action_info, const char *helper) { + const struct alg_exp_node *alg_exp; struct conn *conn; + struct conn_lookup_ctx ctx2; + struct conn conn_for_un_nat_copy; + struct conn conn_for_expectation; + conn_for_un_nat_copy.conn_type = CT_CONN_TYPE_DEFAULT; unsigned bucket = hash_to_bucket(ctx->hash); + bool create_new_conn; + bool ftp_ctl; + bool tftp_ctl; + ct_lock_lock(&ct->buckets[bucket].lock); conn_key_lookup(&ct->buckets[bucket], ctx, now); conn = ctx->conn; @@ -1091,17 +1118,12 @@ process_one(struct conntrack *ct, struct dp_packet *pkt, if (OVS_LIKELY(conn)) { if (conn->conn_type == CT_CONN_TYPE_UN_NAT) { - ctx->reply = true; - - struct conn_lookup_ctx ctx2; ctx2.conn = NULL; ctx2.key = conn->rev_key; ctx2.hash = conn_key_hash(&conn->rev_key, ct->hash_basis); - ct_lock_unlock(&ct->buckets[bucket].lock); bucket = hash_to_bucket(ctx2.hash); - ct_lock_lock(&ct->buckets[bucket].lock); conn_key_lookup(&ct->buckets[bucket], &ctx2, now); @@ -1118,11 +1140,9 @@ process_one(struct conntrack *ct, struct dp_packet *pkt, } } - bool create_new_conn = false; - struct conn conn_for_un_nat_copy; + create_new_conn = false; conn_for_un_nat_copy.conn_type = CT_CONN_TYPE_DEFAULT; - bool ftp_ctl = is_ftp_ctl(pkt); - + ftp_ctl = is_ftp_ctl(pkt); if (OVS_LIKELY(conn)) { if (ftp_ctl) { /* Keep sequence tracking in sync with the source of the @@ -1146,7 +1166,7 @@ process_one(struct conntrack *ct, struct dp_packet *pkt, handle_nat(pkt, conn, zone, ctx->reply, ctx->icmp_related); } - }else if (check_orig_tuple(ct, pkt, ctx, now, &bucket, &conn, + } else if (check_orig_tuple(ct, pkt, ctx, now, &bucket, &conn, nat_action_info)) { create_new_conn = conn_update_state(ct, pkt, ctx, &conn, now, bucket); @@ -1160,7 +1180,7 @@ process_one(struct conntrack *ct, struct dp_packet *pkt, } } - const struct alg_exp_node *alg_exp = NULL; + alg_exp = NULL; if (OVS_UNLIKELY(create_new_conn)) { struct alg_exp_node alg_exp_entry; @@ -1182,13 +1202,10 @@ process_one(struct conntrack *ct, struct dp_packet *pkt, if (conn && setmark) { set_mark(pkt, conn, setmark[0], setmark[1]); } - if (conn && setlabel) { set_label(pkt, conn, &setlabel[0], &setlabel[1]); } - - bool tftp_ctl = is_tftp_ctl(pkt); - struct conn conn_for_expectation; + tftp_ctl = is_tftp_ctl(pkt); if (OVS_UNLIKELY((ftp_ctl || tftp_ctl) && conn)) { conn_for_expectation = *conn; } @@ -1198,7 +1215,6 @@ process_one(struct conntrack *ct, struct dp_packet *pkt, if (is_un_nat_conn_valid(&conn_for_un_nat_copy)) { create_un_nat_conn(ct, &conn_for_un_nat_copy, now, !!alg_exp); } - /* FTP control packet handling with expectation creation. */ if (OVS_UNLIKELY(ftp_ctl && conn)) { handle_ftp_ctl(ct, ctx, pkt, &conn_for_expectation, @@ -1285,9 +1301,14 @@ sweep_bucket(struct conntrack *ct, struct conntrack_bucket *ctb, OVS_REQUIRES(ctb->lock) { struct conn *conn, *next; + struct alg_exp_node *alg_exp_node; + struct alg_exp_node *alg_exp_node_next; long long min_expiration = LLONG_MAX; unsigned i; size_t count = 0; + size_t alg_exp_count; + size_t max_to_expire; + enum { MAX_ALG_EXP_TO_EXPIRE = 1000 }; for (i = 0; i < N_CT_TM; i++) { LIST_FOR_EACH_SAFE (conn, next, exp_node, &ctb->exp_lists[i]) { @@ -1307,13 +1328,11 @@ sweep_bucket(struct conntrack *ct, struct conntrack_bucket *ctb, } } - enum { MAX_ALG_EXP_TO_EXPIRE = 1000 }; - size_t alg_exp_count = hmap_count(&ct->alg_expectations); + alg_exp_count = hmap_count(&ct->alg_expectations); /* XXX: revisit this. */ - size_t max_to_expire = MAX(alg_exp_count/10, MAX_ALG_EXP_TO_EXPIRE); + max_to_expire = MAX(alg_exp_count/10, MAX_ALG_EXP_TO_EXPIRE); count = 0; ct_rwlock_wrlock(&ct->resources_lock); - struct alg_exp_node *alg_exp_node, *alg_exp_node_next; LIST_FOR_EACH_SAFE (alg_exp_node, alg_exp_node_next, exp_node, &ct->alg_exp_list) { if (now < alg_exp_node->expiration || count >= max_to_expire) { @@ -1489,6 +1508,8 @@ extract_l3_ipv6(struct conn_key *key, const void *data, size_t size, const char **new_data) { const struct ovs_16aligned_ip6_hdr *ip6 = data; + uint8_t nw_proto = ip6->ip6_nxt; + uint8_t nw_frag = 0; if (new_data) { if (OVS_UNLIKELY(size < sizeof *ip6)) { @@ -1496,20 +1517,14 @@ extract_l3_ipv6(struct conn_key *key, const void *data, size_t size, } } - uint8_t nw_proto = ip6->ip6_nxt; - uint8_t nw_frag = 0; - data = ip6 + 1; size -= sizeof *ip6; - if (!parse_ipv6_ext_hdrs(&data, &size, &nw_proto, &nw_frag)) { return false; } - if (new_data) { *new_data = data; } - if (nw_frag) { return false; } @@ -1545,11 +1560,13 @@ check_l4_tcp(const struct conn_key *key, const void *data, size_t size, const void *l3, bool validate_checksum) { const struct tcp_header *tcp = data; + size_t tcp_len; + if (size < sizeof *tcp) { return false; } - size_t tcp_len = TCP_OFFSET(tcp->tcp_ctl) * 4; + tcp_len = TCP_OFFSET(tcp->tcp_ctl) * 4; if (OVS_UNLIKELY(tcp_len < TCP_HEADER_LEN || tcp_len > size)) { return false; } @@ -1562,11 +1579,13 @@ check_l4_udp(const struct conn_key *key, const void *data, size_t size, const void *l3, bool validate_checksum) { const struct udp_header *udp = data; + size_t udp_len; + if (size < sizeof *udp) { return false; } - size_t udp_len = ntohs(udp->udp_len); + udp_len = ntohs(udp->udp_len); if (OVS_UNLIKELY(udp_len < UDP_HEADER_LEN || udp_len > size)) { return false; } @@ -1901,10 +1920,12 @@ conn_key_extract(struct conntrack *ct, struct dp_packet *pkt, ovs_be16 dl_type, ctx->key.dl_type = dl_type; if (ctx->key.dl_type == htons(ETH_TYPE_IP)) { bool hwol_bad_l3_csum = dp_packet_ip_checksum_bad(pkt); + if (hwol_bad_l3_csum) { ok = false; } else { bool hwol_good_l3_csum = dp_packet_ip_checksum_valid(pkt); + /* Validate the checksum only when hwol is not supported. */ ok = extract_l3_ipv4(&ctx->key, l3, tail - (char *) l3, NULL, !hwol_good_l3_csum); @@ -1918,8 +1939,10 @@ conn_key_extract(struct conntrack *ct, struct dp_packet *pkt, ovs_be16 dl_type, if (ok) { bool hwol_bad_l4_csum = dp_packet_l4_checksum_bad(pkt); + if (!hwol_bad_l4_csum) { bool hwol_good_l4_csum = dp_packet_l4_checksum_valid(pkt); + /* Validate the checksum only when hwol is not supported. */ if (extract_l4(&ctx->key, l4, tail - l4, &ctx->icmp_related, l3, !hwol_good_l4_csum)) { @@ -1985,6 +2008,7 @@ nat_ipv6_addrs_delta(struct in6_addr *ipv6_aligned_min, uint8_t *ipv6_min_lo = &ipv6_aligned_min->s6_addr[0] + sizeof(uint64_t); uint8_t *ipv6_max_hi = &ipv6_aligned_max->s6_addr[0]; uint8_t *ipv6_max_lo = &ipv6_aligned_max->s6_addr[0] + sizeof(uint64_t); + uint64_t diff; ovs_be64 addr6_64_min_hi; ovs_be64 addr6_64_min_lo; @@ -1996,7 +2020,6 @@ nat_ipv6_addrs_delta(struct in6_addr *ipv6_aligned_min, memcpy(&addr6_64_max_hi, ipv6_max_hi, sizeof addr6_64_max_hi); memcpy(&addr6_64_max_lo, ipv6_max_lo, sizeof addr6_64_max_lo); - uint64_t diff; if (addr6_64_min_hi == addr6_64_max_hi && ntohll(addr6_64_min_lo) <= ntohll(addr6_64_max_lo)) { diff = ntohll(addr6_64_max_lo) - ntohll(addr6_64_min_lo); @@ -2023,6 +2046,7 @@ nat_ipv6_addr_increment(struct in6_addr *ipv6_aligned, uint32_t increment) { uint8_t *ipv6_hi = &ipv6_aligned->s6_addr[0]; uint8_t *ipv6_lo = &ipv6_aligned->s6_addr[0] + sizeof(ovs_be64); + ovs_be64 addr6_64_hi; ovs_be64 addr6_64_lo; memcpy(&addr6_64_hi, ipv6_hi, sizeof addr6_64_hi); @@ -2075,10 +2099,13 @@ nat_select_range_tuple(struct conntrack *ct, const struct conn *conn, enum { MIN_NAT_EPHEMERAL_PORT = 1024, MAX_NAT_EPHEMERAL_PORT = 65535 }; + struct ct_addr ct_addr; + struct ct_addr max_ct_addr; uint16_t min_port; uint16_t max_port; uint16_t first_port; - + uint32_t address_index; + uint32_t deltaa; uint32_t hash = nat_range_hash(conn, ct->hash_basis); if ((conn->nat_info->nat_action & NAT_ACTION_SRC) && @@ -2099,14 +2126,10 @@ nat_select_range_tuple(struct conntrack *ct, const struct conn *conn, max_port = conn->nat_info->max_port; } - uint32_t deltaa = 0; - uint32_t address_index; - struct ct_addr ct_addr; + deltaa = 0; memset(&ct_addr, 0, sizeof ct_addr); - struct ct_addr max_ct_addr; memset(&max_ct_addr, 0, sizeof max_ct_addr); max_ct_addr = conn->nat_info->max_addr; - if (conn->key.dl_type == htons(ETH_TYPE_IP)) { deltaa = ntohl(conn->nat_info->max_addr.ipv4_aligned) - ntohl(conn->nat_info->min_addr.ipv4_aligned); @@ -2134,6 +2157,8 @@ nat_select_range_tuple(struct conntrack *ct, const struct conn *conn, struct ct_addr first_addr = ct_addr; while (true) { + bool new_insert; + if (conn->nat_info->nat_action & NAT_ACTION_SRC) { nat_conn->rev_key.dst.addr = ct_addr; } else { @@ -2149,8 +2174,8 @@ nat_select_range_tuple(struct conntrack *ct, const struct conn *conn, nat_conn->rev_key.src.port = htons(port); } - bool new_insert = nat_conn_keys_insert(&ct->nat_conn_keys, nat_conn, - ct->hash_basis); + new_insert = nat_conn_keys_insert(&ct->nat_conn_keys, nat_conn, + ct->hash_basis); if (new_insert) { return true; } else if (!all_ports_tried) { @@ -2216,15 +2241,17 @@ static bool nat_conn_keys_insert(struct hmap *nat_conn_keys, const struct conn *nat_conn, uint32_t basis) { - struct nat_conn_key_node *nat_conn_key_node = - nat_conn_keys_lookup(nat_conn_keys, &nat_conn->rev_key, basis); + struct nat_conn_key_node *nat_conn_key_node; + struct nat_conn_key_node *nat_conn_key; + uint32_t nat_conn_key_hash; + nat_conn_key_node = nat_conn_keys_lookup(nat_conn_keys, &nat_conn->rev_key, + basis); if (!nat_conn_key_node) { - struct nat_conn_key_node *nat_conn_key = xzalloc(sizeof *nat_conn_key); + nat_conn_key = xzalloc(sizeof *nat_conn_key); nat_conn_key->key = nat_conn->rev_key; nat_conn_key->value = nat_conn->key; - uint32_t nat_conn_key_hash = conn_key_hash(&nat_conn_key->key, - basis); + nat_conn_key_hash = conn_key_hash(&nat_conn_key->key, basis); hmap_insert(nat_conn_keys, &nat_conn_key->node, nat_conn_key_hash); return true; } @@ -2262,13 +2289,13 @@ conn_key_lookup(struct conntrack_bucket *ctb, struct conn_lookup_ctx *ctx, HMAP_FOR_EACH_WITH_HASH (conn, node, hash, &ctb->connections) { if (!conn_key_cmp(&conn->key, &ctx->key) - && !conn_expired(conn, now)) { + && !conn_expired(conn, now)) { ctx->conn = conn; ctx->reply = false; break; } if (!conn_key_cmp(&conn->rev_key, &ctx->key) - && !conn_expired(conn, now)) { + && !conn_expired(conn, now)) { ctx->conn = conn; ctx->reply = true; break; @@ -2306,7 +2333,6 @@ new_conn(struct conntrack_bucket *ctb, struct dp_packet *pkt, struct conn *newconn; newconn = l4_protos[key->nw_proto]->new_conn(ctb, pkt, now); - if (newconn) { newconn->key = *key; } @@ -2413,14 +2439,12 @@ conntrack_dump_next(struct conntrack_dump *dump, struct ct_dpif_entry *entry) { struct conntrack *ct = dump->ct; long long now = time_msec(); + struct hmap_node *node; + struct conn *conn; while (dump->bucket < CONNTRACK_BUCKETS) { - struct hmap_node *node; - ct_lock_lock(&ct->buckets[dump->bucket].lock); for (;;) { - struct conn *conn; - node = hmap_at_position(&ct->buckets[dump->bucket].connections, &dump->bucket_pos); if (!node) { @@ -2457,14 +2481,16 @@ int conntrack_flush(struct conntrack *ct, const uint16_t *zone) { unsigned i; + struct conn *conn; + struct conn *next; + struct alg_exp_node *alg_exp_node; + struct alg_exp_node *alg_exp_node_next; for (i = 0; i < CONNTRACK_BUCKETS; i++) { - struct conn *conn, *next; - ct_lock_lock(&ct->buckets[i].lock); HMAP_FOR_EACH_SAFE (conn, next, node, &ct->buckets[i].connections) { - if ((!zone || *zone == conn->key.zone) && - (conn->conn_type == CT_CONN_TYPE_DEFAULT)) { + if ((!zone || *zone == conn->key.zone) + && (conn->conn_type == CT_CONN_TYPE_DEFAULT)) { conn_clean(ct, conn, &ct->buckets[i]); } } @@ -2472,9 +2498,8 @@ conntrack_flush(struct conntrack *ct, const uint16_t *zone) } ct_rwlock_wrlock(&ct->resources_lock); - struct alg_exp_node *alg_exp_node, *alg_exp_node_next; - HMAP_FOR_EACH_SAFE (alg_exp_node, alg_exp_node_next, - node, &ct->alg_expectations) { + HMAP_FOR_EACH_SAFE (alg_exp_node, alg_exp_node_next, node, + &ct->alg_expectations) { if (!zone || *zone == alg_exp_node->key.zone) { ovs_list_remove(&alg_exp_node->exp_node); hmap_remove(&ct->alg_expectations, &alg_exp_node->node); @@ -2493,8 +2518,8 @@ expectation_lookup(struct hmap *alg_expectations, struct conn_key check_key = *key; check_key.src.port = ALG_WC_SRC_PORT; struct alg_exp_node *alg_exp_node; - uint32_t alg_exp_conn_key_hash = conn_key_hash(&check_key, basis); + HMAP_FOR_EACH_WITH_HASH (alg_exp_node, node, alg_exp_conn_key_hash, alg_expectations) { @@ -2515,6 +2540,9 @@ expectation_create(struct conntrack *ct, struct ct_addr src_addr; struct ct_addr dst_addr; struct ct_addr alg_nat_repl_addr; + struct alg_exp_node *alg_exp; + struct alg_exp_node *alg_exp_node; + uint32_t alg_exp_conn_key_hash; switch (mode) { case CT_FTP_MODE_ACTIVE: @@ -2532,8 +2560,7 @@ expectation_create(struct conntrack *ct, OVS_NOT_REACHED(); } - struct alg_exp_node *alg_exp_node = - xzalloc(sizeof *alg_exp_node); + alg_exp_node = xzalloc(sizeof *alg_exp_node); alg_exp_node->key.dl_type = master_conn->key.dl_type; alg_exp_node->key.nw_proto = master_conn->key.nw_proto; alg_exp_node->key.zone = master_conn->key.zone; @@ -2549,8 +2576,8 @@ expectation_create(struct conntrack *ct, * likely that the lookup will fail and * expectation_create() will be called below. */ ct_rwlock_wrlock(&ct->resources_lock); - struct alg_exp_node *alg_exp = expectation_lookup( - &ct->alg_expectations, &alg_exp_node->key, ct->hash_basis); + alg_exp = expectation_lookup(&ct->alg_expectations, &alg_exp_node->key, + ct->hash_basis); if (alg_exp) { free(alg_exp_node); ct_rwlock_unlock(&ct->resources_lock); @@ -2558,13 +2585,9 @@ expectation_create(struct conntrack *ct, } alg_exp_node->alg_nat_repl_addr = alg_nat_repl_addr; - uint32_t alg_exp_conn_key_hash = - conn_key_hash(&alg_exp_node->key, - ct->hash_basis); - hmap_insert(&ct->alg_expectations, - &alg_exp_node->node, + alg_exp_conn_key_hash = conn_key_hash(&alg_exp_node->key, ct->hash_basis); + hmap_insert(&ct->alg_expectations, &alg_exp_node->node, alg_exp_conn_key_hash); - alg_exp_init_expiration(ct, alg_exp_node, now); ct_rwlock_unlock(&ct->resources_lock); } @@ -2594,34 +2617,43 @@ repl_ftp_v4_addr(struct dp_packet *pkt, ovs_be32 v4_addr_rep, { enum { MAX_FTP_V4_NAT_DELTA = 8 }; + char *byte_str; + int overall_delta; + size_t remain_size; + uint8_t i; /* Do conservative check for pathological MTU usage. */ uint32_t orig_used_size = dp_packet_size(pkt); uint16_t allocated_size = dp_packet_get_allocated(pkt); + if (orig_used_size + MAX_FTP_V4_NAT_DELTA > allocated_size) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); + VLOG_WARN_RL(&rl, "Unsupported effective MTU %u used with FTP", allocated_size); return 0; } - size_t remain_size = tcp_payload_length(pkt) - - addr_offset_from_ftp_data_start; - - int overall_delta = 0; - char *byte_str = ftp_data_start + addr_offset_from_ftp_data_start; + remain_size = tcp_payload_length(pkt) - addr_offset_from_ftp_data_start; + overall_delta = 0; + byte_str = ftp_data_start + addr_offset_from_ftp_data_start; /* Replace the existing IPv4 address by the new one. */ - for (uint8_t i = 0; i < 4; i++) { + for (i = 0; i < 4; i++) { + char *next_delim; + char rep_str[4]; + int substr_size; + int replace_size; + uint8_t rep_byte; + /* Find the end of the string for this octet. */ - char *next_delim = memchr(byte_str, ',', 4); + next_delim = memchr(byte_str, ',', 4); ovs_assert(next_delim); - int substr_size = next_delim - byte_str; + substr_size = next_delim - byte_str; remain_size -= substr_size; /* Compose the new string for this octet, and replace it. */ - char rep_str[4]; - uint8_t rep_byte = get_v4_byte_be(v4_addr_rep, i); - int replace_size = sprintf(rep_str, "%d", rep_byte); + rep_byte = get_v4_byte_be(v4_addr_rep, i); + replace_size = sprintf(rep_str, "%d", rep_byte); replace_substring(byte_str, substr_size, remain_size, rep_str, replace_size); overall_delta += replace_size - substr_size; @@ -2647,6 +2679,7 @@ static char * terminate_number_str(char *str, uint8_t max_digits) { uint8_t digits_found = 0; + while (isdigit(*str) && digits_found <= max_digits) { str++; digits_found++; @@ -2667,8 +2700,7 @@ get_ftp_ctl_msg(struct dp_packet *pkt, char *ftp_msg) LARGEST_FTP_MSG_OF_INTEREST); size_t tcp_hdr_len = TCP_OFFSET(th->tcp_ctl) * 4; - ovs_strlcpy(ftp_msg, tcp_hdr + tcp_hdr_len, - tcp_payload_of_interest); + ovs_strlcpy(ftp_msg, tcp_hdr + tcp_hdr_len, tcp_payload_of_interest); } static enum ftp_ctl_pkt @@ -2677,15 +2709,16 @@ detect_ftp_ctl_type(const struct conn_lookup_ctx *ctx, { char ftp_msg[LARGEST_FTP_MSG_OF_INTEREST + 1] = {0}; + get_ftp_ctl_msg(pkt, ftp_msg); if (ctx->key.dl_type == htons(ETH_TYPE_IPV6)) { - if (strncasecmp(ftp_msg, FTP_EPRT_CMD, strlen(FTP_EPRT_CMD)) && - !strcasestr(ftp_msg, FTP_EPSV_REPLY)) { + if (strncasecmp(ftp_msg, FTP_EPRT_CMD, strlen(FTP_EPRT_CMD)) + && !strcasestr(ftp_msg, FTP_EPSV_REPLY)) { return CT_FTP_CTL_OTHER; } } else { - if (strncasecmp(ftp_msg, FTP_PORT_CMD, strlen(FTP_PORT_CMD)) && - strncasecmp(ftp_msg, FTP_PASV_REPLY_CODE, + if (strncasecmp(ftp_msg, FTP_PORT_CMD, strlen(FTP_PORT_CMD)) + && strncasecmp(ftp_msg, FTP_PASV_REPLY_CODE, strlen(FTP_PASV_REPLY_CODE))) { return CT_FTP_CTL_OTHER; } @@ -2939,38 +2972,41 @@ repl_ftp_v6_addr(struct dp_packet *pkt, struct ct_addr v6_addr_rep, { /* This is slightly bigger than really possible. */ enum { MAX_FTP_V6_NAT_DELTA = 45 }; + int overall_delta; + uint16_t allocated_size; + uint32_t orig_used_size; + size_t replace_addr_size; + size_t remain_size; + const char *rc; + char *pkt_addr_str; + char v6_addr_str[IPV6_SCAN_LEN] = {0}; if (mode == CT_FTP_MODE_PASSIVE) { return 0; } /* Do conservative check for pathological MTU usage. */ - uint32_t orig_used_size = dp_packet_size(pkt); - uint16_t allocated_size = dp_packet_get_allocated(pkt); + orig_used_size = dp_packet_size(pkt); + allocated_size = dp_packet_get_allocated(pkt); if (orig_used_size + MAX_FTP_V6_NAT_DELTA > allocated_size) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); + VLOG_WARN_RL(&rl, "Unsupported effective MTU %u used with FTP", allocated_size); return 0; } - const char *rc; - char v6_addr_str[IPV6_SCAN_LEN] = {0}; rc = inet_ntop(AF_INET6, &v6_addr_rep.ipv6_aligned, v6_addr_str, - IPV6_SCAN_LEN - 1); + IPV6_SCAN_LEN - 1); ovs_assert(rc != NULL); - size_t replace_addr_size = strlen(v6_addr_str); - - size_t remain_size = tcp_payload_length(pkt) - - addr_offset_from_ftp_data_start; - - char *pkt_addr_str = ftp_data_start + addr_offset_from_ftp_data_start; - replace_substring(pkt_addr_str, addr_size, remain_size, - v6_addr_str, replace_addr_size); - - int overall_delta = (int) replace_addr_size - (int) addr_size; + replace_addr_size = strlen(v6_addr_str); + remain_size = tcp_payload_length(pkt) - addr_offset_from_ftp_data_start; + pkt_addr_str = ftp_data_start + addr_offset_from_ftp_data_start; + replace_substring(pkt_addr_str, addr_size, remain_size, v6_addr_str, + replace_addr_size); + overall_delta = (int) replace_addr_size - (int) addr_size; dp_packet_set_size(pkt, orig_used_size + overall_delta); return overall_delta; } @@ -2984,8 +3020,10 @@ handle_ftp_ctl(struct conntrack *ct, const struct conn_lookup_ctx *ctx, struct ip_header *l3_hdr = dp_packet_l3(pkt); ovs_be32 v4_addr_rep = 0; struct ct_addr v6_addr_rep; + struct ovs_16aligned_ip6_hdr *nh6; size_t addr_offset_from_ftp_data_start; size_t addr_size = 0; + int64_t seq_skew; char *ftp_data_start; bool do_seq_skew_adj = true; enum ct_alg_mode mode = CT_FTP_MODE_ACTIVE; @@ -2998,29 +3036,32 @@ handle_ftp_ctl(struct conntrack *ct, const struct conn_lookup_ctx *ctx, do_seq_skew_adj = false; } - struct ovs_16aligned_ip6_hdr *nh6 = dp_packet_l3(pkt); - int64_t seq_skew = 0; + nh6 = dp_packet_l3(pkt); + seq_skew = 0; if (ftp_ctl == CT_FTP_CTL_OTHER) { seq_skew = conn_for_expectation->seq_skew; } else if (ftp_ctl == CT_FTP_CTL_INTEREST) { enum ftp_ctl_pkt rc; + if (ctx->key.dl_type == htons(ETH_TYPE_IPV6)) { - rc = process_ftp_ctl_v6(ct, pkt, conn_for_expectation, - now, &v6_addr_rep, &ftp_data_start, + rc = process_ftp_ctl_v6(ct, pkt, conn_for_expectation, now, + &v6_addr_rep, &ftp_data_start, &addr_offset_from_ftp_data_start, &addr_size, &mode); } else { - rc = process_ftp_ctl_v4(ct, pkt, conn_for_expectation, - now, &v4_addr_rep, &ftp_data_start, + rc = process_ftp_ctl_v4(ct, pkt, conn_for_expectation, now, + &v4_addr_rep, &ftp_data_start, &addr_offset_from_ftp_data_start); } if (rc == CT_FTP_CTL_INVALID) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); + VLOG_WARN_RL(&rl, "Invalid FTP control packet format"); pkt->md.ct_state |= CS_TRACKED | CS_INVALID; return; } else if (rc == CT_FTP_CTL_INTEREST) { uint16_t ip_len; + if (ctx->key.dl_type == htons(ETH_TYPE_IPV6)) { seq_skew = repl_ftp_v6_addr(pkt, v6_addr_rep, ftp_data_start, addr_offset_from_ftp_data_start, @@ -3055,7 +3096,6 @@ handle_ftp_ctl(struct conntrack *ct, const struct conn_lookup_ctx *ctx, struct tcp_header *th = dp_packet_l4(pkt); if (do_seq_skew_adj && seq_skew != 0) { if (ctx->reply != conn_for_expectation->seq_skew_dir) { - uint32_t tcp_ack = ntohl(get_16aligned_be32(&th->tcp_ack)); if ((seq_skew > 0) && (tcp_ack < seq_skew)) { @@ -3070,6 +3110,7 @@ handle_ftp_ctl(struct conntrack *ct, const struct conn_lookup_ctx *ctx, put_16aligned_be32(&th->tcp_ack, new_tcp_ack); } else { uint32_t tcp_seq = ntohl(get_16aligned_be32(&th->tcp_seq)); + if ((seq_skew > 0) && (UINT32_MAX - tcp_seq < seq_skew)) { tcp_seq = seq_skew - (UINT32_MAX - tcp_seq); } else if ((seq_skew < 0) && (tcp_seq < -seq_skew)) { -- 2.13.6 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev