3333#include <net/netfilter/nf_conntrack_acct.h>
3434#include <net/netfilter/ipv6/nf_defrag_ipv6.h>
3535#include <net/netfilter/nf_conntrack_act_ct.h>
36+ #include <net/netfilter/nf_conntrack_seqadj.h>
3637#include <uapi/linux/netfilter/nf_nat.h>
3738
3839static struct workqueue_struct * act_ct_wq ;
@@ -656,7 +657,7 @@ struct tc_ct_action_net {
656657
657658/* Determine whether skb->_nfct is equal to the result of conntrack lookup. */
658659static bool tcf_ct_skb_nfct_cached (struct net * net , struct sk_buff * skb ,
659- u16 zone_id , bool force )
660+ struct tcf_ct_params * p )
660661{
661662 enum ip_conntrack_info ctinfo ;
662663 struct nf_conn * ct ;
@@ -666,11 +667,19 @@ static bool tcf_ct_skb_nfct_cached(struct net *net, struct sk_buff *skb,
666667 return false;
667668 if (!net_eq (net , read_pnet (& ct -> ct_net )))
668669 goto drop_ct ;
669- if (nf_ct_zone (ct )-> id != zone_id )
670+ if (nf_ct_zone (ct )-> id != p -> zone )
670671 goto drop_ct ;
672+ if (p -> helper ) {
673+ struct nf_conn_help * help ;
674+
675+ help = nf_ct_ext_find (ct , NF_CT_EXT_HELPER );
676+ if (help && rcu_access_pointer (help -> helper ) != p -> helper )
677+ goto drop_ct ;
678+ }
671679
672680 /* Force conntrack entry direction. */
673- if (force && CTINFO2DIR (ctinfo ) != IP_CT_DIR_ORIGINAL ) {
681+ if ((p -> ct_action & TCA_CT_ACT_FORCE ) &&
682+ CTINFO2DIR (ctinfo ) != IP_CT_DIR_ORIGINAL ) {
674683 if (nf_ct_is_confirmed (ct ))
675684 nf_ct_kill (ct );
676685
@@ -836,6 +845,13 @@ static int tcf_ct_handle_fragments(struct net *net, struct sk_buff *skb,
836845
837846static void tcf_ct_params_free (struct tcf_ct_params * params )
838847{
848+ if (params -> helper ) {
849+ #if IS_ENABLED (CONFIG_NF_NAT )
850+ if (params -> ct_action & TCA_CT_ACT_NAT )
851+ nf_nat_helper_put (params -> helper );
852+ #endif
853+ nf_conntrack_helper_put (params -> helper );
854+ }
839855 if (params -> ct_ft )
840856 tcf_ct_flow_table_put (params -> ct_ft );
841857 if (params -> tmpl )
@@ -1030,13 +1046,14 @@ static int tcf_ct_act(struct sk_buff *skb, const struct tc_action *a,
10301046 struct tcf_result * res )
10311047{
10321048 struct net * net = dev_net (skb -> dev );
1033- bool cached , commit , clear , force ;
10341049 enum ip_conntrack_info ctinfo ;
10351050 struct tcf_ct * c = to_ct (a );
10361051 struct nf_conn * tmpl = NULL ;
10371052 struct nf_hook_state state ;
1053+ bool cached , commit , clear ;
10381054 int nh_ofs , err , retval ;
10391055 struct tcf_ct_params * p ;
1056+ bool add_helper = false;
10401057 bool skip_add = false;
10411058 bool defrag = false;
10421059 struct nf_conn * ct ;
@@ -1047,7 +1064,6 @@ static int tcf_ct_act(struct sk_buff *skb, const struct tc_action *a,
10471064 retval = READ_ONCE (c -> tcf_action );
10481065 commit = p -> ct_action & TCA_CT_ACT_COMMIT ;
10491066 clear = p -> ct_action & TCA_CT_ACT_CLEAR ;
1050- force = p -> ct_action & TCA_CT_ACT_FORCE ;
10511067 tmpl = p -> tmpl ;
10521068
10531069 tcf_lastuse_update (& c -> tcf_tm );
@@ -1090,7 +1106,7 @@ static int tcf_ct_act(struct sk_buff *skb, const struct tc_action *a,
10901106 * actually run the packet through conntrack twice unless it's for a
10911107 * different zone.
10921108 */
1093- cached = tcf_ct_skb_nfct_cached (net , skb , p -> zone , force );
1109+ cached = tcf_ct_skb_nfct_cached (net , skb , p );
10941110 if (!cached ) {
10951111 if (tcf_ct_flow_table_lookup (p , skb , family )) {
10961112 skip_add = true;
@@ -1123,6 +1139,22 @@ static int tcf_ct_act(struct sk_buff *skb, const struct tc_action *a,
11231139 if (err != NF_ACCEPT )
11241140 goto drop ;
11251141
1142+ if (!nf_ct_is_confirmed (ct ) && commit && p -> helper && !nfct_help (ct )) {
1143+ err = __nf_ct_try_assign_helper (ct , p -> tmpl , GFP_ATOMIC );
1144+ if (err )
1145+ goto drop ;
1146+ add_helper = true;
1147+ if (p -> ct_action & TCA_CT_ACT_NAT && !nfct_seqadj (ct )) {
1148+ if (!nfct_seqadj_ext_add (ct ))
1149+ goto drop ;
1150+ }
1151+ }
1152+
1153+ if (nf_ct_is_confirmed (ct ) ? ((!cached && !skip_add ) || add_helper ) : commit ) {
1154+ if (nf_ct_helper (skb , ct , ctinfo , family ) != NF_ACCEPT )
1155+ goto drop ;
1156+ }
1157+
11261158 if (commit ) {
11271159 tcf_ct_act_set_mark (ct , p -> mark , p -> mark_mask );
11281160 tcf_ct_act_set_labels (ct , p -> labels , p -> labels_mask );
@@ -1171,6 +1203,9 @@ static const struct nla_policy ct_policy[TCA_CT_MAX + 1] = {
11711203 [TCA_CT_NAT_IPV6_MAX ] = NLA_POLICY_EXACT_LEN (sizeof (struct in6_addr )),
11721204 [TCA_CT_NAT_PORT_MIN ] = { .type = NLA_U16 },
11731205 [TCA_CT_NAT_PORT_MAX ] = { .type = NLA_U16 },
1206+ [TCA_CT_HELPER_NAME ] = { .type = NLA_STRING , .len = NF_CT_HELPER_NAME_LEN },
1207+ [TCA_CT_HELPER_FAMILY ] = { .type = NLA_U8 },
1208+ [TCA_CT_HELPER_PROTO ] = { .type = NLA_U8 },
11741209};
11751210
11761211static int tcf_ct_fill_params_nat (struct tcf_ct_params * p ,
@@ -1260,8 +1295,9 @@ static int tcf_ct_fill_params(struct net *net,
12601295{
12611296 struct tc_ct_action_net * tn = net_generic (net , ct_net_id );
12621297 struct nf_conntrack_zone zone ;
1298+ int err , family , proto , len ;
12631299 struct nf_conn * tmpl ;
1264- int err ;
1300+ char * name ;
12651301
12661302 p -> zone = NF_CT_DEFAULT_ZONE_ID ;
12671303
@@ -1322,10 +1358,31 @@ static int tcf_ct_fill_params(struct net *net,
13221358 NL_SET_ERR_MSG_MOD (extack , "Failed to allocate conntrack template" );
13231359 return - ENOMEM ;
13241360 }
1325- __set_bit (IPS_CONFIRMED_BIT , & tmpl -> status );
13261361 p -> tmpl = tmpl ;
1362+ if (tb [TCA_CT_HELPER_NAME ]) {
1363+ name = nla_data (tb [TCA_CT_HELPER_NAME ]);
1364+ len = nla_len (tb [TCA_CT_HELPER_NAME ]);
1365+ if (len > 16 || name [len - 1 ] != '\0' ) {
1366+ NL_SET_ERR_MSG_MOD (extack , "Failed to parse helper name." );
1367+ err = - EINVAL ;
1368+ goto err ;
1369+ }
1370+ family = tb [TCA_CT_HELPER_FAMILY ] ? nla_get_u8 (tb [TCA_CT_HELPER_FAMILY ]) : AF_INET ;
1371+ proto = tb [TCA_CT_HELPER_PROTO ] ? nla_get_u8 (tb [TCA_CT_HELPER_PROTO ]) : IPPROTO_TCP ;
1372+ err = nf_ct_add_helper (tmpl , name , family , proto ,
1373+ p -> ct_action & TCA_CT_ACT_NAT , & p -> helper );
1374+ if (err ) {
1375+ NL_SET_ERR_MSG_MOD (extack , "Failed to add helper" );
1376+ goto err ;
1377+ }
1378+ }
13271379
1380+ __set_bit (IPS_CONFIRMED_BIT , & tmpl -> status );
13281381 return 0 ;
1382+ err :
1383+ nf_ct_put (p -> tmpl );
1384+ p -> tmpl = NULL ;
1385+ return err ;
13291386}
13301387
13311388static int tcf_ct_init (struct net * net , struct nlattr * nla ,
@@ -1494,6 +1551,19 @@ static int tcf_ct_dump_nat(struct sk_buff *skb, struct tcf_ct_params *p)
14941551 return 0 ;
14951552}
14961553
1554+ static int tcf_ct_dump_helper (struct sk_buff * skb , struct nf_conntrack_helper * helper )
1555+ {
1556+ if (!helper )
1557+ return 0 ;
1558+
1559+ if (nla_put_string (skb , TCA_CT_HELPER_NAME , helper -> name ) ||
1560+ nla_put_u8 (skb , TCA_CT_HELPER_FAMILY , helper -> tuple .src .l3num ) ||
1561+ nla_put_u8 (skb , TCA_CT_HELPER_PROTO , helper -> tuple .dst .protonum ))
1562+ return -1 ;
1563+
1564+ return 0 ;
1565+ }
1566+
14971567static inline int tcf_ct_dump (struct sk_buff * skb , struct tc_action * a ,
14981568 int bind , int ref )
14991569{
@@ -1546,6 +1616,9 @@ static inline int tcf_ct_dump(struct sk_buff *skb, struct tc_action *a,
15461616 if (tcf_ct_dump_nat (skb , p ))
15471617 goto nla_put_failure ;
15481618
1619+ if (tcf_ct_dump_helper (skb , p -> helper ))
1620+ goto nla_put_failure ;
1621+
15491622skip_dump :
15501623 if (nla_put (skb , TCA_CT_PARMS , sizeof (opt ), & opt ))
15511624 goto nla_put_failure ;
0 commit comments