1 /* $NetBSD: ip_h323_pxy.c,v 1.9.2.1 2004/08/13 03:55:22 jmc Exp $ */
2
3 /*
4 * Copyright 2001, QNX Software Systems Ltd. All Rights Reserved
5 *
6 * This source code has been published by QNX Software Systems Ltd. (QSSL).
7 * However, any use, reproduction, modification, distribution or transfer of
8 * this software, or any software which includes or is based upon any of this
9 * code, is only permitted under the terms of the QNX Open Community License
10 * version 1.0 (see licensing.qnx.com for details) or as otherwise expressly
11 * authorized by a written license agreement from QSSL. For more information,
12 * please email licensing@qnx.com.
13 *
14 * For more details, see QNX_OCL.txt provided with this distribution.
15 */
16
17 /*
18 * Simple H.323 proxy
19 *
20 * by xtang@canada.com
21 * ported to ipfilter 3.4.20 by Michael Grant mg-ipf@grant.org
22 */
23
24 #if __FreeBSD_version >= 220000 && defined(_KERNEL)
25 # include <sys/fcntl.h>
26 # include <sys/filio.h>
27 #else
28 # ifndef linux
29 # include <sys/ioctl.h>
30 # endif
31 #endif
32
33 #ifdef _KERNEL_OPT
34 #include "opt_ipfilter_log.h"
35 #endif
36
37 __KERNEL_RCSID(1, "$NetBSD: ip_h323_pxy.c,v 1.9.2.1 2004/08/13 03:55:22 jmc Exp $");
38
39 #define IPF_H323_PROXY
40
41 int ippr_h323_init __P((void));
42 void ippr_h323_fini __P((void));
43 int ippr_h323_new __P((fr_info_t *, ap_session_t *, nat_t *));
44 void ippr_h323_del __P((ap_session_t *));
45 int ippr_h323_out __P((fr_info_t *, ap_session_t *, nat_t *));
46 int ippr_h323_in __P((fr_info_t *, ap_session_t *, nat_t *));
47
48 int ippr_h245_new __P((fr_info_t *, ap_session_t *, nat_t *));
49 int ippr_h245_out __P((fr_info_t *, ap_session_t *, nat_t *));
50 int ippr_h245_in __P((fr_info_t *, ap_session_t *, nat_t *));
51
52 static frentry_t h323_fr;
53
54 int h323_proxy_init = 0;
55
56 static int find_port __P((int, caddr_t, int datlen, int *, u_short *));
57
58
59 static int find_port(ipaddr, data, datlen, off, port)
60 int ipaddr;
61 caddr_t data;
62 int datlen, *off;
63 unsigned short *port;
64 {
65 u_32_t addr, netaddr;
66 u_char *dp;
67 int offset;
68
69 if (datlen < 6)
70 return -1;
71
72 *port = 0;
73 offset = *off;
74 dp = (u_char *)data;
75 netaddr = ntohl(ipaddr);
76
77 for (offset = 0; offset <= datlen - 6; offset++, dp++) {
78 addr = (dp[0] << 24) | (dp[1] << 16) | (dp[2] << 8) | dp[3];
79 if (netaddr == addr)
80 {
81 *port = (*(dp + 4) << 8) | *(dp + 5);
82 break;
83 }
84 }
85 *off = offset;
86 return (offset > datlen - 6) ? -1 : 0;
87 }
88
89 /*
90 * Initialize local structures.
91 */
92 int ippr_h323_init()
93 {
94 bzero((char *)&h323_fr, sizeof(h323_fr));
95 h323_fr.fr_ref = 1;
96 h323_fr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
97 MUTEX_INIT(&h323_fr.fr_lock, "H323 proxy rule lock");
98 h323_proxy_init = 1;
99
100 return 0;
101 }
102
103
104 void ippr_h323_fini()
105 {
106 if (h323_proxy_init == 1) {
107 MUTEX_DESTROY(&h323_fr.fr_lock);
108 h323_proxy_init = 0;
109 }
110 }
111
112
113 int ippr_h323_new(fin, aps, nat)
114 fr_info_t *fin;
115 ap_session_t *aps;
116 nat_t *nat;
117 {
118 fin = fin; /* LINT */
119 nat = nat; /* LINT */
120
121 aps->aps_data = NULL;
122 aps->aps_psiz = 0;
123
124 return 0;
125 }
126
127
128 void ippr_h323_del(aps)
129 ap_session_t *aps;
130 {
131 int i;
132 ipnat_t *ipn;
133
134 if (aps->aps_data) {
135 for (i = 0, ipn = aps->aps_data;
136 i < (aps->aps_psiz / sizeof(ipnat_t));
137 i++, ipn = (ipnat_t *)((char *)ipn + sizeof(*ipn)))
138 {
139 /*
140 * Check the comment in ippr_h323_in() function,
141 * just above fr_nat_ioctl() call.
142 * We are lucky here because this function is not
143 * called with ipf_nat locked.
144 */
145 if (fr_nat_ioctl((caddr_t)ipn, SIOCRMNAT, NAT_SYSSPACE|
146 NAT_LOCKHELD|FWRITE) == -1) {
147 /*EMPTY*/;
148 /* log the error */
149 }
150 }
151 KFREES(aps->aps_data, aps->aps_psiz);
152 /* avoid double free */
153 aps->aps_data = NULL;
154 aps->aps_psiz = 0;
155 }
156 return;
157 }
158
159
160 int ippr_h323_in(fin, aps, nat)
161 fr_info_t *fin;
162 ap_session_t *aps;
163 nat_t *nat;
164 {
165 int ipaddr, off, datlen;
166 unsigned short port;
167 caddr_t data;
168 tcphdr_t *tcp;
169 ip_t *ip;
170
171 ip = fin->fin_ip;
172 tcp = (tcphdr_t *)fin->fin_dp;
173 ipaddr = ip->ip_src.s_addr;
174
175 data = (caddr_t)tcp + (TCP_OFF(tcp) << 2);
176 datlen = fin->fin_dlen - (TCP_OFF(tcp) << 2);
177 if (find_port(ipaddr, data, datlen, &off, &port) == 0) {
178 ipnat_t *ipn;
179 char *newarray;
180
181 /* setup a nat rule to set a h245 proxy on tcp-port "port"
182 * it's like:
183 * map <if> <inter_ip>/<mask> -> <gate_ip>/<mask> proxy port <port> <port>/tcp
184 */
185 KMALLOCS(newarray, char *, aps->aps_psiz + sizeof(*ipn));
186 if (newarray == NULL) {
187 return -1;
188 }
189 ipn = (ipnat_t *)&newarray[aps->aps_psiz];
190 bcopy((caddr_t)nat->nat_ptr, (caddr_t)ipn, sizeof(ipnat_t));
191 (void) strncpy(ipn->in_plabel, "h245", APR_LABELLEN);
192
193 ipn->in_inip = nat->nat_inip.s_addr;
194 ipn->in_inmsk = 0xffffffff;
195 ipn->in_dport = htons(port);
196 /*
197 * we got a problem here. we need to call fr_nat_ioctl() to add
198 * the h245 proxy rule, but since we already hold (READ locked)
199 * the nat table rwlock (ipf_nat), if we go into fr_nat_ioctl(),
200 * it will try to WRITE lock it. This will causing dead lock
201 * on RTP.
202 *
203 * The quick & dirty solution here is release the read lock,
204 * call fr_nat_ioctl() and re-lock it.
205 * A (maybe better) solution is do a UPGRADE(), and instead
206 * of calling fr_nat_ioctl(), we add the nat rule ourself.
207 */
208 RWLOCK_EXIT(&ipf_nat);
209 if (fr_nat_ioctl((caddr_t)ipn, SIOCADNAT,
210 NAT_SYSSPACE|FWRITE) == -1) {
211 READ_ENTER(&ipf_nat);
212 return -1;
213 }
214 READ_ENTER(&ipf_nat);
215 if (aps->aps_data != NULL && aps->aps_psiz > 0) {
216 bcopy(aps->aps_data, newarray, aps->aps_psiz);
217 KFREES(aps->aps_data, aps->aps_psiz);
218 }
219 aps->aps_data = newarray;
220 aps->aps_psiz += sizeof(*ipn);
221 }
222 return 0;
223 }
224
225
226 int ippr_h245_new(fin, aps, nat)
227 fr_info_t *fin;
228 ap_session_t *aps;
229 nat_t *nat;
230 {
231 fin = fin; /* LINT */
232 nat = nat; /* LINT */
233
234 aps->aps_data = NULL;
235 aps->aps_psiz = 0;
236 return 0;
237 }
238
239
240 int ippr_h245_out(fin, aps, nat)
241 fr_info_t *fin;
242 ap_session_t *aps;
243 nat_t *nat;
244 {
245 int ipaddr, off, datlen;
246 tcphdr_t *tcp;
247 caddr_t data;
248 u_short port;
249 ip_t *ip;
250
251 aps = aps; /* LINT */
252
253 ip = fin->fin_ip;
254 tcp = (tcphdr_t *)fin->fin_dp;
255 ipaddr = nat->nat_inip.s_addr;
256 data = (caddr_t)tcp + (TCP_OFF(tcp) << 2);
257 datlen = ip->ip_len - fin->fin_hlen - (TCP_OFF(tcp) << 2);
258 if (find_port(ipaddr, data, datlen, &off, &port) == 0) {
259 fr_info_t fi;
260 nat_t *nat2;
261
262 /* port = htons(port); */
263 nat2 = nat_outlookup(fin->fin_ifp, IPN_UDP, IPPROTO_UDP,
264 ip->ip_src, ip->ip_dst);
265 if (nat2 == NULL) {
266 struct ip newip;
267 struct udphdr udp;
268
269 bcopy((caddr_t)ip, (caddr_t)&newip, sizeof(newip));
270 newip.ip_len = fin->fin_hlen + sizeof(udp);
271 newip.ip_p = IPPROTO_UDP;
272 newip.ip_src = nat->nat_inip;
273
274 bzero((char *)&udp, sizeof(udp));
275 udp.uh_sport = port;
276
277 bcopy((caddr_t)fin, (caddr_t)&fi, sizeof(fi));
278 fi.fin_fi.fi_p = IPPROTO_UDP;
279 fi.fin_data[0] = port;
280 fi.fin_data[1] = 0;
281 fi.fin_dp = (char *)&udp;
282
283 nat2 = nat_new(&fi, nat->nat_ptr, NULL,
284 NAT_SLAVE|IPN_UDP|SI_W_DPORT,
285 NAT_OUTBOUND);
286 if (nat2 != NULL) {
287 (void) nat_proto(&fi, nat2, IPN_UDP);
288 nat_update(&fi, nat2, nat2->nat_ptr);
289
290 nat2->nat_ptr->in_hits++;
291 #ifdef IPFILTER_LOG
292 nat_log(nat2, (u_int)(nat->nat_ptr->in_redir));
293 #endif
294 bcopy((caddr_t)&ip->ip_src.s_addr,
295 data + off, 4);
296 bcopy((caddr_t)&nat2->nat_outport,
297 data + off + 4, 2);
298 }
299 }
300 }
301 return 0;
302 }
Cache object: 2c3680a99829d727040e79732241255b
|