blob: 96ccdf78a29ffafb84c5e1229f33487ec28c1429 [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,
Patrick McHardy3b6b9fa2010-02-11 12:23:53 +0100233 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;
236 }
237
238 /* The rport= parameter (RFC 3581) contains the port number
239 * from which the server received the request. */
240 if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen,
241 "rport=", &poff, &plen,
242 &n) > 0 &&
243 htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port &&
244 htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) {
245 __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port;
246 buflen = sprintf(buffer, "%u", ntohs(p));
Patrick McHardy051966c2012-08-26 19:14:04 +0200247 if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100248 poff, plen, buffer, buflen)) {
249 nf_ct_helper_log(skb, ct, "cannot mangle rport");
Patrick McHardy720ac702008-03-25 20:24:41 -0700250 return NF_DROP;
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100251 }
Patrick McHardy720ac702008-03-25 20:24:41 -0700252 }
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800253 }
254
Patrick McHardy720ac702008-03-25 20:24:41 -0700255next:
Patrick McHardyc978cd32008-03-25 20:24:57 -0700256 /* Translate Contact headers */
Patrick McHardy3b6b9fa2010-02-11 12:23:53 +0100257 coff = 0;
Patrick McHardyc978cd32008-03-25 20:24:57 -0700258 in_header = 0;
Patrick McHardy3b6b9fa2010-02-11 12:23:53 +0100259 while (ct_sip_parse_header_uri(ct, *dptr, &coff, *datalen,
Patrick McHardyc978cd32008-03-25 20:24:57 -0700260 SIP_HDR_CONTACT, &in_header,
261 &matchoff, &matchlen,
262 &addr, &port) > 0) {
Patrick McHardy051966c2012-08-26 19:14:04 +0200263 if (!map_addr(skb, protoff, dataoff, dptr, datalen,
264 matchoff, matchlen,
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100265 &addr, port)) {
266 nf_ct_helper_log(skb, ct, "cannot mangle contact");
Patrick McHardyc978cd32008-03-25 20:24:57 -0700267 return NF_DROP;
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100268 }
Patrick McHardyc978cd32008-03-25 20:24:57 -0700269 }
270
Patrick McHardy051966c2012-08-26 19:14:04 +0200271 if (!map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_FROM) ||
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100272 !map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_TO)) {
273 nf_ct_helper_log(skb, ct, "cannot mangle SIP from/to");
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800274 return NF_DROP;
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100275 }
Patrick McHardy48f8ac22010-02-11 12:29:38 +0100276
Kevin Cernekee72665072012-12-17 18:33:58 +0000277 /* Mangle destination port for Cisco phones, then fix up checksums */
278 if (dir == IP_CT_DIR_REPLY && ct_sip_info->forced_dport) {
279 struct udphdr *uh;
280
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100281 if (!skb_make_writable(skb, skb->len)) {
282 nf_ct_helper_log(skb, ct, "cannot mangle packet");
Kevin Cernekee72665072012-12-17 18:33:58 +0000283 return NF_DROP;
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100284 }
Kevin Cernekee72665072012-12-17 18:33:58 +0000285
286 uh = (void *)skb->data + protoff;
287 uh->dest = ct_sip_info->forced_dport;
288
289 if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, protoff,
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100290 0, 0, NULL, 0)) {
291 nf_ct_helper_log(skb, ct, "cannot mangle packet");
Kevin Cernekee72665072012-12-17 18:33:58 +0000292 return NF_DROP;
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100293 }
Kevin Cernekee72665072012-12-17 18:33:58 +0000294 }
295
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800296 return NF_ACCEPT;
297}
298
Patrick McHardy9a664822012-08-26 19:14:25 +0200299static void nf_nat_sip_seq_adjust(struct sk_buff *skb, unsigned int protoff,
300 s16 off)
Patrick McHardy48f8ac22010-02-11 12:29:38 +0100301{
302 enum ip_conntrack_info ctinfo;
303 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
304 const struct tcphdr *th;
305
306 if (nf_ct_protonum(ct) != IPPROTO_TCP || off == 0)
307 return;
308
Patrick McHardy9a664822012-08-26 19:14:25 +0200309 th = (struct tcphdr *)(skb->data + protoff);
Patrick McHardy48f8ac22010-02-11 12:29:38 +0100310 nf_nat_set_seq_adjust(ct, ctinfo, th->seq, off);
311}
312
Patrick McHardy0f32a402008-03-25 20:25:13 -0700313/* Handles expected signalling connections and media streams */
Patrick McHardy9a664822012-08-26 19:14:25 +0200314static void nf_nat_sip_expected(struct nf_conn *ct,
Patrick McHardy0f32a402008-03-25 20:25:13 -0700315 struct nf_conntrack_expect *exp)
316{
Patrick McHardyc7232c92012-08-26 19:14:06 +0200317 struct nf_nat_range range;
Patrick McHardy0f32a402008-03-25 20:25:13 -0700318
319 /* This must be a fresh one. */
320 BUG_ON(ct->status & IPS_NAT_DONE_MASK);
321
322 /* For DST manip, map port here to where it's expected. */
Patrick McHardycbc9f2f2011-12-23 13:59:49 +0100323 range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED);
Patrick McHardyc7232c92012-08-26 19:14:06 +0200324 range.min_proto = range.max_proto = exp->saved_proto;
325 range.min_addr = range.max_addr = exp->saved_addr;
Patrick McHardycbc9f2f2011-12-23 13:59:49 +0100326 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
Patrick McHardy0f32a402008-03-25 20:25:13 -0700327
328 /* Change src to where master sends to, but only if the connection
329 * actually came from the same source. */
Patrick McHardy9a664822012-08-26 19:14:25 +0200330 if (nf_inet_addr_cmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3,
331 &ct->master->tuplehash[exp->dir].tuple.src.u3)) {
Patrick McHardycbc9f2f2011-12-23 13:59:49 +0100332 range.flags = NF_NAT_RANGE_MAP_IPS;
Patrick McHardyc7232c92012-08-26 19:14:06 +0200333 range.min_addr = range.max_addr
334 = ct->master->tuplehash[!exp->dir].tuple.dst.u3;
Patrick McHardycbc9f2f2011-12-23 13:59:49 +0100335 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
Patrick McHardy0f32a402008-03-25 20:25:13 -0700336 }
337}
338
Patrick McHardy9a664822012-08-26 19:14:25 +0200339static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff,
Patrick McHardy051966c2012-08-26 19:14:04 +0200340 unsigned int dataoff,
Patrick McHardy0f32a402008-03-25 20:25:13 -0700341 const char **dptr, unsigned int *datalen,
342 struct nf_conntrack_expect *exp,
343 unsigned int matchoff,
344 unsigned int matchlen)
345{
346 enum ip_conntrack_info ctinfo;
347 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
348 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
Kevin Cernekee72665072012-12-17 18:33:58 +0000349 struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
Patrick McHardy9a664822012-08-26 19:14:25 +0200350 union nf_inet_addr newaddr;
Patrick McHardy0f32a402008-03-25 20:25:13 -0700351 u_int16_t port;
Kevin Cernekee72665072012-12-17 18:33:58 +0000352 __be16 srcport;
Patrick McHardy9a664822012-08-26 19:14:25 +0200353 char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")];
Eric Dumazet95c96172012-04-15 05:58:06 +0000354 unsigned int buflen;
Patrick McHardy0f32a402008-03-25 20:25:13 -0700355
356 /* Connection will come from reply */
Patrick McHardy9a664822012-08-26 19:14:25 +0200357 if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3,
358 &ct->tuplehash[!dir].tuple.dst.u3))
359 newaddr = exp->tuple.dst.u3;
Patrick McHardy0f32a402008-03-25 20:25:13 -0700360 else
Patrick McHardy9a664822012-08-26 19:14:25 +0200361 newaddr = ct->tuplehash[!dir].tuple.dst.u3;
Patrick McHardy0f32a402008-03-25 20:25:13 -0700362
363 /* If the signalling port matches the connection's source port in the
364 * original direction, try to use the destination port in the opposite
365 * direction. */
Kevin Cernekee72665072012-12-17 18:33:58 +0000366 srcport = ct_sip_info->forced_dport ? :
367 ct->tuplehash[dir].tuple.src.u.udp.port;
368 if (exp->tuple.dst.u.udp.port == srcport)
Patrick McHardy0f32a402008-03-25 20:25:13 -0700369 port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port);
370 else
371 port = ntohs(exp->tuple.dst.u.udp.port);
372
Patrick McHardyc7232c92012-08-26 19:14:06 +0200373 exp->saved_addr = exp->tuple.dst.u3;
Patrick McHardy9a664822012-08-26 19:14:25 +0200374 exp->tuple.dst.u3 = newaddr;
Patrick McHardy0f32a402008-03-25 20:25:13 -0700375 exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
376 exp->dir = !dir;
Patrick McHardy9a664822012-08-26 19:14:25 +0200377 exp->expectfn = nf_nat_sip_expected;
Patrick McHardy0f32a402008-03-25 20:25:13 -0700378
379 for (; port != 0; port++) {
Pablo Neira Ayuso5b92b612010-09-22 08:34:12 +0200380 int ret;
381
Patrick McHardy0f32a402008-03-25 20:25:13 -0700382 exp->tuple.dst.u.udp.port = htons(port);
Pablo Neira Ayuso5b92b612010-09-22 08:34:12 +0200383 ret = nf_ct_expect_related(exp);
384 if (ret == 0)
Patrick McHardy0f32a402008-03-25 20:25:13 -0700385 break;
Pablo Neira Ayuso5b92b612010-09-22 08:34:12 +0200386 else if (ret != -EBUSY) {
387 port = 0;
388 break;
389 }
Patrick McHardy0f32a402008-03-25 20:25:13 -0700390 }
391
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100392 if (port == 0) {
393 nf_ct_helper_log(skb, ct, "all ports in use for SIP");
Patrick McHardy0f32a402008-03-25 20:25:13 -0700394 return NF_DROP;
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100395 }
Patrick McHardy0f32a402008-03-25 20:25:13 -0700396
Patrick McHardy9a664822012-08-26 19:14:25 +0200397 if (!nf_inet_addr_cmp(&exp->tuple.dst.u3, &exp->saved_addr) ||
Patrick McHardy0f32a402008-03-25 20:25:13 -0700398 exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) {
Patrick McHardy9a664822012-08-26 19:14:25 +0200399 buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, port);
Patrick McHardy051966c2012-08-26 19:14:04 +0200400 if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100401 matchoff, matchlen, buffer, buflen)) {
402 nf_ct_helper_log(skb, ct, "cannot mangle packet");
Patrick McHardy0f32a402008-03-25 20:25:13 -0700403 goto err;
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100404 }
Patrick McHardy0f32a402008-03-25 20:25:13 -0700405 }
406 return NF_ACCEPT;
407
408err:
409 nf_ct_unexpect_related(exp);
410 return NF_DROP;
411}
412
Patrick McHardy051966c2012-08-26 19:14:04 +0200413static int mangle_content_len(struct sk_buff *skb, unsigned int protoff,
414 unsigned int dataoff,
Patrick McHardy2a6cfb22008-03-25 20:16:54 -0700415 const char **dptr, unsigned int *datalen)
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800416{
Patrick McHardy212440a2008-03-25 20:17:13 -0700417 enum ip_conntrack_info ctinfo;
418 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
Patrick McHardy2a6cfb22008-03-25 20:16:54 -0700419 unsigned int matchoff, matchlen;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800420 char buffer[sizeof("65536")];
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700421 int buflen, c_len;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800422
Joe Perchese00ccd42007-12-20 14:05:03 -0800423 /* Get actual SDP length */
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700424 if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen,
425 SDP_HDR_VERSION, SDP_HDR_UNSPEC,
426 &matchoff, &matchlen) <= 0)
427 return 0;
428 c_len = *datalen - matchoff + strlen("v=");
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800429
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700430 /* Now, update SDP length */
Patrick McHardyea45f122008-03-25 20:18:57 -0700431 if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CONTENT_LENGTH,
432 &matchoff, &matchlen) <= 0)
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700433 return 0;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800434
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700435 buflen = sprintf(buffer, "%u", c_len);
Patrick McHardy051966c2012-08-26 19:14:04 +0200436 return mangle_packet(skb, protoff, dataoff, dptr, datalen,
437 matchoff, matchlen, buffer, buflen);
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700438}
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800439
Patrick McHardy051966c2012-08-26 19:14:04 +0200440static int mangle_sdp_packet(struct sk_buff *skb, unsigned int protoff,
441 unsigned int dataoff,
Patrick McHardy3b6b9fa2010-02-11 12:23:53 +0100442 const char **dptr, unsigned int *datalen,
443 unsigned int sdpoff,
Herbert Xuc71529e2008-07-21 10:03:23 -0700444 enum sdp_header_types type,
445 enum sdp_header_types term,
446 char *buffer, int buflen)
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700447{
448 enum ip_conntrack_info ctinfo;
449 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
450 unsigned int matchlen, matchoff;
451
Patrick McHardy3b6b9fa2010-02-11 12:23:53 +0100452 if (ct_sip_get_sdp_header(ct, *dptr, sdpoff, *datalen, type, term,
Patrick McHardy3e9b4600b2008-03-25 20:17:55 -0700453 &matchoff, &matchlen) <= 0)
Herbert Xuc71529e2008-07-21 10:03:23 -0700454 return -ENOENT;
Patrick McHardy051966c2012-08-26 19:14:04 +0200455 return mangle_packet(skb, protoff, dataoff, dptr, datalen,
456 matchoff, matchlen, buffer, buflen) ? 0 : -EINVAL;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800457}
458
Patrick McHardy9a664822012-08-26 19:14:25 +0200459static unsigned int nf_nat_sdp_addr(struct sk_buff *skb, unsigned int protoff,
Patrick McHardy051966c2012-08-26 19:14:04 +0200460 unsigned int dataoff,
Patrick McHardy3b6b9fa2010-02-11 12:23:53 +0100461 const char **dptr, unsigned int *datalen,
462 unsigned int sdpoff,
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700463 enum sdp_header_types type,
464 enum sdp_header_types term,
465 const union nf_inet_addr *addr)
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800466{
Patrick McHardy9a664822012-08-26 19:14:25 +0200467 enum ip_conntrack_info ctinfo;
468 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
469 char buffer[INET6_ADDRSTRLEN];
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700470 unsigned int buflen;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800471
Patrick McHardy9a664822012-08-26 19:14:25 +0200472 buflen = sip_sprintf_addr(ct, buffer, addr, false);
Patrick McHardy051966c2012-08-26 19:14:04 +0200473 if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen,
474 sdpoff, type, term, buffer, buflen))
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800475 return 0;
476
Patrick McHardy051966c2012-08-26 19:14:04 +0200477 return mangle_content_len(skb, protoff, dataoff, dptr, datalen);
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700478}
479
Patrick McHardy9a664822012-08-26 19:14:25 +0200480static unsigned int nf_nat_sdp_port(struct sk_buff *skb, unsigned int protoff,
Patrick McHardy051966c2012-08-26 19:14:04 +0200481 unsigned int dataoff,
Patrick McHardy3b6b9fa2010-02-11 12:23:53 +0100482 const char **dptr, unsigned int *datalen,
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700483 unsigned int matchoff,
484 unsigned int matchlen,
485 u_int16_t port)
486{
487 char buffer[sizeof("nnnnn")];
488 unsigned int buflen;
489
490 buflen = sprintf(buffer, "%u", port);
Patrick McHardy051966c2012-08-26 19:14:04 +0200491 if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
492 matchoff, matchlen, buffer, buflen))
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800493 return 0;
494
Patrick McHardy051966c2012-08-26 19:14:04 +0200495 return mangle_content_len(skb, protoff, dataoff, dptr, datalen);
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700496}
497
Patrick McHardy9a664822012-08-26 19:14:25 +0200498static unsigned int nf_nat_sdp_session(struct sk_buff *skb, unsigned int protoff,
Patrick McHardy051966c2012-08-26 19:14:04 +0200499 unsigned int dataoff,
Patrick McHardy3b6b9fa2010-02-11 12:23:53 +0100500 const char **dptr, unsigned int *datalen,
501 unsigned int sdpoff,
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700502 const union nf_inet_addr *addr)
503{
Patrick McHardy9a664822012-08-26 19:14:25 +0200504 enum ip_conntrack_info ctinfo;
505 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
506 char buffer[INET6_ADDRSTRLEN];
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700507 unsigned int buflen;
508
509 /* Mangle session description owner and contact addresses */
Patrick McHardy9a664822012-08-26 19:14:25 +0200510 buflen = sip_sprintf_addr(ct, buffer, addr, false);
Patrick McHardy051966c2012-08-26 19:14:04 +0200511 if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff,
Patrick McHardy9a664822012-08-26 19:14:25 +0200512 SDP_HDR_OWNER, SDP_HDR_MEDIA, buffer, buflen))
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700513 return 0;
514
Patrick McHardy051966c2012-08-26 19:14:04 +0200515 switch (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff,
Patrick McHardy9a664822012-08-26 19:14:25 +0200516 SDP_HDR_CONNECTION, SDP_HDR_MEDIA,
Herbert Xuc71529e2008-07-21 10:03:23 -0700517 buffer, buflen)) {
518 case 0:
519 /*
520 * RFC 2327:
521 *
522 * Session description
523 *
524 * c=* (connection information - not required if included in all media)
525 */
526 case -ENOENT:
527 break;
528 default:
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800529 return 0;
Herbert Xuc71529e2008-07-21 10:03:23 -0700530 }
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800531
Patrick McHardy051966c2012-08-26 19:14:04 +0200532 return mangle_content_len(skb, protoff, dataoff, dptr, datalen);
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800533}
534
535/* So, this packet has hit the connection tracking matching code.
536 Mangle it, and change the expectation to match the new version. */
Patrick McHardy9a664822012-08-26 19:14:25 +0200537static unsigned int nf_nat_sdp_media(struct sk_buff *skb, unsigned int protoff,
Patrick McHardy051966c2012-08-26 19:14:04 +0200538 unsigned int dataoff,
Patrick McHardy3b6b9fa2010-02-11 12:23:53 +0100539 const char **dptr, unsigned int *datalen,
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700540 struct nf_conntrack_expect *rtp_exp,
541 struct nf_conntrack_expect *rtcp_exp,
542 unsigned int mediaoff,
543 unsigned int medialen,
544 union nf_inet_addr *rtp_addr)
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800545{
Patrick McHardy212440a2008-03-25 20:17:13 -0700546 enum ip_conntrack_info ctinfo;
547 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800548 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800549 u_int16_t port;
550
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800551 /* Connection will come from reply */
Patrick McHardy9a664822012-08-26 19:14:25 +0200552 if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3,
553 &ct->tuplehash[!dir].tuple.dst.u3))
554 *rtp_addr = rtp_exp->tuple.dst.u3;
Jerome Borsboomf4a607b2007-07-07 22:19:48 -0700555 else
Patrick McHardy9a664822012-08-26 19:14:25 +0200556 *rtp_addr = ct->tuplehash[!dir].tuple.dst.u3;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800557
Patrick McHardyc7232c92012-08-26 19:14:06 +0200558 rtp_exp->saved_addr = rtp_exp->tuple.dst.u3;
Patrick McHardy9a664822012-08-26 19:14:25 +0200559 rtp_exp->tuple.dst.u3 = *rtp_addr;
Patrick McHardya9c1d352008-03-25 20:25:49 -0700560 rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
561 rtp_exp->dir = !dir;
Patrick McHardy9a664822012-08-26 19:14:25 +0200562 rtp_exp->expectfn = nf_nat_sip_expected;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800563
Patrick McHardyc7232c92012-08-26 19:14:06 +0200564 rtcp_exp->saved_addr = rtcp_exp->tuple.dst.u3;
Patrick McHardy9a664822012-08-26 19:14:25 +0200565 rtcp_exp->tuple.dst.u3 = *rtp_addr;
Patrick McHardya9c1d352008-03-25 20:25:49 -0700566 rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
567 rtcp_exp->dir = !dir;
Patrick McHardy9a664822012-08-26 19:14:25 +0200568 rtcp_exp->expectfn = nf_nat_sip_expected;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800569
Patrick McHardya9c1d352008-03-25 20:25:49 -0700570 /* Try to get same pair of ports: if not, try to change them. */
571 for (port = ntohs(rtp_exp->tuple.dst.u.udp.port);
572 port != 0; port += 2) {
Pablo Neira Ayuso5b92b612010-09-22 08:34:12 +0200573 int ret;
574
Patrick McHardya9c1d352008-03-25 20:25:49 -0700575 rtp_exp->tuple.dst.u.udp.port = htons(port);
Pablo Neira Ayuso5b92b612010-09-22 08:34:12 +0200576 ret = nf_ct_expect_related(rtp_exp);
577 if (ret == -EBUSY)
Patrick McHardya9c1d352008-03-25 20:25:49 -0700578 continue;
Pablo Neira Ayuso5b92b612010-09-22 08:34:12 +0200579 else if (ret < 0) {
580 port = 0;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800581 break;
Pablo Neira Ayuso5b92b612010-09-22 08:34:12 +0200582 }
583 rtcp_exp->tuple.dst.u.udp.port = htons(port + 1);
584 ret = nf_ct_expect_related(rtcp_exp);
585 if (ret == 0)
586 break;
Pablo Neira Ayuso3f509c62012-08-29 15:24:09 +0000587 else if (ret == -EBUSY) {
588 nf_ct_unexpect_related(rtp_exp);
589 continue;
590 } else if (ret < 0) {
Pablo Neira Ayuso5b92b612010-09-22 08:34:12 +0200591 nf_ct_unexpect_related(rtp_exp);
592 port = 0;
593 break;
594 }
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800595 }
596
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100597 if (port == 0) {
598 nf_ct_helper_log(skb, ct, "all ports in use for SDP media");
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700599 goto err1;
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100600 }
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800601
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700602 /* Update media port. */
603 if (rtp_exp->tuple.dst.u.udp.port != rtp_exp->saved_proto.udp.port &&
Patrick McHardy9a664822012-08-26 19:14:25 +0200604 !nf_nat_sdp_port(skb, protoff, dataoff, dptr, datalen,
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100605 mediaoff, medialen, port)) {
606 nf_ct_helper_log(skb, ct, "cannot mangle SDP message");
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700607 goto err2;
Pablo Neira Ayusob20ab9cc2013-02-10 18:56:56 +0100608 }
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700609
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800610 return NF_ACCEPT;
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700611
612err2:
613 nf_ct_unexpect_related(rtp_exp);
614 nf_ct_unexpect_related(rtcp_exp);
615err1:
616 return NF_DROP;
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800617}
618
Pablo Neira Ayuso544d5c72012-02-05 03:44:51 +0100619static struct nf_ct_helper_expectfn sip_nat = {
Patrick McHardy9a664822012-08-26 19:14:25 +0200620 .name = "sip",
621 .expectfn = nf_nat_sip_expected,
Pablo Neira Ayuso544d5c72012-02-05 03:44:51 +0100622};
623
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800624static void __exit nf_nat_sip_fini(void)
625{
Stephen Hemmingera9b3cd72011-08-01 16:19:00 +0000626 RCU_INIT_POINTER(nf_nat_sip_hook, NULL);
627 RCU_INIT_POINTER(nf_nat_sip_seq_adjust_hook, NULL);
628 RCU_INIT_POINTER(nf_nat_sip_expect_hook, NULL);
629 RCU_INIT_POINTER(nf_nat_sdp_addr_hook, NULL);
630 RCU_INIT_POINTER(nf_nat_sdp_port_hook, NULL);
631 RCU_INIT_POINTER(nf_nat_sdp_session_hook, NULL);
632 RCU_INIT_POINTER(nf_nat_sdp_media_hook, NULL);
Pablo Neira Ayuso544d5c72012-02-05 03:44:51 +0100633 nf_ct_helper_expectfn_unregister(&sip_nat);
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800634 synchronize_rcu();
635}
636
637static int __init nf_nat_sip_init(void)
638{
Patrick McHardyd1332e02007-11-05 20:43:30 -0800639 BUG_ON(nf_nat_sip_hook != NULL);
Patrick McHardy48f8ac22010-02-11 12:29:38 +0100640 BUG_ON(nf_nat_sip_seq_adjust_hook != NULL);
Patrick McHardy0f32a402008-03-25 20:25:13 -0700641 BUG_ON(nf_nat_sip_expect_hook != NULL);
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700642 BUG_ON(nf_nat_sdp_addr_hook != NULL);
Patrick McHardyc7f485a2008-03-25 20:26:43 -0700643 BUG_ON(nf_nat_sdp_port_hook != NULL);
Patrick McHardy4ab9e642008-03-25 20:26:08 -0700644 BUG_ON(nf_nat_sdp_session_hook != NULL);
645 BUG_ON(nf_nat_sdp_media_hook != NULL);
Patrick McHardy9a664822012-08-26 19:14:25 +0200646 RCU_INIT_POINTER(nf_nat_sip_hook, nf_nat_sip);
647 RCU_INIT_POINTER(nf_nat_sip_seq_adjust_hook, nf_nat_sip_seq_adjust);
648 RCU_INIT_POINTER(nf_nat_sip_expect_hook, nf_nat_sip_expect);
649 RCU_INIT_POINTER(nf_nat_sdp_addr_hook, nf_nat_sdp_addr);
650 RCU_INIT_POINTER(nf_nat_sdp_port_hook, nf_nat_sdp_port);
651 RCU_INIT_POINTER(nf_nat_sdp_session_hook, nf_nat_sdp_session);
652 RCU_INIT_POINTER(nf_nat_sdp_media_hook, nf_nat_sdp_media);
Pablo Neira Ayuso544d5c72012-02-05 03:44:51 +0100653 nf_ct_helper_expectfn_register(&sip_nat);
Patrick McHardy9fafcd72006-12-02 22:09:57 -0800654 return 0;
655}
656
657module_init(nf_nat_sip_init);
658module_exit(nf_nat_sip_fini);