1
2
3
4
5
6
7
8
9
10
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>
20#include <net/netfilter/nf_nat_helper.h>
21#include <net/netfilter/nf_conntrack_helper.h>
22#include <net/netfilter/nf_conntrack_expect.h>
23#include <net/netfilter/nf_conntrack_seqadj.h>
24#include <linux/netfilter/nf_conntrack_sip.h>
25
26#define NAT_HELPER_NAME "sip"
27
28MODULE_LICENSE("GPL");
29MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>");
30MODULE_DESCRIPTION("SIP NAT helper");
31MODULE_ALIAS_NF_NAT_HELPER(NAT_HELPER_NAME);
32
33static struct nf_conntrack_nat_helper nat_helper_sip =
34 NF_CT_NAT_HELPER_INIT(NAT_HELPER_NAME);
35
36static unsigned int mangle_packet(struct sk_buff *skb, unsigned int protoff,
37 unsigned int dataoff,
38 const char **dptr, unsigned int *datalen,
39 unsigned int matchoff, unsigned int matchlen,
40 const char *buffer, unsigned int buflen)
41{
42 enum ip_conntrack_info ctinfo;
43 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
44 struct tcphdr *th;
45 unsigned int baseoff;
46
47 if (nf_ct_protonum(ct) == IPPROTO_TCP) {
48 th = (struct tcphdr *)(skb->data + protoff);
49 baseoff = protoff + th->doff * 4;
50 matchoff += dataoff - baseoff;
51
52 if (!__nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
53 protoff, matchoff, matchlen,
54 buffer, buflen, false))
55 return 0;
56 } else {
57 baseoff = protoff + sizeof(struct udphdr);
58 matchoff += dataoff - baseoff;
59
60 if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo,
61 protoff, matchoff, matchlen,
62 buffer, buflen))
63 return 0;
64 }
65
66
67 *dptr = skb->data + dataoff;
68 *datalen += buflen - matchlen;
69 return 1;
70}
71
72static int sip_sprintf_addr(const struct nf_conn *ct, char *buffer,
73 const union nf_inet_addr *addr, bool delim)
74{
75 if (nf_ct_l3num(ct) == NFPROTO_IPV4)
76 return sprintf(buffer, "%pI4", &addr->ip);
77 else {
78 if (delim)
79 return sprintf(buffer, "[%pI6c]", &addr->ip6);
80 else
81 return sprintf(buffer, "%pI6c", &addr->ip6);
82 }
83}
84
85static int sip_sprintf_addr_port(const struct nf_conn *ct, char *buffer,
86 const union nf_inet_addr *addr, u16 port)
87{
88 if (nf_ct_l3num(ct) == NFPROTO_IPV4)
89 return sprintf(buffer, "%pI4:%u", &addr->ip, port);
90 else
91 return sprintf(buffer, "[%pI6c]:%u", &addr->ip6, port);
92}
93
94static int map_addr(struct sk_buff *skb, unsigned int protoff,
95 unsigned int dataoff,
96 const char **dptr, unsigned int *datalen,
97 unsigned int matchoff, unsigned int matchlen,
98 union nf_inet_addr *addr, __be16 port)
99{
100 enum ip_conntrack_info ctinfo;
101 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
102 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
103 struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
104 char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")];
105 unsigned int buflen;
106 union nf_inet_addr newaddr;
107 __be16 newport;
108
109 if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, addr) &&
110 ct->tuplehash[dir].tuple.src.u.udp.port == port) {
111 newaddr = ct->tuplehash[!dir].tuple.dst.u3;
112 newport = ct->tuplehash[!dir].tuple.dst.u.udp.port;
113 } else if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, addr) &&
114 ct->tuplehash[dir].tuple.dst.u.udp.port == port) {
115 newaddr = ct->tuplehash[!dir].tuple.src.u3;
116 newport = ct_sip_info->forced_dport ? :
117 ct->tuplehash[!dir].tuple.src.u.udp.port;
118 } else
119 return 1;
120
121 if (nf_inet_addr_cmp(&newaddr, addr) && newport == port)
122 return 1;
123
124 buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, ntohs(newport));
125 return mangle_packet(skb, protoff, dataoff, dptr, datalen,
126 matchoff, matchlen, buffer, buflen);
127}
128
129static int map_sip_addr(struct sk_buff *skb, unsigned int protoff,
130 unsigned int dataoff,
131 const char **dptr, unsigned int *datalen,
132 enum sip_header_types type)
133{
134 enum ip_conntrack_info ctinfo;
135 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
136 unsigned int matchlen, matchoff;
137 union nf_inet_addr addr;
138 __be16 port;
139
140 if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, type, NULL,
141 &matchoff, &matchlen, &addr, &port) <= 0)
142 return 1;
143 return map_addr(skb, protoff, dataoff, dptr, datalen,
144 matchoff, matchlen, &addr, port);
145}
146
147static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,
148 unsigned int dataoff,
149 const char **dptr, unsigned int *datalen)
150{
151 enum ip_conntrack_info ctinfo;
152 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
153 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
154 struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
155 unsigned int coff, matchoff, matchlen;
156 enum sip_header_types hdr;
157 union nf_inet_addr addr;
158 __be16 port;
159 int request, in_header;
160
161
162 if (strncasecmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) {
163 if (ct_sip_parse_request(ct, *dptr, *datalen,
164 &matchoff, &matchlen,
165 &addr, &port) > 0 &&
166 !map_addr(skb, protoff, dataoff, dptr, datalen,
167 matchoff, matchlen, &addr, port)) {
168 nf_ct_helper_log(skb, ct, "cannot mangle SIP message");
169 return NF_DROP;
170 }
171 request = 1;
172 } else
173 request = 0;
174
175 if (nf_ct_protonum(ct) == IPPROTO_TCP)
176 hdr = SIP_HDR_VIA_TCP;
177 else
178 hdr = SIP_HDR_VIA_UDP;
179
180
181 if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
182 hdr, NULL, &matchoff, &matchlen,
183 &addr, &port) > 0) {
184 unsigned int olen, matchend, poff, plen, buflen, n;
185 char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")];
186
187
188
189 if (request) {
190 if (!nf_inet_addr_cmp(&addr,
191 &ct->tuplehash[dir].tuple.src.u3) ||
192 port != ct->tuplehash[dir].tuple.src.u.udp.port)
193 goto next;
194 } else {
195 if (!nf_inet_addr_cmp(&addr,
196 &ct->tuplehash[dir].tuple.dst.u3) ||
197 port != ct->tuplehash[dir].tuple.dst.u.udp.port)
198 goto next;
199 }
200
201 olen = *datalen;
202 if (!map_addr(skb, protoff, dataoff, dptr, datalen,
203 matchoff, matchlen, &addr, port)) {
204 nf_ct_helper_log(skb, ct, "cannot mangle Via header");
205 return NF_DROP;
206 }
207
208 matchend = matchoff + matchlen + *datalen - olen;
209
210
211
212 if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
213 "maddr=", &poff, &plen,
214 &addr, true) > 0 &&
215 nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3) &&
216 !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3)) {
217 buflen = sip_sprintf_addr(ct, buffer,
218 &ct->tuplehash[!dir].tuple.dst.u3,
219 true);
220 if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
221 poff, plen, buffer, buflen)) {
222 nf_ct_helper_log(skb, ct, "cannot mangle maddr");
223 return NF_DROP;
224 }
225 }
226
227
228
229 if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
230 "received=", &poff, &plen,
231 &addr, false) > 0 &&
232 nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.dst.u3) &&
233 !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.src.u3)) {
234 buflen = sip_sprintf_addr(ct, buffer,
235 &ct->tuplehash[!dir].tuple.src.u3,
236 false);
237 if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
238 poff, plen, buffer, buflen)) {
239 nf_ct_helper_log(skb, ct, "cannot mangle received");
240 return NF_DROP;
241 }
242 }
243
244
245
246 if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen,
247 "rport=", &poff, &plen,
248 &n) > 0 &&
249 htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port &&
250 htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) {
251 __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port;
252 buflen = sprintf(buffer, "%u", ntohs(p));
253 if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
254 poff, plen, buffer, buflen)) {
255 nf_ct_helper_log(skb, ct, "cannot mangle rport");
256 return NF_DROP;
257 }
258 }
259 }
260
261next:
262
263 coff = 0;
264 in_header = 0;
265 while (ct_sip_parse_header_uri(ct, *dptr, &coff, *datalen,
266 SIP_HDR_CONTACT, &in_header,
267 &matchoff, &matchlen,
268 &addr, &port) > 0) {
269 if (!map_addr(skb, protoff, dataoff, dptr, datalen,
270 matchoff, matchlen,
271 &addr, port)) {
272 nf_ct_helper_log(skb, ct, "cannot mangle contact");
273 return NF_DROP;
274 }
275 }
276
277 if (!map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_FROM) ||
278 !map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_TO)) {
279 nf_ct_helper_log(skb, ct, "cannot mangle SIP from/to");
280 return NF_DROP;
281 }
282
283
284 if (dir == IP_CT_DIR_REPLY && ct_sip_info->forced_dport) {
285 struct udphdr *uh;
286
287 if (!skb_make_writable(skb, skb->len)) {
288 nf_ct_helper_log(skb, ct, "cannot mangle packet");
289 return NF_DROP;
290 }
291
292 uh = (void *)skb->data + protoff;
293 uh->dest = ct_sip_info->forced_dport;
294
295 if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, protoff,
296 0, 0, NULL, 0)) {
297 nf_ct_helper_log(skb, ct, "cannot mangle packet");
298 return NF_DROP;
299 }
300 }
301
302 return NF_ACCEPT;
303}
304
305static void nf_nat_sip_seq_adjust(struct sk_buff *skb, unsigned int protoff,
306 s16 off)
307{
308 enum ip_conntrack_info ctinfo;
309 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
310 const struct tcphdr *th;
311
312 if (nf_ct_protonum(ct) != IPPROTO_TCP || off == 0)
313 return;
314
315 th = (struct tcphdr *)(skb->data + protoff);
316 nf_ct_seqadj_set(ct, ctinfo, th->seq, off);
317}
318
319
320static void nf_nat_sip_expected(struct nf_conn *ct,
321 struct nf_conntrack_expect *exp)
322{
323 struct nf_nat_range2 range;
324
325
326 BUG_ON(ct->status & IPS_NAT_DONE_MASK);
327
328
329 range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED);
330 range.min_proto = range.max_proto = exp->saved_proto;
331 range.min_addr = range.max_addr = exp->saved_addr;
332 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST);
333
334
335
336 if (nf_inet_addr_cmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3,
337 &ct->master->tuplehash[exp->dir].tuple.src.u3)) {
338 range.flags = NF_NAT_RANGE_MAP_IPS;
339 range.min_addr = range.max_addr
340 = ct->master->tuplehash[!exp->dir].tuple.dst.u3;
341 nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC);
342 }
343}
344
345static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff,
346 unsigned int dataoff,
347 const char **dptr, unsigned int *datalen,
348 struct nf_conntrack_expect *exp,
349 unsigned int matchoff,
350 unsigned int matchlen)
351{
352 enum ip_conntrack_info ctinfo;
353 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
354 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
355 struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
356 union nf_inet_addr newaddr;
357 u_int16_t port;
358 __be16 srcport;
359 char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")];
360 unsigned int buflen;
361
362
363 if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3,
364 &ct->tuplehash[!dir].tuple.dst.u3))
365 newaddr = exp->tuple.dst.u3;
366 else
367 newaddr = ct->tuplehash[!dir].tuple.dst.u3;
368
369
370
371
372 srcport = ct_sip_info->forced_dport ? :
373 ct->tuplehash[dir].tuple.src.u.udp.port;
374 if (exp->tuple.dst.u.udp.port == srcport)
375 port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port);
376 else
377 port = ntohs(exp->tuple.dst.u.udp.port);
378
379 exp->saved_addr = exp->tuple.dst.u3;
380 exp->tuple.dst.u3 = newaddr;
381 exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port;
382 exp->dir = !dir;
383 exp->expectfn = nf_nat_sip_expected;
384
385 for (; port != 0; port++) {
386 int ret;
387
388 exp->tuple.dst.u.udp.port = htons(port);
389 ret = nf_ct_expect_related(exp);
390 if (ret == 0)
391 break;
392 else if (ret != -EBUSY) {
393 port = 0;
394 break;
395 }
396 }
397
398 if (port == 0) {
399 nf_ct_helper_log(skb, ct, "all ports in use for SIP");
400 return NF_DROP;
401 }
402
403 if (!nf_inet_addr_cmp(&exp->tuple.dst.u3, &exp->saved_addr) ||
404 exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) {
405 buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, port);
406 if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
407 matchoff, matchlen, buffer, buflen)) {
408 nf_ct_helper_log(skb, ct, "cannot mangle packet");
409 goto err;
410 }
411 }
412 return NF_ACCEPT;
413
414err:
415 nf_ct_unexpect_related(exp);
416 return NF_DROP;
417}
418
419static int mangle_content_len(struct sk_buff *skb, unsigned int protoff,
420 unsigned int dataoff,
421 const char **dptr, unsigned int *datalen)
422{
423 enum ip_conntrack_info ctinfo;
424 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
425 unsigned int matchoff, matchlen;
426 char buffer[sizeof("65536")];
427 int buflen, c_len;
428
429
430 if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen,
431 SDP_HDR_VERSION, SDP_HDR_UNSPEC,
432 &matchoff, &matchlen) <= 0)
433 return 0;
434 c_len = *datalen - matchoff + strlen("v=");
435
436
437 if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CONTENT_LENGTH,
438 &matchoff, &matchlen) <= 0)
439 return 0;
440
441 buflen = sprintf(buffer, "%u", c_len);
442 return mangle_packet(skb, protoff, dataoff, dptr, datalen,
443 matchoff, matchlen, buffer, buflen);
444}
445
446static int mangle_sdp_packet(struct sk_buff *skb, unsigned int protoff,
447 unsigned int dataoff,
448 const char **dptr, unsigned int *datalen,
449 unsigned int sdpoff,
450 enum sdp_header_types type,
451 enum sdp_header_types term,
452 char *buffer, int buflen)
453{
454 enum ip_conntrack_info ctinfo;
455 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
456 unsigned int matchlen, matchoff;
457
458 if (ct_sip_get_sdp_header(ct, *dptr, sdpoff, *datalen, type, term,
459 &matchoff, &matchlen) <= 0)
460 return -ENOENT;
461 return mangle_packet(skb, protoff, dataoff, dptr, datalen,
462 matchoff, matchlen, buffer, buflen) ? 0 : -EINVAL;
463}
464
465static unsigned int nf_nat_sdp_addr(struct sk_buff *skb, unsigned int protoff,
466 unsigned int dataoff,
467 const char **dptr, unsigned int *datalen,
468 unsigned int sdpoff,
469 enum sdp_header_types type,
470 enum sdp_header_types term,
471 const union nf_inet_addr *addr)
472{
473 enum ip_conntrack_info ctinfo;
474 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
475 char buffer[INET6_ADDRSTRLEN];
476 unsigned int buflen;
477
478 buflen = sip_sprintf_addr(ct, buffer, addr, false);
479 if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen,
480 sdpoff, type, term, buffer, buflen))
481 return 0;
482
483 return mangle_content_len(skb, protoff, dataoff, dptr, datalen);
484}
485
486static unsigned int nf_nat_sdp_port(struct sk_buff *skb, unsigned int protoff,
487 unsigned int dataoff,
488 const char **dptr, unsigned int *datalen,
489 unsigned int matchoff,
490 unsigned int matchlen,
491 u_int16_t port)
492{
493 char buffer[sizeof("nnnnn")];
494 unsigned int buflen;
495
496 buflen = sprintf(buffer, "%u", port);
497 if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
498 matchoff, matchlen, buffer, buflen))
499 return 0;
500
501 return mangle_content_len(skb, protoff, dataoff, dptr, datalen);
502}
503
504static unsigned int nf_nat_sdp_session(struct sk_buff *skb, unsigned int protoff,
505 unsigned int dataoff,
506 const char **dptr, unsigned int *datalen,
507 unsigned int sdpoff,
508 const union nf_inet_addr *addr)
509{
510 enum ip_conntrack_info ctinfo;
511 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
512 char buffer[INET6_ADDRSTRLEN];
513 unsigned int buflen;
514
515
516 buflen = sip_sprintf_addr(ct, buffer, addr, false);
517 if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff,
518 SDP_HDR_OWNER, SDP_HDR_MEDIA, buffer, buflen))
519 return 0;
520
521 switch (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff,
522 SDP_HDR_CONNECTION, SDP_HDR_MEDIA,
523 buffer, buflen)) {
524 case 0:
525
526
527
528
529
530
531
532 case -ENOENT:
533 break;
534 default:
535 return 0;
536 }
537
538 return mangle_content_len(skb, protoff, dataoff, dptr, datalen);
539}
540
541
542
543static unsigned int nf_nat_sdp_media(struct sk_buff *skb, unsigned int protoff,
544 unsigned int dataoff,
545 const char **dptr, unsigned int *datalen,
546 struct nf_conntrack_expect *rtp_exp,
547 struct nf_conntrack_expect *rtcp_exp,
548 unsigned int mediaoff,
549 unsigned int medialen,
550 union nf_inet_addr *rtp_addr)
551{
552 enum ip_conntrack_info ctinfo;
553 struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
554 enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
555 u_int16_t port;
556
557
558 if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3,
559 &ct->tuplehash[!dir].tuple.dst.u3))
560 *rtp_addr = rtp_exp->tuple.dst.u3;
561 else
562 *rtp_addr = ct->tuplehash[!dir].tuple.dst.u3;
563
564 rtp_exp->saved_addr = rtp_exp->tuple.dst.u3;
565 rtp_exp->tuple.dst.u3 = *rtp_addr;
566 rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
567 rtp_exp->dir = !dir;
568 rtp_exp->expectfn = nf_nat_sip_expected;
569
570 rtcp_exp->saved_addr = rtcp_exp->tuple.dst.u3;
571 rtcp_exp->tuple.dst.u3 = *rtp_addr;
572 rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
573 rtcp_exp->dir = !dir;
574 rtcp_exp->expectfn = nf_nat_sip_expected;
575
576
577 for (port = ntohs(rtp_exp->tuple.dst.u.udp.port);
578 port != 0; port += 2) {
579 int ret;
580
581 rtp_exp->tuple.dst.u.udp.port = htons(port);
582 ret = nf_ct_expect_related(rtp_exp);
583 if (ret == -EBUSY)
584 continue;
585 else if (ret < 0) {
586 port = 0;
587 break;
588 }
589 rtcp_exp->tuple.dst.u.udp.port = htons(port + 1);
590 ret = nf_ct_expect_related(rtcp_exp);
591 if (ret == 0)
592 break;
593 else if (ret == -EBUSY) {
594 nf_ct_unexpect_related(rtp_exp);
595 continue;
596 } else if (ret < 0) {
597 nf_ct_unexpect_related(rtp_exp);
598 port = 0;
599 break;
600 }
601 }
602
603 if (port == 0) {
604 nf_ct_helper_log(skb, ct, "all ports in use for SDP media");
605 goto err1;
606 }
607
608
609 if (rtp_exp->tuple.dst.u.udp.port != rtp_exp->saved_proto.udp.port &&
610 !nf_nat_sdp_port(skb, protoff, dataoff, dptr, datalen,
611 mediaoff, medialen, port)) {
612 nf_ct_helper_log(skb, ct, "cannot mangle SDP message");
613 goto err2;
614 }
615
616 return NF_ACCEPT;
617
618err2:
619 nf_ct_unexpect_related(rtp_exp);
620 nf_ct_unexpect_related(rtcp_exp);
621err1:
622 return NF_DROP;
623}
624
625static struct nf_ct_helper_expectfn sip_nat = {
626 .name = "sip",
627 .expectfn = nf_nat_sip_expected,
628};
629
630static void __exit nf_nat_sip_fini(void)
631{
632 nf_nat_helper_unregister(&nat_helper_sip);
633 RCU_INIT_POINTER(nf_nat_sip_hooks, NULL);
634 nf_ct_helper_expectfn_unregister(&sip_nat);
635 synchronize_rcu();
636}
637
638static const struct nf_nat_sip_hooks sip_hooks = {
639 .msg = nf_nat_sip,
640 .seq_adjust = nf_nat_sip_seq_adjust,
641 .expect = nf_nat_sip_expect,
642 .sdp_addr = nf_nat_sdp_addr,
643 .sdp_port = nf_nat_sdp_port,
644 .sdp_session = nf_nat_sdp_session,
645 .sdp_media = nf_nat_sdp_media,
646};
647
648static int __init nf_nat_sip_init(void)
649{
650 BUG_ON(nf_nat_sip_hooks != NULL);
651 nf_nat_helper_register(&nat_helper_sip);
652 RCU_INIT_POINTER(nf_nat_sip_hooks, &sip_hooks);
653 nf_ct_helper_expectfn_register(&sip_nat);
654 return 0;
655}
656
657module_init(nf_nat_sip_init);
658module_exit(nf_nat_sip_fini);
659