proxy.c revision 145511
1146822Sharti/* $NetBSD$ */ 2 3/* 4 * Sample transparent proxy program. 5 * 6 * Sample implementation of a program which intercepts a TCP connectiona and 7 * just echos all data back to the origin. Written to work via inetd as a 8 * "nonwait" program running as root; ie. 9 * tcpmux stream tcp nowait root /usr/local/bin/proxy proxy 10 * with a NAT rue like this: 11 * rdr smc0 0/0 port 80 -> 127.0.0.1/32 port 1 12 */ 13#include <stdio.h> 14#include <string.h> 15#include <fcntl.h> 16#include <syslog.h> 17#if !defined(__SVR4) && !defined(__svr4__) 18#include <strings.h> 19#else 20#include <sys/byteorder.h> 21#endif 22#include <sys/types.h> 23#include <sys/time.h> 24#include <sys/param.h> 25#include <stdlib.h> 26#include <unistd.h> 27#include <stddef.h> 28#include <sys/socket.h> 29#include <sys/ioctl.h> 30#if defined(sun) && (defined(__svr4__) || defined(__SVR4)) 31# include <sys/ioccom.h> 32# include <sys/sysmacros.h> 33#endif 34#include <netinet/in.h> 35#include <netinet/in_systm.h> 36#include <netinet/ip.h> 37#include <netinet/tcp.h> 38#include <net/if.h> 39#include <netdb.h> 40#include <arpa/nameser.h> 41#include <arpa/inet.h> 42#include <resolv.h> 43#include <ctype.h> 44#include "netinet/ip_compat.h" 45#include "netinet/ip_fil.h" 46#include "netinet/ip_nat.h" 47#include "netinet/ip_state.h" 48#include "netinet/ip_proxy.h" 49#include "netinet/ip_nat.h" 50#include "netinet/ipl.h" 51 52 53main(argc, argv) 54int argc; 55char *argv[]; 56{ 57 struct sockaddr_in sin, sloc, sout; 58 ipfobj_t obj; 59 natlookup_t natlook; 60 natlookup_t *natlookp = &natlook; 61 char buffer[512]; 62 int namelen, fd, n; 63 64 /* 65 * get IP# and port # of the remote end of the connection (at the 66 * origin). 67 */ 68 namelen = sizeof(sin); 69 if (getpeername(0, (struct sockaddr *)&sin, &namelen) == -1) { 70 perror("getpeername"); 71 exit(-1); 72 } 73 74 /* 75 * get IP# and port # of the local end of the connection (at the 76 * man-in-the-middle). 77 */ 78 namelen = sizeof(sin); 79 if (getsockname(0, (struct sockaddr *)&sloc, &namelen) == -1) { 80 perror("getsockname"); 81 exit(-1); 82 } 83 84 bzero((char *)&obj, sizeof(obj)); 85 obj.ipfo_rev = IPFILTER_VERSION; 86 obj.ipfo_size = sizeof(natlook); 87 obj.ipfo_ptr = &natlook; 88 obj.ipfo_type = IPFOBJ_NATLOOKUP; 89 90 /* 91 * Build up the NAT natlookup structure. 92 */ 93 bzero((char *)&natlook, sizeof(natlook)); 94 natlook.nl_outip = sin.sin_addr; 95 natlook.nl_inip = sloc.sin_addr; 96 natlook.nl_flags = IPN_TCP; 97 natlook.nl_outport = ntohs(sin.sin_port); 98 natlook.nl_inport = ntohs(sloc.sin_port); 99 100 /* 101 * Open the NAT device and lookup the mapping pair. 102 */ 103 fd = open(IPNAT_NAME, O_RDONLY); 104 if (ioctl(fd, SIOCGNATL, &obj) == -1) { 105 perror("ioctl(SIOCGNATL)"); 106 exit(-1); 107 } 108 109#define DO_NAT_OUT 110#ifdef DO_NAT_OUT 111 if (argc > 1) 112 do_nat_out(0, 1, fd, &natlook, argv[1]); 113#else 114 115 /* 116 * Log it 117 */ 118 syslog(LOG_DAEMON|LOG_INFO, "connect to %s,%d", 119 inet_ntoa(natlook.nl_realip), ntohs(natlook.nl_realport)); 120 printf("connect to %s,%d\n", 121 inet_ntoa(natlook.nl_realip), ntohs(natlook.nl_realport)); 122 123 /* 124 * Just echo data read in from stdin to stdout 125 */ 126 while ((n = read(0, buffer, sizeof(buffer))) > 0) 127 if (write(1, buffer, n) != n) 128 break; 129 close(0); 130#endif 131} 132 133 134#ifdef DO_NAT_OUT 135do_nat_out(in, out, fd, nlp, extif) 136int fd; 137natlookup_t *nlp; 138char *extif; 139{ 140 nat_save_t ns, *nsp = &ns; 141 struct sockaddr_in usin; 142 u_32_t sum1, sum2, sumd; 143 int onoff, ofd, slen; 144 ipfobj_t obj; 145 ipnat_t *ipn; 146 nat_t *nat; 147 148 bzero((char *)&ns, sizeof(ns)); 149 150 nat = &ns.ipn_nat; 151 nat->nat_p = IPPROTO_TCP; 152 nat->nat_dir = NAT_OUTBOUND; 153 if ((extif != NULL) && (*extif != '\0')) { 154 strncpy(nat->nat_ifnames[0], extif, 155 sizeof(nat->nat_ifnames[0])); 156 strncpy(nat->nat_ifnames[1], extif, 157 sizeof(nat->nat_ifnames[1])); 158 nat->nat_ifnames[0][sizeof(nat->nat_ifnames[0]) - 1] = '\0'; 159 nat->nat_ifnames[1][sizeof(nat->nat_ifnames[1]) - 1] = '\0'; 160 } 161 162 ofd = socket(AF_INET, SOCK_DGRAM, 0); 163 bzero((char *)&usin, sizeof(usin)); 164 usin.sin_family = AF_INET; 165 usin.sin_addr = nlp->nl_realip; 166 usin.sin_port = nlp->nl_realport; 167 (void) connect(ofd, (struct sockaddr *)&usin, sizeof(usin)); 168 slen = sizeof(usin); 169 (void) getsockname(ofd, (struct sockaddr *)&usin, &slen); 170 close(ofd); 171printf("local IP# to use: %s\n", inet_ntoa(usin.sin_addr)); 172 173 if ((ofd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 174 perror("socket"); 175 usin.sin_port = 0; 176 if (bind(ofd, (struct sockaddr *)&usin, sizeof(usin))) 177 perror("bind"); 178 slen = sizeof(usin); 179 if (getsockname(ofd, (struct sockaddr *)&usin, &slen)) 180 perror("getsockname"); 181printf("local port# to use: %d\n", ntohs(usin.sin_port)); 182 183 nat->nat_inip = usin.sin_addr; 184 nat->nat_outip = nlp->nl_outip; 185 nat->nat_oip = nlp->nl_realip; 186 187 sum1 = LONG_SUM(ntohl(usin.sin_addr.s_addr)) + ntohs(usin.sin_port); 188 sum2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)) + ntohs(nlp->nl_outport); 189 CALC_SUMD(sum1, sum2, sumd); 190 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16); 191 nat->nat_sumd[1] = nat->nat_sumd[0]; 192 193 sum1 = LONG_SUM(ntohl(usin.sin_addr.s_addr)); 194 sum2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)); 195 CALC_SUMD(sum1, sum2, sumd); 196 nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16); 197 198 nat->nat_inport = usin.sin_port; 199 nat->nat_outport = nlp->nl_outport; 200 nat->nat_oport = nlp->nl_realport; 201 202 nat->nat_flags = IPN_TCPUDP; 203 204 bzero((char *)&obj, sizeof(obj)); 205 obj.ipfo_rev = IPFILTER_VERSION; 206 obj.ipfo_size = sizeof(*nsp); 207 obj.ipfo_ptr = nsp; 208 obj.ipfo_type = IPFOBJ_NATSAVE; 209 210 onoff = 1; 211 if (ioctl(fd, SIOCSTLCK, &onoff) == 0) { 212 if (ioctl(fd, SIOCSTPUT, &obj) != 0) 213 perror("SIOCSTPUT"); 214 onoff = 0; 215 if (ioctl(fd, SIOCSTLCK, &onoff) != 0) 216 perror("SIOCSTLCK"); 217 } 218 219 usin.sin_addr = nlp->nl_realip; 220 usin.sin_port = nlp->nl_realport; 221printf("remote end for connection: %s,%d\n", inet_ntoa(usin.sin_addr), 222ntohs(usin.sin_port)); 223fflush(stdout); 224 if (connect(ofd, (struct sockaddr *)&usin, sizeof(usin))) 225 perror("connect"); 226 227 relay(in, out, ofd); 228} 229 230 231relay(in, out, net) 232int in, out, net; 233{ 234 char netbuf[1024], outbuf[1024]; 235 char *nwptr, *nrptr, *owptr, *orptr; 236 size_t nsz, osz; 237 fd_set rd, wr; 238 int i, n, maxfd; 239 240 n = 0; 241 maxfd = in; 242 if (out > maxfd) 243 maxfd = out; 244 if (net > maxfd) 245 maxfd = net; 246 247 nrptr = netbuf; 248 nwptr = netbuf; 249 nsz = sizeof(netbuf); 250 orptr = outbuf; 251 owptr = outbuf; 252 osz = sizeof(outbuf); 253 254 while (n >= 0) { 255 FD_ZERO(&rd); 256 FD_ZERO(&wr); 257 258 if (nrptr - netbuf < sizeof(netbuf)) 259 FD_SET(in, &rd); 260 if (orptr - outbuf < sizeof(outbuf)) 261 FD_SET(net, &rd); 262 263 if (nsz < sizeof(netbuf)) 264 FD_SET(net, &wr); 265 if (osz < sizeof(outbuf)) 266 FD_SET(out, &wr); 267 268 n = select(maxfd + 1, &rd, &wr, NULL, NULL); 269 270 if ((n > 0) && FD_ISSET(in, &rd)) { 271 i = read(in, nrptr, sizeof(netbuf) - (nrptr - netbuf)); 272 if (i <= 0) 273 break; 274 nsz -= i; 275 nrptr += i; 276 n--; 277 } 278 279 if ((n > 0) && FD_ISSET(net, &rd)) { 280 i = read(net, orptr, sizeof(outbuf) - (orptr - outbuf)); 281 if (i <= 0) 282 break; 283 osz -= i; 284 orptr += i; 285 n--; 286 } 287 288 if ((n > 0) && FD_ISSET(out, &wr)) { 289 i = write(out, owptr, orptr - owptr); 290 if (i <= 0) 291 break; 292 osz += i; 293 if (osz == sizeof(outbuf) || owptr == orptr) { 294 orptr = outbuf; 295 owptr = outbuf; 296 } else 297 owptr += i; 298 n--; 299 } 300 301 if ((n > 0) && FD_ISSET(net, &wr)) { 302 i = write(net, nwptr, nrptr - nwptr); 303 if (i <= 0) 304 break; 305 nsz += i; 306 if (nsz == sizeof(netbuf) || nwptr == nrptr) { 307 nrptr = netbuf; 308 nwptr = netbuf; 309 } else 310 nwptr += i; 311 } 312 } 313 314 close(net); 315 close(out); 316 close(in); 317} 318#endif 319