1145519Sdarrenr/* $FreeBSD$ */ 2145510Sdarrenr 331183Speter/* 431183Speter * Sample transparent proxy program. 531183Speter * 631183Speter * Sample implementation of a program which intercepts a TCP connectiona and 731183Speter * just echos all data back to the origin. Written to work via inetd as a 831183Speter * "nonwait" program running as root; ie. 931183Speter * tcpmux stream tcp nowait root /usr/local/bin/proxy proxy 1031183Speter * with a NAT rue like this: 1131183Speter * rdr smc0 0/0 port 80 -> 127.0.0.1/32 port 1 1231183Speter */ 1331183Speter#include <stdio.h> 1431183Speter#include <string.h> 1531183Speter#include <fcntl.h> 1631183Speter#include <syslog.h> 1731183Speter#if !defined(__SVR4) && !defined(__svr4__) 1831183Speter#include <strings.h> 1931183Speter#else 2031183Speter#include <sys/byteorder.h> 2131183Speter#endif 2231183Speter#include <sys/types.h> 2331183Speter#include <sys/time.h> 2431183Speter#include <sys/param.h> 2531183Speter#include <stdlib.h> 2631183Speter#include <unistd.h> 2731183Speter#include <stddef.h> 2831183Speter#include <sys/socket.h> 2931183Speter#include <sys/ioctl.h> 3031183Speter#if defined(sun) && (defined(__svr4__) || defined(__SVR4)) 3131183Speter# include <sys/ioccom.h> 3231183Speter# include <sys/sysmacros.h> 3331183Speter#endif 3431183Speter#include <netinet/in.h> 3531183Speter#include <netinet/in_systm.h> 3631183Speter#include <netinet/ip.h> 3731183Speter#include <netinet/tcp.h> 3831183Speter#include <net/if.h> 3931183Speter#include <netdb.h> 4031183Speter#include <arpa/nameser.h> 4131183Speter#include <arpa/inet.h> 4231183Speter#include <resolv.h> 4331183Speter#include <ctype.h> 4431183Speter#include "netinet/ip_compat.h" 4531183Speter#include "netinet/ip_fil.h" 4692686Sdarrenr#include "netinet/ip_nat.h" 4792686Sdarrenr#include "netinet/ip_state.h" 4831183Speter#include "netinet/ip_proxy.h" 4931183Speter#include "netinet/ip_nat.h" 50145510Sdarrenr#include "netinet/ipl.h" 5131183Speter 5231183Speter 5331183Spetermain(argc, argv) 54255332Scy int argc; 55255332Scy char *argv[]; 5631183Speter{ 5731183Speter struct sockaddr_in sin, sloc, sout; 58145510Sdarrenr ipfobj_t obj; 5931183Speter natlookup_t natlook; 6031183Speter char buffer[512]; 6131183Speter int namelen, fd, n; 6231183Speter 6331183Speter /* 6431183Speter * get IP# and port # of the remote end of the connection (at the 6531183Speter * origin). 6631183Speter */ 6731183Speter namelen = sizeof(sin); 6831183Speter if (getpeername(0, (struct sockaddr *)&sin, &namelen) == -1) { 6931183Speter perror("getpeername"); 7031183Speter exit(-1); 7131183Speter } 7231183Speter 7331183Speter /* 7431183Speter * get IP# and port # of the local end of the connection (at the 7531183Speter * man-in-the-middle). 7631183Speter */ 7731183Speter namelen = sizeof(sin); 7831183Speter if (getsockname(0, (struct sockaddr *)&sloc, &namelen) == -1) { 7931183Speter perror("getsockname"); 8031183Speter exit(-1); 8131183Speter } 8231183Speter 83145510Sdarrenr bzero((char *)&obj, sizeof(obj)); 84145510Sdarrenr obj.ipfo_rev = IPFILTER_VERSION; 85145510Sdarrenr obj.ipfo_size = sizeof(natlook); 86145510Sdarrenr obj.ipfo_ptr = &natlook; 87145510Sdarrenr obj.ipfo_type = IPFOBJ_NATLOOKUP; 88145510Sdarrenr 8931183Speter /* 9031183Speter * Build up the NAT natlookup structure. 9131183Speter */ 9231183Speter bzero((char *)&natlook, sizeof(natlook)); 9331183Speter natlook.nl_outip = sin.sin_addr; 9431183Speter natlook.nl_inip = sloc.sin_addr; 95145510Sdarrenr natlook.nl_flags = IPN_TCP; 96153881Sguido natlook.nl_outport = sin.sin_port; 97153881Sguido natlook.nl_inport = sloc.sin_port; 9831183Speter 9931183Speter /* 10031183Speter * Open the NAT device and lookup the mapping pair. 10131183Speter */ 102145510Sdarrenr fd = open(IPNAT_NAME, O_RDONLY); 103145510Sdarrenr if (ioctl(fd, SIOCGNATL, &obj) == -1) { 10492686Sdarrenr perror("ioctl(SIOCGNATL)"); 10531183Speter exit(-1); 10631183Speter } 10792686Sdarrenr 10892686Sdarrenr#define DO_NAT_OUT 10992686Sdarrenr#ifdef DO_NAT_OUT 11092686Sdarrenr if (argc > 1) 11192686Sdarrenr do_nat_out(0, 1, fd, &natlook, argv[1]); 11292686Sdarrenr#else 11392686Sdarrenr 11431183Speter /* 11531183Speter * Log it 11631183Speter */ 11731183Speter syslog(LOG_DAEMON|LOG_INFO, "connect to %s,%d", 11834739Speter inet_ntoa(natlook.nl_realip), ntohs(natlook.nl_realport)); 11931183Speter printf("connect to %s,%d\n", 12031183Speter inet_ntoa(natlook.nl_realip), ntohs(natlook.nl_realport)); 12131183Speter 12231183Speter /* 12331183Speter * Just echo data read in from stdin to stdout 12431183Speter */ 12531183Speter while ((n = read(0, buffer, sizeof(buffer))) > 0) 12631183Speter if (write(1, buffer, n) != n) 12731183Speter break; 12831183Speter close(0); 12992686Sdarrenr#endif 13031183Speter} 13192686Sdarrenr 13292686Sdarrenr 13392686Sdarrenr#ifdef DO_NAT_OUT 13492686Sdarrenrdo_nat_out(in, out, fd, nlp, extif) 135255332Scy int fd; 136255332Scy natlookup_t *nlp; 137255332Scy char *extif; 13892686Sdarrenr{ 13992686Sdarrenr nat_save_t ns, *nsp = &ns; 14092686Sdarrenr struct sockaddr_in usin; 14192686Sdarrenr u_32_t sum1, sum2, sumd; 14292686Sdarrenr int onoff, ofd, slen; 143145510Sdarrenr ipfobj_t obj; 14492686Sdarrenr ipnat_t *ipn; 14592686Sdarrenr nat_t *nat; 14692686Sdarrenr 14792686Sdarrenr bzero((char *)&ns, sizeof(ns)); 14892686Sdarrenr 14992686Sdarrenr nat = &ns.ipn_nat; 15092686Sdarrenr nat->nat_p = IPPROTO_TCP; 15192686Sdarrenr nat->nat_dir = NAT_OUTBOUND; 15292686Sdarrenr if ((extif != NULL) && (*extif != '\0')) { 153145510Sdarrenr strncpy(nat->nat_ifnames[0], extif, 154145510Sdarrenr sizeof(nat->nat_ifnames[0])); 155145510Sdarrenr strncpy(nat->nat_ifnames[1], extif, 156145510Sdarrenr sizeof(nat->nat_ifnames[1])); 157145510Sdarrenr nat->nat_ifnames[0][sizeof(nat->nat_ifnames[0]) - 1] = '\0'; 158145510Sdarrenr nat->nat_ifnames[1][sizeof(nat->nat_ifnames[1]) - 1] = '\0'; 15992686Sdarrenr } 16092686Sdarrenr 16192686Sdarrenr ofd = socket(AF_INET, SOCK_DGRAM, 0); 16292686Sdarrenr bzero((char *)&usin, sizeof(usin)); 16392686Sdarrenr usin.sin_family = AF_INET; 16492686Sdarrenr usin.sin_addr = nlp->nl_realip; 16592686Sdarrenr usin.sin_port = nlp->nl_realport; 16692686Sdarrenr (void) connect(ofd, (struct sockaddr *)&usin, sizeof(usin)); 16792686Sdarrenr slen = sizeof(usin); 16892686Sdarrenr (void) getsockname(ofd, (struct sockaddr *)&usin, &slen); 16992686Sdarrenr close(ofd); 17092686Sdarrenrprintf("local IP# to use: %s\n", inet_ntoa(usin.sin_addr)); 17192686Sdarrenr 17292686Sdarrenr if ((ofd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 17392686Sdarrenr perror("socket"); 17492686Sdarrenr usin.sin_port = 0; 17592686Sdarrenr if (bind(ofd, (struct sockaddr *)&usin, sizeof(usin))) 17692686Sdarrenr perror("bind"); 17792686Sdarrenr slen = sizeof(usin); 17892686Sdarrenr if (getsockname(ofd, (struct sockaddr *)&usin, &slen)) 17992686Sdarrenr perror("getsockname"); 18092686Sdarrenrprintf("local port# to use: %d\n", ntohs(usin.sin_port)); 18192686Sdarrenr 18292686Sdarrenr nat->nat_inip = usin.sin_addr; 18392686Sdarrenr nat->nat_outip = nlp->nl_outip; 18492686Sdarrenr nat->nat_oip = nlp->nl_realip; 18592686Sdarrenr 18692686Sdarrenr sum1 = LONG_SUM(ntohl(usin.sin_addr.s_addr)) + ntohs(usin.sin_port); 18792686Sdarrenr sum2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)) + ntohs(nlp->nl_outport); 18892686Sdarrenr CALC_SUMD(sum1, sum2, sumd); 18992686Sdarrenr nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); 19092686Sdarrenr nat->nat_sumd[1] = nat->nat_sumd[0]; 19192686Sdarrenr 19292686Sdarrenr sum1 = LONG_SUM(ntohl(usin.sin_addr.s_addr)); 19392686Sdarrenr sum2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)); 19492686Sdarrenr CALC_SUMD(sum1, sum2, sumd); 19592686Sdarrenr nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16); 19692686Sdarrenr 19792686Sdarrenr nat->nat_inport = usin.sin_port; 19892686Sdarrenr nat->nat_outport = nlp->nl_outport; 19992686Sdarrenr nat->nat_oport = nlp->nl_realport; 20092686Sdarrenr 20192686Sdarrenr nat->nat_flags = IPN_TCPUDP; 20292686Sdarrenr 203145510Sdarrenr bzero((char *)&obj, sizeof(obj)); 204145510Sdarrenr obj.ipfo_rev = IPFILTER_VERSION; 205145510Sdarrenr obj.ipfo_size = sizeof(*nsp); 206145510Sdarrenr obj.ipfo_ptr = nsp; 207145510Sdarrenr obj.ipfo_type = IPFOBJ_NATSAVE; 208145510Sdarrenr 20992686Sdarrenr onoff = 1; 21092686Sdarrenr if (ioctl(fd, SIOCSTLCK, &onoff) == 0) { 211145510Sdarrenr if (ioctl(fd, SIOCSTPUT, &obj) != 0) 21292686Sdarrenr perror("SIOCSTPUT"); 21392686Sdarrenr onoff = 0; 21492686Sdarrenr if (ioctl(fd, SIOCSTLCK, &onoff) != 0) 21592686Sdarrenr perror("SIOCSTLCK"); 21692686Sdarrenr } 21792686Sdarrenr 21892686Sdarrenr usin.sin_addr = nlp->nl_realip; 21992686Sdarrenr usin.sin_port = nlp->nl_realport; 22092686Sdarrenrprintf("remote end for connection: %s,%d\n", inet_ntoa(usin.sin_addr), 22192686Sdarrenrntohs(usin.sin_port)); 22292686Sdarrenrfflush(stdout); 22392686Sdarrenr if (connect(ofd, (struct sockaddr *)&usin, sizeof(usin))) 22492686Sdarrenr perror("connect"); 22592686Sdarrenr 22692686Sdarrenr relay(in, out, ofd); 22792686Sdarrenr} 22892686Sdarrenr 22992686Sdarrenr 23092686Sdarrenrrelay(in, out, net) 231255332Scy int in, out, net; 23292686Sdarrenr{ 23392686Sdarrenr char netbuf[1024], outbuf[1024]; 23492686Sdarrenr char *nwptr, *nrptr, *owptr, *orptr; 23592686Sdarrenr size_t nsz, osz; 23692686Sdarrenr fd_set rd, wr; 23792686Sdarrenr int i, n, maxfd; 23892686Sdarrenr 23992686Sdarrenr n = 0; 24092686Sdarrenr maxfd = in; 24192686Sdarrenr if (out > maxfd) 24292686Sdarrenr maxfd = out; 24392686Sdarrenr if (net > maxfd) 24492686Sdarrenr maxfd = net; 24592686Sdarrenr 24692686Sdarrenr nrptr = netbuf; 24792686Sdarrenr nwptr = netbuf; 24892686Sdarrenr nsz = sizeof(netbuf); 24992686Sdarrenr orptr = outbuf; 25092686Sdarrenr owptr = outbuf; 25192686Sdarrenr osz = sizeof(outbuf); 25292686Sdarrenr 25392686Sdarrenr while (n >= 0) { 25492686Sdarrenr FD_ZERO(&rd); 25592686Sdarrenr FD_ZERO(&wr); 25692686Sdarrenr 25792686Sdarrenr if (nrptr - netbuf < sizeof(netbuf)) 25892686Sdarrenr FD_SET(in, &rd); 25992686Sdarrenr if (orptr - outbuf < sizeof(outbuf)) 26092686Sdarrenr FD_SET(net, &rd); 26192686Sdarrenr 26292686Sdarrenr if (nsz < sizeof(netbuf)) 26392686Sdarrenr FD_SET(net, &wr); 26492686Sdarrenr if (osz < sizeof(outbuf)) 26592686Sdarrenr FD_SET(out, &wr); 26692686Sdarrenr 26792686Sdarrenr n = select(maxfd + 1, &rd, &wr, NULL, NULL); 26892686Sdarrenr 26992686Sdarrenr if ((n > 0) && FD_ISSET(in, &rd)) { 27092686Sdarrenr i = read(in, nrptr, sizeof(netbuf) - (nrptr - netbuf)); 27192686Sdarrenr if (i <= 0) 27292686Sdarrenr break; 27392686Sdarrenr nsz -= i; 27492686Sdarrenr nrptr += i; 27592686Sdarrenr n--; 27692686Sdarrenr } 27792686Sdarrenr 27892686Sdarrenr if ((n > 0) && FD_ISSET(net, &rd)) { 27992686Sdarrenr i = read(net, orptr, sizeof(outbuf) - (orptr - outbuf)); 28092686Sdarrenr if (i <= 0) 28192686Sdarrenr break; 28292686Sdarrenr osz -= i; 28392686Sdarrenr orptr += i; 28492686Sdarrenr n--; 28592686Sdarrenr } 28692686Sdarrenr 28792686Sdarrenr if ((n > 0) && FD_ISSET(out, &wr)) { 28892686Sdarrenr i = write(out, owptr, orptr - owptr); 28992686Sdarrenr if (i <= 0) 29092686Sdarrenr break; 29192686Sdarrenr osz += i; 29292686Sdarrenr if (osz == sizeof(outbuf) || owptr == orptr) { 29392686Sdarrenr orptr = outbuf; 29492686Sdarrenr owptr = outbuf; 29592686Sdarrenr } else 29692686Sdarrenr owptr += i; 29792686Sdarrenr n--; 29892686Sdarrenr } 29992686Sdarrenr 30092686Sdarrenr if ((n > 0) && FD_ISSET(net, &wr)) { 30192686Sdarrenr i = write(net, nwptr, nrptr - nwptr); 30292686Sdarrenr if (i <= 0) 30392686Sdarrenr break; 30492686Sdarrenr nsz += i; 30592686Sdarrenr if (nsz == sizeof(netbuf) || nwptr == nrptr) { 30692686Sdarrenr nrptr = netbuf; 30792686Sdarrenr nwptr = netbuf; 30892686Sdarrenr } else 30992686Sdarrenr nwptr += i; 31092686Sdarrenr } 31192686Sdarrenr } 31292686Sdarrenr 31392686Sdarrenr close(net); 31492686Sdarrenr close(out); 31592686Sdarrenr close(in); 31692686Sdarrenr} 31792686Sdarrenr#endif 318