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