1145519Sdarrenr/* $FreeBSD$ */ 2145510Sdarrenr 3145510Sdarrenr/* 4145510Sdarrenr * Sample program to be used as a transparent proxy. 5145510Sdarrenr * 6145510Sdarrenr * Must be executed with permission enough to do an ioctl on /dev/ipl 7145510Sdarrenr * or equivalent. This is just a sample and is only alpha quality. 8145510Sdarrenr * - Darren Reed (8 April 1996) 9145510Sdarrenr */ 10145510Sdarrenr#include <unistd.h> 11145510Sdarrenr#include <stdio.h> 12145510Sdarrenr#include <fcntl.h> 13145510Sdarrenr#include <errno.h> 14145510Sdarrenr#include <sys/types.h> 15145510Sdarrenr#include <sys/time.h> 16145510Sdarrenr#include <sys/syslog.h> 17145510Sdarrenr#include <sys/socket.h> 18145510Sdarrenr#include <sys/ioctl.h> 19145510Sdarrenr#include <netinet/in.h> 20145510Sdarrenr#include <net/if.h> 21153881Sguido#include "netinet/ip_compat.h" 22153881Sguido#include "netinet/ip_fil.h" 23153881Sguido#include "netinet/ip_nat.h" 24145554Sdarrenr#include "netinet/ipl.h" 25145510Sdarrenr 26145510Sdarrenr#define RELAY_BUFSZ 8192 27145510Sdarrenr 28145510Sdarrenrchar ibuff[RELAY_BUFSZ]; 29145510Sdarrenrchar obuff[RELAY_BUFSZ]; 30145510Sdarrenr 31145510Sdarrenrint relay(ifd, ofd, rfd) 32255332Scy int ifd, ofd, rfd; 33145510Sdarrenr{ 34145510Sdarrenr fd_set rfds, wfds; 35145510Sdarrenr char *irh, *irt, *rrh, *rrt; 36145510Sdarrenr char *iwh, *iwt, *rwh, *rwt; 37145510Sdarrenr int nfd, n, rw; 38145510Sdarrenr 39145510Sdarrenr irh = irt = ibuff; 40145510Sdarrenr iwh = iwt = obuff; 41145510Sdarrenr nfd = ifd; 42145510Sdarrenr if (nfd < ofd) 43145510Sdarrenr nfd = ofd; 44145510Sdarrenr if (nfd < rfd) 45145510Sdarrenr nfd = rfd; 46145510Sdarrenr 47145510Sdarrenr while (1) { 48145510Sdarrenr FD_ZERO(&rfds); 49145510Sdarrenr FD_ZERO(&wfds); 50145510Sdarrenr if (irh > irt) 51145510Sdarrenr FD_SET(rfd, &wfds); 52145510Sdarrenr if (irh < (ibuff + RELAY_BUFSZ)) 53145510Sdarrenr FD_SET(ifd, &rfds); 54145510Sdarrenr if (iwh > iwt) 55145510Sdarrenr FD_SET(ofd, &wfds); 56145510Sdarrenr if (iwh < (obuff + RELAY_BUFSZ)) 57145510Sdarrenr FD_SET(rfd, &rfds); 58145510Sdarrenr 59145510Sdarrenr switch ((n = select(nfd + 1, &rfds, &wfds, NULL, NULL))) 60145510Sdarrenr { 61145510Sdarrenr case -1 : 62145510Sdarrenr case 0 : 63145510Sdarrenr return -1; 64145510Sdarrenr default : 65145510Sdarrenr if (FD_ISSET(ifd, &rfds)) { 66145510Sdarrenr rw = read(ifd, irh, ibuff + RELAY_BUFSZ - irh); 67145510Sdarrenr if (rw == -1) 68145510Sdarrenr return -1; 69145510Sdarrenr if (rw == 0) 70145510Sdarrenr return 0; 71145510Sdarrenr irh += rw; 72145510Sdarrenr n--; 73145510Sdarrenr } 74145510Sdarrenr if (n && FD_ISSET(ofd, &wfds)) { 75145510Sdarrenr rw = write(ofd, iwt, iwh - iwt); 76145510Sdarrenr if (rw == -1) 77145510Sdarrenr return -1; 78145510Sdarrenr iwt += rw; 79145510Sdarrenr n--; 80145510Sdarrenr } 81145510Sdarrenr if (n && FD_ISSET(rfd, &rfds)) { 82145510Sdarrenr rw = read(rfd, iwh, obuff + RELAY_BUFSZ - iwh); 83145510Sdarrenr if (rw == -1) 84145510Sdarrenr return -1; 85145510Sdarrenr if (rw == 0) 86145510Sdarrenr return 0; 87145510Sdarrenr iwh += rw; 88145510Sdarrenr n--; 89145510Sdarrenr } 90145510Sdarrenr if (n && FD_ISSET(rfd, &wfds)) { 91145510Sdarrenr rw = write(rfd, irt, irh - irt); 92145510Sdarrenr if (rw == -1) 93145510Sdarrenr return -1; 94145510Sdarrenr irt += rw; 95145510Sdarrenr n--; 96145510Sdarrenr } 97145510Sdarrenr if (irh == irt) 98145510Sdarrenr irh = irt = ibuff; 99145510Sdarrenr if (iwh == iwt) 100145510Sdarrenr iwh = iwt = obuff; 101145510Sdarrenr } 102145510Sdarrenr } 103145510Sdarrenr} 104145510Sdarrenr 105145510Sdarrenrmain(argc, argv) 106255332Scy int argc; 107255332Scy char *argv[]; 108145510Sdarrenr{ 109145510Sdarrenr struct sockaddr_in sin; 110145510Sdarrenr ipfobj_t obj; 111145510Sdarrenr natlookup_t nl; 112145510Sdarrenr natlookup_t *nlp = &nl; 113145510Sdarrenr int fd, sl = sizeof(sl), se; 114145510Sdarrenr 115145510Sdarrenr openlog(argv[0], LOG_PID|LOG_NDELAY, LOG_DAEMON); 116145510Sdarrenr if ((fd = open(IPNAT_NAME, O_RDONLY)) == -1) { 117145510Sdarrenr se = errno; 118145510Sdarrenr perror("open"); 119145510Sdarrenr errno = se; 120145510Sdarrenr syslog(LOG_ERR, "open: %m\n"); 121145510Sdarrenr exit(-1); 122145510Sdarrenr } 123145510Sdarrenr 124145510Sdarrenr bzero(&obj, sizeof(obj)); 125145510Sdarrenr obj.ipfo_rev = IPFILTER_VERSION; 126145510Sdarrenr obj.ipfo_size = sizeof(nl); 127145510Sdarrenr obj.ipfo_ptr = &nl; 128145510Sdarrenr obj.ipfo_type = IPFOBJ_NATLOOKUP; 129145510Sdarrenr 130145510Sdarrenr bzero(&nl, sizeof(nl)); 131145510Sdarrenr nl.nl_flags = IPN_TCP; 132145510Sdarrenr 133145510Sdarrenr bzero(&sin, sizeof(sin)); 134145510Sdarrenr sin.sin_family = AF_INET; 135145510Sdarrenr sl = sizeof(sin); 136145510Sdarrenr if (getsockname(0, (struct sockaddr *)&sin, &sl) == -1) { 137145510Sdarrenr se = errno; 138145510Sdarrenr perror("getsockname"); 139145510Sdarrenr errno = se; 140145510Sdarrenr syslog(LOG_ERR, "getsockname: %m\n"); 141145510Sdarrenr exit(-1); 142145510Sdarrenr } else { 143145510Sdarrenr nl.nl_inip.s_addr = sin.sin_addr.s_addr; 144145510Sdarrenr nl.nl_inport = sin.sin_port; 145145510Sdarrenr } 146145510Sdarrenr 147145510Sdarrenr bzero(&sin, sizeof(sin)); 148145510Sdarrenr sin.sin_family = AF_INET; 149145510Sdarrenr sl = sizeof(sin); 150145510Sdarrenr if (getpeername(0, (struct sockaddr *)&sin, &sl) == -1) { 151145510Sdarrenr se = errno; 152145510Sdarrenr perror("getpeername"); 153145510Sdarrenr errno = se; 154145510Sdarrenr syslog(LOG_ERR, "getpeername: %m\n"); 155145510Sdarrenr exit(-1); 156145510Sdarrenr } else { 157145510Sdarrenr nl.nl_outip.s_addr = sin.sin_addr.s_addr; 158145510Sdarrenr nl.nl_outport = sin.sin_port; 159145510Sdarrenr } 160145510Sdarrenr 161145510Sdarrenr if (ioctl(fd, SIOCGNATL, &obj) == -1) { 162145510Sdarrenr se = errno; 163145510Sdarrenr perror("ioctl"); 164145510Sdarrenr errno = se; 165145510Sdarrenr syslog(LOG_ERR, "ioctl: %m\n"); 166145510Sdarrenr exit(-1); 167145510Sdarrenr } 168145510Sdarrenr 169145510Sdarrenr sin.sin_port = nl.nl_realport; 170145510Sdarrenr sin.sin_addr = nl.nl_realip; 171145510Sdarrenr sl = sizeof(sin); 172145510Sdarrenr 173145510Sdarrenr fd = socket(AF_INET, SOCK_STREAM, 0); 174145510Sdarrenr if (connect(fd, (struct sockaddr *)&sin, sl) == -1) { 175145510Sdarrenr se = errno; 176145510Sdarrenr perror("connect"); 177145510Sdarrenr errno = se; 178145510Sdarrenr syslog(LOG_ERR, "connect: %m\n"); 179145510Sdarrenr exit(-1); 180145510Sdarrenr } 181145510Sdarrenr 182145510Sdarrenr (void) ioctl(fd, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK); 183145510Sdarrenr (void) ioctl(0, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK); 184145510Sdarrenr (void) ioctl(1, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK); 185145510Sdarrenr 186145510Sdarrenr syslog(LOG_NOTICE, "connected to %s,%d\n", inet_ntoa(sin.sin_addr), 187145510Sdarrenr ntohs(sin.sin_port)); 188145510Sdarrenr if (relay(0, 1, fd) == -1) { 189145510Sdarrenr se = errno; 190145510Sdarrenr perror("relay"); 191145510Sdarrenr errno = se; 192145510Sdarrenr syslog(LOG_ERR, "relay: %m\n"); 193145510Sdarrenr exit(-1); 194145510Sdarrenr } 195145510Sdarrenr exit(0); 196145510Sdarrenr} 197