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