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