Blame view
net/netfilter/xt_tcpudp.c
5.68 KB
be91fd5e3 netfilter: xtable... |
1 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
2e4e6a17a [NETFILTER] x_tab... |
2 3 4 |
#include <linux/types.h> #include <linux/module.h> #include <net/ip.h> |
37d8dc82e [NETFILTER] x-tab... |
5 |
#include <linux/ipv6.h> |
2e4e6a17a [NETFILTER] x_tab... |
6 7 8 9 10 11 12 |
#include <net/ipv6.h> #include <net/tcp.h> #include <net/udp.h> #include <linux/netfilter/x_tables.h> #include <linux/netfilter/xt_tcpudp.h> #include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netfilter_ipv6/ip6_tables.h> |
2ae15b64e [NETFILTER]: Upda... |
13 |
MODULE_DESCRIPTION("Xtables: TCP, UDP and UDP-Lite match"); |
2e4e6a17a [NETFILTER] x_tab... |
14 15 16 17 18 19 20 |
MODULE_LICENSE("GPL"); MODULE_ALIAS("xt_tcp"); MODULE_ALIAS("xt_udp"); MODULE_ALIAS("ipt_udp"); MODULE_ALIAS("ipt_tcp"); MODULE_ALIAS("ip6t_udp"); MODULE_ALIAS("ip6t_tcp"); |
2e4e6a17a [NETFILTER] x_tab... |
21 |
/* Returns 1 if the port is matched by the range, 0 otherwise */ |
1d93a9cba [NETFILTER]: x_ta... |
22 23 |
static inline bool port_match(u_int16_t min, u_int16_t max, u_int16_t port, bool invert) |
2e4e6a17a [NETFILTER] x_tab... |
24 |
{ |
1d93a9cba [NETFILTER]: x_ta... |
25 |
return (port >= min && port <= max) ^ invert; |
2e4e6a17a [NETFILTER] x_tab... |
26 |
} |
1d93a9cba [NETFILTER]: x_ta... |
27 |
static bool |
2e4e6a17a [NETFILTER] x_tab... |
28 29 30 31 |
tcp_find_option(u_int8_t option, const struct sk_buff *skb, unsigned int protoff, unsigned int optlen, |
1d93a9cba [NETFILTER]: x_ta... |
32 |
bool invert, |
cff533ac1 [NETFILTER]: x_ta... |
33 |
bool *hotdrop) |
2e4e6a17a [NETFILTER] x_tab... |
34 35 |
{ /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */ |
3cf93c96a [NETFILTER]: anno... |
36 37 |
const u_int8_t *op; u_int8_t _opt[60 - sizeof(struct tcphdr)]; |
2e4e6a17a [NETFILTER] x_tab... |
38 |
unsigned int i; |
be91fd5e3 netfilter: xtable... |
39 40 |
pr_debug("finding option "); |
2e4e6a17a [NETFILTER] x_tab... |
41 42 43 44 45 46 47 48 |
if (!optlen) return invert; /* If we don't have the whole header, drop packet. */ op = skb_header_pointer(skb, protoff + sizeof(struct tcphdr), optlen, _opt); if (op == NULL) { |
cff533ac1 [NETFILTER]: x_ta... |
49 |
*hotdrop = true; |
1d93a9cba [NETFILTER]: x_ta... |
50 |
return false; |
2e4e6a17a [NETFILTER] x_tab... |
51 52 53 54 55 56 57 58 59 60 |
} for (i = 0; i < optlen; ) { if (op[i] == option) return !invert; if (op[i] < 2) i++; else i += op[i+1]?:1; } return invert; } |
62fc80510 netfilter: xtable... |
61 |
static bool tcp_mt(const struct sk_buff *skb, struct xt_action_param *par) |
2e4e6a17a [NETFILTER] x_tab... |
62 |
{ |
3cf93c96a [NETFILTER]: anno... |
63 64 |
const struct tcphdr *th; struct tcphdr _tcph; |
f7108a20d netfilter: xtable... |
65 |
const struct xt_tcp *tcpinfo = par->matchinfo; |
2e4e6a17a [NETFILTER] x_tab... |
66 |
|
f7108a20d netfilter: xtable... |
67 |
if (par->fragoff != 0) { |
2e4e6a17a [NETFILTER] x_tab... |
68 69 70 71 72 73 |
/* To quote Alan: Don't allow a fragment of TCP 8 bytes in. Nobody normal causes this. Its a cracker trying to break in by doing a flag overwrite to pass the direction checks. */ |
f7108a20d netfilter: xtable... |
74 |
if (par->fragoff == 1) { |
be91fd5e3 netfilter: xtable... |
75 76 |
pr_debug("Dropping evil TCP offset=1 frag. "); |
b4ba26119 netfilter: xtable... |
77 |
par->hotdrop = true; |
2e4e6a17a [NETFILTER] x_tab... |
78 79 |
} /* Must not be a fragment. */ |
1d93a9cba [NETFILTER]: x_ta... |
80 |
return false; |
2e4e6a17a [NETFILTER] x_tab... |
81 |
} |
7c4e36bc1 [NETFILTER]: Remo... |
82 |
#define FWINVTCP(bool, invflg) ((bool) ^ !!(tcpinfo->invflags & (invflg))) |
2e4e6a17a [NETFILTER] x_tab... |
83 |
|
f7108a20d netfilter: xtable... |
84 |
th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph); |
2e4e6a17a [NETFILTER] x_tab... |
85 86 87 |
if (th == NULL) { /* We've been asked to examine this packet, and we can't. Hence, no choice but to drop. */ |
be91fd5e3 netfilter: xtable... |
88 89 |
pr_debug("Dropping evil TCP offset=0 tinygram. "); |
b4ba26119 netfilter: xtable... |
90 |
par->hotdrop = true; |
1d93a9cba [NETFILTER]: x_ta... |
91 |
return false; |
2e4e6a17a [NETFILTER] x_tab... |
92 93 94 95 96 |
} if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1], ntohs(th->source), !!(tcpinfo->invflags & XT_TCP_INV_SRCPT))) |
1d93a9cba [NETFILTER]: x_ta... |
97 |
return false; |
2e4e6a17a [NETFILTER] x_tab... |
98 99 100 |
if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1], ntohs(th->dest), !!(tcpinfo->invflags & XT_TCP_INV_DSTPT))) |
1d93a9cba [NETFILTER]: x_ta... |
101 |
return false; |
2e4e6a17a [NETFILTER] x_tab... |
102 103 104 |
if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask) == tcpinfo->flg_cmp, XT_TCP_INV_FLAGS)) |
1d93a9cba [NETFILTER]: x_ta... |
105 |
return false; |
2e4e6a17a [NETFILTER] x_tab... |
106 107 |
if (tcpinfo->option) { if (th->doff * 4 < sizeof(_tcph)) { |
b4ba26119 netfilter: xtable... |
108 |
par->hotdrop = true; |
1d93a9cba [NETFILTER]: x_ta... |
109 |
return false; |
2e4e6a17a [NETFILTER] x_tab... |
110 |
} |
f7108a20d netfilter: xtable... |
111 |
if (!tcp_find_option(tcpinfo->option, skb, par->thoff, |
2e4e6a17a [NETFILTER] x_tab... |
112 113 |
th->doff*4 - sizeof(_tcph), tcpinfo->invflags & XT_TCP_INV_OPTION, |
b4ba26119 netfilter: xtable... |
114 |
&par->hotdrop)) |
1d93a9cba [NETFILTER]: x_ta... |
115 |
return false; |
2e4e6a17a [NETFILTER] x_tab... |
116 |
} |
1d93a9cba [NETFILTER]: x_ta... |
117 |
return true; |
2e4e6a17a [NETFILTER] x_tab... |
118 |
} |
b0f38452f netfilter: xtable... |
119 |
static int tcp_mt_check(const struct xt_mtchk_param *par) |
2e4e6a17a [NETFILTER] x_tab... |
120 |
{ |
9b4fce7a3 netfilter: xtable... |
121 |
const struct xt_tcp *tcpinfo = par->matchinfo; |
2e4e6a17a [NETFILTER] x_tab... |
122 |
|
5d04bff09 [NETFILTER]: Conv... |
123 |
/* Must specify no unknown invflags */ |
bd414ee60 netfilter: xtable... |
124 |
return (tcpinfo->invflags & ~XT_TCP_INV_MASK) ? -EINVAL : 0; |
2e4e6a17a [NETFILTER] x_tab... |
125 |
} |
62fc80510 netfilter: xtable... |
126 |
static bool udp_mt(const struct sk_buff *skb, struct xt_action_param *par) |
2e4e6a17a [NETFILTER] x_tab... |
127 |
{ |
3cf93c96a [NETFILTER]: anno... |
128 129 |
const struct udphdr *uh; struct udphdr _udph; |
f7108a20d netfilter: xtable... |
130 |
const struct xt_udp *udpinfo = par->matchinfo; |
2e4e6a17a [NETFILTER] x_tab... |
131 132 |
/* Must not be a fragment. */ |
f7108a20d netfilter: xtable... |
133 |
if (par->fragoff != 0) |
1d93a9cba [NETFILTER]: x_ta... |
134 |
return false; |
2e4e6a17a [NETFILTER] x_tab... |
135 |
|
f7108a20d netfilter: xtable... |
136 |
uh = skb_header_pointer(skb, par->thoff, sizeof(_udph), &_udph); |
2e4e6a17a [NETFILTER] x_tab... |
137 138 139 |
if (uh == NULL) { /* We've been asked to examine this packet, and we can't. Hence, no choice but to drop. */ |
be91fd5e3 netfilter: xtable... |
140 141 |
pr_debug("Dropping evil UDP tinygram. "); |
b4ba26119 netfilter: xtable... |
142 |
par->hotdrop = true; |
1d93a9cba [NETFILTER]: x_ta... |
143 |
return false; |
2e4e6a17a [NETFILTER] x_tab... |
144 145 146 147 148 149 150 151 152 |
} return port_match(udpinfo->spts[0], udpinfo->spts[1], ntohs(uh->source), !!(udpinfo->invflags & XT_UDP_INV_SRCPT)) && port_match(udpinfo->dpts[0], udpinfo->dpts[1], ntohs(uh->dest), !!(udpinfo->invflags & XT_UDP_INV_DSTPT)); } |
b0f38452f netfilter: xtable... |
153 |
static int udp_mt_check(const struct xt_mtchk_param *par) |
2e4e6a17a [NETFILTER] x_tab... |
154 |
{ |
9b4fce7a3 netfilter: xtable... |
155 |
const struct xt_udp *udpinfo = par->matchinfo; |
2e4e6a17a [NETFILTER] x_tab... |
156 |
|
5d04bff09 [NETFILTER]: Conv... |
157 |
/* Must specify no unknown invflags */ |
bd414ee60 netfilter: xtable... |
158 |
return (udpinfo->invflags & ~XT_UDP_INV_MASK) ? -EINVAL : 0; |
2e4e6a17a [NETFILTER] x_tab... |
159 |
} |
d3c5ee6d5 [NETFILTER]: x_ta... |
160 |
static struct xt_match tcpudp_mt_reg[] __read_mostly = { |
4470bbc74 [NETFILTER]: x_ta... |
161 162 |
{ .name = "tcp", |
ee999d8b9 netfilter: x_tabl... |
163 |
.family = NFPROTO_IPV4, |
d3c5ee6d5 [NETFILTER]: x_ta... |
164 165 |
.checkentry = tcp_mt_check, .match = tcp_mt, |
4470bbc74 [NETFILTER]: x_ta... |
166 167 168 169 170 171 |
.matchsize = sizeof(struct xt_tcp), .proto = IPPROTO_TCP, .me = THIS_MODULE, }, { .name = "tcp", |
ee999d8b9 netfilter: x_tabl... |
172 |
.family = NFPROTO_IPV6, |
d3c5ee6d5 [NETFILTER]: x_ta... |
173 174 |
.checkentry = tcp_mt_check, .match = tcp_mt, |
4470bbc74 [NETFILTER]: x_ta... |
175 176 177 178 179 180 |
.matchsize = sizeof(struct xt_tcp), .proto = IPPROTO_TCP, .me = THIS_MODULE, }, { .name = "udp", |
ee999d8b9 netfilter: x_tabl... |
181 |
.family = NFPROTO_IPV4, |
d3c5ee6d5 [NETFILTER]: x_ta... |
182 183 |
.checkentry = udp_mt_check, .match = udp_mt, |
4470bbc74 [NETFILTER]: x_ta... |
184 185 186 187 188 189 |
.matchsize = sizeof(struct xt_udp), .proto = IPPROTO_UDP, .me = THIS_MODULE, }, { .name = "udp", |
ee999d8b9 netfilter: x_tabl... |
190 |
.family = NFPROTO_IPV6, |
d3c5ee6d5 [NETFILTER]: x_ta... |
191 192 |
.checkentry = udp_mt_check, .match = udp_mt, |
4470bbc74 [NETFILTER]: x_ta... |
193 194 195 196 |
.matchsize = sizeof(struct xt_udp), .proto = IPPROTO_UDP, .me = THIS_MODULE, }, |
ba4e58eca [NET]: Supporting... |
197 198 |
{ .name = "udplite", |
ee999d8b9 netfilter: x_tabl... |
199 |
.family = NFPROTO_IPV4, |
d3c5ee6d5 [NETFILTER]: x_ta... |
200 201 |
.checkentry = udp_mt_check, .match = udp_mt, |
ba4e58eca [NET]: Supporting... |
202 203 204 205 206 207 |
.matchsize = sizeof(struct xt_udp), .proto = IPPROTO_UDPLITE, .me = THIS_MODULE, }, { .name = "udplite", |
ee999d8b9 netfilter: x_tabl... |
208 |
.family = NFPROTO_IPV6, |
d3c5ee6d5 [NETFILTER]: x_ta... |
209 210 |
.checkentry = udp_mt_check, .match = udp_mt, |
ba4e58eca [NET]: Supporting... |
211 212 213 214 |
.matchsize = sizeof(struct xt_udp), .proto = IPPROTO_UDPLITE, .me = THIS_MODULE, }, |
2e4e6a17a [NETFILTER] x_tab... |
215 |
}; |
d3c5ee6d5 [NETFILTER]: x_ta... |
216 |
static int __init tcpudp_mt_init(void) |
2e4e6a17a [NETFILTER] x_tab... |
217 |
{ |
d3c5ee6d5 [NETFILTER]: x_ta... |
218 |
return xt_register_matches(tcpudp_mt_reg, ARRAY_SIZE(tcpudp_mt_reg)); |
2e4e6a17a [NETFILTER] x_tab... |
219 |
} |
d3c5ee6d5 [NETFILTER]: x_ta... |
220 |
static void __exit tcpudp_mt_exit(void) |
2e4e6a17a [NETFILTER] x_tab... |
221 |
{ |
d3c5ee6d5 [NETFILTER]: x_ta... |
222 |
xt_unregister_matches(tcpudp_mt_reg, ARRAY_SIZE(tcpudp_mt_reg)); |
2e4e6a17a [NETFILTER] x_tab... |
223 |
} |
d3c5ee6d5 [NETFILTER]: x_ta... |
224 225 |
module_init(tcpudp_mt_init); module_exit(tcpudp_mt_exit); |