Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* Kernel module to match connection tracking information. |
2 | * Superset of Rusty's minimalistic state match. | |
3 | * | |
4 | * (C) 2001 Marc Boucher (marc@mbsi.ca). | |
5 | * | |
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. | |
9 | */ | |
10 | ||
11 | #include <linux/module.h> | |
12 | #include <linux/skbuff.h> | |
13 | #include <linux/netfilter_ipv4/ip_conntrack.h> | |
14 | #include <linux/netfilter_ipv4/ip_tables.h> | |
15 | #include <linux/netfilter_ipv4/ipt_conntrack.h> | |
16 | ||
17 | MODULE_LICENSE("GPL"); | |
18 | MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>"); | |
19 | MODULE_DESCRIPTION("iptables connection tracking match module"); | |
20 | ||
21 | static int | |
22 | match(const struct sk_buff *skb, | |
23 | const struct net_device *in, | |
24 | const struct net_device *out, | |
25 | const void *matchinfo, | |
26 | int offset, | |
27 | int *hotdrop) | |
28 | { | |
29 | const struct ipt_conntrack_info *sinfo = matchinfo; | |
30 | struct ip_conntrack *ct; | |
31 | enum ip_conntrack_info ctinfo; | |
32 | unsigned int statebit; | |
33 | ||
34 | ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); | |
35 | ||
36 | #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg)) | |
37 | ||
38 | if (ct == &ip_conntrack_untracked) | |
39 | statebit = IPT_CONNTRACK_STATE_UNTRACKED; | |
40 | else if (ct) | |
41 | statebit = IPT_CONNTRACK_STATE_BIT(ctinfo); | |
42 | else | |
43 | statebit = IPT_CONNTRACK_STATE_INVALID; | |
44 | ||
45 | if(sinfo->flags & IPT_CONNTRACK_STATE) { | |
46 | if (ct) { | |
47 | if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip != | |
48 | ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip) | |
49 | statebit |= IPT_CONNTRACK_STATE_SNAT; | |
50 | ||
51 | if(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip != | |
52 | ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip) | |
53 | statebit |= IPT_CONNTRACK_STATE_DNAT; | |
54 | } | |
55 | ||
56 | if (FWINV((statebit & sinfo->statemask) == 0, IPT_CONNTRACK_STATE)) | |
57 | return 0; | |
58 | } | |
59 | ||
60 | if(sinfo->flags & IPT_CONNTRACK_PROTO) { | |
61 | if (!ct || FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum, IPT_CONNTRACK_PROTO)) | |
62 | return 0; | |
63 | } | |
64 | ||
65 | if(sinfo->flags & IPT_CONNTRACK_ORIGSRC) { | |
66 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip, IPT_CONNTRACK_ORIGSRC)) | |
67 | return 0; | |
68 | } | |
69 | ||
70 | if(sinfo->flags & IPT_CONNTRACK_ORIGDST) { | |
71 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) != sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip, IPT_CONNTRACK_ORIGDST)) | |
72 | return 0; | |
73 | } | |
74 | ||
75 | if(sinfo->flags & IPT_CONNTRACK_REPLSRC) { | |
76 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip&sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].src.ip, IPT_CONNTRACK_REPLSRC)) | |
77 | return 0; | |
78 | } | |
79 | ||
80 | if(sinfo->flags & IPT_CONNTRACK_REPLDST) { | |
81 | if (!ct || FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip&sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) != sinfo->tuple[IP_CT_DIR_REPLY].dst.ip, IPT_CONNTRACK_REPLDST)) | |
82 | return 0; | |
83 | } | |
84 | ||
85 | if(sinfo->flags & IPT_CONNTRACK_STATUS) { | |
86 | if (!ct || FWINV((ct->status & sinfo->statusmask) == 0, IPT_CONNTRACK_STATUS)) | |
87 | return 0; | |
88 | } | |
89 | ||
90 | if(sinfo->flags & IPT_CONNTRACK_EXPIRES) { | |
91 | unsigned long expires; | |
92 | ||
93 | if(!ct) | |
94 | return 0; | |
95 | ||
96 | expires = timer_pending(&ct->timeout) ? (ct->timeout.expires - jiffies)/HZ : 0; | |
97 | ||
98 | if (FWINV(!(expires >= sinfo->expires_min && expires <= sinfo->expires_max), IPT_CONNTRACK_EXPIRES)) | |
99 | return 0; | |
100 | } | |
101 | ||
102 | return 1; | |
103 | } | |
104 | ||
105 | static int check(const char *tablename, | |
106 | const struct ipt_ip *ip, | |
107 | void *matchinfo, | |
108 | unsigned int matchsize, | |
109 | unsigned int hook_mask) | |
110 | { | |
111 | if (matchsize != IPT_ALIGN(sizeof(struct ipt_conntrack_info))) | |
112 | return 0; | |
113 | ||
114 | return 1; | |
115 | } | |
116 | ||
117 | static struct ipt_match conntrack_match = { | |
118 | .name = "conntrack", | |
119 | .match = &match, | |
120 | .checkentry = &check, | |
121 | .me = THIS_MODULE, | |
122 | }; | |
123 | ||
124 | static int __init init(void) | |
125 | { | |
126 | need_ip_conntrack(); | |
127 | return ipt_register_match(&conntrack_match); | |
128 | } | |
129 | ||
130 | static void __exit fini(void) | |
131 | { | |
132 | ipt_unregister_match(&conntrack_match); | |
133 | } | |
134 | ||
135 | module_init(init); | |
136 | module_exit(fini); |