From patchwork Tue Sep 29 20:40:32 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joe Stringer X-Patchwork-Id: 524024 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from archives.nicira.com (li376-54.members.linode.com [96.126.127.54]) by ozlabs.org (Postfix) with ESMTP id D2885140180 for ; Wed, 30 Sep 2015 06:42:30 +1000 (AEST) Received: from archives.nicira.com (localhost [127.0.0.1]) by archives.nicira.com (Postfix) with ESMTP id A18AA107D6; Tue, 29 Sep 2015 13:41:27 -0700 (PDT) X-Original-To: dev@openvswitch.org Delivered-To: dev@openvswitch.org Received: from mx3v1.cudamail.com (mx3.cudamail.com [64.34.241.5]) by archives.nicira.com (Postfix) with ESMTPS id 45D7F10704 for ; Tue, 29 Sep 2015 13:41:26 -0700 (PDT) Received: from bar3.cudamail.com (bar1 [192.168.15.1]) by mx3v1.cudamail.com (Postfix) with ESMTP id 5FA986183C5 for ; Tue, 29 Sep 2015 14:41:19 -0600 (MDT) X-ASG-Debug-ID: 1443559278-03dd7b4f9f01860001-byXFYA Received: from mx3-pf1.cudamail.com ([192.168.14.2]) by bar3.cudamail.com with ESMTP id sILTWCM3MjJTULn5 (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Tue, 29 Sep 2015 14:41:18 -0600 (MDT) X-Barracuda-Envelope-From: joestringer@nicira.com X-Barracuda-RBL-Trusted-Forwarder: 192.168.14.2 Received: from unknown (HELO mail-pa0-f42.google.com) (209.85.220.42) by mx3-pf1.cudamail.com with ESMTPS (RC4-SHA encrypted); 29 Sep 2015 20:41:18 -0000 Received-SPF: unknown (mx3-pf1.cudamail.com: Multiple SPF records returned) X-Barracuda-RBL-Trusted-Forwarder: 209.85.220.42 Received: by padhy16 with SMTP id hy16so15881608pad.1 for ; Tue, 29 Sep 2015 13:41:17 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=xfTd/V46brm7uuvCA1Xw4iiCM7eNxWJ0lwFg/RmG7DY=; b=TqrQ9ecBPP1EYRueO39KeczLRV57GjOuP3us5dij3Y9sAKx+sS2Vto5rlzKdPeU+Cv NgTHSb3IYyCGcLbfZC4ugeYKBXckLo9aEW/y9Zol6OCajywPH4WkiPH6IEd92/4AOLn6 CmoV01xjguk15X3gVZoN4SmnGS5mfrZEWXd7QKi2d88gPCeErbXtCOWJ61paJDsiFhkU PSN6Rco7c7deQj/BqaESRVJQ8UAXovKu7HkVY+JeWXbH7daVB22p//TvlMOrtd+03aVH /BaFrNYHR9IGsWIJfUHTZBj10IN96hbljNBrTKmY4oVY09VI4CassKM/DiYwTen5HG+s G/BA== X-Gm-Message-State: ALoCoQle6Yp3czI7O5z4LafrtzttEGx3zFbwTrucv3sd+yAkHtLP2ZA8WcGcmwXHNKdpoMvZBiuY X-Received: by 10.66.131.81 with SMTP id ok17mr34511767pab.150.1443559277476; Tue, 29 Sep 2015 13:41:17 -0700 (PDT) Received: from localhost.localdomain ([208.91.2.4]) by smtp.gmail.com with ESMTPSA id fe8sm27450431pab.40.2015.09.29.13.41.14 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 29 Sep 2015 13:41:17 -0700 (PDT) X-CudaMail-Envelope-Sender: joestringer@nicira.com X-Barracuda-Apparent-Source-IP: 208.91.2.4 From: Joe Stringer To: dev@openvswitch.org X-CudaMail-Whitelist-To: dev@openvswitch.org X-CudaMail-MID: CM-V1-928069486 X-CudaMail-DTE: 092915 X-CudaMail-Originating-IP: 209.85.220.42 Date: Tue, 29 Sep 2015 13:40:32 -0700 X-ASG-Orig-Subj: [##CM-V1-928069486##][PATCHv3 09/11] Add support for connection tracking helper/ALGs. Message-Id: <1443559234-7330-10-git-send-email-joestringer@nicira.com> X-Mailer: git-send-email 2.1.4 In-Reply-To: <1443559234-7330-1-git-send-email-joestringer@nicira.com> References: <1443559234-7330-1-git-send-email-joestringer@nicira.com> X-Barracuda-Connect: UNKNOWN[192.168.14.2] X-Barracuda-Start-Time: 1443559278 X-Barracuda-Encrypted: DHE-RSA-AES256-SHA X-Barracuda-URL: https://web.cudamail.com:443/cgi-mod/mark.cgi X-ASG-Whitelist: Header =?UTF-8?B?eFwtY3VkYW1haWxcLXdoaXRlbGlzdFwtdG8=?= X-Virus-Scanned: by bsmtpd at cudamail.com X-Barracuda-BRTS-Status: 1 Subject: [ovs-dev] [PATCHv3 09/11] Add support for connection tracking helper/ALGs. X-BeenThere: dev@openvswitch.org X-Mailman-Version: 2.1.16 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dev-bounces@openvswitch.org Sender: "dev" This patch adds support for specifying a "helper" or ALG to assist connection tracking for protocols that consist of multiple streams. Initially, only support for FTP is included. Below is an example set of flows to allow FTP control connections from port 1->2 to establish active data connections in the reverse direction: table=0,priority=1,action=drop table=0,arp,action=normal table=0,in_port=1,tcp,action=ct(alg=ftp,commit),2 table=0,in_port=2,tcp,ct_state=-trk,action=ct(table=1) table=1,in_port=2,tcp,ct_state=+trk+est,action=1 table=1,in_port=2,tcp,ct_state=+trk+rel,action=ct(commit),1 Signed-off-by: Joe Stringer Acked-by: Jarno Rajahalme Acked-by: Ben Pfaff --- v3: - Simplify action formatting using ds_chomp - Improve documentation - Add openflow wire format tests v2: - Address feedback from v1 --- datapath/linux/compat/include/linux/openvswitch.h | 3 + include/sparse/netinet/in.h | 2 + include/windows/netinet/in.h | 1 + lib/netlink.c | 11 ++ lib/netlink.h | 2 + lib/odp-util.c | 26 +++- lib/ofp-actions.c | 21 +++- lib/ofp-actions.h | 1 + lib/ofp-parse.c | 15 +++ lib/ofp-parse.h | 1 + ofproto/ofproto-dpif-xlate.c | 16 +++ tests/atlocal.in | 7 ++ tests/odp.at | 1 + tests/ofp-actions.at | 3 + tests/system-traffic.at | 145 ++++++++++++++++++++++ utilities/ovs-ofctl.8.in | 10 ++ 16 files changed, 263 insertions(+), 2 deletions(-) diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h index 9881c77..3c5a697 100644 --- a/datapath/linux/compat/include/linux/openvswitch.h +++ b/datapath/linux/compat/include/linux/openvswitch.h @@ -669,6 +669,7 @@ struct ovs_action_push_tnl { * @OVS_CT_ATTR_LABEL: %OVS_CT_LABEL_LEN value followed by %OVS_CT_LABEL_LEN * mask. For each bit set in the mask, the corresponding bit in the value is * copied to the connection tracking label field in the connection. + * @OVS_CT_ATTR_HELPER: variable length string defining conntrack ALG. */ enum ovs_ct_attr { OVS_CT_ATTR_UNSPEC, @@ -676,6 +677,8 @@ enum ovs_ct_attr { OVS_CT_ATTR_ZONE, /* u16 zone id. */ OVS_CT_ATTR_MARK, /* mark to associate with this connection. */ OVS_CT_ATTR_LABEL, /* label to associate with this connection. */ + OVS_CT_ATTR_HELPER, /* netlink helper to assist detection of + related connections. */ __OVS_CT_ATTR_MAX }; diff --git a/include/sparse/netinet/in.h b/include/sparse/netinet/in.h index f66f205..1223553 100644 --- a/include/sparse/netinet/in.h +++ b/include/sparse/netinet/in.h @@ -74,6 +74,8 @@ struct sockaddr_in6 { #define IPPROTO_DSTOPTS 60 #define IPPROTO_SCTP 132 +#define IPPORT_FTP 21 + /* All the IP options documented in Linux ip(7). */ #define IP_ADD_MEMBERSHIP 0 #define IP_DROP_MEMBERSHIP 1 diff --git a/include/windows/netinet/in.h b/include/windows/netinet/in.h index 7143cf5..e416999 100644 --- a/include/windows/netinet/in.h +++ b/include/windows/netinet/in.h @@ -18,5 +18,6 @@ #define __NETINET_IN_H 1 #define IPPROTO_GRE 47 +#define IPPORT_FTP 21 #endif /* netinet/in.h */ diff --git a/lib/netlink.c b/lib/netlink.c index 09723b2..66b4927 100644 --- a/lib/netlink.c +++ b/lib/netlink.c @@ -316,6 +316,17 @@ nl_msg_put_odp_port(struct ofpbuf *msg, uint16_t type, odp_port_t value) nl_msg_put_u32(msg, type, odp_to_u32(value)); } +/* Appends a Netlink attribute of the given 'type' with the 'len' characters + * of 'value', followed by the null byte to 'msg'. */ +void +nl_msg_put_string__(struct ofpbuf *msg, uint16_t type, const char *value, + size_t len) +{ + char *data = nl_msg_put_unspec_uninit(msg, type, len + 1); + + memcpy(data, value, len); + data[len] = '\0'; +} /* Appends a Netlink attribute of the given 'type' and the given * null-terminated string 'value' to 'msg'. */ diff --git a/lib/netlink.h b/lib/netlink.h index 6068f5d..210cab5 100644 --- a/lib/netlink.h +++ b/lib/netlink.h @@ -70,6 +70,8 @@ void nl_msg_put_be16(struct ofpbuf *, uint16_t type, ovs_be16 value); void nl_msg_put_be32(struct ofpbuf *, uint16_t type, ovs_be32 value); void nl_msg_put_be64(struct ofpbuf *, uint16_t type, ovs_be64 value); void nl_msg_put_odp_port(struct ofpbuf *, uint16_t type, odp_port_t value); +void nl_msg_put_string__(struct ofpbuf *, uint16_t type, const char *value, + size_t len); void nl_msg_put_string(struct ofpbuf *, uint16_t type, const char *value); size_t nl_msg_start_nested(struct ofpbuf *, uint16_t type); diff --git a/lib/odp-util.c b/lib/odp-util.c index 2694bbf..f75fc34 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -52,6 +52,7 @@ VLOG_DEFINE_THIS_MODULE(odp_util); /* The set of characters that may separate one action or one key attribute * from another. */ static const char *delimiters = ", \t\r\n"; +static const char *delimiters_end = ", \t\r\n)"; struct attr_len_tbl { int len; @@ -544,6 +545,8 @@ static const struct nl_policy ovs_conntrack_policy[] = { .min_len = sizeof(uint32_t) * 2 }, [OVS_CT_ATTR_LABEL] = { .type = NL_A_UNSPEC, .optional = true, .min_len = sizeof(ovs_u128) * 2 }, + [OVS_CT_ATTR_HELPER] = { .type = NL_A_STRING, .optional = true, + .min_len = 1, .max_len = 16 }, }; static void @@ -552,6 +555,7 @@ format_odp_conntrack_action(struct ds *ds, const struct nlattr *attr) struct nlattr *a[ARRAY_SIZE(ovs_conntrack_policy)]; const ovs_u128 *label; const uint32_t *mark; + const char *helper; uint32_t flags; uint16_t zone; @@ -564,9 +568,10 @@ format_odp_conntrack_action(struct ds *ds, const struct nlattr *attr) zone = a[OVS_CT_ATTR_ZONE] ? nl_attr_get_u16(a[OVS_CT_ATTR_ZONE]) : 0; mark = a[OVS_CT_ATTR_MARK] ? nl_attr_get(a[OVS_CT_ATTR_MARK]) : NULL; label = a[OVS_CT_ATTR_LABEL] ? nl_attr_get(a[OVS_CT_ATTR_LABEL]): NULL; + helper = a[OVS_CT_ATTR_HELPER] ? nl_attr_get(a[OVS_CT_ATTR_HELPER]) : NULL; ds_put_format(ds, "ct"); - if (flags || zone || mark || label) { + if (flags || zone || mark || label || helper) { ds_put_cstr(ds, "("); if (flags & OVS_CT_F_COMMIT) { ds_put_format(ds, "commit,"); @@ -585,6 +590,9 @@ format_odp_conntrack_action(struct ds *ds, const struct nlattr *attr) ds_put_hex(ds, (label + 1), sizeof(*label)); ds_put_char(ds, ','); } + if (helper) { + ds_put_format(ds, "helper=%s,", helper); + } ds_chomp(ds, ','); ds_put_cstr(ds, ")"); } @@ -1044,6 +1052,8 @@ parse_conntrack_action(const char *s_, struct ofpbuf *actions) const char *s = s_; if (ovs_scan(s, "ct")) { + const char *helper = NULL; + size_t helper_len = 0; uint32_t flags = 0; uint16_t zone = 0; struct { @@ -1103,6 +1113,16 @@ parse_conntrack_action(const char *s_, struct ofpbuf *actions) s = tail; continue; } + if (ovs_scan(s, "helper=%n", &n)) { + s += n; + helper_len = strcspn(s, delimiters_end); + if (!helper_len || helper_len > 15) { + return -EINVAL; + } + helper = s; + s += helper_len; + continue; + } return -EINVAL; } @@ -1124,6 +1144,10 @@ parse_conntrack_action(const char *s_, struct ofpbuf *actions) nl_msg_put_unspec(actions, OVS_CT_ATTR_LABEL, &ct_label, sizeof(ct_label)); } + if (helper) { + nl_msg_put_string__(actions, OVS_CT_ATTR_HELPER, helper, + helper_len); + } nl_msg_end_nested(actions, start); } diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c index dd0c7cc..97447fc 100644 --- a/lib/ofp-actions.c +++ b/lib/ofp-actions.c @@ -15,6 +15,8 @@ */ #include +#include + #include "ofp-actions.h" #include "bundle.h" #include "byte-order.h" @@ -4696,7 +4698,9 @@ struct nx_action_conntrack { }; uint8_t recirc_table; /* Recirculate to a specific table, or NX_CT_RECIRC_NONE for no recirculation. */ - uint8_t pad[5]; /* Zeroes */ + uint8_t pad[3]; /* Zeroes */ + ovs_be16 alg; /* Well-known port number for the protocol. + * 0 indicates no ALG is required. */ /* Followed by a sequence of ofpact elements, until the end of the action * is reached. */ }; @@ -4746,6 +4750,7 @@ decode_NXAST_RAW_CT(const struct nx_action_conntrack *nac, goto out; } conntrack->recirc_table = nac->recirc_table; + conntrack->alg = ntohs(nac->alg); ofpbuf_pull(out, sizeof(*conntrack)); @@ -4793,6 +4798,7 @@ encode_CT(const struct ofpact_conntrack *conntrack, nac->zone_imm = htons(conntrack->zone_imm); } nac->recirc_table = conntrack->recirc_table; + nac->alg = htons(conntrack->alg); len = ofpacts_put_openflow_actions(conntrack->actions, ofpact_ct_get_action_len(conntrack), @@ -4837,6 +4843,8 @@ parse_CT(char *arg, struct ofpbuf *ofpacts, return error; } } + } else if (!strcmp(key, "alg")) { + error = str_to_connhelper(value, &oc->alg); } else if (!strcmp(key, "exec")) { /* Hide existing actions from ofpacts_parse_copy(), so the * nesting can be handled transparently. */ @@ -4860,6 +4868,16 @@ parse_CT(char *arg, struct ofpbuf *ofpacts, } static void +format_alg(int port, struct ds *s) +{ + if (port == IPPORT_FTP) { + ds_put_format(s, "alg=ftp,"); + } else if (port) { + ds_put_format(s, "alg=%d,", port); + } +} + +static void format_CT(const struct ofpact_conntrack *a, struct ds *s) { ds_put_cstr(s, "ct("); @@ -4881,6 +4899,7 @@ format_CT(const struct ofpact_conntrack *a, struct ds *s) ofpacts_format(a->actions, ofpact_ct_get_action_len(a), s); ds_put_format(s, "),"); } + format_alg(a->alg, s); ds_chomp(s, ','); ds_put_char(s, ')'); } diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h index a0e270c..1311a55 100644 --- a/lib/ofp-actions.h +++ b/lib/ofp-actions.h @@ -496,6 +496,7 @@ struct { \ uint16_t flags; \ uint16_t zone_imm; \ struct mf_subfield zone_src; \ + uint16_t alg; \ uint8_t recirc_table; \ } diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index 5950f06..8437656 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "byte-order.h" #include "dynamic-string.h" @@ -168,6 +169,20 @@ str_to_ip(const char *str, ovs_be32 *ip) return NULL; } +/* Parses 'str' as a conntrack helper into 'alg'. + * + * Returns NULL if successful, otherwise a malloc()'d string describing the + * error. The caller is responsible for freeing the returned string. */ +char * OVS_WARN_UNUSED_RESULT +str_to_connhelper(const char *str, uint16_t *alg) +{ + if (!strcmp(str, "ftp")) { + *alg = IPPORT_FTP; + return NULL; + } + return xasprintf("invalid conntrack helper \"%s\"", str); +} + struct protocol { const char *name; uint16_t dl_type; diff --git a/lib/ofp-parse.h b/lib/ofp-parse.h index b64a32e..36f9acc 100644 --- a/lib/ofp-parse.h +++ b/lib/ofp-parse.h @@ -99,5 +99,6 @@ char *str_to_u64(const char *str, uint64_t *valuep) OVS_WARN_UNUSED_RESULT; char *str_to_be64(const char *str, ovs_be64 *valuep) OVS_WARN_UNUSED_RESULT; char *str_to_mac(const char *str, struct eth_addr *mac) OVS_WARN_UNUSED_RESULT; char *str_to_ip(const char *str, ovs_be32 *ip) OVS_WARN_UNUSED_RESULT; +char *str_to_connhelper(const char *str, uint16_t *alg) OVS_WARN_UNUSED_RESULT; #endif /* ofp-parse.h */ diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c index 5628b64..a7ac3e1 100644 --- a/ofproto/ofproto-dpif-xlate.c +++ b/ofproto/ofproto-dpif-xlate.c @@ -4192,6 +4192,21 @@ put_ct_label(const struct flow *flow, struct flow *base_flow, } static void +put_ct_helper(struct ofpbuf *odp_actions, struct ofpact_conntrack *ofc) +{ + if (ofc->alg) { + if (ofc->alg == IPPORT_FTP) { + const char *helper = "ftp"; + + nl_msg_put_string__(odp_actions, OVS_CT_ATTR_HELPER, helper, + strlen(helper)); + } else { + VLOG_WARN("Cannot serialize connhelper %d\n", ofc->alg); + } + } +} + +static void compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc) { ovs_u128 old_ct_label = ctx->base_flow.ct_label; @@ -4221,6 +4236,7 @@ compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc) nl_msg_put_u16(ctx->odp_actions, OVS_CT_ATTR_ZONE, zone); put_ct_mark(&ctx->xin->flow, &ctx->base_flow, ctx->odp_actions, ctx->wc); put_ct_label(&ctx->xin->flow, &ctx->base_flow, ctx->odp_actions, ctx->wc); + put_ct_helper(ctx->odp_actions, ofc); nl_msg_end_nested(ctx->odp_actions, ct_offset); /* Restore the original ct fields in the key. These should only be exposed diff --git a/tests/atlocal.in b/tests/atlocal.in index 8e9fd9b..095bc40 100644 --- a/tests/atlocal.in +++ b/tests/atlocal.in @@ -117,3 +117,10 @@ if test x`which conntrack` != x; then else HAVE_CONNTRACK="no" fi + +if test "$HAVE_PYTHON" = "yes" \ + && test "x`$PYTHON $abs_top_srcdir/tests/test-l7.py --help | grep 'ftp'`" != x; then + HAVE_PYFTPDLIB="yes" +else + HAVE_PYFTPDLIB="no" +fi diff --git a/tests/odp.at b/tests/odp.at index c09d24c..fe61886 100644 --- a/tests/odp.at +++ b/tests/odp.at @@ -311,6 +311,7 @@ ct(commit) ct(commit,zone=5) ct(commit,mark=0xa0a0a0a0/0xfefefefe) ct(commit,label=0x1234567890abcdef1234567890abcdef/0xf1f2f3f4f5f6f7f8f9f0fafbfcfdfeff) +ct(commit,helper=ftp) ]) AT_CHECK_UNQUOTED([ovstest test-odp parse-actions < actions.txt], [0], [`cat actions.txt` diff --git a/tests/ofp-actions.at b/tests/ofp-actions.at index fd48a8b..01e5b67 100644 --- a/tests/ofp-actions.at +++ b/tests/ofp-actions.at @@ -184,6 +184,9 @@ ffff 0018 00002320 0023 0000 00000000 0000 FF 000000 0000 ffff 0030 00002320 0023 0001 00000000 0000 FF 000000 0000 dnl ffff 0018 00002320 0007 001f 00010004 000000000000f009 +# actions=ct(alg=ftp) +ffff 0018 00002320 0023 0000 00000000 0000 FF 000000 0015 + ]) sed '/^[[#&]]/d' < test-data > input.txt sed -n 's/^# //p; /^$/p' < test-data > expout diff --git a/tests/system-traffic.at b/tests/system-traffic.at index 71440cc..f6d0bdd 100644 --- a/tests/system-traffic.at +++ b/tests/system-traffic.at @@ -782,3 +782,148 @@ icmp,vlan_tci=0x0000,dl_src=c6:f9:4e:cb:72:db,dl_dst=e6:4c:47:35:28:c9,nw_src=17 OVS_TRAFFIC_VSWITCHD_STOP AT_CLEANUP + +AT_SETUP([conntrack - FTP]) +AT_SKIP_IF([test $HAVE_PYFTPDLIB = no]) +CHECK_CONNTRACK() +OVS_TRAFFIC_VSWITCHD_START( + [set-fail-mode br0 standalone -- ]) + +ADD_NAMESPACES(at_ns0, at_ns1) + +ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24") +ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24") + +dnl Allow any traffic from ns0->ns1. Only allow nd, return traffic from ns1->ns0. +AT_DATA([flows1.txt], [dnl +priority=1,action=drop +priority=10,arp,action=normal +priority=10,icmp,action=normal +priority=100,in_port=1,tcp,action=ct(alg=ftp,commit),2 +priority=100,in_port=2,tcp,ct_state=-trk,action=ct(table=0) +priority=100,in_port=2,tcp,ct_state=+trk+est,action=1 +priority=100,in_port=2,tcp,ct_state=+trk+rel,action=1 +]) + +dnl Similar policy but without allowing all traffic from ns0->ns1. +AT_DATA([flows2.txt], [dnl +priority=1,action=drop +priority=10,arp,action=normal +priority=10,icmp,action=normal +priority=100,in_port=1,tcp,ct_state=-trk,action=ct(table=0) +priority=100,in_port=1,tcp,ct_state=+trk+new,action=ct(commit,alg=ftp),2 +priority=100,in_port=1,tcp,ct_state=+trk+est,action=2 +priority=100,in_port=2,tcp,ct_state=-trk,action=ct(table=0) +priority=100,in_port=2,tcp,ct_state=+trk+new+rel,action=ct(commit),1 +priority=100,in_port=2,tcp,ct_state=+trk+est,action=1 +priority=100,in_port=2,tcp,ct_state=+trk-new+rel,action=1 +]) + +AT_CHECK([ovs-ofctl add-flows br0 flows1.txt]) + +NETNS_DAEMONIZE([at_ns0], [[$PYTHON $srcdir/test-l7.py ftp]], [ftp1.pid]) +NETNS_DAEMONIZE([at_ns1], [[$PYTHON $srcdir/test-l7.py ftp]], [ftp0.pid]) + +dnl FTP requests from p1->p0 should fail due to network failure. +dnl Try 3 times, in 1 second intervals. +NS_CHECK_EXEC([at_ns1], [wget ftp://10.1.1.1 --no-passive-ftp -t 3 -T 1 -v -o wget1.log], [4]) +AT_CHECK([conntrack -L 2>&1 | FORMAT_CT(10.1.1.1)], [0], [dnl +]) + +dnl FTP requests from p0->p1 should work fine. +NS_CHECK_EXEC([at_ns0], [wget ftp://10.1.1.2 --no-passive-ftp -t 3 -T 1 --retry-connrefused -v -o wget0.log]) +AT_CHECK([conntrack -L 2>&1 | FORMAT_CT(10.1.1.2) | grep -v "FIN"], [0], [dnl +TIME_WAIT src=10.1.1.1 dst=10.1.1.2 sport= dport= src=10.1.1.2 dst=10.1.1.1 sport= dport= [[ASSURED]] mark=0 helper=ftp use=1 +]) + +dnl Try the second set of flows. +conntrack -F +AT_CHECK([ovs-ofctl del-flows br0]) +AT_CHECK([ovs-ofctl add-flows br0 flows2.txt]) + +dnl FTP requests from p1->p0 should fail due to network failure. +dnl Try 3 times, in 1 second intervals. +NS_CHECK_EXEC([at_ns1], [wget ftp://10.1.1.1 --no-passive-ftp -t 3 -T 1 -v -o wget1.log], [4]) +AT_CHECK([conntrack -L 2>&1 | FORMAT_CT(10.1.1.1)], [0], [dnl +]) + +dnl Active FTP requests from p0->p1 should work fine. +NS_CHECK_EXEC([at_ns0], [wget ftp://10.1.1.2 --no-passive-ftp -t 3 -T 1 --retry-connrefused -v -o wget0.log]) +AT_CHECK([conntrack -L 2>&1 | FORMAT_CT(10.1.1.2) | grep -v "FIN"], [0], [dnl +TIME_WAIT src=10.1.1.1 dst=10.1.1.2 sport= dport= src=10.1.1.2 dst=10.1.1.1 sport= dport= [[ASSURED]] mark=0 helper=ftp use=2 +TIME_WAIT src=10.1.1.2 dst=10.1.1.1 sport= dport= src=10.1.1.1 dst=10.1.1.2 sport= dport= [[ASSURED]] mark=0 use=1 +]) + +AT_CHECK([conntrack -F 2>/dev/null]) + +dnl Passive FTP requests from p0->p1 should work fine. +NS_CHECK_EXEC([at_ns0], [wget ftp://10.1.1.2 -t 3 -T 1 --retry-connrefused -v -o wget0.log]) +AT_CHECK([conntrack -L 2>&1 | FORMAT_CT(10.1.1.2) | grep -v "FIN"], [0], [dnl +TIME_WAIT src=10.1.1.1 dst=10.1.1.2 sport= dport= src=10.1.1.2 dst=10.1.1.1 sport= dport= [[ASSURED]] mark=0 helper=ftp use=2 +TIME_WAIT src=10.1.1.1 dst=10.1.1.2 sport= dport= src=10.1.1.2 dst=10.1.1.1 sport= dport= [[ASSURED]] mark=0 use=1 +]) + +OVS_TRAFFIC_VSWITCHD_STOP +AT_CLEANUP + +AT_SETUP([conntrack - FTP with multiple expectations]) +AT_SKIP_IF([test $HAVE_PYFTPDLIB = no]) +CHECK_CONNTRACK() +OVS_TRAFFIC_VSWITCHD_START( + [set-fail-mode br0 standalone -- ]) + +ADD_NAMESPACES(at_ns0, at_ns1) + +ADD_VETH(p0, at_ns0, br0, "10.1.1.1/24") +ADD_VETH(p1, at_ns1, br0, "10.1.1.2/24") + +dnl Dual-firewall, allow all from ns1->ns2, allow established and ftp ns2->ns1. +AT_DATA([flows.txt], [dnl +priority=1,action=drop +priority=10,arp,action=normal +priority=10,icmp,action=normal +priority=100,in_port=1,tcp,ct_state=-trk,action=ct(table=0,zone=1) +priority=100,in_port=1,tcp,ct_zone=1,ct_state=+trk+new,action=ct(commit,alg=ftp,zone=1),ct(commit,alg=ftp,zone=2),2 +priority=100,in_port=1,tcp,ct_zone=1,ct_state=+trk+est,action=ct(table=0,zone=2) +priority=100,in_port=1,tcp,ct_zone=2,ct_state=+trk+new,action=ct(commit,alg=ftp,zone=2) +priority=100,in_port=1,tcp,ct_zone=2,ct_state=+trk+est,action=2 +priority=100,in_port=2,tcp,ct_state=-trk,action=ct(table=0,zone=2) +priority=100,in_port=2,tcp,ct_zone=2,ct_state=+trk+rel,action=ct(commit,zone=2),ct(commit,zone=1),1 +priority=100,in_port=2,tcp,ct_zone=2,ct_state=+trk+est,action=ct(table=0,zone=1) +priority=100,in_port=2,tcp,ct_zone=1,ct_state=+trk+rel,action=ct(commit,zone=2),ct(commit,zone=1),1 +priority=100,in_port=2,tcp,ct_zone=1,ct_state=+trk+est,action=1 +]) + +AT_CHECK([ovs-ofctl add-flows br0 flows.txt]) + +NETNS_DAEMONIZE([at_ns0], [[$PYTHON $srcdir/test-l7.py ftp]], [ftp1.pid]) +NETNS_DAEMONIZE([at_ns1], [[$PYTHON $srcdir/test-l7.py ftp]], [ftp0.pid]) + +dnl FTP requests from p1->p0 should fail due to network failure. +dnl Try 3 times, in 1 second intervals. +NS_CHECK_EXEC([at_ns1], [wget ftp://10.1.1.1 --no-passive-ftp -t 3 -T 1 -v -o wget1.log], [4]) +AT_CHECK([conntrack -L 2>&1 | FORMAT_CT(10.1.1.1)], [0], [dnl +]) + +dnl Active FTP requests from p0->p1 should work fine. +NS_CHECK_EXEC([at_ns0], [wget ftp://10.1.1.2 --no-passive-ftp -t 3 -T 1 --retry-connrefused -v -o wget0.log]) +AT_CHECK([conntrack -L 2>&1 | FORMAT_CT(10.1.1.2) | grep -v "FIN"], [0], [dnl +TIME_WAIT src=10.1.1.1 dst=10.1.1.2 sport= dport= src=10.1.1.2 dst=10.1.1.1 sport= dport= [[ASSURED]] mark=0 zone=1 helper=ftp use=2 +TIME_WAIT src=10.1.1.1 dst=10.1.1.2 sport= dport= src=10.1.1.2 dst=10.1.1.1 sport= dport= [[ASSURED]] mark=0 zone=2 helper=ftp use=2 +TIME_WAIT src=10.1.1.2 dst=10.1.1.1 sport= dport= src=10.1.1.1 dst=10.1.1.2 sport= dport= [[ASSURED]] mark=0 zone=1 use=1 +TIME_WAIT src=10.1.1.2 dst=10.1.1.1 sport= dport= src=10.1.1.1 dst=10.1.1.2 sport= dport= [[ASSURED]] mark=0 zone=2 use=1 +]) + +AT_CHECK([conntrack -F 2>/dev/null]) + +dnl Passive FTP requests from p0->p1 should work fine. +NS_CHECK_EXEC([at_ns0], [wget ftp://10.1.1.2 -t 3 -T 1 --retry-connrefused -v -o wget0.log]) +AT_CHECK([conntrack -L 2>&1 | FORMAT_CT(10.1.1.2) | grep -v "FIN"], [0], [dnl +TIME_WAIT src=10.1.1.1 dst=10.1.1.2 sport= dport= src=10.1.1.2 dst=10.1.1.1 sport= dport= [[ASSURED]] mark=0 zone=1 helper=ftp use=2 +TIME_WAIT src=10.1.1.1 dst=10.1.1.2 sport= dport= src=10.1.1.2 dst=10.1.1.1 sport= dport= [[ASSURED]] mark=0 zone=1 use=1 +TIME_WAIT src=10.1.1.1 dst=10.1.1.2 sport= dport= src=10.1.1.2 dst=10.1.1.1 sport= dport= [[ASSURED]] mark=0 zone=2 helper=ftp use=2 +TIME_WAIT src=10.1.1.1 dst=10.1.1.2 sport= dport= src=10.1.1.2 dst=10.1.1.1 sport= dport= [[ASSURED]] mark=0 zone=2 use=1 +]) + +OVS_TRAFFIC_VSWITCHD_STOP +AT_CLEANUP diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index fcb47d8..3273885 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -1692,6 +1692,16 @@ connection tracker with the \fBtable\fR specified. .IP The \fBcommit\fR parameter must be specified to use \fBexec(...)\fR. . +.IP \fBalg=\fR\fIalg\fR +Specify application layer gateway \fIalg\fR to track specific connection +types. Supported types include: +.RS +.IP \fBftp\fR +Look for negotiation of FTP data connections. If a subsequent FTP data +connection arrives which is related, the \fBct\fR action will set the +\fBrel\fR flag in the \fBct_state\fR field for packets sent through \fBct\fR. +.RE +. .RE .IP The \fBct\fR action may be used as a primitive to construct stateful firewalls