]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c
Import IP Filter 4.1.13
[FreeBSD/FreeBSD.git] / sys / contrib / ipfilter / netinet / ip_rcmd_pxy.c
1 /*
2  * Copyright (C) 1998-2003 by Darren Reed
3  *
4  * See the IPFILTER.LICENCE file for details on licencing.
5  *
6  * $Id: ip_rcmd_pxy.c,v 1.41.2.6 2006/04/01 10:14:54 darrenr Exp $
7  *
8  * Simple RCMD transparent proxy for in-kernel use.  For use with the NAT
9  * code.
10  */
11
12 #define IPF_RCMD_PROXY
13
14
15 int ippr_rcmd_init __P((void));
16 void ippr_rcmd_fini __P((void));
17 int ippr_rcmd_new __P((fr_info_t *, ap_session_t *, nat_t *));
18 int ippr_rcmd_out __P((fr_info_t *, ap_session_t *, nat_t *));
19 int ippr_rcmd_in __P((fr_info_t *, ap_session_t *, nat_t *));
20 u_short ipf_rcmd_atoi __P((char *));
21 int ippr_rcmd_portmsg __P((fr_info_t *, ap_session_t *, nat_t *));
22
23 static  frentry_t       rcmdfr;
24
25 int     rcmd_proxy_init = 0;
26
27
28 /*
29  * RCMD application proxy initialization.
30  */
31 int ippr_rcmd_init()
32 {
33         bzero((char *)&rcmdfr, sizeof(rcmdfr));
34         rcmdfr.fr_ref = 1;
35         rcmdfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
36         MUTEX_INIT(&rcmdfr.fr_lock, "RCMD proxy rule lock");
37         rcmd_proxy_init = 1;
38
39         return 0;
40 }
41
42
43 void ippr_rcmd_fini()
44 {
45         if (rcmd_proxy_init == 1) {
46                 MUTEX_DESTROY(&rcmdfr.fr_lock);
47                 rcmd_proxy_init = 0;
48         }
49 }
50
51
52 /*
53  * Setup for a new RCMD proxy.
54  */
55 int ippr_rcmd_new(fin, aps, nat)
56 fr_info_t *fin;
57 ap_session_t *aps;
58 nat_t *nat;
59 {
60         tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp;
61
62         fin = fin;      /* LINT */
63         nat = nat;      /* LINT */
64
65         aps->aps_psiz = sizeof(u_32_t);
66         KMALLOCS(aps->aps_data, u_32_t *, sizeof(u_32_t));
67         if (aps->aps_data == NULL) {
68 #ifdef IP_RCMD_PROXY_DEBUG
69                 printf("ippr_rcmd_new:KMALLOCS(%d) failed\n", sizeof(u_32_t));
70 #endif
71                 return -1;
72         }
73         *(u_32_t *)aps->aps_data = 0;
74         aps->aps_sport = tcp->th_sport;
75         aps->aps_dport = tcp->th_dport;
76         return 0;
77 }
78
79
80 /*
81  * ipf_rcmd_atoi - implement a simple version of atoi
82  */
83 u_short ipf_rcmd_atoi(ptr)
84 char *ptr;
85 {
86         register char *s = ptr, c;
87         register u_short i = 0;
88
89         while (((c = *s++) != '\0') && ISDIGIT(c)) {
90                 i *= 10;
91                 i += c - '0';
92         }
93         return i;
94 }
95
96
97 int ippr_rcmd_portmsg(fin, aps, nat)
98 fr_info_t *fin;
99 ap_session_t *aps;
100 nat_t *nat;
101 {
102         tcphdr_t *tcp, tcph, *tcp2 = &tcph;
103         struct in_addr swip, swip2;
104         int off, dlen, nflags;
105         char portbuf[8], *s;
106         fr_info_t fi;
107         u_short sp;
108         nat_t *nat2;
109         ip_t *ip;
110         mb_t *m;
111
112         tcp = (tcphdr_t *)fin->fin_dp;
113
114         if (tcp->th_flags & TH_SYN) {
115                 *(u_32_t *)aps->aps_data = htonl(ntohl(tcp->th_seq) + 1);
116                 return 0;
117         }
118
119         if ((*(u_32_t *)aps->aps_data != 0) &&
120             (tcp->th_seq != *(u_32_t *)aps->aps_data))
121                 return 0;
122
123         m = fin->fin_m;
124         ip = fin->fin_ip;
125         off = (char *)tcp - (char *)ip + (TCP_OFF(tcp) << 2) + fin->fin_ipoff;
126
127 #ifdef __sgi
128         dlen = fin->fin_plen - off;
129 #else
130         dlen = MSGDSIZE(m) - off;
131 #endif
132         if (dlen <= 0)
133                 return 0;
134
135         bzero(portbuf, sizeof(portbuf));
136         COPYDATA(m, off, MIN(sizeof(portbuf), dlen), portbuf);
137
138         portbuf[sizeof(portbuf) - 1] = '\0';
139         s = portbuf;
140         sp = ipf_rcmd_atoi(s);
141         if (sp == 0) {
142 #ifdef IP_RCMD_PROXY_DEBUG
143                 printf("ippr_rcmd_portmsg:sp == 0 dlen %d [%s]\n",
144                        dlen, portbuf);
145 #endif
146                 return 0;
147         }
148
149         /*
150          * Add skeleton NAT entry for connection which will come back the
151          * other way.
152          */
153         bcopy((char *)fin, (char *)&fi, sizeof(fi));
154         fi.fin_state = NULL;
155         fi.fin_nat = NULL;
156         fi.fin_flx |= FI_IGNORE;
157         fi.fin_data[0] = sp;
158         fi.fin_data[1] = 0;
159         if (nat->nat_dir == NAT_OUTBOUND)
160                 nat2 = nat_outlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p,
161                                      nat->nat_inip, nat->nat_oip);
162         else
163                 nat2 = nat_inlookup(&fi, NAT_SEARCH|IPN_TCP, nat->nat_p,
164                                     nat->nat_inip, nat->nat_oip);
165         if (nat2 == NULL) {
166                 int slen;
167
168                 slen = ip->ip_len;
169                 ip->ip_len = fin->fin_hlen + sizeof(*tcp);
170                 bzero((char *)tcp2, sizeof(*tcp2));
171                 tcp2->th_win = htons(8192);
172                 tcp2->th_sport = htons(sp);
173                 tcp2->th_dport = 0; /* XXX - don't specify remote port */
174                 TCP_OFF_A(tcp2, 5);
175                 tcp2->th_flags = TH_SYN;
176                 fi.fin_dp = (char *)tcp2;
177                 fi.fin_fr = &rcmdfr;
178                 fi.fin_dlen = sizeof(*tcp2);
179                 fi.fin_plen = fi.fin_hlen + sizeof(*tcp2);
180                 fi.fin_flx &= FI_LOWTTL|FI_FRAG|FI_TCPUDP|FI_OPTIONS|FI_IGNORE;
181                 nflags = NAT_SLAVE|IPN_TCP|SI_W_DPORT;
182
183                 swip = ip->ip_src;
184                 swip2 = ip->ip_dst;
185
186                 if (nat->nat_dir == NAT_OUTBOUND) {
187                         fi.fin_fi.fi_saddr = nat->nat_inip.s_addr;
188                         ip->ip_src = nat->nat_inip;
189                 } else {
190                         fi.fin_fi.fi_saddr = nat->nat_oip.s_addr;
191                         ip->ip_src = nat->nat_oip;
192                         nflags |= NAT_NOTRULEPORT;
193                 }
194
195                 nat2 = nat_new(&fi, nat->nat_ptr, NULL, nflags, nat->nat_dir);
196
197                 if (nat2 != NULL) {
198                         (void) nat_proto(&fi, nat2, IPN_TCP);
199                         nat_update(&fi, nat2, nat2->nat_ptr);
200                         fi.fin_ifp = NULL;
201                         if (nat->nat_dir == NAT_INBOUND) {
202                                 fi.fin_fi.fi_daddr = nat->nat_inip.s_addr;
203                                 ip->ip_dst = nat->nat_inip;
204                         }
205                         (void) fr_addstate(&fi, NULL, SI_W_DPORT);
206                         if (fi.fin_state != NULL)
207                                 fr_statederef(&fi, (ipstate_t **)&fi.fin_state);
208                 }
209                 ip->ip_len = slen;
210                 ip->ip_src = swip;
211                 ip->ip_dst = swip2;
212         }
213         return 0;
214 }
215
216
217 int ippr_rcmd_out(fin, aps, nat)
218 fr_info_t *fin;
219 ap_session_t *aps;
220 nat_t *nat;
221 {
222         if (nat->nat_dir == NAT_OUTBOUND)
223                 return ippr_rcmd_portmsg(fin, aps, nat);
224         return 0;
225 }
226
227
228 int ippr_rcmd_in(fin, aps, nat)
229 fr_info_t *fin;
230 ap_session_t *aps;
231 nat_t *nat;
232 {
233         if (nat->nat_dir == NAT_INBOUND)
234                 return ippr_rcmd_portmsg(fin, aps, nat);
235         return 0;
236 }