184f3bb9aSPatrick McHardy /* 284f3bb9aSPatrick McHardy * Copyright (c) 2010 Patrick McHardy <kaber@trash.net> 384f3bb9aSPatrick McHardy * 484f3bb9aSPatrick McHardy * This program is free software; you can redistribute it and/or modify 584f3bb9aSPatrick McHardy * it under the terms of the GNU General Public License version 2 as 684f3bb9aSPatrick McHardy * published by the Free Software Foundation. 784f3bb9aSPatrick McHardy */ 884f3bb9aSPatrick McHardy 984f3bb9aSPatrick McHardy #include <linux/module.h> 1084f3bb9aSPatrick McHardy #include <linux/skbuff.h> 1184f3bb9aSPatrick McHardy #include <linux/selinux.h> 1284f3bb9aSPatrick McHardy #include <linux/netfilter_ipv4/ip_tables.h> 1384f3bb9aSPatrick McHardy #include <linux/netfilter_ipv6/ip6_tables.h> 1484f3bb9aSPatrick McHardy #include <linux/netfilter/x_tables.h> 1584f3bb9aSPatrick McHardy #include <linux/netfilter/xt_CT.h> 1684f3bb9aSPatrick McHardy #include <net/netfilter/nf_conntrack.h> 1784f3bb9aSPatrick McHardy #include <net/netfilter/nf_conntrack_helper.h> 1884f3bb9aSPatrick McHardy #include <net/netfilter/nf_conntrack_ecache.h> 195d0aa2ccSPatrick McHardy #include <net/netfilter/nf_conntrack_zones.h> 2084f3bb9aSPatrick McHardy 2184f3bb9aSPatrick McHardy static unsigned int xt_ct_target(struct sk_buff *skb, 2284f3bb9aSPatrick McHardy const struct xt_target_param *par) 2384f3bb9aSPatrick McHardy { 2484f3bb9aSPatrick McHardy const struct xt_ct_target_info *info = par->targinfo; 2584f3bb9aSPatrick McHardy struct nf_conn *ct = info->ct; 2684f3bb9aSPatrick McHardy 2784f3bb9aSPatrick McHardy /* Previously seen (loopback)? Ignore. */ 2884f3bb9aSPatrick McHardy if (skb->nfct != NULL) 2984f3bb9aSPatrick McHardy return XT_CONTINUE; 3084f3bb9aSPatrick McHardy 3184f3bb9aSPatrick McHardy atomic_inc(&ct->ct_general.use); 3284f3bb9aSPatrick McHardy skb->nfct = &ct->ct_general; 3384f3bb9aSPatrick McHardy skb->nfctinfo = IP_CT_NEW; 3484f3bb9aSPatrick McHardy 3584f3bb9aSPatrick McHardy return XT_CONTINUE; 3684f3bb9aSPatrick McHardy } 3784f3bb9aSPatrick McHardy 3884f3bb9aSPatrick McHardy static u8 xt_ct_find_proto(const struct xt_tgchk_param *par) 3984f3bb9aSPatrick McHardy { 40076f7839SJan Engelhardt if (par->family == NFPROTO_IPV4) { 4184f3bb9aSPatrick McHardy const struct ipt_entry *e = par->entryinfo; 4284f3bb9aSPatrick McHardy 4384f3bb9aSPatrick McHardy if (e->ip.invflags & IPT_INV_PROTO) 4484f3bb9aSPatrick McHardy return 0; 4584f3bb9aSPatrick McHardy return e->ip.proto; 46076f7839SJan Engelhardt } else if (par->family == NFPROTO_IPV6) { 4784f3bb9aSPatrick McHardy const struct ip6t_entry *e = par->entryinfo; 4884f3bb9aSPatrick McHardy 4984f3bb9aSPatrick McHardy if (e->ipv6.invflags & IP6T_INV_PROTO) 5084f3bb9aSPatrick McHardy return 0; 5184f3bb9aSPatrick McHardy return e->ipv6.proto; 5284f3bb9aSPatrick McHardy } else 5384f3bb9aSPatrick McHardy return 0; 5484f3bb9aSPatrick McHardy } 5584f3bb9aSPatrick McHardy 56135367b8SJan Engelhardt static int xt_ct_tg_check(const struct xt_tgchk_param *par) 5784f3bb9aSPatrick McHardy { 5884f3bb9aSPatrick McHardy struct xt_ct_target_info *info = par->targinfo; 5984f3bb9aSPatrick McHardy struct nf_conntrack_tuple t; 6084f3bb9aSPatrick McHardy struct nf_conn_help *help; 6184f3bb9aSPatrick McHardy struct nf_conn *ct; 6284f3bb9aSPatrick McHardy u8 proto; 6384f3bb9aSPatrick McHardy 6484f3bb9aSPatrick McHardy if (info->flags & ~XT_CT_NOTRACK) 65d6b00a53SJan Engelhardt return -EINVAL; 6684f3bb9aSPatrick McHardy 6784f3bb9aSPatrick McHardy if (info->flags & XT_CT_NOTRACK) { 6884f3bb9aSPatrick McHardy ct = &nf_conntrack_untracked; 6984f3bb9aSPatrick McHardy atomic_inc(&ct->ct_general.use); 7084f3bb9aSPatrick McHardy goto out; 7184f3bb9aSPatrick McHardy } 7284f3bb9aSPatrick McHardy 735d0aa2ccSPatrick McHardy #ifndef CONFIG_NF_CONNTRACK_ZONES 745d0aa2ccSPatrick McHardy if (info->zone) 755d0aa2ccSPatrick McHardy goto err1; 765d0aa2ccSPatrick McHardy #endif 775d0aa2ccSPatrick McHardy 7884f3bb9aSPatrick McHardy if (nf_ct_l3proto_try_module_get(par->family) < 0) 7984f3bb9aSPatrick McHardy goto err1; 8084f3bb9aSPatrick McHardy 8184f3bb9aSPatrick McHardy memset(&t, 0, sizeof(t)); 825d0aa2ccSPatrick McHardy ct = nf_conntrack_alloc(par->net, info->zone, &t, &t, GFP_KERNEL); 8384f3bb9aSPatrick McHardy if (IS_ERR(ct)) 8484f3bb9aSPatrick McHardy goto err2; 8584f3bb9aSPatrick McHardy 8684f3bb9aSPatrick McHardy if ((info->ct_events || info->exp_events) && 8784f3bb9aSPatrick McHardy !nf_ct_ecache_ext_add(ct, info->ct_events, info->exp_events, 8884f3bb9aSPatrick McHardy GFP_KERNEL)) 8984f3bb9aSPatrick McHardy goto err3; 9084f3bb9aSPatrick McHardy 9184f3bb9aSPatrick McHardy if (info->helper[0]) { 9284f3bb9aSPatrick McHardy proto = xt_ct_find_proto(par); 9384f3bb9aSPatrick McHardy if (!proto) 9484f3bb9aSPatrick McHardy goto err3; 9584f3bb9aSPatrick McHardy 9684f3bb9aSPatrick McHardy help = nf_ct_helper_ext_add(ct, GFP_KERNEL); 9784f3bb9aSPatrick McHardy if (help == NULL) 9884f3bb9aSPatrick McHardy goto err3; 9984f3bb9aSPatrick McHardy 10084f3bb9aSPatrick McHardy help->helper = nf_conntrack_helper_try_module_get(info->helper, 10184f3bb9aSPatrick McHardy par->family, 10284f3bb9aSPatrick McHardy proto); 10384f3bb9aSPatrick McHardy if (help->helper == NULL) 10484f3bb9aSPatrick McHardy goto err3; 10584f3bb9aSPatrick McHardy } 10684f3bb9aSPatrick McHardy 10784f3bb9aSPatrick McHardy __set_bit(IPS_TEMPLATE_BIT, &ct->status); 10884f3bb9aSPatrick McHardy __set_bit(IPS_CONFIRMED_BIT, &ct->status); 10984f3bb9aSPatrick McHardy out: 11084f3bb9aSPatrick McHardy info->ct = ct; 111d6b00a53SJan Engelhardt return 0; 11284f3bb9aSPatrick McHardy 11384f3bb9aSPatrick McHardy err3: 11484f3bb9aSPatrick McHardy nf_conntrack_free(ct); 11584f3bb9aSPatrick McHardy err2: 11684f3bb9aSPatrick McHardy nf_ct_l3proto_module_put(par->family); 11784f3bb9aSPatrick McHardy err1: 118d6b00a53SJan Engelhardt return -EINVAL; 11984f3bb9aSPatrick McHardy } 12084f3bb9aSPatrick McHardy 12184f3bb9aSPatrick McHardy static void xt_ct_tg_destroy(const struct xt_tgdtor_param *par) 12284f3bb9aSPatrick McHardy { 12384f3bb9aSPatrick McHardy struct xt_ct_target_info *info = par->targinfo; 12484f3bb9aSPatrick McHardy struct nf_conn *ct = info->ct; 12584f3bb9aSPatrick McHardy struct nf_conn_help *help; 12684f3bb9aSPatrick McHardy 12784f3bb9aSPatrick McHardy if (ct != &nf_conntrack_untracked) { 12884f3bb9aSPatrick McHardy help = nfct_help(ct); 12984f3bb9aSPatrick McHardy if (help) 13084f3bb9aSPatrick McHardy module_put(help->helper->me); 13184f3bb9aSPatrick McHardy 13284f3bb9aSPatrick McHardy nf_ct_l3proto_module_put(par->family); 13384f3bb9aSPatrick McHardy } 13484f3bb9aSPatrick McHardy nf_ct_put(info->ct); 13584f3bb9aSPatrick McHardy } 13684f3bb9aSPatrick McHardy 13784f3bb9aSPatrick McHardy static struct xt_target xt_ct_tg __read_mostly = { 13884f3bb9aSPatrick McHardy .name = "CT", 13984f3bb9aSPatrick McHardy .family = NFPROTO_UNSPEC, 1407d5f7ed8SJan Engelhardt .targetsize = sizeof(struct xt_ct_target_info), 14184f3bb9aSPatrick McHardy .checkentry = xt_ct_tg_check, 14284f3bb9aSPatrick McHardy .destroy = xt_ct_tg_destroy, 14384f3bb9aSPatrick McHardy .target = xt_ct_target, 14484f3bb9aSPatrick McHardy .table = "raw", 14584f3bb9aSPatrick McHardy .me = THIS_MODULE, 14684f3bb9aSPatrick McHardy }; 14784f3bb9aSPatrick McHardy 14884f3bb9aSPatrick McHardy static int __init xt_ct_tg_init(void) 14984f3bb9aSPatrick McHardy { 15084f3bb9aSPatrick McHardy return xt_register_target(&xt_ct_tg); 15184f3bb9aSPatrick McHardy } 15284f3bb9aSPatrick McHardy 15384f3bb9aSPatrick McHardy static void __exit xt_ct_tg_exit(void) 15484f3bb9aSPatrick McHardy { 15584f3bb9aSPatrick McHardy xt_unregister_target(&xt_ct_tg); 15684f3bb9aSPatrick McHardy } 15784f3bb9aSPatrick McHardy 15884f3bb9aSPatrick McHardy module_init(xt_ct_tg_init); 15984f3bb9aSPatrick McHardy module_exit(xt_ct_tg_exit); 16084f3bb9aSPatrick McHardy 16184f3bb9aSPatrick McHardy MODULE_LICENSE("GPL"); 16284f3bb9aSPatrick McHardy MODULE_DESCRIPTION("Xtables: connection tracking target"); 16384f3bb9aSPatrick McHardy MODULE_ALIAS("ipt_CT"); 16484f3bb9aSPatrick McHardy MODULE_ALIAS("ip6t_CT"); 165