diff options
-rw-r--r-- | include/linux/netfilter/nf_conntrack_sip.h | 18 | ||||
-rw-r--r-- | include/net/netfilter/nf_conntrack.h | 4 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_nat_sip.c | 111 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_sip.c | 232 |
4 files changed, 332 insertions, 33 deletions
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 87e402825dba..7cc84ed0c5da 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h | |||
@@ -5,6 +5,17 @@ | |||
5 | #define SIP_PORT 5060 | 5 | #define SIP_PORT 5060 |
6 | #define SIP_TIMEOUT 3600 | 6 | #define SIP_TIMEOUT 3600 |
7 | 7 | ||
8 | struct nf_ct_sip_master { | ||
9 | unsigned int register_cseq; | ||
10 | }; | ||
11 | |||
12 | enum sip_expectation_classes { | ||
13 | SIP_EXPECT_SIGNALLING, | ||
14 | SIP_EXPECT_AUDIO, | ||
15 | __SIP_EXPECT_MAX | ||
16 | }; | ||
17 | #define SIP_EXPECT_MAX (__SIP_EXPECT_MAX - 1) | ||
18 | |||
8 | struct sip_handler { | 19 | struct sip_handler { |
9 | const char *method; | 20 | const char *method; |
10 | unsigned int len; | 21 | unsigned int len; |
@@ -59,6 +70,7 @@ enum sip_header_types { | |||
59 | SIP_HDR_TO, | 70 | SIP_HDR_TO, |
60 | SIP_HDR_CONTACT, | 71 | SIP_HDR_CONTACT, |
61 | SIP_HDR_VIA, | 72 | SIP_HDR_VIA, |
73 | SIP_HDR_EXPIRES, | ||
62 | SIP_HDR_CONTENT_LENGTH, | 74 | SIP_HDR_CONTENT_LENGTH, |
63 | }; | 75 | }; |
64 | 76 | ||
@@ -75,6 +87,12 @@ enum sdp_header_types { | |||
75 | extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, | 87 | extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, |
76 | const char **dptr, | 88 | const char **dptr, |
77 | unsigned int *datalen); | 89 | unsigned int *datalen); |
90 | extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, | ||
91 | const char **dptr, | ||
92 | unsigned int *datalen, | ||
93 | struct nf_conntrack_expect *exp, | ||
94 | unsigned int matchoff, | ||
95 | unsigned int matchlen); | ||
78 | extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, | 96 | extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, |
79 | const char **dptr, | 97 | const char **dptr, |
80 | unsigned int *datalen, | 98 | unsigned int *datalen, |
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 922877133598..4a4f870d2a5e 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h | |||
@@ -46,6 +46,7 @@ union nf_conntrack_expect_proto { | |||
46 | #include <linux/netfilter/nf_conntrack_pptp.h> | 46 | #include <linux/netfilter/nf_conntrack_pptp.h> |
47 | #include <linux/netfilter/nf_conntrack_h323.h> | 47 | #include <linux/netfilter/nf_conntrack_h323.h> |
48 | #include <linux/netfilter/nf_conntrack_sane.h> | 48 | #include <linux/netfilter/nf_conntrack_sane.h> |
49 | #include <linux/netfilter/nf_conntrack_sip.h> | ||
49 | 50 | ||
50 | /* per conntrack: application helper private data */ | 51 | /* per conntrack: application helper private data */ |
51 | union nf_conntrack_help { | 52 | union nf_conntrack_help { |
@@ -54,6 +55,7 @@ union nf_conntrack_help { | |||
54 | struct nf_ct_pptp_master ct_pptp_info; | 55 | struct nf_ct_pptp_master ct_pptp_info; |
55 | struct nf_ct_h323_master ct_h323_info; | 56 | struct nf_ct_h323_master ct_h323_info; |
56 | struct nf_ct_sane_master ct_sane_info; | 57 | struct nf_ct_sane_master ct_sane_info; |
58 | struct nf_ct_sip_master ct_sip_info; | ||
57 | }; | 59 | }; |
58 | 60 | ||
59 | #include <linux/types.h> | 61 | #include <linux/types.h> |
@@ -76,7 +78,7 @@ do { \ | |||
76 | struct nf_conntrack_helper; | 78 | struct nf_conntrack_helper; |
77 | 79 | ||
78 | /* Must be kept in sync with the classes defined by helpers */ | 80 | /* Must be kept in sync with the classes defined by helpers */ |
79 | #define NF_CT_MAX_EXPECT_CLASSES 1 | 81 | #define NF_CT_MAX_EXPECT_CLASSES 2 |
80 | 82 | ||
81 | /* nf_conn feature for connections that have a helper */ | 83 | /* nf_conn feature for connections that have a helper */ |
82 | struct nf_conn_help { | 84 | struct nf_conn_help { |
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index b443618a857f..4b85e21a2a4a 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c | |||
@@ -205,6 +205,91 @@ next: | |||
205 | return NF_ACCEPT; | 205 | return NF_ACCEPT; |
206 | } | 206 | } |
207 | 207 | ||
208 | /* Handles expected signalling connections and media streams */ | ||
209 | static void ip_nat_sip_expected(struct nf_conn *ct, | ||
210 | struct nf_conntrack_expect *exp) | ||
211 | { | ||
212 | struct nf_nat_range range; | ||
213 | |||
214 | /* This must be a fresh one. */ | ||
215 | BUG_ON(ct->status & IPS_NAT_DONE_MASK); | ||
216 | |||
217 | /* For DST manip, map port here to where it's expected. */ | ||
218 | range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); | ||
219 | range.min = range.max = exp->saved_proto; | ||
220 | range.min_ip = range.max_ip = exp->saved_ip; | ||
221 | nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST); | ||
222 | |||
223 | /* Change src to where master sends to, but only if the connection | ||
224 | * actually came from the same source. */ | ||
225 | if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == | ||
226 | ct->master->tuplehash[exp->dir].tuple.src.u3.ip) { | ||
227 | range.flags = IP_NAT_RANGE_MAP_IPS; | ||
228 | range.min_ip = range.max_ip | ||
229 | = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; | ||
230 | nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC); | ||
231 | } | ||
232 | } | ||
233 | |||
234 | static unsigned int ip_nat_sip_expect(struct sk_buff *skb, | ||
235 | const char **dptr, unsigned int *datalen, | ||
236 | struct nf_conntrack_expect *exp, | ||
237 | unsigned int matchoff, | ||
238 | unsigned int matchlen) | ||
239 | { | ||
240 | enum ip_conntrack_info ctinfo; | ||
241 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | ||
242 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
243 | __be32 newip; | ||
244 | u_int16_t port; | ||
245 | char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; | ||
246 | unsigned buflen; | ||
247 | |||
248 | /* Connection will come from reply */ | ||
249 | if (ct->tuplehash[dir].tuple.src.u3.ip == ct->tuplehash[!dir].tuple.dst.u3.ip) | ||
250 | newip = exp->tuple.dst.u3.ip; | ||
251 | else | ||
252 | newip = ct->tuplehash[!dir].tuple.dst.u3.ip; | ||
253 | |||
254 | /* If the signalling port matches the connection's source port in the | ||
255 | * original direction, try to use the destination port in the opposite | ||
256 | * direction. */ | ||
257 | if (exp->tuple.dst.u.udp.port == | ||
258 | ct->tuplehash[dir].tuple.src.u.udp.port) | ||
259 | port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port); | ||
260 | else | ||
261 | port = ntohs(exp->tuple.dst.u.udp.port); | ||
262 | |||
263 | exp->saved_ip = exp->tuple.dst.u3.ip; | ||
264 | exp->tuple.dst.u3.ip = newip; | ||
265 | exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port; | ||
266 | exp->dir = !dir; | ||
267 | exp->expectfn = ip_nat_sip_expected; | ||
268 | |||
269 | for (; port != 0; port++) { | ||
270 | exp->tuple.dst.u.udp.port = htons(port); | ||
271 | if (nf_ct_expect_related(exp) == 0) | ||
272 | break; | ||
273 | } | ||
274 | |||
275 | if (port == 0) | ||
276 | return NF_DROP; | ||
277 | |||
278 | if (exp->tuple.dst.u3.ip != exp->saved_ip || | ||
279 | exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) { | ||
280 | buflen = sprintf(buffer, "%u.%u.%u.%u:%u", | ||
281 | NIPQUAD(newip), port); | ||
282 | if (!mangle_packet(skb, dptr, datalen, matchoff, matchlen, | ||
283 | buffer, buflen)) | ||
284 | goto err; | ||
285 | } | ||
286 | return NF_ACCEPT; | ||
287 | |||
288 | err: | ||
289 | nf_ct_unexpect_related(exp); | ||
290 | return NF_DROP; | ||
291 | } | ||
292 | |||
208 | static int mangle_content_len(struct sk_buff *skb, | 293 | static int mangle_content_len(struct sk_buff *skb, |
209 | const char **dptr, unsigned int *datalen) | 294 | const char **dptr, unsigned int *datalen) |
210 | { | 295 | { |
@@ -275,27 +360,6 @@ static unsigned int mangle_sdp(struct sk_buff *skb, | |||
275 | return mangle_content_len(skb, dptr, datalen); | 360 | return mangle_content_len(skb, dptr, datalen); |
276 | } | 361 | } |
277 | 362 | ||
278 | static void ip_nat_sdp_expect(struct nf_conn *ct, | ||
279 | struct nf_conntrack_expect *exp) | ||
280 | { | ||
281 | struct nf_nat_range range; | ||
282 | |||
283 | /* This must be a fresh one. */ | ||
284 | BUG_ON(ct->status & IPS_NAT_DONE_MASK); | ||
285 | |||
286 | /* For DST manip, map port here to where it's expected. */ | ||
287 | range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); | ||
288 | range.min = range.max = exp->saved_proto; | ||
289 | range.min_ip = range.max_ip = exp->saved_ip; | ||
290 | nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST); | ||
291 | |||
292 | /* Change src to where master sends to */ | ||
293 | range.flags = IP_NAT_RANGE_MAP_IPS; | ||
294 | range.min_ip = range.max_ip | ||
295 | = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; | ||
296 | nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC); | ||
297 | } | ||
298 | |||
299 | /* So, this packet has hit the connection tracking matching code. | 363 | /* So, this packet has hit the connection tracking matching code. |
300 | Mangle it, and change the expectation to match the new version. */ | 364 | Mangle it, and change the expectation to match the new version. */ |
301 | static unsigned int ip_nat_sdp(struct sk_buff *skb, | 365 | static unsigned int ip_nat_sdp(struct sk_buff *skb, |
@@ -322,7 +386,7 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb, | |||
322 | 386 | ||
323 | /* When you see the packet, we need to NAT it the same as the | 387 | /* When you see the packet, we need to NAT it the same as the |
324 | this one. */ | 388 | this one. */ |
325 | exp->expectfn = ip_nat_sdp_expect; | 389 | exp->expectfn = ip_nat_sip_expected; |
326 | 390 | ||
327 | /* Try to get same port: if not, try to change it. */ | 391 | /* Try to get same port: if not, try to change it. */ |
328 | for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) { | 392 | for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) { |
@@ -344,6 +408,7 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb, | |||
344 | static void __exit nf_nat_sip_fini(void) | 408 | static void __exit nf_nat_sip_fini(void) |
345 | { | 409 | { |
346 | rcu_assign_pointer(nf_nat_sip_hook, NULL); | 410 | rcu_assign_pointer(nf_nat_sip_hook, NULL); |
411 | rcu_assign_pointer(nf_nat_sip_expect_hook, NULL); | ||
347 | rcu_assign_pointer(nf_nat_sdp_hook, NULL); | 412 | rcu_assign_pointer(nf_nat_sdp_hook, NULL); |
348 | synchronize_rcu(); | 413 | synchronize_rcu(); |
349 | } | 414 | } |
@@ -351,8 +416,10 @@ static void __exit nf_nat_sip_fini(void) | |||
351 | static int __init nf_nat_sip_init(void) | 416 | static int __init nf_nat_sip_init(void) |
352 | { | 417 | { |
353 | BUG_ON(nf_nat_sip_hook != NULL); | 418 | BUG_ON(nf_nat_sip_hook != NULL); |
419 | BUG_ON(nf_nat_sip_expect_hook != NULL); | ||
354 | BUG_ON(nf_nat_sdp_hook != NULL); | 420 | BUG_ON(nf_nat_sdp_hook != NULL); |
355 | rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); | 421 | rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); |
422 | rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect); | ||
356 | rcu_assign_pointer(nf_nat_sdp_hook, ip_nat_sdp); | 423 | rcu_assign_pointer(nf_nat_sdp_hook, ip_nat_sdp); |
357 | return 0; | 424 | return 0; |
358 | } | 425 | } |
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 126f30842d60..043aa557e7a8 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c | |||
@@ -37,11 +37,24 @@ static unsigned int sip_timeout __read_mostly = SIP_TIMEOUT; | |||
37 | module_param(sip_timeout, uint, 0600); | 37 | module_param(sip_timeout, uint, 0600); |
38 | MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session"); | 38 | MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session"); |
39 | 39 | ||
40 | static int sip_direct_signalling __read_mostly = 1; | ||
41 | module_param(sip_direct_signalling, int, 0600); | ||
42 | MODULE_PARM_DESC(sip_direct_signalling, "expect incoming calls from registrar " | ||
43 | "only (default 1)"); | ||
44 | |||
40 | unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, | 45 | unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, |
41 | const char **dptr, | 46 | const char **dptr, |
42 | unsigned int *datalen) __read_mostly; | 47 | unsigned int *datalen) __read_mostly; |
43 | EXPORT_SYMBOL_GPL(nf_nat_sip_hook); | 48 | EXPORT_SYMBOL_GPL(nf_nat_sip_hook); |
44 | 49 | ||
50 | unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, | ||
51 | const char **dptr, | ||
52 | unsigned int *datalen, | ||
53 | struct nf_conntrack_expect *exp, | ||
54 | unsigned int matchoff, | ||
55 | unsigned int matchlen) __read_mostly; | ||
56 | EXPORT_SYMBOL_GPL(nf_nat_sip_expect_hook); | ||
57 | |||
45 | unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, | 58 | unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, |
46 | const char **dptr, | 59 | const char **dptr, |
47 | unsigned int *datalen, | 60 | unsigned int *datalen, |
@@ -218,6 +231,7 @@ static const struct sip_header ct_sip_hdrs[] = { | |||
218 | [SIP_HDR_TO] = SIP_HDR("To", "t", "sip:", skp_epaddr_len), | 231 | [SIP_HDR_TO] = SIP_HDR("To", "t", "sip:", skp_epaddr_len), |
219 | [SIP_HDR_CONTACT] = SIP_HDR("Contact", "m", "sip:", skp_epaddr_len), | 232 | [SIP_HDR_CONTACT] = SIP_HDR("Contact", "m", "sip:", skp_epaddr_len), |
220 | [SIP_HDR_VIA] = SIP_HDR("Via", "v", "UDP ", epaddr_len), | 233 | [SIP_HDR_VIA] = SIP_HDR("Via", "v", "UDP ", epaddr_len), |
234 | [SIP_HDR_EXPIRES] = SIP_HDR("Expires", NULL, NULL, digits_len), | ||
221 | [SIP_HDR_CONTENT_LENGTH] = SIP_HDR("Content-Length", "l", NULL, digits_len), | 235 | [SIP_HDR_CONTENT_LENGTH] = SIP_HDR("Content-Length", "l", NULL, digits_len), |
222 | }; | 236 | }; |
223 | 237 | ||
@@ -592,18 +606,50 @@ int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr, | |||
592 | } | 606 | } |
593 | EXPORT_SYMBOL_GPL(ct_sip_get_sdp_header); | 607 | EXPORT_SYMBOL_GPL(ct_sip_get_sdp_header); |
594 | 608 | ||
595 | static void flush_expectations(struct nf_conn *ct) | 609 | static int refresh_signalling_expectation(struct nf_conn *ct, |
610 | union nf_inet_addr *addr, | ||
611 | __be16 port, | ||
612 | unsigned int expires) | ||
596 | { | 613 | { |
597 | struct nf_conn_help *help = nfct_help(ct); | 614 | struct nf_conn_help *help = nfct_help(ct); |
598 | struct nf_conntrack_expect *exp; | 615 | struct nf_conntrack_expect *exp; |
599 | struct hlist_node *n, *next; | 616 | struct hlist_node *n, *next; |
617 | int found = 0; | ||
600 | 618 | ||
601 | spin_lock_bh(&nf_conntrack_lock); | 619 | spin_lock_bh(&nf_conntrack_lock); |
602 | hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) { | 620 | hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) { |
621 | if (exp->class != SIP_EXPECT_SIGNALLING || | ||
622 | !nf_inet_addr_cmp(&exp->tuple.dst.u3, addr) || | ||
623 | exp->tuple.dst.u.udp.port != port) | ||
624 | continue; | ||
625 | if (!del_timer(&exp->timeout)) | ||
626 | continue; | ||
627 | exp->flags &= ~NF_CT_EXPECT_INACTIVE; | ||
628 | exp->timeout.expires = jiffies + expires * HZ; | ||
629 | add_timer(&exp->timeout); | ||
630 | found = 1; | ||
631 | break; | ||
632 | } | ||
633 | spin_unlock_bh(&nf_conntrack_lock); | ||
634 | return found; | ||
635 | } | ||
636 | |||
637 | static void flush_expectations(struct nf_conn *ct, bool media) | ||
638 | { | ||
639 | struct nf_conn_help *help = nfct_help(ct); | ||
640 | struct nf_conntrack_expect *exp; | ||
641 | struct hlist_node *n, *next; | ||
642 | |||
643 | spin_lock_bh(&nf_conntrack_lock); | ||
644 | hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) { | ||
645 | if ((exp->class != SIP_EXPECT_SIGNALLING) ^ media) | ||
646 | continue; | ||
603 | if (!del_timer(&exp->timeout)) | 647 | if (!del_timer(&exp->timeout)) |
604 | continue; | 648 | continue; |
605 | nf_ct_unlink_expect(exp); | 649 | nf_ct_unlink_expect(exp); |
606 | nf_ct_expect_put(exp); | 650 | nf_ct_expect_put(exp); |
651 | if (!media) | ||
652 | break; | ||
607 | } | 653 | } |
608 | spin_unlock_bh(&nf_conntrack_lock); | 654 | spin_unlock_bh(&nf_conntrack_lock); |
609 | } | 655 | } |
@@ -623,7 +669,7 @@ static int set_expected_rtp(struct sk_buff *skb, | |||
623 | exp = nf_ct_expect_alloc(ct); | 669 | exp = nf_ct_expect_alloc(ct); |
624 | if (exp == NULL) | 670 | if (exp == NULL) |
625 | return NF_DROP; | 671 | return NF_DROP; |
626 | nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, family, | 672 | nf_ct_expect_init(exp, SIP_EXPECT_AUDIO, family, |
627 | &ct->tuplehash[!dir].tuple.src.u3, addr, | 673 | &ct->tuplehash[!dir].tuple.src.u3, addr, |
628 | IPPROTO_UDP, NULL, &port); | 674 | IPPROTO_UDP, NULL, &port); |
629 | 675 | ||
@@ -688,7 +734,7 @@ static int process_invite_response(struct sk_buff *skb, | |||
688 | (code >= 200 && code <= 299)) | 734 | (code >= 200 && code <= 299)) |
689 | return process_sdp(skb, dptr, datalen, cseq); | 735 | return process_sdp(skb, dptr, datalen, cseq); |
690 | else { | 736 | else { |
691 | flush_expectations(ct); | 737 | flush_expectations(ct, true); |
692 | return NF_ACCEPT; | 738 | return NF_ACCEPT; |
693 | } | 739 | } |
694 | } | 740 | } |
@@ -704,7 +750,7 @@ static int process_update_response(struct sk_buff *skb, | |||
704 | (code >= 200 && code <= 299)) | 750 | (code >= 200 && code <= 299)) |
705 | return process_sdp(skb, dptr, datalen, cseq); | 751 | return process_sdp(skb, dptr, datalen, cseq); |
706 | else { | 752 | else { |
707 | flush_expectations(ct); | 753 | flush_expectations(ct, true); |
708 | return NF_ACCEPT; | 754 | return NF_ACCEPT; |
709 | } | 755 | } |
710 | } | 756 | } |
@@ -720,7 +766,7 @@ static int process_prack_response(struct sk_buff *skb, | |||
720 | (code >= 200 && code <= 299)) | 766 | (code >= 200 && code <= 299)) |
721 | return process_sdp(skb, dptr, datalen, cseq); | 767 | return process_sdp(skb, dptr, datalen, cseq); |
722 | else { | 768 | else { |
723 | flush_expectations(ct); | 769 | flush_expectations(ct, true); |
724 | return NF_ACCEPT; | 770 | return NF_ACCEPT; |
725 | } | 771 | } |
726 | } | 772 | } |
@@ -732,7 +778,165 @@ static int process_bye_request(struct sk_buff *skb, | |||
732 | enum ip_conntrack_info ctinfo; | 778 | enum ip_conntrack_info ctinfo; |
733 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 779 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
734 | 780 | ||
735 | flush_expectations(ct); | 781 | flush_expectations(ct, true); |
782 | return NF_ACCEPT; | ||
783 | } | ||
784 | |||
785 | /* Parse a REGISTER request and create a permanent expectation for incoming | ||
786 | * signalling connections. The expectation is marked inactive and is activated | ||
787 | * when receiving a response indicating success from the registrar. | ||
788 | */ | ||
789 | static int process_register_request(struct sk_buff *skb, | ||
790 | const char **dptr, unsigned int *datalen, | ||
791 | unsigned int cseq) | ||
792 | { | ||
793 | enum ip_conntrack_info ctinfo; | ||
794 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | ||
795 | struct nf_conn_help *help = nfct_help(ct); | ||
796 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
797 | int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; | ||
798 | unsigned int matchoff, matchlen; | ||
799 | struct nf_conntrack_expect *exp; | ||
800 | union nf_inet_addr *saddr, daddr; | ||
801 | __be16 port; | ||
802 | unsigned int expires = 0; | ||
803 | int ret; | ||
804 | typeof(nf_nat_sip_expect_hook) nf_nat_sip_expect; | ||
805 | |||
806 | /* Expected connections can not register again. */ | ||
807 | if (ct->status & IPS_EXPECTED) | ||
808 | return NF_ACCEPT; | ||
809 | |||
810 | /* We must check the expiration time: a value of zero signals the | ||
811 | * registrar to release the binding. We'll remove our expectation | ||
812 | * when receiving the new bindings in the response, but we don't | ||
813 | * want to create new ones. | ||
814 | * | ||
815 | * The expiration time may be contained in Expires: header, the | ||
816 | * Contact: header parameters or the URI parameters. | ||
817 | */ | ||
818 | if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, | ||
819 | &matchoff, &matchlen) > 0) | ||
820 | expires = simple_strtoul(*dptr + matchoff, NULL, 10); | ||
821 | |||
822 | ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, | ||
823 | SIP_HDR_CONTACT, NULL, | ||
824 | &matchoff, &matchlen, &daddr, &port); | ||
825 | if (ret < 0) | ||
826 | return NF_DROP; | ||
827 | else if (ret == 0) | ||
828 | return NF_ACCEPT; | ||
829 | |||
830 | /* We don't support third-party registrations */ | ||
831 | if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, &daddr)) | ||
832 | return NF_ACCEPT; | ||
833 | |||
834 | if (ct_sip_parse_numerical_param(ct, *dptr, | ||
835 | matchoff + matchlen, *datalen, | ||
836 | "expires=", NULL, NULL, &expires) < 0) | ||
837 | return NF_DROP; | ||
838 | |||
839 | if (expires == 0) { | ||
840 | ret = NF_ACCEPT; | ||
841 | goto store_cseq; | ||
842 | } | ||
843 | |||
844 | exp = nf_ct_expect_alloc(ct); | ||
845 | if (!exp) | ||
846 | return NF_DROP; | ||
847 | |||
848 | saddr = NULL; | ||
849 | if (sip_direct_signalling) | ||
850 | saddr = &ct->tuplehash[!dir].tuple.src.u3; | ||
851 | |||
852 | nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, family, saddr, &daddr, | ||
853 | IPPROTO_UDP, NULL, &port); | ||
854 | exp->timeout.expires = sip_timeout * HZ; | ||
855 | exp->helper = nfct_help(ct)->helper; | ||
856 | exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE; | ||
857 | |||
858 | nf_nat_sip_expect = rcu_dereference(nf_nat_sip_expect_hook); | ||
859 | if (nf_nat_sip_expect && ct->status & IPS_NAT_MASK) | ||
860 | ret = nf_nat_sip_expect(skb, dptr, datalen, exp, | ||
861 | matchoff, matchlen); | ||
862 | else { | ||
863 | if (nf_ct_expect_related(exp) != 0) | ||
864 | ret = NF_DROP; | ||
865 | else | ||
866 | ret = NF_ACCEPT; | ||
867 | } | ||
868 | nf_ct_expect_put(exp); | ||
869 | |||
870 | store_cseq: | ||
871 | if (ret == NF_ACCEPT) | ||
872 | help->help.ct_sip_info.register_cseq = cseq; | ||
873 | return ret; | ||
874 | } | ||
875 | |||
876 | static int process_register_response(struct sk_buff *skb, | ||
877 | const char **dptr, unsigned int *datalen, | ||
878 | unsigned int cseq, unsigned int code) | ||
879 | { | ||
880 | enum ip_conntrack_info ctinfo; | ||
881 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | ||
882 | struct nf_conn_help *help = nfct_help(ct); | ||
883 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
884 | union nf_inet_addr addr; | ||
885 | __be16 port; | ||
886 | unsigned int matchoff, matchlen, dataoff = 0; | ||
887 | unsigned int expires = 0; | ||
888 | int in_contact = 0, ret; | ||
889 | |||
890 | /* According to RFC 3261, "UAs MUST NOT send a new registration until | ||
891 | * they have received a final response from the registrar for the | ||
892 | * previous one or the previous REGISTER request has timed out". | ||
893 | * | ||
894 | * However, some servers fail to detect retransmissions and send late | ||
895 | * responses, so we store the sequence number of the last valid | ||
896 | * request and compare it here. | ||
897 | */ | ||
898 | if (help->help.ct_sip_info.register_cseq != cseq) | ||
899 | return NF_ACCEPT; | ||
900 | |||
901 | if (code >= 100 && code <= 199) | ||
902 | return NF_ACCEPT; | ||
903 | if (code < 200 || code > 299) | ||
904 | goto flush; | ||
905 | |||
906 | if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, | ||
907 | &matchoff, &matchlen) > 0) | ||
908 | expires = simple_strtoul(*dptr + matchoff, NULL, 10); | ||
909 | |||
910 | while (1) { | ||
911 | unsigned int c_expires = expires; | ||
912 | |||
913 | ret = ct_sip_parse_header_uri(ct, *dptr, &dataoff, *datalen, | ||
914 | SIP_HDR_CONTACT, &in_contact, | ||
915 | &matchoff, &matchlen, | ||
916 | &addr, &port); | ||
917 | if (ret < 0) | ||
918 | return NF_DROP; | ||
919 | else if (ret == 0) | ||
920 | break; | ||
921 | |||
922 | /* We don't support third-party registrations */ | ||
923 | if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, &addr)) | ||
924 | continue; | ||
925 | |||
926 | ret = ct_sip_parse_numerical_param(ct, *dptr, | ||
927 | matchoff + matchlen, | ||
928 | *datalen, "expires=", | ||
929 | NULL, NULL, &c_expires); | ||
930 | if (ret < 0) | ||
931 | return NF_DROP; | ||
932 | if (c_expires == 0) | ||
933 | break; | ||
934 | if (refresh_signalling_expectation(ct, &addr, port, c_expires)) | ||
935 | return NF_ACCEPT; | ||
936 | } | ||
937 | |||
938 | flush: | ||
939 | flush_expectations(ct, false); | ||
736 | return NF_ACCEPT; | 940 | return NF_ACCEPT; |
737 | } | 941 | } |
738 | 942 | ||
@@ -742,6 +946,7 @@ static const struct sip_handler sip_handlers[] = { | |||
742 | SIP_HANDLER("ACK", process_sdp, NULL), | 946 | SIP_HANDLER("ACK", process_sdp, NULL), |
743 | SIP_HANDLER("PRACK", process_sdp, process_prack_response), | 947 | SIP_HANDLER("PRACK", process_sdp, process_prack_response), |
744 | SIP_HANDLER("BYE", process_bye_request, NULL), | 948 | SIP_HANDLER("BYE", process_bye_request, NULL), |
949 | SIP_HANDLER("REGISTER", process_register_request, process_register_response), | ||
745 | }; | 950 | }; |
746 | 951 | ||
747 | static int process_sip_response(struct sk_buff *skb, | 952 | static int process_sip_response(struct sk_buff *skb, |
@@ -853,9 +1058,15 @@ static int sip_help(struct sk_buff *skb, | |||
853 | static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly; | 1058 | static struct nf_conntrack_helper sip[MAX_PORTS][2] __read_mostly; |
854 | static char sip_names[MAX_PORTS][2][sizeof("sip-65535")] __read_mostly; | 1059 | static char sip_names[MAX_PORTS][2][sizeof("sip-65535")] __read_mostly; |
855 | 1060 | ||
856 | static const struct nf_conntrack_expect_policy sip_exp_policy = { | 1061 | static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1] = { |
857 | .max_expected = 2, | 1062 | [SIP_EXPECT_SIGNALLING] = { |
858 | .timeout = 3 * 60, | 1063 | .max_expected = 1, |
1064 | .timeout = 3 * 60, | ||
1065 | }, | ||
1066 | [SIP_EXPECT_AUDIO] = { | ||
1067 | .max_expected = IP_CT_DIR_MAX, | ||
1068 | .timeout = 3 * 60, | ||
1069 | }, | ||
859 | }; | 1070 | }; |
860 | 1071 | ||
861 | static void nf_conntrack_sip_fini(void) | 1072 | static void nf_conntrack_sip_fini(void) |
@@ -887,7 +1098,8 @@ static int __init nf_conntrack_sip_init(void) | |||
887 | for (j = 0; j < 2; j++) { | 1098 | for (j = 0; j < 2; j++) { |
888 | sip[i][j].tuple.dst.protonum = IPPROTO_UDP; | 1099 | sip[i][j].tuple.dst.protonum = IPPROTO_UDP; |
889 | sip[i][j].tuple.src.u.udp.port = htons(ports[i]); | 1100 | sip[i][j].tuple.src.u.udp.port = htons(ports[i]); |
890 | sip[i][j].expect_policy = &sip_exp_policy; | 1101 | sip[i][j].expect_policy = sip_exp_policy; |
1102 | sip[i][j].expect_class_max = SIP_EXPECT_MAX; | ||
891 | sip[i][j].me = THIS_MODULE; | 1103 | sip[i][j].me = THIS_MODULE; |
892 | sip[i][j].help = sip_help; | 1104 | sip[i][j].help = sip_help; |
893 | 1105 | ||