1 /* Kernel module to match connection tracking information.
2 * Superset of Rusty's minimalistic state match.
4 * (C) 2001 Marc Boucher (marc@mbsi.ca).
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
11 #include <linux/module.h>
12 #include <linux/skbuff.h>
13 #include <linux/netfilter/x_tables.h>
14 #include <linux/netfilter/xt_conntrack.h>
15 #include <net/netfilter/nf_conntrack.h>
17 MODULE_LICENSE("GPL");
18 MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
19 MODULE_DESCRIPTION("iptables connection tracking match module");
20 MODULE_ALIAS("ipt_conntrack");
23 match(const struct sk_buff
*skb
,
24 const struct net_device
*in
,
25 const struct net_device
*out
,
26 const struct xt_match
*match
,
27 const void *matchinfo
,
32 const struct xt_conntrack_info
*sinfo
= matchinfo
;
33 const struct nf_conn
*ct
;
34 enum ip_conntrack_info ctinfo
;
35 unsigned int statebit
;
37 ct
= nf_ct_get(skb
, &ctinfo
);
39 #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
41 if (ct
== &nf_conntrack_untracked
)
42 statebit
= XT_CONNTRACK_STATE_UNTRACKED
;
44 statebit
= XT_CONNTRACK_STATE_BIT(ctinfo
);
46 statebit
= XT_CONNTRACK_STATE_INVALID
;
48 if (sinfo
->flags
& XT_CONNTRACK_STATE
) {
50 if (test_bit(IPS_SRC_NAT_BIT
, &ct
->status
))
51 statebit
|= XT_CONNTRACK_STATE_SNAT
;
52 if (test_bit(IPS_DST_NAT_BIT
, &ct
->status
))
53 statebit
|= XT_CONNTRACK_STATE_DNAT
;
55 if (FWINV((statebit
& sinfo
->statemask
) == 0,
61 if (sinfo
->flags
& ~XT_CONNTRACK_STATE
)
66 if (sinfo
->flags
& XT_CONNTRACK_PROTO
&&
67 FWINV(ct
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
.dst
.protonum
!=
68 sinfo
->tuple
[IP_CT_DIR_ORIGINAL
].dst
.protonum
,
72 if (sinfo
->flags
& XT_CONNTRACK_ORIGSRC
&&
73 FWINV((ct
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
.src
.u3
.ip
&
74 sinfo
->sipmsk
[IP_CT_DIR_ORIGINAL
].s_addr
) !=
75 sinfo
->tuple
[IP_CT_DIR_ORIGINAL
].src
.ip
,
76 XT_CONNTRACK_ORIGSRC
))
79 if (sinfo
->flags
& XT_CONNTRACK_ORIGDST
&&
80 FWINV((ct
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
.dst
.u3
.ip
&
81 sinfo
->dipmsk
[IP_CT_DIR_ORIGINAL
].s_addr
) !=
82 sinfo
->tuple
[IP_CT_DIR_ORIGINAL
].dst
.ip
,
83 XT_CONNTRACK_ORIGDST
))
86 if (sinfo
->flags
& XT_CONNTRACK_REPLSRC
&&
87 FWINV((ct
->tuplehash
[IP_CT_DIR_REPLY
].tuple
.src
.u3
.ip
&
88 sinfo
->sipmsk
[IP_CT_DIR_REPLY
].s_addr
) !=
89 sinfo
->tuple
[IP_CT_DIR_REPLY
].src
.ip
,
90 XT_CONNTRACK_REPLSRC
))
93 if (sinfo
->flags
& XT_CONNTRACK_REPLDST
&&
94 FWINV((ct
->tuplehash
[IP_CT_DIR_REPLY
].tuple
.dst
.u3
.ip
&
95 sinfo
->dipmsk
[IP_CT_DIR_REPLY
].s_addr
) !=
96 sinfo
->tuple
[IP_CT_DIR_REPLY
].dst
.ip
,
97 XT_CONNTRACK_REPLDST
))
100 if (sinfo
->flags
& XT_CONNTRACK_STATUS
&&
101 FWINV((ct
->status
& sinfo
->statusmask
) == 0,
102 XT_CONNTRACK_STATUS
))
105 if(sinfo
->flags
& XT_CONNTRACK_EXPIRES
) {
106 unsigned long expires
= timer_pending(&ct
->timeout
) ?
107 (ct
->timeout
.expires
- jiffies
)/HZ
: 0;
109 if (FWINV(!(expires
>= sinfo
->expires_min
&&
110 expires
<= sinfo
->expires_max
),
111 XT_CONNTRACK_EXPIRES
))
118 checkentry(const char *tablename
,
120 const struct xt_match
*match
,
122 unsigned int hook_mask
)
124 if (nf_ct_l3proto_try_module_get(match
->family
) < 0) {
125 printk(KERN_WARNING
"can't load conntrack support for "
126 "proto=%d\n", match
->family
);
132 static void destroy(const struct xt_match
*match
, void *matchinfo
)
134 nf_ct_l3proto_module_put(match
->family
);
138 struct compat_xt_conntrack_info
140 compat_uint_t statemask
;
141 compat_uint_t statusmask
;
142 struct ip_conntrack_old_tuple tuple
[IP_CT_DIR_MAX
];
143 struct in_addr sipmsk
[IP_CT_DIR_MAX
];
144 struct in_addr dipmsk
[IP_CT_DIR_MAX
];
145 compat_ulong_t expires_min
;
146 compat_ulong_t expires_max
;
151 static void compat_from_user(void *dst
, void *src
)
153 const struct compat_xt_conntrack_info
*cm
= src
;
154 struct xt_conntrack_info m
= {
155 .statemask
= cm
->statemask
,
156 .statusmask
= cm
->statusmask
,
157 .expires_min
= cm
->expires_min
,
158 .expires_max
= cm
->expires_max
,
160 .invflags
= cm
->invflags
,
162 memcpy(m
.tuple
, cm
->tuple
, sizeof(m
.tuple
));
163 memcpy(m
.sipmsk
, cm
->sipmsk
, sizeof(m
.sipmsk
));
164 memcpy(m
.dipmsk
, cm
->dipmsk
, sizeof(m
.dipmsk
));
165 memcpy(dst
, &m
, sizeof(m
));
168 static int compat_to_user(void __user
*dst
, void *src
)
170 const struct xt_conntrack_info
*m
= src
;
171 struct compat_xt_conntrack_info cm
= {
172 .statemask
= m
->statemask
,
173 .statusmask
= m
->statusmask
,
174 .expires_min
= m
->expires_min
,
175 .expires_max
= m
->expires_max
,
177 .invflags
= m
->invflags
,
179 memcpy(cm
.tuple
, m
->tuple
, sizeof(cm
.tuple
));
180 memcpy(cm
.sipmsk
, m
->sipmsk
, sizeof(cm
.sipmsk
));
181 memcpy(cm
.dipmsk
, m
->dipmsk
, sizeof(cm
.dipmsk
));
182 return copy_to_user(dst
, &cm
, sizeof(cm
)) ? -EFAULT
: 0;
186 static struct xt_match conntrack_match __read_mostly
= {
189 .checkentry
= checkentry
,
191 .matchsize
= sizeof(struct xt_conntrack_info
),
193 .compatsize
= sizeof(struct compat_xt_conntrack_info
),
194 .compat_from_user
= compat_from_user
,
195 .compat_to_user
= compat_to_user
,
201 static int __init
xt_conntrack_init(void)
203 return xt_register_match(&conntrack_match
);
206 static void __exit
xt_conntrack_fini(void)
208 xt_unregister_match(&conntrack_match
);
211 module_init(xt_conntrack_init
);
212 module_exit(xt_conntrack_fini
);