Initial import from FreeBSD RELENG_4:
[games.git] / sys / contrib / ipfilter / netinet / ip_rcmd_pxy.c
1 /*
2  * $Id: ip_rcmd_pxy.c,v 1.4.2.6 2002/10/01 15:24:59 darrenr Exp $
3  */
4 /*
5  * Simple RCMD transparent proxy for in-kernel use.  For use with the NAT
6  * code.
7  * $FreeBSD: src/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c,v 1.8.2.3 2003/03/01 03:55:54 darrenr Exp $
8  */
9 #if SOLARIS && defined(_KERNEL)
10 extern  kmutex_t        ipf_rw;
11 #endif
12
13 #define isdigit(x)      ((x) >= '0' && (x) <= '9')
14
15 #define IPF_RCMD_PROXY
16
17
18 int ippr_rcmd_init __P((void));
19 int ippr_rcmd_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *));
20 int ippr_rcmd_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *));
21 u_short ipf_rcmd_atoi __P((char *));
22 int ippr_rcmd_portmsg __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *));
23
24 static  frentry_t       rcmdfr;
25
26
27 /*
28  * RCMD application proxy initialization.
29  */
30 int ippr_rcmd_init()
31 {
32         bzero((char *)&rcmdfr, sizeof(rcmdfr));
33         rcmdfr.fr_ref = 1;
34         rcmdfr.fr_flags = FR_INQUE|FR_PASS|FR_QUICK|FR_KEEPSTATE;
35         return 0;
36 }
37
38
39 /*
40  * Setup for a new RCMD proxy.
41  */
42 int ippr_rcmd_new(fin, ip, aps, nat)
43 fr_info_t *fin;
44 ip_t *ip;
45 ap_session_t *aps;
46 nat_t *nat;
47 {
48         tcphdr_t *tcp = (tcphdr_t *)fin->fin_dp;
49
50         aps->aps_psiz = sizeof(u_32_t);
51         KMALLOCS(aps->aps_data, u_32_t *, sizeof(u_32_t));
52         if (aps->aps_data == NULL)
53                 return -1;
54         *(u_32_t *)aps->aps_data = 0;
55         aps->aps_sport = tcp->th_sport;
56         aps->aps_dport = tcp->th_dport;
57         return 0;
58 }
59
60
61 /*
62  * ipf_rcmd_atoi - implement a simple version of atoi
63  */
64 u_short ipf_rcmd_atoi(ptr)
65 char *ptr;
66 {
67         register char *s = ptr, c;
68         register u_short i = 0;
69
70         while ((c = *s++) && isdigit(c)) {
71                 i *= 10;
72                 i += c - '0';
73         }
74         return i;
75 }
76
77
78 int ippr_rcmd_portmsg(fin, ip, aps, nat)
79 fr_info_t *fin;
80 ip_t *ip;
81 ap_session_t *aps;
82 nat_t *nat;
83 {
84         char portbuf[8], *s;
85         struct in_addr swip;
86         int off, dlen;
87         tcphdr_t *tcp, tcph, *tcp2 = &tcph;
88         fr_info_t fi;
89         u_short sp;
90         nat_t *ipn;
91         mb_t *m;
92 #if     SOLARIS
93         mb_t *m1;
94 #endif
95
96         tcp = (tcphdr_t *)fin->fin_dp;
97
98         if (tcp->th_flags & TH_SYN) {
99                 *(u_32_t *)aps->aps_data = htonl(ntohl(tcp->th_seq) + 1);
100                 return 0;
101         }
102
103         if ((*(u_32_t *)aps->aps_data != 0) &&
104             (tcp->th_seq != *(u_32_t *)aps->aps_data))
105                 return 0;
106
107         off = fin->fin_hlen + (tcp->th_off << 2);
108
109 #if     SOLARIS
110         m = fin->fin_qfm;
111
112         dlen = msgdsize(m) - off;
113         bzero(portbuf, sizeof(portbuf));
114         copyout_mblk(m, off, MIN(sizeof(portbuf), dlen), portbuf);
115 #else
116         m = *(mb_t **)fin->fin_mp;
117         dlen = mbufchainlen(m) - off;
118         bzero(portbuf, sizeof(portbuf));
119         m_copydata(m, off, MIN(sizeof(portbuf), dlen), portbuf);
120 #endif
121
122         portbuf[sizeof(portbuf) - 1] = '\0';
123         s = portbuf;
124         sp = ipf_rcmd_atoi(s);
125         if (!sp)
126                 return 0;
127
128         /*
129          * Add skeleton NAT entry for connection which will come back the
130          * other way.
131          */
132         bcopy((char *)fin, (char *)&fi, sizeof(fi));
133         fi.fin_data[0] = sp;
134         fi.fin_data[1] = fin->fin_data[1];
135         ipn = nat_outlookup(&fi, IPN_TCP, nat->nat_p, nat->nat_inip,
136                             ip->ip_dst, 0);
137         if (ipn == NULL) {
138                 int slen;
139
140                 slen = ip->ip_len;
141                 ip->ip_len = fin->fin_hlen + sizeof(*tcp);
142                 bzero((char *)tcp2, sizeof(*tcp2));
143                 tcp2->th_win = htons(8192);
144                 tcp2->th_sport = htons(sp);
145                 tcp2->th_dport = 0; /* XXX - don't specify remote port */
146                 tcp2->th_off = 5;
147                 tcp2->th_flags = TH_SYN;
148                 fi.fin_data[1] = 0;
149                 fi.fin_dp = (char *)tcp2;
150                 fi.fin_dlen = sizeof(*tcp2);
151                 swip = ip->ip_src;
152                 ip->ip_src = nat->nat_inip;
153                 ipn = nat_new(&fi, ip, nat->nat_ptr, NULL, IPN_TCP|FI_W_DPORT,
154                               NAT_OUTBOUND);
155                 if (ipn != NULL) {
156                         ipn->nat_age = fr_defnatage;
157                         fi.fin_fr = &rcmdfr;
158                         (void) fr_addstate(ip, &fi, NULL,
159                                            FI_W_DPORT|FI_IGNOREPKT);
160                 }
161                 ip->ip_len = slen;
162                 ip->ip_src = swip;
163         }
164         return 0;
165 }
166
167
168 int ippr_rcmd_out(fin, ip, aps, nat)
169 fr_info_t *fin;
170 ip_t *ip;
171 ap_session_t *aps;
172 nat_t *nat;
173 {
174         return ippr_rcmd_portmsg(fin, ip, aps, nat);
175 }