ip_rcmd_pxy.c revision 110916
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: head/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c 110916 2003-02-15 06:25:25Z darrenr $
8 */
9#if SOLARIS && defined(_KERNEL)
10extern	kmutex_t	ipf_rw;
11#endif
12
13#define	isdigit(x)	((x) >= '0' && (x) <= '9')
14
15#define	IPF_RCMD_PROXY
16
17
18int ippr_rcmd_init __P((void));
19int ippr_rcmd_new __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *));
20int ippr_rcmd_out __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *));
21u_short ipf_rcmd_atoi __P((char *));
22int ippr_rcmd_portmsg __P((fr_info_t *, ip_t *, ap_session_t *, nat_t *));
23
24static	frentry_t	rcmdfr;
25
26
27/*
28 * RCMD application proxy initialization.
29 */
30int 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 */
42int ippr_rcmd_new(fin, ip, aps, nat)
43fr_info_t *fin;
44ip_t *ip;
45ap_session_t *aps;
46nat_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 */
64u_short ipf_rcmd_atoi(ptr)
65char *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
78int ippr_rcmd_portmsg(fin, ip, aps, nat)
79fr_info_t *fin;
80ip_t *ip;
81ap_session_t *aps;
82nat_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
168int ippr_rcmd_out(fin, ip, aps, nat)
169fr_info_t *fin;
170ip_t *ip;
171ap_session_t *aps;
172nat_t *nat;
173{
174	return ippr_rcmd_portmsg(fin, ip, aps, nat);
175}
176