}
static enum ct_alg_ctl_type
-get_alg_ctl_type(const struct dp_packet *pkt)
+get_alg_ctl_type(const struct dp_packet *pkt, ovs_be16 tp_src, ovs_be16 tp_dst,
+ const char *helper)
{
- uint8_t ip_proto = get_ip_proto(pkt);
- struct udp_header *uh = dp_packet_l4(pkt);
- struct tcp_header *th = dp_packet_l4(pkt);
-
/* CT_IPPORT_FTP/TFTP is used because IPPORT_FTP/TFTP in not defined
* in OSX, at least in in.h. Since these values will never change, remove
* the external dependency. */
enum { CT_IPPORT_FTP = 21 };
enum { CT_IPPORT_TFTP = 69 };
+ uint8_t ip_proto = get_ip_proto(pkt);
+ struct udp_header *uh = dp_packet_l4(pkt);
+ struct tcp_header *th = dp_packet_l4(pkt);
+ ovs_be16 ftp_src_port = htons(CT_IPPORT_FTP);
+ ovs_be16 ftp_dst_port = htons(CT_IPPORT_FTP);
+ ovs_be16 tftp_dst_port = htons(CT_IPPORT_TFTP);
+
+ if (OVS_UNLIKELY(tp_dst)) {
+ if (helper && !strncmp(helper, "ftp", strlen("ftp"))) {
+ ftp_dst_port = tp_dst;
+ } else if (helper && !strncmp(helper, "tftp", strlen("tftp"))) {
+ tftp_dst_port = tp_dst;
+ }
+ } else if (OVS_UNLIKELY(tp_src)) {
+ if (helper && !strncmp(helper, "ftp", strlen("ftp"))) {
+ ftp_src_port = tp_src;
+ }
+ }
- if (ip_proto == IPPROTO_UDP && uh->udp_dst == htons(CT_IPPORT_TFTP)) {
+ if (ip_proto == IPPROTO_UDP && uh->udp_dst == tftp_dst_port) {
return CT_ALG_CTL_TFTP;
} else if (ip_proto == IPPROTO_TCP &&
- (th->tcp_src == htons(CT_IPPORT_FTP) ||
- th->tcp_dst == htons(CT_IPPORT_FTP))) {
+ (th->tcp_src == ftp_src_port || th->tcp_dst == ftp_dst_port)) {
return CT_ALG_CTL_FTP;
}
return CT_ALG_CTL_NONE;
const struct conn *conn_for_expectation)
{
/* ALG control packet handling with expectation creation. */
- if (OVS_UNLIKELY(alg_helpers[ct_alg_ctl] && conn)) {
+ if (OVS_UNLIKELY(alg_helpers[ct_alg_ctl] && conn && conn->alg)) {
alg_helpers[ct_alg_ctl](ct, ctx, pkt, conn_for_expectation, now,
CT_FTP_CTL_INTEREST, nat);
}
}
}
+static bool
+ct_verify_helper(const char *helper, enum ct_alg_ctl_type ct_alg_ctl)
+{
+ if (ct_alg_ctl == CT_ALG_CTL_NONE) {
+ return true;
+ } else if (helper) {
+ if ((ct_alg_ctl == CT_ALG_CTL_FTP) &&
+ !strncmp(helper, "ftp", strlen("ftp"))) {
+ return true;
+ } else if ((ct_alg_ctl == CT_ALG_CTL_TFTP) &&
+ !strncmp(helper, "tftp", strlen("tftp"))) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+}
+
/* This function is called with the bucket lock held. */
static struct conn *
conn_not_found(struct conntrack *ct, struct dp_packet *pkt,
const struct nat_action_info_t *nat_action_info,
struct conn *conn_for_un_nat_copy,
const char *helper,
- const struct alg_exp_node *alg_exp)
+ const struct alg_exp_node *alg_exp,
+ enum ct_alg_ctl_type ct_alg_ctl)
{
unsigned bucket = hash_to_bucket(ctx->hash);
struct conn *nc = NULL;
nc->rev_key = nc->key;
conn_key_reverse(&nc->rev_key);
- if (helper) {
- nc->alg = xstrdup(helper);
+ if (ct_verify_helper(helper, ct_alg_ctl)) {
+ nc->alg = nullable_xstrdup(helper);
}
if (alg_exp) {
bool force, bool commit, long long now, const uint32_t *setmark,
const struct ovs_key_ct_labels *setlabel,
const struct nat_action_info_t *nat_action_info,
- const char *helper)
+ ovs_be16 tp_src, ovs_be16 tp_dst, const char *helper)
{
struct conn *conn;
unsigned bucket = hash_to_bucket(ctx->hash);
struct conn conn_for_un_nat_copy;
conn_for_un_nat_copy.conn_type = CT_CONN_TYPE_DEFAULT;
- enum ct_alg_ctl_type ct_alg_ctl = get_alg_ctl_type(pkt);
+ enum ct_alg_ctl_type ct_alg_ctl = get_alg_ctl_type(pkt, tp_src, tp_dst,
+ helper);
if (OVS_LIKELY(conn)) {
if (OVS_LIKELY(!conn_update_state_alg(ct, pkt, ctx, conn,
ct_rwlock_unlock(&ct->resources_lock);
conn = conn_not_found(ct, pkt, ctx, commit, now, nat_action_info,
- &conn_for_un_nat_copy, helper, alg_exp);
+ &conn_for_un_nat_copy, helper, alg_exp,
+ ct_alg_ctl);
}
write_ct_md(pkt, zone, conn, &ctx->key, alg_exp);
ovs_be16 dl_type, bool force, bool commit, uint16_t zone,
const uint32_t *setmark,
const struct ovs_key_ct_labels *setlabel,
- const char *helper,
+ ovs_be16 tp_src, ovs_be16 tp_dst, const char *helper,
const struct nat_action_info_t *nat_action_info,
long long now)
{
continue;
}
process_one(ct, packet, &ctx, zone, force, commit, now, setmark,
- setlabel, nat_action_info, helper);
+ setlabel, nat_action_info, tp_src, tp_dst, helper);
}
return 0;
return false;
}
- if (inner_key.src.addr.ipv4_aligned != key->dst.addr.ipv4_aligned
- || inner_key.dst.addr.ipv4_aligned != key->src.addr.ipv4_aligned) {
+ if (inner_key.src.addr.ipv4_aligned != key->dst.addr.ipv4_aligned) {
return false;
}
/* pf doesn't do this, but it seems a good idea */
if (!ipv6_addr_equals(&inner_key.src.addr.ipv6_aligned,
- &key->dst.addr.ipv6_aligned)
- || !ipv6_addr_equals(&inner_key.dst.addr.ipv6_aligned,
- &key->src.addr.ipv6_aligned)) {
+ &key->dst.addr.ipv6_aligned)) {
return false;
}