Blame view
net/netfilter/xt_tcpudp.c
5.61 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 |
} |
f7108a20d netfilter: xtable... |
82 |
th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph); |
2e4e6a17a [NETFILTER] x_tab... |
83 84 85 |
if (th == NULL) { /* We've been asked to examine this packet, and we can't. Hence, no choice but to drop. */ |
be91fd5e3 netfilter: xtable... |
86 87 |
pr_debug("Dropping evil TCP offset=0 tinygram. "); |
b4ba26119 netfilter: xtable... |
88 |
par->hotdrop = true; |
1d93a9cba [NETFILTER]: x_ta... |
89 |
return false; |
2e4e6a17a [NETFILTER] x_tab... |
90 91 92 93 94 |
} if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1], ntohs(th->source), !!(tcpinfo->invflags & XT_TCP_INV_SRCPT))) |
1d93a9cba [NETFILTER]: x_ta... |
95 |
return false; |
2e4e6a17a [NETFILTER] x_tab... |
96 97 98 |
if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1], ntohs(th->dest), !!(tcpinfo->invflags & XT_TCP_INV_DSTPT))) |
1d93a9cba [NETFILTER]: x_ta... |
99 |
return false; |
c37a2dfa6 netfilter: Conver... |
100 101 |
if (!NF_INVF(tcpinfo, XT_TCP_INV_FLAGS, (((unsigned char *)th)[13] & tcpinfo->flg_mask) == tcpinfo->flg_cmp)) |
1d93a9cba [NETFILTER]: x_ta... |
102 |
return false; |
2e4e6a17a [NETFILTER] x_tab... |
103 104 |
if (tcpinfo->option) { if (th->doff * 4 < sizeof(_tcph)) { |
b4ba26119 netfilter: xtable... |
105 |
par->hotdrop = true; |
1d93a9cba [NETFILTER]: x_ta... |
106 |
return false; |
2e4e6a17a [NETFILTER] x_tab... |
107 |
} |
f7108a20d netfilter: xtable... |
108 |
if (!tcp_find_option(tcpinfo->option, skb, par->thoff, |
2e4e6a17a [NETFILTER] x_tab... |
109 110 |
th->doff*4 - sizeof(_tcph), tcpinfo->invflags & XT_TCP_INV_OPTION, |
b4ba26119 netfilter: xtable... |
111 |
&par->hotdrop)) |
1d93a9cba [NETFILTER]: x_ta... |
112 |
return false; |
2e4e6a17a [NETFILTER] x_tab... |
113 |
} |
1d93a9cba [NETFILTER]: x_ta... |
114 |
return true; |
2e4e6a17a [NETFILTER] x_tab... |
115 |
} |
b0f38452f netfilter: xtable... |
116 |
static int tcp_mt_check(const struct xt_mtchk_param *par) |
2e4e6a17a [NETFILTER] x_tab... |
117 |
{ |
9b4fce7a3 netfilter: xtable... |
118 |
const struct xt_tcp *tcpinfo = par->matchinfo; |
2e4e6a17a [NETFILTER] x_tab... |
119 |
|
5d04bff09 [NETFILTER]: Conv... |
120 |
/* Must specify no unknown invflags */ |
bd414ee60 netfilter: xtable... |
121 |
return (tcpinfo->invflags & ~XT_TCP_INV_MASK) ? -EINVAL : 0; |
2e4e6a17a [NETFILTER] x_tab... |
122 |
} |
62fc80510 netfilter: xtable... |
123 |
static bool udp_mt(const struct sk_buff *skb, struct xt_action_param *par) |
2e4e6a17a [NETFILTER] x_tab... |
124 |
{ |
3cf93c96a [NETFILTER]: anno... |
125 126 |
const struct udphdr *uh; struct udphdr _udph; |
f7108a20d netfilter: xtable... |
127 |
const struct xt_udp *udpinfo = par->matchinfo; |
2e4e6a17a [NETFILTER] x_tab... |
128 129 |
/* Must not be a fragment. */ |
f7108a20d netfilter: xtable... |
130 |
if (par->fragoff != 0) |
1d93a9cba [NETFILTER]: x_ta... |
131 |
return false; |
2e4e6a17a [NETFILTER] x_tab... |
132 |
|
f7108a20d netfilter: xtable... |
133 |
uh = skb_header_pointer(skb, par->thoff, sizeof(_udph), &_udph); |
2e4e6a17a [NETFILTER] x_tab... |
134 135 136 |
if (uh == NULL) { /* We've been asked to examine this packet, and we can't. Hence, no choice but to drop. */ |
be91fd5e3 netfilter: xtable... |
137 138 |
pr_debug("Dropping evil UDP tinygram. "); |
b4ba26119 netfilter: xtable... |
139 |
par->hotdrop = true; |
1d93a9cba [NETFILTER]: x_ta... |
140 |
return false; |
2e4e6a17a [NETFILTER] x_tab... |
141 142 143 144 145 146 147 148 149 |
} 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... |
150 |
static int udp_mt_check(const struct xt_mtchk_param *par) |
2e4e6a17a [NETFILTER] x_tab... |
151 |
{ |
9b4fce7a3 netfilter: xtable... |
152 |
const struct xt_udp *udpinfo = par->matchinfo; |
2e4e6a17a [NETFILTER] x_tab... |
153 |
|
5d04bff09 [NETFILTER]: Conv... |
154 |
/* Must specify no unknown invflags */ |
bd414ee60 netfilter: xtable... |
155 |
return (udpinfo->invflags & ~XT_UDP_INV_MASK) ? -EINVAL : 0; |
2e4e6a17a [NETFILTER] x_tab... |
156 |
} |
d3c5ee6d5 [NETFILTER]: x_ta... |
157 |
static struct xt_match tcpudp_mt_reg[] __read_mostly = { |
4470bbc74 [NETFILTER]: x_ta... |
158 159 |
{ .name = "tcp", |
ee999d8b9 netfilter: x_tabl... |
160 |
.family = NFPROTO_IPV4, |
d3c5ee6d5 [NETFILTER]: x_ta... |
161 162 |
.checkentry = tcp_mt_check, .match = tcp_mt, |
4470bbc74 [NETFILTER]: x_ta... |
163 164 165 166 167 168 |
.matchsize = sizeof(struct xt_tcp), .proto = IPPROTO_TCP, .me = THIS_MODULE, }, { .name = "tcp", |
ee999d8b9 netfilter: x_tabl... |
169 |
.family = NFPROTO_IPV6, |
d3c5ee6d5 [NETFILTER]: x_ta... |
170 171 |
.checkentry = tcp_mt_check, .match = tcp_mt, |
4470bbc74 [NETFILTER]: x_ta... |
172 173 174 175 176 177 |
.matchsize = sizeof(struct xt_tcp), .proto = IPPROTO_TCP, .me = THIS_MODULE, }, { .name = "udp", |
ee999d8b9 netfilter: x_tabl... |
178 |
.family = NFPROTO_IPV4, |
d3c5ee6d5 [NETFILTER]: x_ta... |
179 180 |
.checkentry = udp_mt_check, .match = udp_mt, |
4470bbc74 [NETFILTER]: x_ta... |
181 182 183 184 185 186 |
.matchsize = sizeof(struct xt_udp), .proto = IPPROTO_UDP, .me = THIS_MODULE, }, { .name = "udp", |
ee999d8b9 netfilter: x_tabl... |
187 |
.family = NFPROTO_IPV6, |
d3c5ee6d5 [NETFILTER]: x_ta... |
188 189 |
.checkentry = udp_mt_check, .match = udp_mt, |
4470bbc74 [NETFILTER]: x_ta... |
190 191 192 193 |
.matchsize = sizeof(struct xt_udp), .proto = IPPROTO_UDP, .me = THIS_MODULE, }, |
ba4e58eca [NET]: Supporting... |
194 195 |
{ .name = "udplite", |
ee999d8b9 netfilter: x_tabl... |
196 |
.family = NFPROTO_IPV4, |
d3c5ee6d5 [NETFILTER]: x_ta... |
197 198 |
.checkentry = udp_mt_check, .match = udp_mt, |
ba4e58eca [NET]: Supporting... |
199 200 201 202 203 204 |
.matchsize = sizeof(struct xt_udp), .proto = IPPROTO_UDPLITE, .me = THIS_MODULE, }, { .name = "udplite", |
ee999d8b9 netfilter: x_tabl... |
205 |
.family = NFPROTO_IPV6, |
d3c5ee6d5 [NETFILTER]: x_ta... |
206 207 |
.checkentry = udp_mt_check, .match = udp_mt, |
ba4e58eca [NET]: Supporting... |
208 209 210 211 |
.matchsize = sizeof(struct xt_udp), .proto = IPPROTO_UDPLITE, .me = THIS_MODULE, }, |
2e4e6a17a [NETFILTER] x_tab... |
212 |
}; |
d3c5ee6d5 [NETFILTER]: x_ta... |
213 |
static int __init tcpudp_mt_init(void) |
2e4e6a17a [NETFILTER] x_tab... |
214 |
{ |
d3c5ee6d5 [NETFILTER]: x_ta... |
215 |
return xt_register_matches(tcpudp_mt_reg, ARRAY_SIZE(tcpudp_mt_reg)); |
2e4e6a17a [NETFILTER] x_tab... |
216 |
} |
d3c5ee6d5 [NETFILTER]: x_ta... |
217 |
static void __exit tcpudp_mt_exit(void) |
2e4e6a17a [NETFILTER] x_tab... |
218 |
{ |
d3c5ee6d5 [NETFILTER]: x_ta... |
219 |
xt_unregister_matches(tcpudp_mt_reg, ARRAY_SIZE(tcpudp_mt_reg)); |
2e4e6a17a [NETFILTER] x_tab... |
220 |
} |
d3c5ee6d5 [NETFILTER]: x_ta... |
221 222 |
module_init(tcpudp_mt_init); module_exit(tcpudp_mt_exit); |