Blame view
net/netfilter/nf_nat_sip.c
20 KB
48f8ac265 netfilter: nf_nat... |
1 |
/* SIP extension for NAT alteration. |
9fafcd7b2 [NETFILTER]: nf_c... |
2 3 4 |
* * (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar> * based on RR's ip_nat_ftp.c and other modules. |
f49e1aa13 [NETFILTER]: nf_c... |
5 |
* (C) 2007 United Security Providers |
9a6648210 netfilter: nf_nat... |
6 |
* (C) 2007, 2008, 2011, 2012 Patrick McHardy <kaber@trash.net> |
9fafcd7b2 [NETFILTER]: nf_c... |
7 8 9 10 11 12 13 14 |
* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include <linux/module.h> #include <linux/skbuff.h> |
9a6648210 netfilter: nf_nat... |
15 |
#include <linux/inet.h> |
9fafcd7b2 [NETFILTER]: nf_c... |
16 |
#include <linux/udp.h> |
48f8ac265 netfilter: nf_nat... |
17 |
#include <linux/tcp.h> |
9fafcd7b2 [NETFILTER]: nf_c... |
18 19 20 |
#include <net/netfilter/nf_nat.h> #include <net/netfilter/nf_nat_helper.h> |
9fafcd7b2 [NETFILTER]: nf_c... |
21 22 23 24 25 26 27 28 |
#include <net/netfilter/nf_conntrack_helper.h> #include <net/netfilter/nf_conntrack_expect.h> #include <linux/netfilter/nf_conntrack_sip.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>"); MODULE_DESCRIPTION("SIP NAT helper"); MODULE_ALIAS("ip_nat_sip"); |
9fafcd7b2 [NETFILTER]: nf_c... |
29 |
|
051966c0c netfilter: nf_nat... |
30 31 |
static unsigned int mangle_packet(struct sk_buff *skb, unsigned int protoff, unsigned int dataoff, |
2a6cfb22a [NETFILTER]: nf_c... |
32 33 34 35 36 37 |
const char **dptr, unsigned int *datalen, unsigned int matchoff, unsigned int matchlen, const char *buffer, unsigned int buflen) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
48f8ac265 netfilter: nf_nat... |
38 39 40 41 |
struct tcphdr *th; unsigned int baseoff; if (nf_ct_protonum(ct) == IPPROTO_TCP) { |
9a6648210 netfilter: nf_nat... |
42 43 |
th = (struct tcphdr *)(skb->data + protoff); baseoff = protoff + th->doff * 4; |
48f8ac265 netfilter: nf_nat... |
44 45 46 |
matchoff += dataoff - baseoff; if (!__nf_nat_mangle_tcp_packet(skb, ct, ctinfo, |
051966c0c netfilter: nf_nat... |
47 |
protoff, matchoff, matchlen, |
48f8ac265 netfilter: nf_nat... |
48 49 50 |
buffer, buflen, false)) return 0; } else { |
9a6648210 netfilter: nf_nat... |
51 |
baseoff = protoff + sizeof(struct udphdr); |
48f8ac265 netfilter: nf_nat... |
52 53 54 |
matchoff += dataoff - baseoff; if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, |
051966c0c netfilter: nf_nat... |
55 |
protoff, matchoff, matchlen, |
48f8ac265 netfilter: nf_nat... |
56 57 58 |
buffer, buflen)) return 0; } |
2a6cfb22a [NETFILTER]: nf_c... |
59 60 |
/* Reload data pointer and adjust datalen value */ |
3b6b9fab4 netfilter: nf_con... |
61 |
*dptr = skb->data + dataoff; |
2a6cfb22a [NETFILTER]: nf_c... |
62 63 64 |
*datalen += buflen - matchlen; return 1; } |
9a6648210 netfilter: nf_nat... |
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
static int sip_sprintf_addr(const struct nf_conn *ct, char *buffer, const union nf_inet_addr *addr, bool delim) { if (nf_ct_l3num(ct) == NFPROTO_IPV4) return sprintf(buffer, "%pI4", &addr->ip); else { if (delim) return sprintf(buffer, "[%pI6c]", &addr->ip6); else return sprintf(buffer, "%pI6c", &addr->ip6); } } static int sip_sprintf_addr_port(const struct nf_conn *ct, char *buffer, const union nf_inet_addr *addr, u16 port) { if (nf_ct_l3num(ct) == NFPROTO_IPV4) return sprintf(buffer, "%pI4:%u", &addr->ip, port); else return sprintf(buffer, "[%pI6c]:%u", &addr->ip6, port); } |
051966c0c netfilter: nf_nat... |
86 87 |
static int map_addr(struct sk_buff *skb, unsigned int protoff, unsigned int dataoff, |
ac3677406 [NETFILTER]: nf_c... |
88 89 |
const char **dptr, unsigned int *datalen, unsigned int matchoff, unsigned int matchlen, |
624f8b7bb [NETFILTER]: nf_n... |
90 |
union nf_inet_addr *addr, __be16 port) |
9fafcd7b2 [NETFILTER]: nf_c... |
91 |
{ |
212440a7d [NETFILTER]: nf_c... |
92 |
enum ip_conntrack_info ctinfo; |
624f8b7bb [NETFILTER]: nf_n... |
93 |
struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
9fafcd7b2 [NETFILTER]: nf_c... |
94 |
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
7266507d8 netfilter: nf_ct_... |
95 |
struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct); |
9a6648210 netfilter: nf_nat... |
96 |
char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")]; |
624f8b7bb [NETFILTER]: nf_n... |
97 |
unsigned int buflen; |
9a6648210 netfilter: nf_nat... |
98 |
union nf_inet_addr newaddr; |
624f8b7bb [NETFILTER]: nf_n... |
99 |
__be16 newport; |
9a6648210 netfilter: nf_nat... |
100 |
if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, addr) && |
624f8b7bb [NETFILTER]: nf_n... |
101 |
ct->tuplehash[dir].tuple.src.u.udp.port == port) { |
9a6648210 netfilter: nf_nat... |
102 |
newaddr = ct->tuplehash[!dir].tuple.dst.u3; |
624f8b7bb [NETFILTER]: nf_n... |
103 |
newport = ct->tuplehash[!dir].tuple.dst.u.udp.port; |
9a6648210 netfilter: nf_nat... |
104 |
} else if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, addr) && |
624f8b7bb [NETFILTER]: nf_n... |
105 |
ct->tuplehash[dir].tuple.dst.u.udp.port == port) { |
9a6648210 netfilter: nf_nat... |
106 |
newaddr = ct->tuplehash[!dir].tuple.src.u3; |
7266507d8 netfilter: nf_ct_... |
107 108 |
newport = ct_sip_info->forced_dport ? : ct->tuplehash[!dir].tuple.src.u.udp.port; |
9fafcd7b2 [NETFILTER]: nf_c... |
109 110 |
} else return 1; |
9a6648210 netfilter: nf_nat... |
111 |
if (nf_inet_addr_cmp(&newaddr, addr) && newport == port) |
624f8b7bb [NETFILTER]: nf_n... |
112 |
return 1; |
9a6648210 netfilter: nf_nat... |
113 |
buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, ntohs(newport)); |
051966c0c netfilter: nf_nat... |
114 115 |
return mangle_packet(skb, protoff, dataoff, dptr, datalen, matchoff, matchlen, buffer, buflen); |
9fafcd7b2 [NETFILTER]: nf_c... |
116 |
} |
051966c0c netfilter: nf_nat... |
117 118 |
static int map_sip_addr(struct sk_buff *skb, unsigned int protoff, unsigned int dataoff, |
ac3677406 [NETFILTER]: nf_c... |
119 |
const char **dptr, unsigned int *datalen, |
624f8b7bb [NETFILTER]: nf_n... |
120 |
enum sip_header_types type) |
ac3677406 [NETFILTER]: nf_c... |
121 122 123 124 |
{ enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); unsigned int matchlen, matchoff; |
624f8b7bb [NETFILTER]: nf_n... |
125 126 |
union nf_inet_addr addr; __be16 port; |
ac3677406 [NETFILTER]: nf_c... |
127 |
|
624f8b7bb [NETFILTER]: nf_n... |
128 129 |
if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, type, NULL, &matchoff, &matchlen, &addr, &port) <= 0) |
ac3677406 [NETFILTER]: nf_c... |
130 |
return 1; |
051966c0c netfilter: nf_nat... |
131 132 |
return map_addr(skb, protoff, dataoff, dptr, datalen, matchoff, matchlen, &addr, port); |
ac3677406 [NETFILTER]: nf_c... |
133 |
} |
9a6648210 netfilter: nf_nat... |
134 |
static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, |
051966c0c netfilter: nf_nat... |
135 |
unsigned int dataoff, |
2a6cfb22a [NETFILTER]: nf_c... |
136 |
const char **dptr, unsigned int *datalen) |
9fafcd7b2 [NETFILTER]: nf_c... |
137 |
{ |
212440a7d [NETFILTER]: nf_c... |
138 139 |
enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
720ac7085 [NETFILTER]: nf_n... |
140 |
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
7266507d8 netfilter: nf_ct_... |
141 |
struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct); |
3b6b9fab4 netfilter: nf_con... |
142 |
unsigned int coff, matchoff, matchlen; |
48f8ac265 netfilter: nf_nat... |
143 |
enum sip_header_types hdr; |
624f8b7bb [NETFILTER]: nf_n... |
144 145 |
union nf_inet_addr addr; __be16 port; |
c978cd3a9 [NETFILTER]: nf_n... |
146 |
int request, in_header; |
9fafcd7b2 [NETFILTER]: nf_c... |
147 |
|
9fafcd7b2 [NETFILTER]: nf_c... |
148 |
/* Basic rules: requests and responses. */ |
779382eb3 [NETFILTER]: nf_c... |
149 |
if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) { |
ac3677406 [NETFILTER]: nf_c... |
150 |
if (ct_sip_parse_request(ct, *dptr, *datalen, |
624f8b7bb [NETFILTER]: nf_n... |
151 152 |
&matchoff, &matchlen, &addr, &port) > 0 && |
051966c0c netfilter: nf_nat... |
153 |
!map_addr(skb, protoff, dataoff, dptr, datalen, |
b20ab9cc6 netfilter: nf_ct_... |
154 155 |
matchoff, matchlen, &addr, port)) { nf_ct_helper_log(skb, ct, "cannot mangle SIP message"); |
9fafcd7b2 [NETFILTER]: nf_c... |
156 |
return NF_DROP; |
b20ab9cc6 netfilter: nf_ct_... |
157 |
} |
720ac7085 [NETFILTER]: nf_n... |
158 159 160 |
request = 1; } else request = 0; |
48f8ac265 netfilter: nf_nat... |
161 162 163 164 |
if (nf_ct_protonum(ct) == IPPROTO_TCP) hdr = SIP_HDR_VIA_TCP; else hdr = SIP_HDR_VIA_UDP; |
720ac7085 [NETFILTER]: nf_n... |
165 166 |
/* Translate topmost Via header and parameters */ if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, |
48f8ac265 netfilter: nf_nat... |
167 |
hdr, NULL, &matchoff, &matchlen, |
720ac7085 [NETFILTER]: nf_n... |
168 |
&addr, &port) > 0) { |
f22eb25cf netfilter: nf_nat... |
169 |
unsigned int olen, matchend, poff, plen, buflen, n; |
9a6648210 netfilter: nf_nat... |
170 |
char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")]; |
720ac7085 [NETFILTER]: nf_n... |
171 172 173 174 |
/* We're only interested in headers related to this * connection */ if (request) { |
9a6648210 netfilter: nf_nat... |
175 176 |
if (!nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3) || |
720ac7085 [NETFILTER]: nf_n... |
177 178 179 |
port != ct->tuplehash[dir].tuple.src.u.udp.port) goto next; } else { |
9a6648210 netfilter: nf_nat... |
180 181 |
if (!nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.dst.u3) || |
720ac7085 [NETFILTER]: nf_n... |
182 183 184 |
port != ct->tuplehash[dir].tuple.dst.u.udp.port) goto next; } |
f22eb25cf netfilter: nf_nat... |
185 |
olen = *datalen; |
051966c0c netfilter: nf_nat... |
186 |
if (!map_addr(skb, protoff, dataoff, dptr, datalen, |
b20ab9cc6 netfilter: nf_ct_... |
187 188 |
matchoff, matchlen, &addr, port)) { nf_ct_helper_log(skb, ct, "cannot mangle Via header"); |
720ac7085 [NETFILTER]: nf_n... |
189 |
return NF_DROP; |
b20ab9cc6 netfilter: nf_ct_... |
190 |
} |
720ac7085 [NETFILTER]: nf_n... |
191 |
|
f22eb25cf netfilter: nf_nat... |
192 |
matchend = matchoff + matchlen + *datalen - olen; |
720ac7085 [NETFILTER]: nf_n... |
193 194 195 196 197 |
/* The maddr= parameter (RFC 2361) specifies where to send * the reply. */ if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen, "maddr=", &poff, &plen, |
02b69cbdc netfilter: nf_ct_... |
198 |
&addr, true) > 0 && |
9a6648210 netfilter: nf_nat... |
199 200 201 202 203 |
nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3) && !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3)) { buflen = sip_sprintf_addr(ct, buffer, &ct->tuplehash[!dir].tuple.dst.u3, true); |
051966c0c netfilter: nf_nat... |
204 |
if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, |
b20ab9cc6 netfilter: nf_ct_... |
205 206 |
poff, plen, buffer, buflen)) { nf_ct_helper_log(skb, ct, "cannot mangle maddr"); |
720ac7085 [NETFILTER]: nf_n... |
207 |
return NF_DROP; |
b20ab9cc6 netfilter: nf_ct_... |
208 |
} |
720ac7085 [NETFILTER]: nf_n... |
209 210 211 212 213 214 |
} /* The received= parameter (RFC 2361) contains the address * from which the server received the request. */ if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen, "received=", &poff, &plen, |
02b69cbdc netfilter: nf_ct_... |
215 |
&addr, false) > 0 && |
9a6648210 netfilter: nf_nat... |
216 217 218 219 220 |
nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.dst.u3) && !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.src.u3)) { buflen = sip_sprintf_addr(ct, buffer, &ct->tuplehash[!dir].tuple.src.u3, false); |
051966c0c netfilter: nf_nat... |
221 |
if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, |
5aed93875 netfilter: nf_nat... |
222 |
poff, plen, buffer, buflen)) { |
b20ab9cc6 netfilter: nf_ct_... |
223 |
nf_ct_helper_log(skb, ct, "cannot mangle received"); |
720ac7085 [NETFILTER]: nf_n... |
224 |
return NF_DROP; |
5aed93875 netfilter: nf_nat... |
225 |
} |
720ac7085 [NETFILTER]: nf_n... |
226 227 228 229 230 231 232 233 234 235 236 |
} /* The rport= parameter (RFC 3581) contains the port number * from which the server received the request. */ if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen, "rport=", &poff, &plen, &n) > 0 && htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; buflen = sprintf(buffer, "%u", ntohs(p)); |
051966c0c netfilter: nf_nat... |
237 |
if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, |
b20ab9cc6 netfilter: nf_ct_... |
238 239 |
poff, plen, buffer, buflen)) { nf_ct_helper_log(skb, ct, "cannot mangle rport"); |
720ac7085 [NETFILTER]: nf_n... |
240 |
return NF_DROP; |
b20ab9cc6 netfilter: nf_ct_... |
241 |
} |
720ac7085 [NETFILTER]: nf_n... |
242 |
} |
9fafcd7b2 [NETFILTER]: nf_c... |
243 |
} |
720ac7085 [NETFILTER]: nf_n... |
244 |
next: |
c978cd3a9 [NETFILTER]: nf_n... |
245 |
/* Translate Contact headers */ |
3b6b9fab4 netfilter: nf_con... |
246 |
coff = 0; |
c978cd3a9 [NETFILTER]: nf_n... |
247 |
in_header = 0; |
3b6b9fab4 netfilter: nf_con... |
248 |
while (ct_sip_parse_header_uri(ct, *dptr, &coff, *datalen, |
c978cd3a9 [NETFILTER]: nf_n... |
249 250 251 |
SIP_HDR_CONTACT, &in_header, &matchoff, &matchlen, &addr, &port) > 0) { |
051966c0c netfilter: nf_nat... |
252 253 |
if (!map_addr(skb, protoff, dataoff, dptr, datalen, matchoff, matchlen, |
b20ab9cc6 netfilter: nf_ct_... |
254 255 |
&addr, port)) { nf_ct_helper_log(skb, ct, "cannot mangle contact"); |
c978cd3a9 [NETFILTER]: nf_n... |
256 |
return NF_DROP; |
b20ab9cc6 netfilter: nf_ct_... |
257 |
} |
c978cd3a9 [NETFILTER]: nf_n... |
258 |
} |
051966c0c netfilter: nf_nat... |
259 |
if (!map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_FROM) || |
b20ab9cc6 netfilter: nf_ct_... |
260 261 |
!map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_TO)) { nf_ct_helper_log(skb, ct, "cannot mangle SIP from/to"); |
9fafcd7b2 [NETFILTER]: nf_c... |
262 |
return NF_DROP; |
b20ab9cc6 netfilter: nf_ct_... |
263 |
} |
48f8ac265 netfilter: nf_nat... |
264 |
|
7266507d8 netfilter: nf_ct_... |
265 266 267 |
/* Mangle destination port for Cisco phones, then fix up checksums */ if (dir == IP_CT_DIR_REPLY && ct_sip_info->forced_dport) { struct udphdr *uh; |
b20ab9cc6 netfilter: nf_ct_... |
268 269 |
if (!skb_make_writable(skb, skb->len)) { nf_ct_helper_log(skb, ct, "cannot mangle packet"); |
7266507d8 netfilter: nf_ct_... |
270 |
return NF_DROP; |
b20ab9cc6 netfilter: nf_ct_... |
271 |
} |
7266507d8 netfilter: nf_ct_... |
272 273 274 275 276 |
uh = (void *)skb->data + protoff; uh->dest = ct_sip_info->forced_dport; if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, protoff, |
b20ab9cc6 netfilter: nf_ct_... |
277 278 |
0, 0, NULL, 0)) { nf_ct_helper_log(skb, ct, "cannot mangle packet"); |
7266507d8 netfilter: nf_ct_... |
279 |
return NF_DROP; |
b20ab9cc6 netfilter: nf_ct_... |
280 |
} |
7266507d8 netfilter: nf_ct_... |
281 |
} |
9fafcd7b2 [NETFILTER]: nf_c... |
282 283 |
return NF_ACCEPT; } |
9a6648210 netfilter: nf_nat... |
284 285 |
static void nf_nat_sip_seq_adjust(struct sk_buff *skb, unsigned int protoff, s16 off) |
48f8ac265 netfilter: nf_nat... |
286 287 288 289 290 291 292 |
{ enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); const struct tcphdr *th; if (nf_ct_protonum(ct) != IPPROTO_TCP || off == 0) return; |
9a6648210 netfilter: nf_nat... |
293 |
th = (struct tcphdr *)(skb->data + protoff); |
48f8ac265 netfilter: nf_nat... |
294 295 |
nf_nat_set_seq_adjust(ct, ctinfo, th->seq, off); } |
0f32a40fc [NETFILTER]: nf_c... |
296 |
/* Handles expected signalling connections and media streams */ |
9a6648210 netfilter: nf_nat... |
297 |
static void nf_nat_sip_expected(struct nf_conn *ct, |
0f32a40fc [NETFILTER]: nf_c... |
298 299 |
struct nf_conntrack_expect *exp) { |
c7232c997 netfilter: add pr... |
300 |
struct nf_nat_range range; |
0f32a40fc [NETFILTER]: nf_c... |
301 302 303 304 305 |
/* This must be a fresh one. */ BUG_ON(ct->status & IPS_NAT_DONE_MASK); /* For DST manip, map port here to where it's expected. */ |
cbc9f2f4f netfilter: nf_nat... |
306 |
range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED); |
c7232c997 netfilter: add pr... |
307 308 |
range.min_proto = range.max_proto = exp->saved_proto; range.min_addr = range.max_addr = exp->saved_addr; |
cbc9f2f4f netfilter: nf_nat... |
309 |
nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST); |
0f32a40fc [NETFILTER]: nf_c... |
310 311 312 |
/* Change src to where master sends to, but only if the connection * actually came from the same source. */ |
9a6648210 netfilter: nf_nat... |
313 314 |
if (nf_inet_addr_cmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3, &ct->master->tuplehash[exp->dir].tuple.src.u3)) { |
cbc9f2f4f netfilter: nf_nat... |
315 |
range.flags = NF_NAT_RANGE_MAP_IPS; |
c7232c997 netfilter: add pr... |
316 317 |
range.min_addr = range.max_addr = ct->master->tuplehash[!exp->dir].tuple.dst.u3; |
cbc9f2f4f netfilter: nf_nat... |
318 |
nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC); |
0f32a40fc [NETFILTER]: nf_c... |
319 320 |
} } |
9a6648210 netfilter: nf_nat... |
321 |
static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff, |
051966c0c netfilter: nf_nat... |
322 |
unsigned int dataoff, |
0f32a40fc [NETFILTER]: nf_c... |
323 324 325 326 327 328 329 330 |
const char **dptr, unsigned int *datalen, struct nf_conntrack_expect *exp, unsigned int matchoff, unsigned int matchlen) { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
7266507d8 netfilter: nf_ct_... |
331 |
struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct); |
9a6648210 netfilter: nf_nat... |
332 |
union nf_inet_addr newaddr; |
0f32a40fc [NETFILTER]: nf_c... |
333 |
u_int16_t port; |
7266507d8 netfilter: nf_ct_... |
334 |
__be16 srcport; |
9a6648210 netfilter: nf_nat... |
335 |
char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")]; |
95c961747 net: cleanup unsi... |
336 |
unsigned int buflen; |
0f32a40fc [NETFILTER]: nf_c... |
337 338 |
/* Connection will come from reply */ |
9a6648210 netfilter: nf_nat... |
339 340 341 |
if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, &ct->tuplehash[!dir].tuple.dst.u3)) newaddr = exp->tuple.dst.u3; |
0f32a40fc [NETFILTER]: nf_c... |
342 |
else |
9a6648210 netfilter: nf_nat... |
343 |
newaddr = ct->tuplehash[!dir].tuple.dst.u3; |
0f32a40fc [NETFILTER]: nf_c... |
344 345 346 347 |
/* If the signalling port matches the connection's source port in the * original direction, try to use the destination port in the opposite * direction. */ |
7266507d8 netfilter: nf_ct_... |
348 349 350 |
srcport = ct_sip_info->forced_dport ? : ct->tuplehash[dir].tuple.src.u.udp.port; if (exp->tuple.dst.u.udp.port == srcport) |
0f32a40fc [NETFILTER]: nf_c... |
351 352 353 |
port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port); else port = ntohs(exp->tuple.dst.u.udp.port); |
c7232c997 netfilter: add pr... |
354 |
exp->saved_addr = exp->tuple.dst.u3; |
9a6648210 netfilter: nf_nat... |
355 |
exp->tuple.dst.u3 = newaddr; |
0f32a40fc [NETFILTER]: nf_c... |
356 357 |
exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port; exp->dir = !dir; |
9a6648210 netfilter: nf_nat... |
358 |
exp->expectfn = nf_nat_sip_expected; |
0f32a40fc [NETFILTER]: nf_c... |
359 360 |
for (; port != 0; port++) { |
5b92b61f3 netfilter: nf_nat... |
361 |
int ret; |
0f32a40fc [NETFILTER]: nf_c... |
362 |
exp->tuple.dst.u.udp.port = htons(port); |
5b92b61f3 netfilter: nf_nat... |
363 364 365 366 367 |
ret = nf_ct_expect_related(exp); if (ret == 0) break; else if (ret != -EBUSY) { port = 0; |
0f32a40fc [NETFILTER]: nf_c... |
368 |
break; |
5b92b61f3 netfilter: nf_nat... |
369 |
} |
0f32a40fc [NETFILTER]: nf_c... |
370 |
} |
b20ab9cc6 netfilter: nf_ct_... |
371 372 |
if (port == 0) { nf_ct_helper_log(skb, ct, "all ports in use for SIP"); |
0f32a40fc [NETFILTER]: nf_c... |
373 |
return NF_DROP; |
b20ab9cc6 netfilter: nf_ct_... |
374 |
} |
0f32a40fc [NETFILTER]: nf_c... |
375 |
|
9a6648210 netfilter: nf_nat... |
376 |
if (!nf_inet_addr_cmp(&exp->tuple.dst.u3, &exp->saved_addr) || |
0f32a40fc [NETFILTER]: nf_c... |
377 |
exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) { |
9a6648210 netfilter: nf_nat... |
378 |
buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, port); |
051966c0c netfilter: nf_nat... |
379 |
if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, |
b20ab9cc6 netfilter: nf_ct_... |
380 381 |
matchoff, matchlen, buffer, buflen)) { nf_ct_helper_log(skb, ct, "cannot mangle packet"); |
0f32a40fc [NETFILTER]: nf_c... |
382 |
goto err; |
b20ab9cc6 netfilter: nf_ct_... |
383 |
} |
0f32a40fc [NETFILTER]: nf_c... |
384 385 386 387 388 389 390 |
} return NF_ACCEPT; err: nf_ct_unexpect_related(exp); return NF_DROP; } |
051966c0c netfilter: nf_nat... |
391 392 |
static int mangle_content_len(struct sk_buff *skb, unsigned int protoff, unsigned int dataoff, |
3e9b4600b [NETFILTER]: nf_c... |
393 |
const char **dptr, unsigned int *datalen) |
9fafcd7b2 [NETFILTER]: nf_c... |
394 |
{ |
212440a7d [NETFILTER]: nf_c... |
395 396 |
enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
3e9b4600b [NETFILTER]: nf_c... |
397 398 399 |
unsigned int matchoff, matchlen; char buffer[sizeof("65536")]; int buflen, c_len; |
9fafcd7b2 [NETFILTER]: nf_c... |
400 |
|
3e9b4600b [NETFILTER]: nf_c... |
401 402 403 404 405 406 407 408 |
/* Get actual SDP length */ if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, SDP_HDR_VERSION, SDP_HDR_UNSPEC, &matchoff, &matchlen) <= 0) return 0; c_len = *datalen - matchoff + strlen("v="); /* Now, update SDP length */ |
ea45f12a2 [NETFILTER]: nf_c... |
409 410 |
if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CONTENT_LENGTH, &matchoff, &matchlen) <= 0) |
9fafcd7b2 [NETFILTER]: nf_c... |
411 |
return 0; |
3e9b4600b [NETFILTER]: nf_c... |
412 |
buflen = sprintf(buffer, "%u", c_len); |
051966c0c netfilter: nf_nat... |
413 414 |
return mangle_packet(skb, protoff, dataoff, dptr, datalen, matchoff, matchlen, buffer, buflen); |
9fafcd7b2 [NETFILTER]: nf_c... |
415 |
} |
051966c0c netfilter: nf_nat... |
416 417 |
static int mangle_sdp_packet(struct sk_buff *skb, unsigned int protoff, unsigned int dataoff, |
3b6b9fab4 netfilter: nf_con... |
418 419 |
const char **dptr, unsigned int *datalen, unsigned int sdpoff, |
c71529e42 netfilter: nf_nat... |
420 421 422 |
enum sdp_header_types type, enum sdp_header_types term, char *buffer, int buflen) |
9fafcd7b2 [NETFILTER]: nf_c... |
423 |
{ |
212440a7d [NETFILTER]: nf_c... |
424 425 |
enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
3e9b4600b [NETFILTER]: nf_c... |
426 |
unsigned int matchlen, matchoff; |
9fafcd7b2 [NETFILTER]: nf_c... |
427 |
|
3b6b9fab4 netfilter: nf_con... |
428 |
if (ct_sip_get_sdp_header(ct, *dptr, sdpoff, *datalen, type, term, |
3e9b4600b [NETFILTER]: nf_c... |
429 |
&matchoff, &matchlen) <= 0) |
c71529e42 netfilter: nf_nat... |
430 |
return -ENOENT; |
051966c0c netfilter: nf_nat... |
431 432 |
return mangle_packet(skb, protoff, dataoff, dptr, datalen, matchoff, matchlen, buffer, buflen) ? 0 : -EINVAL; |
9fafcd7b2 [NETFILTER]: nf_c... |
433 |
} |
9a6648210 netfilter: nf_nat... |
434 |
static unsigned int nf_nat_sdp_addr(struct sk_buff *skb, unsigned int protoff, |
051966c0c netfilter: nf_nat... |
435 |
unsigned int dataoff, |
3b6b9fab4 netfilter: nf_con... |
436 437 |
const char **dptr, unsigned int *datalen, unsigned int sdpoff, |
4ab9e64e5 [NETFILTER]: nf_n... |
438 439 440 |
enum sdp_header_types type, enum sdp_header_types term, const union nf_inet_addr *addr) |
9fafcd7b2 [NETFILTER]: nf_c... |
441 |
{ |
9a6648210 netfilter: nf_nat... |
442 443 444 |
enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); char buffer[INET6_ADDRSTRLEN]; |
4ab9e64e5 [NETFILTER]: nf_n... |
445 |
unsigned int buflen; |
9fafcd7b2 [NETFILTER]: nf_c... |
446 |
|
9a6648210 netfilter: nf_nat... |
447 |
buflen = sip_sprintf_addr(ct, buffer, addr, false); |
051966c0c netfilter: nf_nat... |
448 449 |
if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff, type, term, buffer, buflen)) |
9fafcd7b2 [NETFILTER]: nf_c... |
450 |
return 0; |
051966c0c netfilter: nf_nat... |
451 |
return mangle_content_len(skb, protoff, dataoff, dptr, datalen); |
4ab9e64e5 [NETFILTER]: nf_n... |
452 |
} |
9a6648210 netfilter: nf_nat... |
453 |
static unsigned int nf_nat_sdp_port(struct sk_buff *skb, unsigned int protoff, |
051966c0c netfilter: nf_nat... |
454 |
unsigned int dataoff, |
3b6b9fab4 netfilter: nf_con... |
455 |
const char **dptr, unsigned int *datalen, |
4ab9e64e5 [NETFILTER]: nf_n... |
456 457 458 459 460 461 462 463 |
unsigned int matchoff, unsigned int matchlen, u_int16_t port) { char buffer[sizeof("nnnnn")]; unsigned int buflen; buflen = sprintf(buffer, "%u", port); |
051966c0c netfilter: nf_nat... |
464 465 |
if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, matchoff, matchlen, buffer, buflen)) |
9fafcd7b2 [NETFILTER]: nf_c... |
466 |
return 0; |
051966c0c netfilter: nf_nat... |
467 |
return mangle_content_len(skb, protoff, dataoff, dptr, datalen); |
4ab9e64e5 [NETFILTER]: nf_n... |
468 |
} |
9a6648210 netfilter: nf_nat... |
469 |
static unsigned int nf_nat_sdp_session(struct sk_buff *skb, unsigned int protoff, |
051966c0c netfilter: nf_nat... |
470 |
unsigned int dataoff, |
3b6b9fab4 netfilter: nf_con... |
471 472 |
const char **dptr, unsigned int *datalen, unsigned int sdpoff, |
4ab9e64e5 [NETFILTER]: nf_n... |
473 474 |
const union nf_inet_addr *addr) { |
9a6648210 netfilter: nf_nat... |
475 476 477 |
enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); char buffer[INET6_ADDRSTRLEN]; |
4ab9e64e5 [NETFILTER]: nf_n... |
478 479 480 |
unsigned int buflen; /* Mangle session description owner and contact addresses */ |
9a6648210 netfilter: nf_nat... |
481 |
buflen = sip_sprintf_addr(ct, buffer, addr, false); |
051966c0c netfilter: nf_nat... |
482 |
if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff, |
9a6648210 netfilter: nf_nat... |
483 |
SDP_HDR_OWNER, SDP_HDR_MEDIA, buffer, buflen)) |
4ab9e64e5 [NETFILTER]: nf_n... |
484 |
return 0; |
051966c0c netfilter: nf_nat... |
485 |
switch (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff, |
9a6648210 netfilter: nf_nat... |
486 |
SDP_HDR_CONNECTION, SDP_HDR_MEDIA, |
c71529e42 netfilter: nf_nat... |
487 488 489 490 491 492 493 494 495 496 497 498 |
buffer, buflen)) { case 0: /* * RFC 2327: * * Session description * * c=* (connection information - not required if included in all media) */ case -ENOENT: break; default: |
9fafcd7b2 [NETFILTER]: nf_c... |
499 |
return 0; |
c71529e42 netfilter: nf_nat... |
500 |
} |
9fafcd7b2 [NETFILTER]: nf_c... |
501 |
|
051966c0c netfilter: nf_nat... |
502 |
return mangle_content_len(skb, protoff, dataoff, dptr, datalen); |
9fafcd7b2 [NETFILTER]: nf_c... |
503 504 505 506 |
} /* So, this packet has hit the connection tracking matching code. Mangle it, and change the expectation to match the new version. */ |
9a6648210 netfilter: nf_nat... |
507 |
static unsigned int nf_nat_sdp_media(struct sk_buff *skb, unsigned int protoff, |
051966c0c netfilter: nf_nat... |
508 |
unsigned int dataoff, |
3b6b9fab4 netfilter: nf_con... |
509 |
const char **dptr, unsigned int *datalen, |
4ab9e64e5 [NETFILTER]: nf_n... |
510 511 512 513 514 |
struct nf_conntrack_expect *rtp_exp, struct nf_conntrack_expect *rtcp_exp, unsigned int mediaoff, unsigned int medialen, union nf_inet_addr *rtp_addr) |
9fafcd7b2 [NETFILTER]: nf_c... |
515 |
{ |
212440a7d [NETFILTER]: nf_c... |
516 517 |
enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
9fafcd7b2 [NETFILTER]: nf_c... |
518 |
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
9fafcd7b2 [NETFILTER]: nf_c... |
519 |
u_int16_t port; |
9fafcd7b2 [NETFILTER]: nf_c... |
520 |
/* Connection will come from reply */ |
9a6648210 netfilter: nf_nat... |
521 522 523 |
if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, &ct->tuplehash[!dir].tuple.dst.u3)) *rtp_addr = rtp_exp->tuple.dst.u3; |
f4a607bfa [NETFILTER]: nf_n... |
524 |
else |
9a6648210 netfilter: nf_nat... |
525 |
*rtp_addr = ct->tuplehash[!dir].tuple.dst.u3; |
9fafcd7b2 [NETFILTER]: nf_c... |
526 |
|
c7232c997 netfilter: add pr... |
527 |
rtp_exp->saved_addr = rtp_exp->tuple.dst.u3; |
9a6648210 netfilter: nf_nat... |
528 |
rtp_exp->tuple.dst.u3 = *rtp_addr; |
a9c1d3591 [NETFILTER]: nf_c... |
529 530 |
rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port; rtp_exp->dir = !dir; |
9a6648210 netfilter: nf_nat... |
531 |
rtp_exp->expectfn = nf_nat_sip_expected; |
a9c1d3591 [NETFILTER]: nf_c... |
532 |
|
c7232c997 netfilter: add pr... |
533 |
rtcp_exp->saved_addr = rtcp_exp->tuple.dst.u3; |
9a6648210 netfilter: nf_nat... |
534 |
rtcp_exp->tuple.dst.u3 = *rtp_addr; |
a9c1d3591 [NETFILTER]: nf_c... |
535 536 |
rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port; rtcp_exp->dir = !dir; |
9a6648210 netfilter: nf_nat... |
537 |
rtcp_exp->expectfn = nf_nat_sip_expected; |
a9c1d3591 [NETFILTER]: nf_c... |
538 539 540 541 |
/* Try to get same pair of ports: if not, try to change them. */ for (port = ntohs(rtp_exp->tuple.dst.u.udp.port); port != 0; port += 2) { |
5b92b61f3 netfilter: nf_nat... |
542 |
int ret; |
a9c1d3591 [NETFILTER]: nf_c... |
543 |
rtp_exp->tuple.dst.u.udp.port = htons(port); |
5b92b61f3 netfilter: nf_nat... |
544 545 |
ret = nf_ct_expect_related(rtp_exp); if (ret == -EBUSY) |
a9c1d3591 [NETFILTER]: nf_c... |
546 |
continue; |
5b92b61f3 netfilter: nf_nat... |
547 548 549 550 |
else if (ret < 0) { port = 0; break; } |
a9c1d3591 [NETFILTER]: nf_c... |
551 |
rtcp_exp->tuple.dst.u.udp.port = htons(port + 1); |
5b92b61f3 netfilter: nf_nat... |
552 553 |
ret = nf_ct_expect_related(rtcp_exp); if (ret == 0) |
9fafcd7b2 [NETFILTER]: nf_c... |
554 |
break; |
3f509c689 netfilter: nf_nat... |
555 556 557 558 |
else if (ret == -EBUSY) { nf_ct_unexpect_related(rtp_exp); continue; } else if (ret < 0) { |
5b92b61f3 netfilter: nf_nat... |
559 560 561 562 |
nf_ct_unexpect_related(rtp_exp); port = 0; break; } |
9fafcd7b2 [NETFILTER]: nf_c... |
563 |
} |
b20ab9cc6 netfilter: nf_ct_... |
564 565 |
if (port == 0) { nf_ct_helper_log(skb, ct, "all ports in use for SDP media"); |
4ab9e64e5 [NETFILTER]: nf_n... |
566 |
goto err1; |
b20ab9cc6 netfilter: nf_ct_... |
567 |
} |
4ab9e64e5 [NETFILTER]: nf_n... |
568 569 570 |
/* Update media port. */ if (rtp_exp->tuple.dst.u.udp.port != rtp_exp->saved_proto.udp.port && |
9a6648210 netfilter: nf_nat... |
571 |
!nf_nat_sdp_port(skb, protoff, dataoff, dptr, datalen, |
b20ab9cc6 netfilter: nf_ct_... |
572 573 |
mediaoff, medialen, port)) { nf_ct_helper_log(skb, ct, "cannot mangle SDP message"); |
4ab9e64e5 [NETFILTER]: nf_n... |
574 |
goto err2; |
b20ab9cc6 netfilter: nf_ct_... |
575 |
} |
9fafcd7b2 [NETFILTER]: nf_c... |
576 |
|
9fafcd7b2 [NETFILTER]: nf_c... |
577 |
return NF_ACCEPT; |
4ab9e64e5 [NETFILTER]: nf_n... |
578 579 580 581 582 583 |
err2: nf_ct_unexpect_related(rtp_exp); nf_ct_unexpect_related(rtcp_exp); err1: return NF_DROP; |
9fafcd7b2 [NETFILTER]: nf_c... |
584 |
} |
544d5c7d9 netfilter: ctnetl... |
585 |
static struct nf_ct_helper_expectfn sip_nat = { |
9a6648210 netfilter: nf_nat... |
586 587 |
.name = "sip", .expectfn = nf_nat_sip_expected, |
544d5c7d9 netfilter: ctnetl... |
588 |
}; |
9fafcd7b2 [NETFILTER]: nf_c... |
589 590 |
static void __exit nf_nat_sip_fini(void) { |
a9b3cd7f3 rcu: convert uses... |
591 592 593 594 595 596 597 |
RCU_INIT_POINTER(nf_nat_sip_hook, NULL); RCU_INIT_POINTER(nf_nat_sip_seq_adjust_hook, NULL); RCU_INIT_POINTER(nf_nat_sip_expect_hook, NULL); RCU_INIT_POINTER(nf_nat_sdp_addr_hook, NULL); RCU_INIT_POINTER(nf_nat_sdp_port_hook, NULL); RCU_INIT_POINTER(nf_nat_sdp_session_hook, NULL); RCU_INIT_POINTER(nf_nat_sdp_media_hook, NULL); |
544d5c7d9 netfilter: ctnetl... |
598 |
nf_ct_helper_expectfn_unregister(&sip_nat); |
9fafcd7b2 [NETFILTER]: nf_c... |
599 600 601 602 603 |
synchronize_rcu(); } static int __init nf_nat_sip_init(void) { |
d1332e0ab [NETFILTER]: remo... |
604 |
BUG_ON(nf_nat_sip_hook != NULL); |
48f8ac265 netfilter: nf_nat... |
605 |
BUG_ON(nf_nat_sip_seq_adjust_hook != NULL); |
0f32a40fc [NETFILTER]: nf_c... |
606 |
BUG_ON(nf_nat_sip_expect_hook != NULL); |
4ab9e64e5 [NETFILTER]: nf_n... |
607 |
BUG_ON(nf_nat_sdp_addr_hook != NULL); |
c7f485abd [NETFILTER]: nf_c... |
608 |
BUG_ON(nf_nat_sdp_port_hook != NULL); |
4ab9e64e5 [NETFILTER]: nf_n... |
609 610 |
BUG_ON(nf_nat_sdp_session_hook != NULL); BUG_ON(nf_nat_sdp_media_hook != NULL); |
9a6648210 netfilter: nf_nat... |
611 612 613 614 615 616 617 |
RCU_INIT_POINTER(nf_nat_sip_hook, nf_nat_sip); RCU_INIT_POINTER(nf_nat_sip_seq_adjust_hook, nf_nat_sip_seq_adjust); RCU_INIT_POINTER(nf_nat_sip_expect_hook, nf_nat_sip_expect); RCU_INIT_POINTER(nf_nat_sdp_addr_hook, nf_nat_sdp_addr); RCU_INIT_POINTER(nf_nat_sdp_port_hook, nf_nat_sdp_port); RCU_INIT_POINTER(nf_nat_sdp_session_hook, nf_nat_sdp_session); RCU_INIT_POINTER(nf_nat_sdp_media_hook, nf_nat_sdp_media); |
544d5c7d9 netfilter: ctnetl... |
618 |
nf_ct_helper_expectfn_register(&sip_nat); |
9fafcd7b2 [NETFILTER]: nf_c... |
619 620 621 622 623 |
return 0; } module_init(nf_nat_sip_init); module_exit(nf_nat_sip_fini); |