1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * H.323 extension for NAT alteration.
4 *
5 * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net>
6 * Copyright (c) 2006-2012 Patrick McHardy <kaber@trash.net>
7 *
8 * Based on the 'brute force' H.323 NAT module by
9 * Jozsef Kadlecsik <kadlec@netfilter.org>
10 */
11
12#include <linux/module.h>
13#include <linux/tcp.h>
14#include <net/tcp.h>
15
16#include <net/netfilter/nf_nat.h>
17#include <net/netfilter/nf_nat_helper.h>
18#include <net/netfilter/nf_conntrack_helper.h>
19#include <net/netfilter/nf_conntrack_expect.h>
20#include <linux/netfilter/nf_conntrack_h323.h>
21
22/****************************************************************************/
23static int set_addr(struct sk_buff *skb, unsigned int protoff,
24		    unsigned char **data, int dataoff,
25		    unsigned int addroff, __be32 ip, __be16 port)
26{
27	enum ip_conntrack_info ctinfo;
28	struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
29	struct {
30		__be32 ip;
31		__be16 port;
32	} __attribute__ ((__packed__)) buf;
33	const struct tcphdr *th;
34	struct tcphdr _tcph;
35
36	buf.ip = ip;
37	buf.port = port;
38	addroff += dataoff;
39
40	if (ip_hdr(skb)->protocol == IPPROTO_TCP) {
41		if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
42					      protoff, addroff, sizeof(buf),
43					      (char *) &buf, sizeof(buf))) {
44			net_notice_ratelimited("nf_nat_h323: nf_nat_mangle_tcp_packet error\n");
45			return -1;
46		}
47
48		/* Relocate data pointer */
49		th = skb_header_pointer(skb, ip_hdrlen(skb),
50					sizeof(_tcph), &_tcph);
51		if (th == NULL)
52			return -1;
53		*data = skb->data + ip_hdrlen(skb) + th->doff * 4 + dataoff;
54	} else {
55		if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo,
56					      protoff, addroff, sizeof(buf),
57					      (char *) &buf, sizeof(buf))) {
58			net_notice_ratelimited("nf_nat_h323: nf_nat_mangle_udp_packet error\n");
59			return -1;
60		}
61		/* nf_nat_mangle_udp_packet uses skb_ensure_writable() to copy
62		 * or pull everything in a linear buffer, so we can safely
63		 * use the skb pointers now */
64		*data = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr);
65	}
66
67	return 0;
68}
69
70/****************************************************************************/
71static int set_h225_addr(struct sk_buff *skb, unsigned int protoff,
72			 unsigned char **data, int dataoff,
73			 TransportAddress *taddr,
74			 union nf_inet_addr *addr, __be16 port)
75{
76	return set_addr(skb, protoff, data, dataoff, taddr->ipAddress.ip,
77			addr->ip, port);
78}
79
80/****************************************************************************/
81static int set_h245_addr(struct sk_buff *skb, unsigned protoff,
82			 unsigned char **data, int dataoff,
83			 H245_TransportAddress *taddr,
84			 union nf_inet_addr *addr, __be16 port)
85{
86	return set_addr(skb, protoff, data, dataoff,
87			taddr->unicastAddress.iPAddress.network,
88			addr->ip, port);
89}
90
91/****************************************************************************/
92static int set_sig_addr(struct sk_buff *skb, struct nf_conn *ct,
93			enum ip_conntrack_info ctinfo,
94			unsigned int protoff, unsigned char **data,
95			TransportAddress *taddr, int count)
96{
97	const struct nf_ct_h323_master *info = nfct_help_data(ct);
98	int dir = CTINFO2DIR(ctinfo);
99	int i;
100	__be16 port;
101	union nf_inet_addr addr;
102
103	for (i = 0; i < count; i++) {
104		if (get_h225_addr(ct, *data, &taddr[i], &addr, &port)) {
105			if (addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
106			    port == info->sig_port[dir]) {
107				/* GW->GK */
108
109				/* Fix for Gnomemeeting */
110				if (i > 0 &&
111				    get_h225_addr(ct, *data, &taddr[0],
112						  &addr, &port) &&
113				    (ntohl(addr.ip) & 0xff000000) == 0x7f000000)
114					i = 0;
115
116				pr_debug("nf_nat_ras: set signal address %pI4:%hu->%pI4:%hu\n",
117					 &addr.ip, port,
118					 &ct->tuplehash[!dir].tuple.dst.u3.ip,
119					 info->sig_port[!dir]);
120				return set_h225_addr(skb, protoff, data, 0,
121						     &taddr[i],
122						     &ct->tuplehash[!dir].
123						     tuple.dst.u3,
124						     info->sig_port[!dir]);
125			} else if (addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
126				   port == info->sig_port[dir]) {
127				/* GK->GW */
128				pr_debug("nf_nat_ras: set signal address %pI4:%hu->%pI4:%hu\n",
129					 &addr.ip, port,
130					 &ct->tuplehash[!dir].tuple.src.u3.ip,
131					 info->sig_port[!dir]);
132				return set_h225_addr(skb, protoff, data, 0,
133						     &taddr[i],
134						     &ct->tuplehash[!dir].
135						     tuple.src.u3,
136						     info->sig_port[!dir]);
137			}
138		}
139	}
140
141	return 0;
142}
143
144/****************************************************************************/
145static int set_ras_addr(struct sk_buff *skb, struct nf_conn *ct,
146			enum ip_conntrack_info ctinfo,
147			unsigned int protoff, unsigned char **data,
148			TransportAddress *taddr, int count)
149{
150	int dir = CTINFO2DIR(ctinfo);
151	int i;
152	__be16 port;
153	union nf_inet_addr addr;
154
155	for (i = 0; i < count; i++) {
156		if (get_h225_addr(ct, *data, &taddr[i], &addr, &port) &&
157		    addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
158		    port == ct->tuplehash[dir].tuple.src.u.udp.port) {
159			pr_debug("nf_nat_ras: set rasAddress %pI4:%hu->%pI4:%hu\n",
160				 &addr.ip, ntohs(port),
161				 &ct->tuplehash[!dir].tuple.dst.u3.ip,
162				 ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port));
163			return set_h225_addr(skb, protoff, data, 0, &taddr[i],
164					     &ct->tuplehash[!dir].tuple.dst.u3,
165					     ct->tuplehash[!dir].tuple.
166								dst.u.udp.port);
167		}
168	}
169
170	return 0;
171}
172
173/****************************************************************************/
174static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
175			enum ip_conntrack_info ctinfo,
176			unsigned int protoff, unsigned char **data, int dataoff,
177			H245_TransportAddress *taddr,
178			__be16 port, __be16 rtp_port,
179			struct nf_conntrack_expect *rtp_exp,
180			struct nf_conntrack_expect *rtcp_exp)
181{
182	struct nf_ct_h323_master *info = nfct_help_data(ct);
183	int dir = CTINFO2DIR(ctinfo);
184	int i;
185	u_int16_t nated_port;
186
187	/* Set expectations for NAT */
188	rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
189	rtp_exp->expectfn = nf_nat_follow_master;
190	rtp_exp->dir = !dir;
191	rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
192	rtcp_exp->expectfn = nf_nat_follow_master;
193	rtcp_exp->dir = !dir;
194
195	/* Lookup existing expects */
196	for (i = 0; i < H323_RTP_CHANNEL_MAX; i++) {
197		if (info->rtp_port[i][dir] == rtp_port) {
198			/* Expected */
199
200			/* Use allocated ports first. This will refresh
201			 * the expects */
202			rtp_exp->tuple.dst.u.udp.port = info->rtp_port[i][dir];
203			rtcp_exp->tuple.dst.u.udp.port =
204			    htons(ntohs(info->rtp_port[i][dir]) + 1);
205			break;
206		} else if (info->rtp_port[i][dir] == 0) {
207			/* Not expected */
208			break;
209		}
210	}
211
212	/* Run out of expectations */
213	if (i >= H323_RTP_CHANNEL_MAX) {
214		net_notice_ratelimited("nf_nat_h323: out of expectations\n");
215		return 0;
216	}
217
218	/* Try to get a pair of ports. */
219	for (nated_port = ntohs(rtp_exp->tuple.dst.u.udp.port);
220	     nated_port != 0; nated_port += 2) {
221		int ret;
222
223		rtp_exp->tuple.dst.u.udp.port = htons(nated_port);
224		ret = nf_ct_expect_related(rtp_exp, 0);
225		if (ret == 0) {
226			rtcp_exp->tuple.dst.u.udp.port =
227			    htons(nated_port + 1);
228			ret = nf_ct_expect_related(rtcp_exp, 0);
229			if (ret == 0)
230				break;
231			else if (ret == -EBUSY) {
232				nf_ct_unexpect_related(rtp_exp);
233				continue;
234			} else if (ret < 0) {
235				nf_ct_unexpect_related(rtp_exp);
236				nated_port = 0;
237				break;
238			}
239		} else if (ret != -EBUSY) {
240			nated_port = 0;
241			break;
242		}
243	}
244
245	if (nated_port == 0) {	/* No port available */
246		net_notice_ratelimited("nf_nat_h323: out of RTP ports\n");
247		return 0;
248	}
249
250	/* Modify signal */
251	if (set_h245_addr(skb, protoff, data, dataoff, taddr,
252			  &ct->tuplehash[!dir].tuple.dst.u3,
253			  htons((port & htons(1)) ? nated_port + 1 :
254						    nated_port))) {
255		nf_ct_unexpect_related(rtp_exp);
256		nf_ct_unexpect_related(rtcp_exp);
257		return -1;
258	}
259
260	/* Save ports */
261	info->rtp_port[i][dir] = rtp_port;
262	info->rtp_port[i][!dir] = htons(nated_port);
263
264	/* Success */
265	pr_debug("nf_nat_h323: expect RTP %pI4:%hu->%pI4:%hu\n",
266		 &rtp_exp->tuple.src.u3.ip,
267		 ntohs(rtp_exp->tuple.src.u.udp.port),
268		 &rtp_exp->tuple.dst.u3.ip,
269		 ntohs(rtp_exp->tuple.dst.u.udp.port));
270	pr_debug("nf_nat_h323: expect RTCP %pI4:%hu->%pI4:%hu\n",
271		 &rtcp_exp->tuple.src.u3.ip,
272		 ntohs(rtcp_exp->tuple.src.u.udp.port),
273		 &rtcp_exp->tuple.dst.u3.ip,
274		 ntohs(rtcp_exp->tuple.dst.u.udp.port));
275
276	return 0;
277}
278
279/****************************************************************************/
280static int nat_t120(struct sk_buff *skb, struct nf_conn *ct,
281		    enum ip_conntrack_info ctinfo,
282		    unsigned int protoff, unsigned char **data, int dataoff,
283		    H245_TransportAddress *taddr, __be16 port,
284		    struct nf_conntrack_expect *exp)
285{
286	int dir = CTINFO2DIR(ctinfo);
287	u_int16_t nated_port = ntohs(port);
288
289	/* Set expectations for NAT */
290	exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
291	exp->expectfn = nf_nat_follow_master;
292	exp->dir = !dir;
293
294	nated_port = nf_nat_exp_find_port(exp, nated_port);
295	if (nated_port == 0) {	/* No port available */
296		net_notice_ratelimited("nf_nat_h323: out of TCP ports\n");
297		return 0;
298	}
299
300	/* Modify signal */
301	if (set_h245_addr(skb, protoff, data, dataoff, taddr,
302			  &ct->tuplehash[!dir].tuple.dst.u3,
303			  htons(nated_port)) < 0) {
304		nf_ct_unexpect_related(exp);
305		return -1;
306	}
307
308	pr_debug("nf_nat_h323: expect T.120 %pI4:%hu->%pI4:%hu\n",
309		 &exp->tuple.src.u3.ip,
310		 ntohs(exp->tuple.src.u.tcp.port),
311		 &exp->tuple.dst.u3.ip,
312		 ntohs(exp->tuple.dst.u.tcp.port));
313
314	return 0;
315}
316
317/****************************************************************************/
318static int nat_h245(struct sk_buff *skb, struct nf_conn *ct,
319		    enum ip_conntrack_info ctinfo,
320		    unsigned int protoff, unsigned char **data, int dataoff,
321		    TransportAddress *taddr, __be16 port,
322		    struct nf_conntrack_expect *exp)
323{
324	struct nf_ct_h323_master *info = nfct_help_data(ct);
325	int dir = CTINFO2DIR(ctinfo);
326	u_int16_t nated_port = ntohs(port);
327
328	/* Set expectations for NAT */
329	exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
330	exp->expectfn = nf_nat_follow_master;
331	exp->dir = !dir;
332
333	/* Check existing expects */
334	if (info->sig_port[dir] == port)
335		nated_port = ntohs(info->sig_port[!dir]);
336
337	nated_port = nf_nat_exp_find_port(exp, nated_port);
338	if (nated_port == 0) {	/* No port available */
339		net_notice_ratelimited("nf_nat_q931: out of TCP ports\n");
340		return 0;
341	}
342
343	/* Modify signal */
344	if (set_h225_addr(skb, protoff, data, dataoff, taddr,
345			  &ct->tuplehash[!dir].tuple.dst.u3,
346			  htons(nated_port))) {
347		nf_ct_unexpect_related(exp);
348		return -1;
349	}
350
351	/* Save ports */
352	info->sig_port[dir] = port;
353	info->sig_port[!dir] = htons(nated_port);
354
355	pr_debug("nf_nat_q931: expect H.245 %pI4:%hu->%pI4:%hu\n",
356		 &exp->tuple.src.u3.ip,
357		 ntohs(exp->tuple.src.u.tcp.port),
358		 &exp->tuple.dst.u3.ip,
359		 ntohs(exp->tuple.dst.u.tcp.port));
360
361	return 0;
362}
363
364/****************************************************************************
365 * This conntrack expect function replaces nf_conntrack_q931_expect()
366 * which was set by nf_conntrack_h323.c.
367 ****************************************************************************/
368static void ip_nat_q931_expect(struct nf_conn *new,
369			       struct nf_conntrack_expect *this)
370{
371	struct nf_nat_range2 range;
372
373	if (this->tuple.src.u3.ip != 0) {	/* Only accept calls from GK */
374		nf_nat_follow_master(new, this);
375		return;
376	}
377
378	/* This must be a fresh one. */
379	BUG_ON(new->status & IPS_NAT_DONE_MASK);
380
381	/* Change src to where master sends to */
382	range.flags = NF_NAT_RANGE_MAP_IPS;
383	range.min_addr = range.max_addr =
384	    new->tuplehash[!this->dir].tuple.src.u3;
385	nf_nat_setup_info(new, &range, NF_NAT_MANIP_SRC);
386
387	/* For DST manip, map port here to where it's expected. */
388	range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED);
389	range.min_proto = range.max_proto = this->saved_proto;
390	range.min_addr = range.max_addr =
391	    new->master->tuplehash[!this->dir].tuple.src.u3;
392	nf_nat_setup_info(new, &range, NF_NAT_MANIP_DST);
393}
394
395/****************************************************************************/
396static int nat_q931(struct sk_buff *skb, struct nf_conn *ct,
397		    enum ip_conntrack_info ctinfo,
398		    unsigned int protoff, unsigned char **data,
399		    TransportAddress *taddr, int idx,
400		    __be16 port, struct nf_conntrack_expect *exp)
401{
402	struct nf_ct_h323_master *info = nfct_help_data(ct);
403	int dir = CTINFO2DIR(ctinfo);
404	u_int16_t nated_port = ntohs(port);
405	union nf_inet_addr addr;
406
407	/* Set expectations for NAT */
408	exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
409	exp->expectfn = ip_nat_q931_expect;
410	exp->dir = !dir;
411
412	/* Check existing expects */
413	if (info->sig_port[dir] == port)
414		nated_port = ntohs(info->sig_port[!dir]);
415
416	nated_port = nf_nat_exp_find_port(exp, nated_port);
417	if (nated_port == 0) {	/* No port available */
418		net_notice_ratelimited("nf_nat_ras: out of TCP ports\n");
419		return 0;
420	}
421
422	/* Modify signal */
423	if (set_h225_addr(skb, protoff, data, 0, &taddr[idx],
424			  &ct->tuplehash[!dir].tuple.dst.u3,
425			  htons(nated_port))) {
426		nf_ct_unexpect_related(exp);
427		return -1;
428	}
429
430	/* Save ports */
431	info->sig_port[dir] = port;
432	info->sig_port[!dir] = htons(nated_port);
433
434	/* Fix for Gnomemeeting */
435	if (idx > 0 &&
436	    get_h225_addr(ct, *data, &taddr[0], &addr, &port) &&
437	    (ntohl(addr.ip) & 0xff000000) == 0x7f000000) {
438		if (set_h225_addr(skb, protoff, data, 0, &taddr[0],
439				  &ct->tuplehash[!dir].tuple.dst.u3,
440				  info->sig_port[!dir])) {
441			nf_ct_unexpect_related(exp);
442			return -1;
443		}
444	}
445
446	/* Success */
447	pr_debug("nf_nat_ras: expect Q.931 %pI4:%hu->%pI4:%hu\n",
448		 &exp->tuple.src.u3.ip,
449		 ntohs(exp->tuple.src.u.tcp.port),
450		 &exp->tuple.dst.u3.ip,
451		 ntohs(exp->tuple.dst.u.tcp.port));
452
453	return 0;
454}
455
456/****************************************************************************/
457static void ip_nat_callforwarding_expect(struct nf_conn *new,
458					 struct nf_conntrack_expect *this)
459{
460	struct nf_nat_range2 range;
461
462	/* This must be a fresh one. */
463	BUG_ON(new->status & IPS_NAT_DONE_MASK);
464
465	/* Change src to where master sends to */
466	range.flags = NF_NAT_RANGE_MAP_IPS;
467	range.min_addr = range.max_addr =
468	    new->tuplehash[!this->dir].tuple.src.u3;
469	nf_nat_setup_info(new, &range, NF_NAT_MANIP_SRC);
470
471	/* For DST manip, map port here to where it's expected. */
472	range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED);
473	range.min_proto = range.max_proto = this->saved_proto;
474	range.min_addr = range.max_addr = this->saved_addr;
475	nf_nat_setup_info(new, &range, NF_NAT_MANIP_DST);
476}
477
478/****************************************************************************/
479static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct,
480			      enum ip_conntrack_info ctinfo,
481			      unsigned int protoff,
482			      unsigned char **data, int dataoff,
483			      TransportAddress *taddr, __be16 port,
484			      struct nf_conntrack_expect *exp)
485{
486	int dir = CTINFO2DIR(ctinfo);
487	u_int16_t nated_port;
488
489	/* Set expectations for NAT */
490	exp->saved_addr = exp->tuple.dst.u3;
491	exp->tuple.dst.u3.ip = ct->tuplehash[!dir].tuple.dst.u3.ip;
492	exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
493	exp->expectfn = ip_nat_callforwarding_expect;
494	exp->dir = !dir;
495
496	nated_port = nf_nat_exp_find_port(exp, ntohs(port));
497	if (nated_port == 0) {	/* No port available */
498		net_notice_ratelimited("nf_nat_q931: out of TCP ports\n");
499		return 0;
500	}
501
502	/* Modify signal */
503	if (set_h225_addr(skb, protoff, data, dataoff, taddr,
504			  &ct->tuplehash[!dir].tuple.dst.u3,
505			  htons(nated_port))) {
506		nf_ct_unexpect_related(exp);
507		return -1;
508	}
509
510	/* Success */
511	pr_debug("nf_nat_q931: expect Call Forwarding %pI4:%hu->%pI4:%hu\n",
512		 &exp->tuple.src.u3.ip,
513		 ntohs(exp->tuple.src.u.tcp.port),
514		 &exp->tuple.dst.u3.ip,
515		 ntohs(exp->tuple.dst.u.tcp.port));
516
517	return 0;
518}
519
520static struct nf_ct_helper_expectfn q931_nat = {
521	.name		= "Q.931",
522	.expectfn	= ip_nat_q931_expect,
523};
524
525static struct nf_ct_helper_expectfn callforwarding_nat = {
526	.name		= "callforwarding",
527	.expectfn	= ip_nat_callforwarding_expect,
528};
529
530static const struct nfct_h323_nat_hooks nathooks = {
531	.set_h245_addr = set_h245_addr,
532	.set_h225_addr = set_h225_addr,
533	.set_sig_addr = set_sig_addr,
534	.set_ras_addr = set_ras_addr,
535	.nat_rtp_rtcp = nat_rtp_rtcp,
536	.nat_t120 = nat_t120,
537	.nat_h245 = nat_h245,
538	.nat_callforwarding = nat_callforwarding,
539	.nat_q931 = nat_q931,
540};
541
542/****************************************************************************/
543static int __init nf_nat_h323_init(void)
544{
545	RCU_INIT_POINTER(nfct_h323_nat_hook, &nathooks);
546	nf_ct_helper_expectfn_register(&q931_nat);
547	nf_ct_helper_expectfn_register(&callforwarding_nat);
548	return 0;
549}
550
551/****************************************************************************/
552static void __exit nf_nat_h323_fini(void)
553{
554	RCU_INIT_POINTER(nfct_h323_nat_hook, NULL);
555	nf_ct_helper_expectfn_unregister(&q931_nat);
556	nf_ct_helper_expectfn_unregister(&callforwarding_nat);
557	synchronize_rcu();
558}
559
560/****************************************************************************/
561module_init(nf_nat_h323_init);
562module_exit(nf_nat_h323_fini);
563
564MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>");
565MODULE_DESCRIPTION("H.323 NAT helper");
566MODULE_LICENSE("GPL");
567MODULE_ALIAS_NF_NAT_HELPER("h323");
568