xref: /netbsd-src/external/bsd/ipf/dist/samples/relay.c (revision bc4097aacfdd9307c19b7947c13c6ad6982527a9)
1*bc4097aaSchristos /*	$NetBSD: relay.c,v 1.1.1.1 2012/03/23 21:20:15 christos Exp $	*/
2*bc4097aaSchristos 
3*bc4097aaSchristos /*
4*bc4097aaSchristos  * Sample program to be used as a transparent proxy.
5*bc4097aaSchristos  *
6*bc4097aaSchristos  * Must be executed with permission enough to do an ioctl on /dev/ipl
7*bc4097aaSchristos  * or equivalent.  This is just a sample and is only alpha quality.
8*bc4097aaSchristos  * - Darren Reed (8 April 1996)
9*bc4097aaSchristos  */
10*bc4097aaSchristos #include <unistd.h>
11*bc4097aaSchristos #include <stdio.h>
12*bc4097aaSchristos #include <fcntl.h>
13*bc4097aaSchristos #include <errno.h>
14*bc4097aaSchristos #include <sys/types.h>
15*bc4097aaSchristos #include <sys/time.h>
16*bc4097aaSchristos #include <sys/syslog.h>
17*bc4097aaSchristos #include <sys/socket.h>
18*bc4097aaSchristos #include <sys/ioctl.h>
19*bc4097aaSchristos #include <netinet/in.h>
20*bc4097aaSchristos #include <net/if.h>
21*bc4097aaSchristos #include "netinet/ip_compat.h"
22*bc4097aaSchristos #include "netinet/ip_fil.h"
23*bc4097aaSchristos #include "netinet/ip_nat.h"
24*bc4097aaSchristos #include "netinet/ipl.h"
25*bc4097aaSchristos 
26*bc4097aaSchristos #define	RELAY_BUFSZ	8192
27*bc4097aaSchristos 
28*bc4097aaSchristos char	ibuff[RELAY_BUFSZ];
29*bc4097aaSchristos char	obuff[RELAY_BUFSZ];
30*bc4097aaSchristos 
relay(ifd,ofd,rfd)31*bc4097aaSchristos int relay(ifd, ofd, rfd)
32*bc4097aaSchristos 	int ifd, ofd, rfd;
33*bc4097aaSchristos {
34*bc4097aaSchristos 	fd_set	rfds, wfds;
35*bc4097aaSchristos 	char	*irh, *irt, *rrh, *rrt;
36*bc4097aaSchristos 	char	*iwh, *iwt, *rwh, *rwt;
37*bc4097aaSchristos 	int	nfd, n, rw;
38*bc4097aaSchristos 
39*bc4097aaSchristos 	irh = irt = ibuff;
40*bc4097aaSchristos 	iwh = iwt = obuff;
41*bc4097aaSchristos 	nfd = ifd;
42*bc4097aaSchristos 	if (nfd < ofd)
43*bc4097aaSchristos 		nfd = ofd;
44*bc4097aaSchristos 	if (nfd < rfd)
45*bc4097aaSchristos 		nfd = rfd;
46*bc4097aaSchristos 
47*bc4097aaSchristos 	while (1) {
48*bc4097aaSchristos 		FD_ZERO(&rfds);
49*bc4097aaSchristos 		FD_ZERO(&wfds);
50*bc4097aaSchristos 		if (irh > irt)
51*bc4097aaSchristos 			FD_SET(rfd, &wfds);
52*bc4097aaSchristos 		if (irh < (ibuff + RELAY_BUFSZ))
53*bc4097aaSchristos 			FD_SET(ifd, &rfds);
54*bc4097aaSchristos 		if (iwh > iwt)
55*bc4097aaSchristos 			FD_SET(ofd, &wfds);
56*bc4097aaSchristos 		if (iwh < (obuff + RELAY_BUFSZ))
57*bc4097aaSchristos 			FD_SET(rfd, &rfds);
58*bc4097aaSchristos 
59*bc4097aaSchristos 		switch ((n = select(nfd + 1, &rfds, &wfds, NULL, NULL)))
60*bc4097aaSchristos 		{
61*bc4097aaSchristos 		case -1 :
62*bc4097aaSchristos 		case 0 :
63*bc4097aaSchristos 			return -1;
64*bc4097aaSchristos 		default :
65*bc4097aaSchristos 			if (FD_ISSET(ifd, &rfds)) {
66*bc4097aaSchristos 				rw = read(ifd, irh, ibuff + RELAY_BUFSZ - irh);
67*bc4097aaSchristos 				if (rw == -1)
68*bc4097aaSchristos 					return -1;
69*bc4097aaSchristos 				if (rw == 0)
70*bc4097aaSchristos 					return 0;
71*bc4097aaSchristos 				irh += rw;
72*bc4097aaSchristos 				n--;
73*bc4097aaSchristos 			}
74*bc4097aaSchristos 			if (n && FD_ISSET(ofd, &wfds)) {
75*bc4097aaSchristos 				rw = write(ofd, iwt, iwh  - iwt);
76*bc4097aaSchristos 				if (rw == -1)
77*bc4097aaSchristos 					return -1;
78*bc4097aaSchristos 				iwt += rw;
79*bc4097aaSchristos 				n--;
80*bc4097aaSchristos 			}
81*bc4097aaSchristos 			if (n && FD_ISSET(rfd, &rfds)) {
82*bc4097aaSchristos 				rw = read(rfd, iwh, obuff + RELAY_BUFSZ - iwh);
83*bc4097aaSchristos 				if (rw == -1)
84*bc4097aaSchristos 					return -1;
85*bc4097aaSchristos 				if (rw == 0)
86*bc4097aaSchristos 					return 0;
87*bc4097aaSchristos 				iwh += rw;
88*bc4097aaSchristos 				n--;
89*bc4097aaSchristos 			}
90*bc4097aaSchristos 			if (n && FD_ISSET(rfd, &wfds)) {
91*bc4097aaSchristos 				rw = write(rfd, irt, irh  - irt);
92*bc4097aaSchristos 				if (rw == -1)
93*bc4097aaSchristos 					return -1;
94*bc4097aaSchristos 				irt += rw;
95*bc4097aaSchristos 				n--;
96*bc4097aaSchristos 			}
97*bc4097aaSchristos 			if (irh == irt)
98*bc4097aaSchristos 				irh = irt = ibuff;
99*bc4097aaSchristos 			if (iwh == iwt)
100*bc4097aaSchristos 				iwh = iwt = obuff;
101*bc4097aaSchristos 		}
102*bc4097aaSchristos 	}
103*bc4097aaSchristos }
104*bc4097aaSchristos 
main(argc,argv)105*bc4097aaSchristos main(argc, argv)
106*bc4097aaSchristos 	int argc;
107*bc4097aaSchristos 	char *argv[];
108*bc4097aaSchristos {
109*bc4097aaSchristos 	struct	sockaddr_in	sin;
110*bc4097aaSchristos 	ipfobj_t	obj;
111*bc4097aaSchristos 	natlookup_t	nl;
112*bc4097aaSchristos 	natlookup_t	*nlp = &nl;
113*bc4097aaSchristos 	int	fd, sl = sizeof(sl), se;
114*bc4097aaSchristos 
115*bc4097aaSchristos 	openlog(argv[0], LOG_PID|LOG_NDELAY, LOG_DAEMON);
116*bc4097aaSchristos 	if ((fd = open(IPNAT_NAME, O_RDONLY)) == -1) {
117*bc4097aaSchristos 		se = errno;
118*bc4097aaSchristos 		perror("open");
119*bc4097aaSchristos 		errno = se;
120*bc4097aaSchristos 		syslog(LOG_ERR, "open: %m\n");
121*bc4097aaSchristos 		exit(-1);
122*bc4097aaSchristos 	}
123*bc4097aaSchristos 
124*bc4097aaSchristos 	bzero(&obj, sizeof(obj));
125*bc4097aaSchristos 	obj.ipfo_rev = IPFILTER_VERSION;
126*bc4097aaSchristos 	obj.ipfo_size = sizeof(nl);
127*bc4097aaSchristos 	obj.ipfo_ptr = &nl;
128*bc4097aaSchristos 	obj.ipfo_type = IPFOBJ_NATLOOKUP;
129*bc4097aaSchristos 
130*bc4097aaSchristos 	bzero(&nl, sizeof(nl));
131*bc4097aaSchristos 	nl.nl_flags = IPN_TCP;
132*bc4097aaSchristos 
133*bc4097aaSchristos 	bzero(&sin, sizeof(sin));
134*bc4097aaSchristos 	sin.sin_family = AF_INET;
135*bc4097aaSchristos 	sl = sizeof(sin);
136*bc4097aaSchristos 	if (getsockname(0, (struct sockaddr *)&sin, &sl) == -1) {
137*bc4097aaSchristos 		se = errno;
138*bc4097aaSchristos 		perror("getsockname");
139*bc4097aaSchristos 		errno = se;
140*bc4097aaSchristos 		syslog(LOG_ERR, "getsockname: %m\n");
141*bc4097aaSchristos 		exit(-1);
142*bc4097aaSchristos 	} else {
143*bc4097aaSchristos 		nl.nl_inip.s_addr = sin.sin_addr.s_addr;
144*bc4097aaSchristos 		nl.nl_inport = sin.sin_port;
145*bc4097aaSchristos 	}
146*bc4097aaSchristos 
147*bc4097aaSchristos 	bzero(&sin, sizeof(sin));
148*bc4097aaSchristos 	sin.sin_family = AF_INET;
149*bc4097aaSchristos 	sl = sizeof(sin);
150*bc4097aaSchristos 	if (getpeername(0, (struct sockaddr *)&sin, &sl) == -1) {
151*bc4097aaSchristos 		se = errno;
152*bc4097aaSchristos 		perror("getpeername");
153*bc4097aaSchristos 		errno = se;
154*bc4097aaSchristos 		syslog(LOG_ERR, "getpeername: %m\n");
155*bc4097aaSchristos 		exit(-1);
156*bc4097aaSchristos 	} else {
157*bc4097aaSchristos 		nl.nl_outip.s_addr = sin.sin_addr.s_addr;
158*bc4097aaSchristos 		nl.nl_outport = sin.sin_port;
159*bc4097aaSchristos 	}
160*bc4097aaSchristos 
161*bc4097aaSchristos 	if (ioctl(fd, SIOCGNATL, &obj) == -1) {
162*bc4097aaSchristos 		se = errno;
163*bc4097aaSchristos 		perror("ioctl");
164*bc4097aaSchristos 		errno = se;
165*bc4097aaSchristos 		syslog(LOG_ERR, "ioctl: %m\n");
166*bc4097aaSchristos 		exit(-1);
167*bc4097aaSchristos 	}
168*bc4097aaSchristos 
169*bc4097aaSchristos 	sin.sin_port = nl.nl_realport;
170*bc4097aaSchristos 	sin.sin_addr = nl.nl_realip;
171*bc4097aaSchristos 	sl = sizeof(sin);
172*bc4097aaSchristos 
173*bc4097aaSchristos 	fd = socket(AF_INET, SOCK_STREAM, 0);
174*bc4097aaSchristos 	if (connect(fd, (struct sockaddr *)&sin, sl) == -1) {
175*bc4097aaSchristos 		se = errno;
176*bc4097aaSchristos 		perror("connect");
177*bc4097aaSchristos 		errno = se;
178*bc4097aaSchristos 		syslog(LOG_ERR, "connect: %m\n");
179*bc4097aaSchristos 		exit(-1);
180*bc4097aaSchristos 	}
181*bc4097aaSchristos 
182*bc4097aaSchristos 	(void) ioctl(fd, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK);
183*bc4097aaSchristos 	(void) ioctl(0, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK);
184*bc4097aaSchristos 	(void) ioctl(1, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK);
185*bc4097aaSchristos 
186*bc4097aaSchristos 	syslog(LOG_NOTICE, "connected to %s,%d\n", inet_ntoa(sin.sin_addr),
187*bc4097aaSchristos 		ntohs(sin.sin_port));
188*bc4097aaSchristos 	if (relay(0, 1, fd) == -1) {
189*bc4097aaSchristos 		se = errno;
190*bc4097aaSchristos 		perror("relay");
191*bc4097aaSchristos 		errno = se;
192*bc4097aaSchristos 		syslog(LOG_ERR, "relay: %m\n");
193*bc4097aaSchristos 		exit(-1);
194*bc4097aaSchristos 	}
195*bc4097aaSchristos 	exit(0);
196*bc4097aaSchristos }
197