blob: f73ab4883b753d752543f23d6ee8788d5f18e4c1 [file] [log] [blame]
Patrick McHardy9fafcd72006-12-02 22:09:57 -08001/* SIP extension for UDP NAT alteration.
2 *
3 * (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar>
4 * based on RR's ip_nat_ftp.c and other modules.
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/ip.h>
Arnaldo Carvalho de Meloc9bdd4b2007-03-12 20:09:15 -030014#include <net/ip.h>
Patrick McHardy9fafcd72006-12-02 22:09:57 -080015#include <linux/udp.h>
16
17#include <net/netfilter/nf_nat.h>
18#include <net/netfilter/nf_nat_helper.h>
19#include <net/netfilter/nf_nat_rule.h>
20#include <net/netfilter/nf_conntrack_helper.h>
21#include <net/netfilter/nf_conntrack_expect.h>
22#include <linux/netfilter/nf_conntrack_sip.h>
23
24MODULE_LICENSE("GPL");
25MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
26MODULE_DESCRIPTION("SIP NAT helper");
27MODULE_ALIAS("ip_nat_sip");
28
Patrick McHardy9fafcd72006-12-02 22:09:57 -080029
Patrick McHardy2a6cfb22008-03-25 20:16:54 -070030static unsigned int mangle_packet(struct sk_buff *skb,
31 const char **dptr, unsigned int *datalen,
32 unsigned int matchoff, unsigned int matchlen,
33 const char *buffer, unsigned int buflen)
34{
35 enum ip_conntrack_info ctinfo;
36 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
37
38 if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, matchoff, matchlen,
39 buffer, buflen))
40 return 0;
41
42 /* Reload data pointer and adjust datalen value */
43 *dptr = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr);
44 *datalen += buflen - matchlen;
45 return 1;
46}
47
Patrick McHardyac367742008-03-25 20:18:40 -070048static int map_addr(struct sk_buff *skb,
49 const char **dptr, unsigned int *datalen,
50 unsigned int matchoff, unsigned int matchlen,
Patrick McHardy624f8b72008-03-25 20:19:30 -070051 union nf_inet_addr *addr, __be16 port)
Patrick McHardy9fafcd72006-12-02 22:09:57 -080052{
Patrick McHardy212440a2008-03-25 20:17:13 -070053 enum ip_conntrack_info ctinfo;
Patrick McHardy624f8b72008-03-25 20:19:30 -070054 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
Patrick McHardy9fafcd72006-12-02 22:09:57 -080055 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
Patrick McHardy624f8b72008-03-25 20:19:30 -070056 char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
57 unsigned int buflen;
58 __be32 newaddr;
59 __be16 newport;
Patrick McHardy9fafcd72006-12-02 22:09:57 -080060
Patrick McHardy624f8b72008-03-25 20:19:30 -070061 if (ct->tuplehash[dir].tuple.src.u3.ip == addr->ip &&
62 ct->tuplehash[dir].tuple.src.u.udp.port == port) {
63 newaddr = ct->tuplehash[!dir].tuple.dst.u3.ip;
64 newport = ct->tuplehash[!dir].tuple.dst.u.udp.port;
65 } else if (ct->tuplehash[dir].tuple.dst.u3.ip == addr->ip &&
66 ct->tuplehash[dir].tuple.dst.u.udp.port == port) {
67 newaddr = ct->tuplehash[!dir].tuple.src.u3.ip;
68 newport = ct->tuplehash[!dir].tuple.src.u.udp.port;
Patrick McHardy9fafcd72006-12-02 22:09:57 -080069 } else
70 return 1;
71
Patrick McHardy624f8b72008-03-25 20:19:30 -070072 if (newaddr == addr->ip && newport == port)
73 return 1;
74
75 buflen = sprintf(buffer, "%u.%u.%u.%u:%u",
76 NIPQUAD(newaddr), ntohs(newport));
77
Patrick McHardy2a6cfb22008-03-25 20:16:54 -070078 return mangle_packet(skb, dptr, datalen, matchoff, matchlen,
Patrick McHardy624f8b72008-03-25 20:19:30 -070079 buffer, buflen);
Patrick McHardy9fafcd72006-12-02 22:09:57 -080080}
81
Patrick McHardyac367742008-03-25 20:18:40 -070082static int map_sip_addr(struct sk_buff *skb,
83 const char **dptr, unsigned int *datalen,
Patrick McHardy624f8b72008-03-25 20:19:30 -070084 enum sip_header_types type)
Patrick McHardyac367742008-03-25 20:18:40 -070085{
86 enum ip_conntrack_info ctinfo;
87 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
88 unsigned int matchlen, matchoff;
Patrick McHardy624f8b72008-03-25 20:19:30 -070089 union nf_inet_addr addr;
90 __be16 port;
Patrick McHardyac367742008-03-25 20:18:40 -070091
Patrick McHardy624f8b72008-03-25 20:19:30 -070092 if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, type, NULL,
93 &matchoff, &matchlen, &addr, &port) <= 0)
Patrick McHardyac367742008-03-25 20:18:40 -070094 return 1;
Patrick McHardy624f8b72008-03-25 20:19:30 -070095 return map_addr(skb, dptr, datalen, matchoff, matchlen, &addr, port);
Patrick McHardyac367742008-03-25 20:18:40 -070096}
97
Herbert Xu3db05fe2007-10-15 00:53:15 -070098static unsigned int ip_nat_sip(struct sk_buff *skb,
Patrick McHardy2a6cfb22008-03-25 20:16:54 -070099 const char **dptr, unsigned int *datalen)
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800100{
Patrick McHardy212440a2008-03-25 20:17:13 -0700101 enum ip_conntrack_info ctinfo;
102 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
Patrick McHardy720ac702008-03-25 20:24:41 -0700103 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
Patrick McHardyc978cd32008-03-25 20:24:57 -0700104 unsigned int dataoff, matchoff, matchlen;
Patrick McHardy624f8b72008-03-25 20:19:30 -0700105 union nf_inet_addr addr;
106 __be16 port;
Patrick McHardyc978cd32008-03-25 20:24:57 -0700107 int request, in_header;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800108
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800109 /* Basic rules: requests and responses. */
Patrick McHardy779382e2008-03-25 20:17:36 -0700110 if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) {
Patrick McHardyac367742008-03-25 20:18:40 -0700111 if (ct_sip_parse_request(ct, *dptr, *datalen,
Patrick McHardy624f8b72008-03-25 20:19:30 -0700112 &matchoff, &matchlen,
113 &addr, &port) > 0 &&
114 !map_addr(skb, dptr, datalen, matchoff, matchlen,
115 &addr, port))
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800116 return NF_DROP;
Patrick McHardy720ac702008-03-25 20:24:41 -0700117 request = 1;
118 } else
119 request = 0;
120
121 /* Translate topmost Via header and parameters */
122 if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
123 SIP_HDR_VIA, NULL, &matchoff, &matchlen,
124 &addr, &port) > 0) {
125 unsigned int matchend, poff, plen, buflen, n;
126 char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
127
128 /* We're only interested in headers related to this
129 * connection */
130 if (request) {
131 if (addr.ip != ct->tuplehash[dir].tuple.src.u3.ip ||
132 port != ct->tuplehash[dir].tuple.src.u.udp.port)
133 goto next;
134 } else {
135 if (addr.ip != ct->tuplehash[dir].tuple.dst.u3.ip ||
136 port != ct->tuplehash[dir].tuple.dst.u.udp.port)
137 goto next;
138 }
139
140 if (!map_addr(skb, dptr, datalen, matchoff, matchlen,
141 &addr, port))
142 return NF_DROP;
143
144 matchend = matchoff + matchlen;
145
146 /* The maddr= parameter (RFC 2361) specifies where to send
147 * the reply. */
148 if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
149 "maddr=", &poff, &plen,
150 &addr) > 0 &&
151 addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
152 addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) {
153 __be32 ip = ct->tuplehash[!dir].tuple.dst.u3.ip;
154 buflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(ip));
155 if (!mangle_packet(skb, dptr, datalen, poff, plen,
156 buffer, buflen))
157 return NF_DROP;
158 }
159
160 /* The received= parameter (RFC 2361) contains the address
161 * from which the server received the request. */
162 if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
163 "received=", &poff, &plen,
164 &addr) > 0 &&
165 addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
166 addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) {
167 __be32 ip = ct->tuplehash[!dir].tuple.src.u3.ip;
168 buflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(ip));
169 if (!mangle_packet(skb, dptr, datalen, poff, plen,
170 buffer, buflen))
171 return NF_DROP;
172 }
173
174 /* The rport= parameter (RFC 3581) contains the port number
175 * from which the server received the request. */
176 if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen,
177 "rport=", &poff, &plen,
178 &n) > 0 &&
179 htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port &&
180 htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) {
181 __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port;
182 buflen = sprintf(buffer, "%u", ntohs(p));
183 if (!mangle_packet(skb, dptr, datalen, poff, plen,
184 buffer, buflen))
185 return NF_DROP;
186 }
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800187 }
188
Patrick McHardy720ac702008-03-25 20:24:41 -0700189next:
Patrick McHardyc978cd32008-03-25 20:24:57 -0700190 /* Translate Contact headers */
191 dataoff = 0;
192 in_header = 0;
193 while (ct_sip_parse_header_uri(ct, *dptr, &dataoff, *datalen,
194 SIP_HDR_CONTACT, &in_header,
195 &matchoff, &matchlen,
196 &addr, &port) > 0) {
197 if (!map_addr(skb, dptr, datalen, matchoff, matchlen,
198 &addr, port))
199 return NF_DROP;
200 }
201
Patrick McHardy624f8b72008-03-25 20:19:30 -0700202 if (!map_sip_addr(skb, dptr, datalen, SIP_HDR_FROM) ||
Patrick McHardyc978cd32008-03-25 20:24:57 -0700203 !map_sip_addr(skb, dptr, datalen, SIP_HDR_TO))
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800204 return NF_DROP;
205 return NF_ACCEPT;
206}
207
Patrick McHardy0f32a402008-03-25 20:25:13 -0700208/* Handles expected signalling connections and media streams */
209static void ip_nat_sip_expected(struct nf_conn *ct,
210 struct nf_conntrack_expect *exp)
211{
212 struct nf_nat_range range;
213
214 /* This must be a fresh one. */
215 BUG_ON(ct->status & IPS_NAT_DONE_MASK);
216
217 /* For DST manip, map port here to where it's expected. */
218 range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED);
219 range.min = range.max = exp->saved_proto;
220 range.min_ip = range.max_ip = exp->saved_ip;
221 nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST);
222
223 /* Change src to where master sends to, but only if the connection
224 * actually came from the same source. */
225 if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip ==
226 ct->master->tuplehash[exp->dir].tuple.src.u3.ip) {
227 range.flags = IP_NAT_RANGE_MAP_IPS;
228 range.min_ip = range.max_ip
229 = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip;
230 nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC);
231 }
232}
233
234static unsigned int ip_nat_sip_expect(struct sk_buff *skb,
235 const char **dptr, unsigned int *datalen,
236 struct nf_conntrack_expect *exp,
237 unsigned int matchoff,
238 unsigned int matchlen)
239{
240 enum ip_conntrack_info ctinfo;
241 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
242 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
243 __be32 newip;
244 u_int16_t port;
245 char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
246 unsigned buflen;
247
248 /* Connection will come from reply */
249 if (ct->tuplehash[dir].tuple.src.u3.ip == ct->tuplehash[!dir].tuple.dst.u3.ip)
250 newip = exp->tuple.dst.u3.ip;
251 else
252 newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
253
254 /* If the signalling port matches the connection's source port in the
255 * original direction, try to use the destination port in the opposite
256 * direction. */
257 if (exp->tuple.dst.u.udp.port ==
258 ct->tuplehash[dir].tuple.src.u.udp.port)
259 port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port);
260 else
261 port = ntohs(exp->tuple.dst.u.udp.port);
262
263 exp->saved_ip = exp->tuple.dst.u3.ip;
264 exp->tuple.dst.u3.ip = newip;
265 exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
266 exp->dir = !dir;
267 exp->expectfn = ip_nat_sip_expected;
268
269 for (; port != 0; port++) {
270 exp->tuple.dst.u.udp.port = htons(port);
271 if (nf_ct_expect_related(exp) == 0)
272 break;
273 }
274
275 if (port == 0)
276 return NF_DROP;
277
278 if (exp->tuple.dst.u3.ip != exp->saved_ip ||
279 exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) {
280 buflen = sprintf(buffer, "%u.%u.%u.%u:%u",
281 NIPQUAD(newip), port);
282 if (!mangle_packet(skb, dptr, datalen, matchoff, matchlen,
283 buffer, buflen))
284 goto err;
285 }
286 return NF_ACCEPT;
287
288err:
289 nf_ct_unexpect_related(exp);
290 return NF_DROP;
291}
292
Herbert Xu3db05fe2007-10-15 00:53:15 -0700293static int mangle_content_len(struct sk_buff *skb,
Patrick McHardy2a6cfb22008-03-25 20:16:54 -0700294 const char **dptr, unsigned int *datalen)
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800295{
Patrick McHardy212440a2008-03-25 20:17:13 -0700296 enum ip_conntrack_info ctinfo;
297 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
Patrick McHardy2a6cfb22008-03-25 20:16:54 -0700298 unsigned int matchoff, matchlen;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800299 char buffer[sizeof("65536")];
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700300 int buflen, c_len;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800301
Joe Perchese00ccd42007-12-20 14:05:03 -0800302 /* Get actual SDP length */
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700303 if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen,
304 SDP_HDR_VERSION, SDP_HDR_UNSPEC,
305 &matchoff, &matchlen) <= 0)
306 return 0;
307 c_len = *datalen - matchoff + strlen("v=");
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800308
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700309 /* Now, update SDP length */
Patrick McHardyea45f122008-03-25 20:18:57 -0700310 if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CONTENT_LENGTH,
311 &matchoff, &matchlen) <= 0)
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700312 return 0;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800313
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700314 buflen = sprintf(buffer, "%u", c_len);
315 return mangle_packet(skb, dptr, datalen, matchoff, matchlen,
316 buffer, buflen);
317}
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800318
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700319static unsigned mangle_sdp_packet(struct sk_buff *skb,
320 const char **dptr, unsigned int *datalen,
321 enum sdp_header_types type,
322 char *buffer, int buflen)
323{
324 enum ip_conntrack_info ctinfo;
325 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
326 unsigned int matchlen, matchoff;
327
328 if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, type, SDP_HDR_UNSPEC,
329 &matchoff, &matchlen) <= 0)
330 return 0;
331 return mangle_packet(skb, dptr, datalen, matchoff, matchlen,
332 buffer, buflen);
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800333}
334
Herbert Xu3db05fe2007-10-15 00:53:15 -0700335static unsigned int mangle_sdp(struct sk_buff *skb,
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800336 enum ip_conntrack_info ctinfo,
337 struct nf_conn *ct,
338 __be32 newip, u_int16_t port,
Patrick McHardy2a6cfb22008-03-25 20:16:54 -0700339 const char **dptr, unsigned int *datalen)
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800340{
341 char buffer[sizeof("nnn.nnn.nnn.nnn")];
Patrick McHardy2a6cfb22008-03-25 20:16:54 -0700342 unsigned int bufflen;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800343
344 /* Mangle owner and contact info. */
345 bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700346 if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_OWNER_IP4,
347 buffer, bufflen))
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800348 return 0;
349
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700350 if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_CONNECTION_IP4,
351 buffer, bufflen))
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800352 return 0;
353
354 /* Mangle media port. */
355 bufflen = sprintf(buffer, "%u", port);
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700356 if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_MEDIA,
357 buffer, bufflen))
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800358 return 0;
359
Patrick McHardy212440a2008-03-25 20:17:13 -0700360 return mangle_content_len(skb, dptr, datalen);
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800361}
362
363/* So, this packet has hit the connection tracking matching code.
364 Mangle it, and change the expectation to match the new version. */
Herbert Xu3db05fe2007-10-15 00:53:15 -0700365static unsigned int ip_nat_sdp(struct sk_buff *skb,
Patrick McHardy212440a2008-03-25 20:17:13 -0700366 const char **dptr, unsigned int *datalen,
Patrick McHardya9c1d352008-03-25 20:25:49 -0700367 struct nf_conntrack_expect *rtp_exp,
368 struct nf_conntrack_expect *rtcp_exp)
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800369{
Patrick McHardy212440a2008-03-25 20:17:13 -0700370 enum ip_conntrack_info ctinfo;
371 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800372 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
373 __be32 newip;
374 u_int16_t port;
375
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800376 /* Connection will come from reply */
Jerome Borsboomf4a607b2007-07-07 22:19:48 -0700377 if (ct->tuplehash[dir].tuple.src.u3.ip ==
378 ct->tuplehash[!dir].tuple.dst.u3.ip)
Patrick McHardya9c1d352008-03-25 20:25:49 -0700379 newip = rtp_exp->tuple.dst.u3.ip;
Jerome Borsboomf4a607b2007-07-07 22:19:48 -0700380 else
381 newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800382
Patrick McHardya9c1d352008-03-25 20:25:49 -0700383 rtp_exp->saved_ip = rtp_exp->tuple.dst.u3.ip;
384 rtp_exp->tuple.dst.u3.ip = newip;
385 rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
386 rtp_exp->dir = !dir;
387 rtp_exp->expectfn = ip_nat_sip_expected;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800388
Patrick McHardya9c1d352008-03-25 20:25:49 -0700389 rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip;
390 rtcp_exp->tuple.dst.u3.ip = newip;
391 rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
392 rtcp_exp->dir = !dir;
393 rtcp_exp->expectfn = ip_nat_sip_expected;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800394
Patrick McHardya9c1d352008-03-25 20:25:49 -0700395 /* Try to get same pair of ports: if not, try to change them. */
396 for (port = ntohs(rtp_exp->tuple.dst.u.udp.port);
397 port != 0; port += 2) {
398 rtp_exp->tuple.dst.u.udp.port = htons(port);
399 if (nf_ct_expect_related(rtp_exp) != 0)
400 continue;
401 rtcp_exp->tuple.dst.u.udp.port = htons(port + 1);
402 if (nf_ct_expect_related(rtcp_exp) == 0)
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800403 break;
Patrick McHardya9c1d352008-03-25 20:25:49 -0700404 nf_ct_unexpect_related(rtp_exp);
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800405 }
406
407 if (port == 0)
408 return NF_DROP;
409
Patrick McHardy2a6cfb22008-03-25 20:16:54 -0700410 if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr, datalen)) {
Patrick McHardya9c1d352008-03-25 20:25:49 -0700411 nf_ct_unexpect_related(rtp_exp);
412 nf_ct_unexpect_related(rtcp_exp);
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800413 return NF_DROP;
414 }
415 return NF_ACCEPT;
416}
417
418static void __exit nf_nat_sip_fini(void)
419{
420 rcu_assign_pointer(nf_nat_sip_hook, NULL);
Patrick McHardy0f32a402008-03-25 20:25:13 -0700421 rcu_assign_pointer(nf_nat_sip_expect_hook, NULL);
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800422 rcu_assign_pointer(nf_nat_sdp_hook, NULL);
423 synchronize_rcu();
424}
425
426static int __init nf_nat_sip_init(void)
427{
Patrick McHardyd1332e02007-11-05 20:43:30 -0800428 BUG_ON(nf_nat_sip_hook != NULL);
Patrick McHardy0f32a402008-03-25 20:25:13 -0700429 BUG_ON(nf_nat_sip_expect_hook != NULL);
Patrick McHardyd1332e02007-11-05 20:43:30 -0800430 BUG_ON(nf_nat_sdp_hook != NULL);
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800431 rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip);
Patrick McHardy0f32a402008-03-25 20:25:13 -0700432 rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect);
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800433 rcu_assign_pointer(nf_nat_sdp_hook, ip_nat_sdp);
434 return 0;
435}
436
437module_init(nf_nat_sip_init);
438module_exit(nf_nat_sip_fini);