blob: dac11f73868e50df4e20add9e754d55629716f25 [file] [log] [blame]
Patrick McHardy48f8ac22010-02-11 12:29:38 +01001/* SIP extension for NAT alteration.
Patrick McHardy9fafcd72006-12-02 22:09:57 -08002 *
3 * (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar>
4 * based on RR's ip_nat_ftp.c and other modules.
Patrick McHardyf49e1aa2008-03-25 20:27:05 -07005 * (C) 2007 United Security Providers
Patrick McHardy9a664822012-08-26 19:14:25 +02006 * (C) 2007, 2008, 2011, 2012 Patrick McHardy <kaber@trash.net>
Patrick McHardy9fafcd72006-12-02 22:09:57 -08007 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/module.h>
14#include <linux/skbuff.h>
Patrick McHardy9a664822012-08-26 19:14:25 +020015#include <linux/inet.h>
Patrick McHardy9fafcd72006-12-02 22:09:57 -080016#include <linux/udp.h>
Patrick McHardy48f8ac22010-02-11 12:29:38 +010017#include <linux/tcp.h>
Patrick McHardy9fafcd72006-12-02 22:09:57 -080018
19#include <net/netfilter/nf_nat.h>
20#include <net/netfilter/nf_nat_helper.h>
Patrick McHardy9fafcd72006-12-02 22:09:57 -080021#include <net/netfilter/nf_conntrack_helper.h>
22#include <net/netfilter/nf_conntrack_expect.h>
23#include <linux/netfilter/nf_conntrack_sip.h>
24
25MODULE_LICENSE("GPL");
26MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
27MODULE_DESCRIPTION("SIP NAT helper");
28MODULE_ALIAS("ip_nat_sip");
29
Patrick McHardy9fafcd72006-12-02 22:09:57 -080030
Patrick McHardy051966c2012-08-26 19:14:04 +020031static unsigned int mangle_packet(struct sk_buff *skb, unsigned int protoff,
32 unsigned int dataoff,
Patrick McHardy2a6cfb22008-03-25 20:16:54 -070033 const char **dptr, unsigned int *datalen,
34 unsigned int matchoff, unsigned int matchlen,
35 const char *buffer, unsigned int buflen)
36{
37 enum ip_conntrack_info ctinfo;
38 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
Patrick McHardy48f8ac22010-02-11 12:29:38 +010039 struct tcphdr *th;
40 unsigned int baseoff;
Patrick McHardy2a6cfb22008-03-25 20:16:54 -070041
Patrick McHardy48f8ac22010-02-11 12:29:38 +010042 if (nf_ct_protonum(ct) == IPPROTO_TCP) {
Patrick McHardy9a664822012-08-26 19:14:25 +020043 th = (struct tcphdr *)(skb->data + protoff);
44 baseoff = protoff + th->doff * 4;
Patrick McHardy48f8ac22010-02-11 12:29:38 +010045 matchoff += dataoff - baseoff;
46
47 if (!__nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
Patrick McHardy051966c2012-08-26 19:14:04 +020048 protoff, matchoff, matchlen,
Patrick McHardy48f8ac22010-02-11 12:29:38 +010049 buffer, buflen, false))
50 return 0;
51 } else {
Patrick McHardy9a664822012-08-26 19:14:25 +020052 baseoff = protoff + sizeof(struct udphdr);
Patrick McHardy48f8ac22010-02-11 12:29:38 +010053 matchoff += dataoff - baseoff;
54
55 if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo,
Patrick McHardy051966c2012-08-26 19:14:04 +020056 protoff, matchoff, matchlen,
Patrick McHardy48f8ac22010-02-11 12:29:38 +010057 buffer, buflen))
58 return 0;
59 }
Patrick McHardy2a6cfb22008-03-25 20:16:54 -070060
61 /* Reload data pointer and adjust datalen value */
Patrick McHardy3b6b9fa2010-02-11 12:23:53 +010062 *dptr = skb->data + dataoff;
Patrick McHardy2a6cfb22008-03-25 20:16:54 -070063 *datalen += buflen - matchlen;
64 return 1;
65}
66
Patrick McHardy9a664822012-08-26 19:14:25 +020067static int sip_sprintf_addr(const struct nf_conn *ct, char *buffer,
68 const union nf_inet_addr *addr, bool delim)
69{
70 if (nf_ct_l3num(ct) == NFPROTO_IPV4)
71 return sprintf(buffer, "%pI4", &addr->ip);
72 else {
73 if (delim)
74 return sprintf(buffer, "[%pI6c]", &addr->ip6);
75 else
76 return sprintf(buffer, "%pI6c", &addr->ip6);
77 }
78}
79
80static int sip_sprintf_addr_port(const struct nf_conn *ct, char *buffer,
81 const union nf_inet_addr *addr, u16 port)
82{
83 if (nf_ct_l3num(ct) == NFPROTO_IPV4)
84 return sprintf(buffer, "%pI4:%u", &addr->ip, port);
85 else
86 return sprintf(buffer, "[%pI6c]:%u", &addr->ip6, port);
87}
88
Patrick McHardy051966c2012-08-26 19:14:04 +020089static int map_addr(struct sk_buff *skb, unsigned int protoff,
90 unsigned int dataoff,
Patrick McHardyac367742008-03-25 20:18:40 -070091 const char **dptr, unsigned int *datalen,
92 unsigned int matchoff, unsigned int matchlen,
Patrick McHardy624f8b72008-03-25 20:19:30 -070093 union nf_inet_addr *addr, __be16 port)
Patrick McHardy9fafcd72006-12-02 22:09:57 -080094{
Patrick McHardy212440a2008-03-25 20:17:13 -070095 enum ip_conntrack_info ctinfo;
Patrick McHardy624f8b72008-03-25 20:19:30 -070096 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
Patrick McHardy9fafcd72006-12-02 22:09:57 -080097 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
Kevin Cernekee72665072012-12-17 18:33:58 +000098 struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
Patrick McHardy9a664822012-08-26 19:14:25 +020099 char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")];
Patrick McHardy624f8b72008-03-25 20:19:30 -0700100 unsigned int buflen;
Patrick McHardy9a664822012-08-26 19:14:25 +0200101 union nf_inet_addr newaddr;
Patrick McHardy624f8b72008-03-25 20:19:30 -0700102 __be16 newport;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800103
Patrick McHardy9a664822012-08-26 19:14:25 +0200104 if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, addr) &&
Patrick McHardy624f8b72008-03-25 20:19:30 -0700105 ct->tuplehash[dir].tuple.src.u.udp.port == port) {
Patrick McHardy9a664822012-08-26 19:14:25 +0200106 newaddr = ct->tuplehash[!dir].tuple.dst.u3;
Patrick McHardy624f8b72008-03-25 20:19:30 -0700107 newport = ct->tuplehash[!dir].tuple.dst.u.udp.port;
Patrick McHardy9a664822012-08-26 19:14:25 +0200108 } else if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, addr) &&
Patrick McHardy624f8b72008-03-25 20:19:30 -0700109 ct->tuplehash[dir].tuple.dst.u.udp.port == port) {
Patrick McHardy9a664822012-08-26 19:14:25 +0200110 newaddr = ct->tuplehash[!dir].tuple.src.u3;
Kevin Cernekee72665072012-12-17 18:33:58 +0000111 newport = ct_sip_info->forced_dport ? :
112 ct->tuplehash[!dir].tuple.src.u.udp.port;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800113 } else
114 return 1;
115
Patrick McHardy9a664822012-08-26 19:14:25 +0200116 if (nf_inet_addr_cmp(&newaddr, addr) && newport == port)
Patrick McHardy624f8b72008-03-25 20:19:30 -0700117 return 1;
118
Patrick McHardy9a664822012-08-26 19:14:25 +0200119 buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, ntohs(newport));
Patrick McHardy051966c2012-08-26 19:14:04 +0200120 return mangle_packet(skb, protoff, dataoff, dptr, datalen,
121 matchoff, matchlen, buffer, buflen);
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800122}
123
Patrick McHardy051966c2012-08-26 19:14:04 +0200124static int map_sip_addr(struct sk_buff *skb, unsigned int protoff,
125 unsigned int dataoff,
Patrick McHardyac367742008-03-25 20:18:40 -0700126 const char **dptr, unsigned int *datalen,
Patrick McHardy624f8b72008-03-25 20:19:30 -0700127 enum sip_header_types type)
Patrick McHardyac367742008-03-25 20:18:40 -0700128{
129 enum ip_conntrack_info ctinfo;
130 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
131 unsigned int matchlen, matchoff;
Patrick McHardy624f8b72008-03-25 20:19:30 -0700132 union nf_inet_addr addr;
133 __be16 port;
Patrick McHardyac367742008-03-25 20:18:40 -0700134
Patrick McHardy624f8b72008-03-25 20:19:30 -0700135 if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, type, NULL,
136 &matchoff, &matchlen, &addr, &port) <= 0)
Patrick McHardyac367742008-03-25 20:18:40 -0700137 return 1;
Patrick McHardy051966c2012-08-26 19:14:04 +0200138 return map_addr(skb, protoff, dataoff, dptr, datalen,
139 matchoff, matchlen, &addr, port);
Patrick McHardyac367742008-03-25 20:18:40 -0700140}
141
Patrick McHardy9a664822012-08-26 19:14:25 +0200142static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,
Patrick McHardy051966c2012-08-26 19:14:04 +0200143 unsigned int dataoff,
Patrick McHardy2a6cfb22008-03-25 20:16:54 -0700144 const char **dptr, unsigned int *datalen)
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800145{
Patrick McHardy212440a2008-03-25 20:17:13 -0700146 enum ip_conntrack_info ctinfo;
147 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
Patrick McHardy720ac702008-03-25 20:24:41 -0700148 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
Kevin Cernekee72665072012-12-17 18:33:58 +0000149 struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
Patrick McHardy3b6b9fa2010-02-11 12:23:53 +0100150 unsigned int coff, matchoff, matchlen;
Patrick McHardy48f8ac22010-02-11 12:29:38 +0100151 enum sip_header_types hdr;
Patrick McHardy624f8b72008-03-25 20:19:30 -0700152 union nf_inet_addr addr;
153 __be16 port;
Patrick McHardyc978cd32008-03-25 20:24:57 -0700154 int request, in_header;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800155
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800156 /* Basic rules: requests and responses. */
Patrick McHardy779382e2008-03-25 20:17:36 -0700157 if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) {
Patrick McHardyac367742008-03-25 20:18:40 -0700158 if (ct_sip_parse_request(ct, *dptr, *datalen,
Patrick McHardy624f8b72008-03-25 20:19:30 -0700159 &matchoff, &matchlen,
160 &addr, &port) > 0 &&
Patrick McHardy051966c2012-08-26 19:14:04 +0200161 !map_addr(skb, protoff, dataoff, dptr, datalen,
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100162 matchoff, matchlen, &addr, port)) {
163 nf_ct_helper_log(skb, ct, "cannot mangle SIP message");
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800164 return NF_DROP;
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100165 }
Patrick McHardy720ac702008-03-25 20:24:41 -0700166 request = 1;
167 } else
168 request = 0;
169
Patrick McHardy48f8ac22010-02-11 12:29:38 +0100170 if (nf_ct_protonum(ct) == IPPROTO_TCP)
171 hdr = SIP_HDR_VIA_TCP;
172 else
173 hdr = SIP_HDR_VIA_UDP;
174
Patrick McHardy720ac702008-03-25 20:24:41 -0700175 /* Translate topmost Via header and parameters */
176 if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
Patrick McHardy48f8ac22010-02-11 12:29:38 +0100177 hdr, NULL, &matchoff, &matchlen,
Patrick McHardy720ac702008-03-25 20:24:41 -0700178 &addr, &port) > 0) {
Patrick McHardyf22eb252012-08-09 10:08:47 +0000179 unsigned int olen, matchend, poff, plen, buflen, n;
Patrick McHardy9a664822012-08-26 19:14:25 +0200180 char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")];
Patrick McHardy720ac702008-03-25 20:24:41 -0700181
182 /* We're only interested in headers related to this
183 * connection */
184 if (request) {
Patrick McHardy9a664822012-08-26 19:14:25 +0200185 if (!nf_inet_addr_cmp(&addr,
186 &ct->tuplehash[dir].tuple.src.u3) ||
Patrick McHardy720ac702008-03-25 20:24:41 -0700187 port != ct->tuplehash[dir].tuple.src.u.udp.port)
188 goto next;
189 } else {
Patrick McHardy9a664822012-08-26 19:14:25 +0200190 if (!nf_inet_addr_cmp(&addr,
191 &ct->tuplehash[dir].tuple.dst.u3) ||
Patrick McHardy720ac702008-03-25 20:24:41 -0700192 port != ct->tuplehash[dir].tuple.dst.u.udp.port)
193 goto next;
194 }
195
Patrick McHardyf22eb252012-08-09 10:08:47 +0000196 olen = *datalen;
Patrick McHardy051966c2012-08-26 19:14:04 +0200197 if (!map_addr(skb, protoff, dataoff, dptr, datalen,
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100198 matchoff, matchlen, &addr, port)) {
199 nf_ct_helper_log(skb, ct, "cannot mangle Via header");
Patrick McHardy720ac702008-03-25 20:24:41 -0700200 return NF_DROP;
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100201 }
Patrick McHardy720ac702008-03-25 20:24:41 -0700202
Patrick McHardyf22eb252012-08-09 10:08:47 +0000203 matchend = matchoff + matchlen + *datalen - olen;
Patrick McHardy720ac702008-03-25 20:24:41 -0700204
205 /* The maddr= parameter (RFC 2361) specifies where to send
206 * the reply. */
207 if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
208 "maddr=", &poff, &plen,
Patrick McHardy02b69cb2012-08-09 10:08:46 +0000209 &addr, true) > 0 &&
Patrick McHardy9a664822012-08-26 19:14:25 +0200210 nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3) &&
211 !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3)) {
212 buflen = sip_sprintf_addr(ct, buffer,
213 &ct->tuplehash[!dir].tuple.dst.u3,
214 true);
Patrick McHardy051966c2012-08-26 19:14:04 +0200215 if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100216 poff, plen, buffer, buflen)) {
217 nf_ct_helper_log(skb, ct, "cannot mangle maddr");
Patrick McHardy720ac702008-03-25 20:24:41 -0700218 return NF_DROP;
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100219 }
Patrick McHardy720ac702008-03-25 20:24:41 -0700220 }
221
222 /* The received= parameter (RFC 2361) contains the address
223 * from which the server received the request. */
224 if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
225 "received=", &poff, &plen,
Patrick McHardy02b69cb2012-08-09 10:08:46 +0000226 &addr, false) > 0 &&
Patrick McHardy9a664822012-08-26 19:14:25 +0200227 nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.dst.u3) &&
228 !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.src.u3)) {
229 buflen = sip_sprintf_addr(ct, buffer,
230 &ct->tuplehash[!dir].tuple.src.u3,
231 false);
Patrick McHardy051966c2012-08-26 19:14:04 +0200232 if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
Balazs Peter Odor5aed9382013-06-22 19:24:43 +0200233 poff, plen, buffer, buflen)) {
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100234 nf_ct_helper_log(skb, ct, "cannot mangle received");
Patrick McHardy720ac702008-03-25 20:24:41 -0700235 return NF_DROP;
Balazs Peter Odor5aed9382013-06-22 19:24:43 +0200236 }
Patrick McHardy720ac702008-03-25 20:24:41 -0700237 }
238
239 /* The rport= parameter (RFC 3581) contains the port number
240 * from which the server received the request. */
241 if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen,
242 "rport=", &poff, &plen,
243 &n) > 0 &&
244 htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port &&
245 htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) {
246 __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port;
247 buflen = sprintf(buffer, "%u", ntohs(p));
Patrick McHardy051966c2012-08-26 19:14:04 +0200248 if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100249 poff, plen, buffer, buflen)) {
250 nf_ct_helper_log(skb, ct, "cannot mangle rport");
Patrick McHardy720ac702008-03-25 20:24:41 -0700251 return NF_DROP;
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100252 }
Patrick McHardy720ac702008-03-25 20:24:41 -0700253 }
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800254 }
255
Patrick McHardy720ac702008-03-25 20:24:41 -0700256next:
Patrick McHardyc978cd32008-03-25 20:24:57 -0700257 /* Translate Contact headers */
Patrick McHardy3b6b9fa2010-02-11 12:23:53 +0100258 coff = 0;
Patrick McHardyc978cd32008-03-25 20:24:57 -0700259 in_header = 0;
Patrick McHardy3b6b9fa2010-02-11 12:23:53 +0100260 while (ct_sip_parse_header_uri(ct, *dptr, &coff, *datalen,
Patrick McHardyc978cd32008-03-25 20:24:57 -0700261 SIP_HDR_CONTACT, &in_header,
262 &matchoff, &matchlen,
263 &addr, &port) > 0) {
Patrick McHardy051966c2012-08-26 19:14:04 +0200264 if (!map_addr(skb, protoff, dataoff, dptr, datalen,
265 matchoff, matchlen,
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100266 &addr, port)) {
267 nf_ct_helper_log(skb, ct, "cannot mangle contact");
Patrick McHardyc978cd32008-03-25 20:24:57 -0700268 return NF_DROP;
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100269 }
Patrick McHardyc978cd32008-03-25 20:24:57 -0700270 }
271
Patrick McHardy051966c2012-08-26 19:14:04 +0200272 if (!map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_FROM) ||
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100273 !map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_TO)) {
274 nf_ct_helper_log(skb, ct, "cannot mangle SIP from/to");
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800275 return NF_DROP;
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100276 }
Patrick McHardy48f8ac22010-02-11 12:29:38 +0100277
Kevin Cernekee72665072012-12-17 18:33:58 +0000278 /* Mangle destination port for Cisco phones, then fix up checksums */
279 if (dir == IP_CT_DIR_REPLY && ct_sip_info->forced_dport) {
280 struct udphdr *uh;
281
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100282 if (!skb_make_writable(skb, skb->len)) {
283 nf_ct_helper_log(skb, ct, "cannot mangle packet");
Kevin Cernekee72665072012-12-17 18:33:58 +0000284 return NF_DROP;
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100285 }
Kevin Cernekee72665072012-12-17 18:33:58 +0000286
287 uh = (void *)skb->data + protoff;
288 uh->dest = ct_sip_info->forced_dport;
289
290 if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, protoff,
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100291 0, 0, NULL, 0)) {
292 nf_ct_helper_log(skb, ct, "cannot mangle packet");
Kevin Cernekee72665072012-12-17 18:33:58 +0000293 return NF_DROP;
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100294 }
Kevin Cernekee72665072012-12-17 18:33:58 +0000295 }
296
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800297 return NF_ACCEPT;
298}
299
Patrick McHardy9a664822012-08-26 19:14:25 +0200300static void nf_nat_sip_seq_adjust(struct sk_buff *skb, unsigned int protoff,
301 s16 off)
Patrick McHardy48f8ac22010-02-11 12:29:38 +0100302{
303 enum ip_conntrack_info ctinfo;
304 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
305 const struct tcphdr *th;
306
307 if (nf_ct_protonum(ct) != IPPROTO_TCP || off == 0)
308 return;
309
Patrick McHardy9a664822012-08-26 19:14:25 +0200310 th = (struct tcphdr *)(skb->data + protoff);
Patrick McHardy48f8ac22010-02-11 12:29:38 +0100311 nf_nat_set_seq_adjust(ct, ctinfo, th->seq, off);
312}
313
Patrick McHardy0f32a402008-03-25 20:25:13 -0700314/* Handles expected signalling connections and media streams */
Patrick McHardy9a664822012-08-26 19:14:25 +0200315static void nf_nat_sip_expected(struct nf_conn *ct,
Patrick McHardy0f32a402008-03-25 20:25:13 -0700316 struct nf_conntrack_expect *exp)
317{
Patrick McHardyc7232c92012-08-26 19:14:06 +0200318 struct nf_nat_range range;
Patrick McHardy0f32a402008-03-25 20:25:13 -0700319
320 /* This must be a fresh one. */
321 BUG_ON(ct->status & IPS_NAT_DONE_MASK);
322
323 /* For DST manip, map port here to where it's expected. */
Patrick McHardycbc9f2f2011-12-23 13:59:49 +0100324 range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED);
Patrick McHardyc7232c92012-08-26 19:14:06 +0200325 range.min_proto = range.max_proto = exp->saved_proto;
326 range.min_addr = range.max_addr = exp->saved_addr;
Patrick McHardycbc9f2f2011-12-23 13:59:49 +0100327 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
Patrick McHardy0f32a402008-03-25 20:25:13 -0700328
329 /* Change src to where master sends to, but only if the connection
330 * actually came from the same source. */
Patrick McHardy9a664822012-08-26 19:14:25 +0200331 if (nf_inet_addr_cmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3,
332 &ct->master->tuplehash[exp->dir].tuple.src.u3)) {
Patrick McHardycbc9f2f2011-12-23 13:59:49 +0100333 range.flags = NF_NAT_RANGE_MAP_IPS;
Patrick McHardyc7232c92012-08-26 19:14:06 +0200334 range.min_addr = range.max_addr
335 = ct->master->tuplehash[!exp->dir].tuple.dst.u3;
Patrick McHardycbc9f2f2011-12-23 13:59:49 +0100336 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
Patrick McHardy0f32a402008-03-25 20:25:13 -0700337 }
338}
339
Patrick McHardy9a664822012-08-26 19:14:25 +0200340static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff,
Patrick McHardy051966c2012-08-26 19:14:04 +0200341 unsigned int dataoff,
Patrick McHardy0f32a402008-03-25 20:25:13 -0700342 const char **dptr, unsigned int *datalen,
343 struct nf_conntrack_expect *exp,
344 unsigned int matchoff,
345 unsigned int matchlen)
346{
347 enum ip_conntrack_info ctinfo;
348 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
349 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
Kevin Cernekee72665072012-12-17 18:33:58 +0000350 struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
Patrick McHardy9a664822012-08-26 19:14:25 +0200351 union nf_inet_addr newaddr;
Patrick McHardy0f32a402008-03-25 20:25:13 -0700352 u_int16_t port;
Kevin Cernekee72665072012-12-17 18:33:58 +0000353 __be16 srcport;
Patrick McHardy9a664822012-08-26 19:14:25 +0200354 char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")];
Eric Dumazet95c96172012-04-15 05:58:06 +0000355 unsigned int buflen;
Patrick McHardy0f32a402008-03-25 20:25:13 -0700356
357 /* Connection will come from reply */
Patrick McHardy9a664822012-08-26 19:14:25 +0200358 if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3,
359 &ct->tuplehash[!dir].tuple.dst.u3))
360 newaddr = exp->tuple.dst.u3;
Patrick McHardy0f32a402008-03-25 20:25:13 -0700361 else
Patrick McHardy9a664822012-08-26 19:14:25 +0200362 newaddr = ct->tuplehash[!dir].tuple.dst.u3;
Patrick McHardy0f32a402008-03-25 20:25:13 -0700363
364 /* If the signalling port matches the connection's source port in the
365 * original direction, try to use the destination port in the opposite
366 * direction. */
Kevin Cernekee72665072012-12-17 18:33:58 +0000367 srcport = ct_sip_info->forced_dport ? :
368 ct->tuplehash[dir].tuple.src.u.udp.port;
369 if (exp->tuple.dst.u.udp.port == srcport)
Patrick McHardy0f32a402008-03-25 20:25:13 -0700370 port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port);
371 else
372 port = ntohs(exp->tuple.dst.u.udp.port);
373
Patrick McHardyc7232c92012-08-26 19:14:06 +0200374 exp->saved_addr = exp->tuple.dst.u3;
Patrick McHardy9a664822012-08-26 19:14:25 +0200375 exp->tuple.dst.u3 = newaddr;
Patrick McHardy0f32a402008-03-25 20:25:13 -0700376 exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
377 exp->dir = !dir;
Patrick McHardy9a664822012-08-26 19:14:25 +0200378 exp->expectfn = nf_nat_sip_expected;
Patrick McHardy0f32a402008-03-25 20:25:13 -0700379
380 for (; port != 0; port++) {
Pablo Neira Ayuso5b92b612010-09-22 08:34:12 +0200381 int ret;
382
Patrick McHardy0f32a402008-03-25 20:25:13 -0700383 exp->tuple.dst.u.udp.port = htons(port);
Pablo Neira Ayuso5b92b612010-09-22 08:34:12 +0200384 ret = nf_ct_expect_related(exp);
385 if (ret == 0)
Patrick McHardy0f32a402008-03-25 20:25:13 -0700386 break;
Pablo Neira Ayuso5b92b612010-09-22 08:34:12 +0200387 else if (ret != -EBUSY) {
388 port = 0;
389 break;
390 }
Patrick McHardy0f32a402008-03-25 20:25:13 -0700391 }
392
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100393 if (port == 0) {
394 nf_ct_helper_log(skb, ct, "all ports in use for SIP");
Patrick McHardy0f32a402008-03-25 20:25:13 -0700395 return NF_DROP;
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100396 }
Patrick McHardy0f32a402008-03-25 20:25:13 -0700397
Patrick McHardy9a664822012-08-26 19:14:25 +0200398 if (!nf_inet_addr_cmp(&exp->tuple.dst.u3, &exp->saved_addr) ||
Patrick McHardy0f32a402008-03-25 20:25:13 -0700399 exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) {
Patrick McHardy9a664822012-08-26 19:14:25 +0200400 buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, port);
Patrick McHardy051966c2012-08-26 19:14:04 +0200401 if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100402 matchoff, matchlen, buffer, buflen)) {
403 nf_ct_helper_log(skb, ct, "cannot mangle packet");
Patrick McHardy0f32a402008-03-25 20:25:13 -0700404 goto err;
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100405 }
Patrick McHardy0f32a402008-03-25 20:25:13 -0700406 }
407 return NF_ACCEPT;
408
409err:
410 nf_ct_unexpect_related(exp);
411 return NF_DROP;
412}
413
Patrick McHardy051966c2012-08-26 19:14:04 +0200414static int mangle_content_len(struct sk_buff *skb, unsigned int protoff,
415 unsigned int dataoff,
Patrick McHardy2a6cfb22008-03-25 20:16:54 -0700416 const char **dptr, unsigned int *datalen)
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800417{
Patrick McHardy212440a2008-03-25 20:17:13 -0700418 enum ip_conntrack_info ctinfo;
419 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
Patrick McHardy2a6cfb22008-03-25 20:16:54 -0700420 unsigned int matchoff, matchlen;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800421 char buffer[sizeof("65536")];
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700422 int buflen, c_len;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800423
Joe Perchese00ccd42007-12-20 14:05:03 -0800424 /* Get actual SDP length */
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700425 if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen,
426 SDP_HDR_VERSION, SDP_HDR_UNSPEC,
427 &matchoff, &matchlen) <= 0)
428 return 0;
429 c_len = *datalen - matchoff + strlen("v=");
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800430
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700431 /* Now, update SDP length */
Patrick McHardyea45f122008-03-25 20:18:57 -0700432 if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CONTENT_LENGTH,
433 &matchoff, &matchlen) <= 0)
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700434 return 0;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800435
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700436 buflen = sprintf(buffer, "%u", c_len);
Patrick McHardy051966c2012-08-26 19:14:04 +0200437 return mangle_packet(skb, protoff, dataoff, dptr, datalen,
438 matchoff, matchlen, buffer, buflen);
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700439}
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800440
Patrick McHardy051966c2012-08-26 19:14:04 +0200441static int mangle_sdp_packet(struct sk_buff *skb, unsigned int protoff,
442 unsigned int dataoff,
Patrick McHardy3b6b9fa2010-02-11 12:23:53 +0100443 const char **dptr, unsigned int *datalen,
444 unsigned int sdpoff,
Herbert Xuc71529e2008-07-21 10:03:23 -0700445 enum sdp_header_types type,
446 enum sdp_header_types term,
447 char *buffer, int buflen)
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700448{
449 enum ip_conntrack_info ctinfo;
450 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
451 unsigned int matchlen, matchoff;
452
Patrick McHardy3b6b9fa2010-02-11 12:23:53 +0100453 if (ct_sip_get_sdp_header(ct, *dptr, sdpoff, *datalen, type, term,
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700454 &matchoff, &matchlen) <= 0)
Herbert Xuc71529e2008-07-21 10:03:23 -0700455 return -ENOENT;
Patrick McHardy051966c2012-08-26 19:14:04 +0200456 return mangle_packet(skb, protoff, dataoff, dptr, datalen,
457 matchoff, matchlen, buffer, buflen) ? 0 : -EINVAL;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800458}
459
Patrick McHardy9a664822012-08-26 19:14:25 +0200460static unsigned int nf_nat_sdp_addr(struct sk_buff *skb, unsigned int protoff,
Patrick McHardy051966c2012-08-26 19:14:04 +0200461 unsigned int dataoff,
Patrick McHardy3b6b9fa2010-02-11 12:23:53 +0100462 const char **dptr, unsigned int *datalen,
463 unsigned int sdpoff,
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700464 enum sdp_header_types type,
465 enum sdp_header_types term,
466 const union nf_inet_addr *addr)
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800467{
Patrick McHardy9a664822012-08-26 19:14:25 +0200468 enum ip_conntrack_info ctinfo;
469 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
470 char buffer[INET6_ADDRSTRLEN];
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700471 unsigned int buflen;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800472
Patrick McHardy9a664822012-08-26 19:14:25 +0200473 buflen = sip_sprintf_addr(ct, buffer, addr, false);
Patrick McHardy051966c2012-08-26 19:14:04 +0200474 if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen,
475 sdpoff, type, term, buffer, buflen))
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800476 return 0;
477
Patrick McHardy051966c2012-08-26 19:14:04 +0200478 return mangle_content_len(skb, protoff, dataoff, dptr, datalen);
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700479}
480
Patrick McHardy9a664822012-08-26 19:14:25 +0200481static unsigned int nf_nat_sdp_port(struct sk_buff *skb, unsigned int protoff,
Patrick McHardy051966c2012-08-26 19:14:04 +0200482 unsigned int dataoff,
Patrick McHardy3b6b9fa2010-02-11 12:23:53 +0100483 const char **dptr, unsigned int *datalen,
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700484 unsigned int matchoff,
485 unsigned int matchlen,
486 u_int16_t port)
487{
488 char buffer[sizeof("nnnnn")];
489 unsigned int buflen;
490
491 buflen = sprintf(buffer, "%u", port);
Patrick McHardy051966c2012-08-26 19:14:04 +0200492 if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
493 matchoff, matchlen, buffer, buflen))
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800494 return 0;
495
Patrick McHardy051966c2012-08-26 19:14:04 +0200496 return mangle_content_len(skb, protoff, dataoff, dptr, datalen);
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700497}
498
Patrick McHardy9a664822012-08-26 19:14:25 +0200499static unsigned int nf_nat_sdp_session(struct sk_buff *skb, unsigned int protoff,
Patrick McHardy051966c2012-08-26 19:14:04 +0200500 unsigned int dataoff,
Patrick McHardy3b6b9fa2010-02-11 12:23:53 +0100501 const char **dptr, unsigned int *datalen,
502 unsigned int sdpoff,
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700503 const union nf_inet_addr *addr)
504{
Patrick McHardy9a664822012-08-26 19:14:25 +0200505 enum ip_conntrack_info ctinfo;
506 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
507 char buffer[INET6_ADDRSTRLEN];
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700508 unsigned int buflen;
509
510 /* Mangle session description owner and contact addresses */
Patrick McHardy9a664822012-08-26 19:14:25 +0200511 buflen = sip_sprintf_addr(ct, buffer, addr, false);
Patrick McHardy051966c2012-08-26 19:14:04 +0200512 if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff,
Patrick McHardy9a664822012-08-26 19:14:25 +0200513 SDP_HDR_OWNER, SDP_HDR_MEDIA, buffer, buflen))
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700514 return 0;
515
Patrick McHardy051966c2012-08-26 19:14:04 +0200516 switch (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff,
Patrick McHardy9a664822012-08-26 19:14:25 +0200517 SDP_HDR_CONNECTION, SDP_HDR_MEDIA,
Herbert Xuc71529e2008-07-21 10:03:23 -0700518 buffer, buflen)) {
519 case 0:
520 /*
521 * RFC 2327:
522 *
523 * Session description
524 *
525 * c=* (connection information - not required if included in all media)
526 */
527 case -ENOENT:
528 break;
529 default:
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800530 return 0;
Herbert Xuc71529e2008-07-21 10:03:23 -0700531 }
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800532
Patrick McHardy051966c2012-08-26 19:14:04 +0200533 return mangle_content_len(skb, protoff, dataoff, dptr, datalen);
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800534}
535
536/* So, this packet has hit the connection tracking matching code.
537 Mangle it, and change the expectation to match the new version. */
Patrick McHardy9a664822012-08-26 19:14:25 +0200538static unsigned int nf_nat_sdp_media(struct sk_buff *skb, unsigned int protoff,
Patrick McHardy051966c2012-08-26 19:14:04 +0200539 unsigned int dataoff,
Patrick McHardy3b6b9fa2010-02-11 12:23:53 +0100540 const char **dptr, unsigned int *datalen,
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700541 struct nf_conntrack_expect *rtp_exp,
542 struct nf_conntrack_expect *rtcp_exp,
543 unsigned int mediaoff,
544 unsigned int medialen,
545 union nf_inet_addr *rtp_addr)
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800546{
Patrick McHardy212440a2008-03-25 20:17:13 -0700547 enum ip_conntrack_info ctinfo;
548 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800549 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800550 u_int16_t port;
551
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800552 /* Connection will come from reply */
Patrick McHardy9a664822012-08-26 19:14:25 +0200553 if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3,
554 &ct->tuplehash[!dir].tuple.dst.u3))
555 *rtp_addr = rtp_exp->tuple.dst.u3;
Jerome Borsboomf4a607b2007-07-07 22:19:48 -0700556 else
Patrick McHardy9a664822012-08-26 19:14:25 +0200557 *rtp_addr = ct->tuplehash[!dir].tuple.dst.u3;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800558
Patrick McHardyc7232c92012-08-26 19:14:06 +0200559 rtp_exp->saved_addr = rtp_exp->tuple.dst.u3;
Patrick McHardy9a664822012-08-26 19:14:25 +0200560 rtp_exp->tuple.dst.u3 = *rtp_addr;
Patrick McHardya9c1d352008-03-25 20:25:49 -0700561 rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
562 rtp_exp->dir = !dir;
Patrick McHardy9a664822012-08-26 19:14:25 +0200563 rtp_exp->expectfn = nf_nat_sip_expected;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800564
Patrick McHardyc7232c92012-08-26 19:14:06 +0200565 rtcp_exp->saved_addr = rtcp_exp->tuple.dst.u3;
Patrick McHardy9a664822012-08-26 19:14:25 +0200566 rtcp_exp->tuple.dst.u3 = *rtp_addr;
Patrick McHardya9c1d352008-03-25 20:25:49 -0700567 rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
568 rtcp_exp->dir = !dir;
Patrick McHardy9a664822012-08-26 19:14:25 +0200569 rtcp_exp->expectfn = nf_nat_sip_expected;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800570
Patrick McHardya9c1d352008-03-25 20:25:49 -0700571 /* Try to get same pair of ports: if not, try to change them. */
572 for (port = ntohs(rtp_exp->tuple.dst.u.udp.port);
573 port != 0; port += 2) {
Pablo Neira Ayuso5b92b612010-09-22 08:34:12 +0200574 int ret;
575
Patrick McHardya9c1d352008-03-25 20:25:49 -0700576 rtp_exp->tuple.dst.u.udp.port = htons(port);
Pablo Neira Ayuso5b92b612010-09-22 08:34:12 +0200577 ret = nf_ct_expect_related(rtp_exp);
578 if (ret == -EBUSY)
Patrick McHardya9c1d352008-03-25 20:25:49 -0700579 continue;
Pablo Neira Ayuso5b92b612010-09-22 08:34:12 +0200580 else if (ret < 0) {
581 port = 0;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800582 break;
Pablo Neira Ayuso5b92b612010-09-22 08:34:12 +0200583 }
584 rtcp_exp->tuple.dst.u.udp.port = htons(port + 1);
585 ret = nf_ct_expect_related(rtcp_exp);
586 if (ret == 0)
587 break;
Pablo Neira Ayuso3f509c62012-08-29 15:24:09 +0000588 else if (ret == -EBUSY) {
589 nf_ct_unexpect_related(rtp_exp);
590 continue;
591 } else if (ret < 0) {
Pablo Neira Ayuso5b92b612010-09-22 08:34:12 +0200592 nf_ct_unexpect_related(rtp_exp);
593 port = 0;
594 break;
595 }
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800596 }
597
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100598 if (port == 0) {
599 nf_ct_helper_log(skb, ct, "all ports in use for SDP media");
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700600 goto err1;
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100601 }
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800602
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700603 /* Update media port. */
604 if (rtp_exp->tuple.dst.u.udp.port != rtp_exp->saved_proto.udp.port &&
Patrick McHardy9a664822012-08-26 19:14:25 +0200605 !nf_nat_sdp_port(skb, protoff, dataoff, dptr, datalen,
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100606 mediaoff, medialen, port)) {
607 nf_ct_helper_log(skb, ct, "cannot mangle SDP message");
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700608 goto err2;
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100609 }
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700610
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800611 return NF_ACCEPT;
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700612
613err2:
614 nf_ct_unexpect_related(rtp_exp);
615 nf_ct_unexpect_related(rtcp_exp);
616err1:
617 return NF_DROP;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800618}
619
Pablo Neira Ayuso544d5c72012-02-05 03:44:51 +0100620static struct nf_ct_helper_expectfn sip_nat = {
Patrick McHardy9a664822012-08-26 19:14:25 +0200621 .name = "sip",
622 .expectfn = nf_nat_sip_expected,
Pablo Neira Ayuso544d5c72012-02-05 03:44:51 +0100623};
624
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800625static void __exit nf_nat_sip_fini(void)
626{
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +0000627 RCU_INIT_POINTER(nf_nat_sip_hook, NULL);
628 RCU_INIT_POINTER(nf_nat_sip_seq_adjust_hook, NULL);
629 RCU_INIT_POINTER(nf_nat_sip_expect_hook, NULL);
630 RCU_INIT_POINTER(nf_nat_sdp_addr_hook, NULL);
631 RCU_INIT_POINTER(nf_nat_sdp_port_hook, NULL);
632 RCU_INIT_POINTER(nf_nat_sdp_session_hook, NULL);
633 RCU_INIT_POINTER(nf_nat_sdp_media_hook, NULL);
Pablo Neira Ayuso544d5c72012-02-05 03:44:51 +0100634 nf_ct_helper_expectfn_unregister(&sip_nat);
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800635 synchronize_rcu();
636}
637
638static int __init nf_nat_sip_init(void)
639{
Patrick McHardyd1332e02007-11-05 20:43:30 -0800640 BUG_ON(nf_nat_sip_hook != NULL);
Patrick McHardy48f8ac22010-02-11 12:29:38 +0100641 BUG_ON(nf_nat_sip_seq_adjust_hook != NULL);
Patrick McHardy0f32a402008-03-25 20:25:13 -0700642 BUG_ON(nf_nat_sip_expect_hook != NULL);
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700643 BUG_ON(nf_nat_sdp_addr_hook != NULL);
Patrick McHardyc7f485a2008-03-25 20:26:43 -0700644 BUG_ON(nf_nat_sdp_port_hook != NULL);
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700645 BUG_ON(nf_nat_sdp_session_hook != NULL);
646 BUG_ON(nf_nat_sdp_media_hook != NULL);
Patrick McHardy9a664822012-08-26 19:14:25 +0200647 RCU_INIT_POINTER(nf_nat_sip_hook, nf_nat_sip);
648 RCU_INIT_POINTER(nf_nat_sip_seq_adjust_hook, nf_nat_sip_seq_adjust);
649 RCU_INIT_POINTER(nf_nat_sip_expect_hook, nf_nat_sip_expect);
650 RCU_INIT_POINTER(nf_nat_sdp_addr_hook, nf_nat_sdp_addr);
651 RCU_INIT_POINTER(nf_nat_sdp_port_hook, nf_nat_sdp_port);
652 RCU_INIT_POINTER(nf_nat_sdp_session_hook, nf_nat_sdp_session);
653 RCU_INIT_POINTER(nf_nat_sdp_media_hook, nf_nat_sdp_media);
Pablo Neira Ayuso544d5c72012-02-05 03:44:51 +0100654 nf_ct_helper_expectfn_register(&sip_nat);
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800655 return 0;
656}
657
658module_init(nf_nat_sip_init);
659module_exit(nf_nat_sip_fini);