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