2 * Sample transparent proxy program.
4 * Sample implementation of a program which intercepts a TCP connectiona and
5 * just echos all data back to the origin. Written to work via inetd as a
6 * "nonwait" program running as root; ie.
7 * tcpmux stream tcp nowait root /usr/local/bin/proxy proxy
8 * with a NAT rue like this:
9 * rdr smc0 0/0 port 80 -> 127.0.0.1/32 port 1
15 #if !defined(__SVR4) && !defined(__svr4__)
18 #include <sys/byteorder.h>
20 #include <sys/types.h>
22 #include <sys/param.h>
26 #include <sys/socket.h>
27 #include <sys/ioctl.h>
28 #if defined(sun) && (defined(__svr4__) || defined(__SVR4))
29 # include <sys/ioccom.h>
30 # include <sys/sysmacros.h>
32 #include <netinet/in.h>
33 #include <netinet/in_systm.h>
34 #include <netinet/ip.h>
35 #include <netinet/tcp.h>
38 #include <arpa/nameser.h>
39 #include <arpa/inet.h>
42 #include "netinet/ip_compat.h"
43 #include "netinet/ip_fil.h"
44 #include "netinet/ip_nat.h"
45 #include "netinet/ip_state.h"
46 #include "netinet/ip_proxy.h"
47 #include "netinet/ip_nat.h"
54 struct sockaddr_in sin, sloc, sout;
56 natlookup_t *natlookp = &natlook;
61 * get IP# and port # of the remote end of the connection (at the
64 namelen = sizeof(sin);
65 if (getpeername(0, (struct sockaddr *)&sin, &namelen) == -1) {
66 perror("getpeername");
71 * get IP# and port # of the local end of the connection (at the
74 namelen = sizeof(sin);
75 if (getsockname(0, (struct sockaddr *)&sloc, &namelen) == -1) {
76 perror("getsockname");
81 * Build up the NAT natlookup structure.
83 bzero((char *)&natlook, sizeof(natlook));
84 natlook.nl_outip = sin.sin_addr;
85 natlook.nl_inip = sloc.sin_addr;
86 natlook.nl_flags = IPN_TCPUDP;
87 natlook.nl_outport = ntohs(sin.sin_port);
88 natlook.nl_inport = ntohs(sloc.sin_port);
91 * Open the NAT device and lookup the mapping pair.
93 fd = open(IPL_NAT, O_RDONLY);
94 if (ioctl(fd, SIOCGNATL, &natlookp) == -1) {
95 perror("ioctl(SIOCGNATL)");
102 do_nat_out(0, 1, fd, &natlook, argv[1]);
108 syslog(LOG_DAEMON|LOG_INFO, "connect to %s,%d",
109 inet_ntoa(natlook.nl_realip), ntohs(natlook.nl_realport));
110 printf("connect to %s,%d\n",
111 inet_ntoa(natlook.nl_realip), ntohs(natlook.nl_realport));
114 * Just echo data read in from stdin to stdout
116 while ((n = read(0, buffer, sizeof(buffer))) > 0)
117 if (write(1, buffer, n) != n)
125 do_nat_out(in, out, fd, nlp, extif)
130 nat_save_t ns, *nsp = &ns;
131 struct sockaddr_in usin;
132 u_32_t sum1, sum2, sumd;
133 int onoff, ofd, slen;
137 bzero((char *)&ns, sizeof(ns));
140 nat->nat_p = IPPROTO_TCP;
141 nat->nat_dir = NAT_OUTBOUND;
142 if ((extif != NULL) && (*extif != '\0')) {
143 strncpy(nat->nat_ifname, extif, sizeof(nat->nat_ifname));
144 nat->nat_ifname[sizeof(nat->nat_ifname) - 1] = '\0';
147 ofd = socket(AF_INET, SOCK_DGRAM, 0);
148 bzero((char *)&usin, sizeof(usin));
149 usin.sin_family = AF_INET;
150 usin.sin_addr = nlp->nl_realip;
151 usin.sin_port = nlp->nl_realport;
152 (void) connect(ofd, (struct sockaddr *)&usin, sizeof(usin));
154 (void) getsockname(ofd, (struct sockaddr *)&usin, &slen);
156 printf("local IP# to use: %s\n", inet_ntoa(usin.sin_addr));
158 if ((ofd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
161 if (bind(ofd, (struct sockaddr *)&usin, sizeof(usin)))
164 if (getsockname(ofd, (struct sockaddr *)&usin, &slen))
165 perror("getsockname");
166 printf("local port# to use: %d\n", ntohs(usin.sin_port));
168 nat->nat_inip = usin.sin_addr;
169 nat->nat_outip = nlp->nl_outip;
170 nat->nat_oip = nlp->nl_realip;
172 sum1 = LONG_SUM(ntohl(usin.sin_addr.s_addr)) + ntohs(usin.sin_port);
173 sum2 = LONG_SUM(ntohl(nat->nat_outip.s_addr)) + ntohs(nlp->nl_outport);
174 CALC_SUMD(sum1, sum2, sumd);
175 nat->nat_sumd[0] = (sumd & 0xffff) + (sumd >> 16);
176 nat->nat_sumd[1] = nat->nat_sumd[0];
178 sum1 = LONG_SUM(ntohl(usin.sin_addr.s_addr));
179 sum2 = LONG_SUM(ntohl(nat->nat_outip.s_addr));
180 CALC_SUMD(sum1, sum2, sumd);
181 nat->nat_ipsumd = (sumd & 0xffff) + (sumd >> 16);
183 nat->nat_inport = usin.sin_port;
184 nat->nat_outport = nlp->nl_outport;
185 nat->nat_oport = nlp->nl_realport;
187 nat->nat_flags = IPN_TCPUDP;
190 if (ioctl(fd, SIOCSTLCK, &onoff) == 0) {
191 if (ioctl(fd, SIOCSTPUT, &nsp) != 0)
194 if (ioctl(fd, SIOCSTLCK, &onoff) != 0)
198 usin.sin_addr = nlp->nl_realip;
199 usin.sin_port = nlp->nl_realport;
200 printf("remote end for connection: %s,%d\n", inet_ntoa(usin.sin_addr),
201 ntohs(usin.sin_port));
203 if (connect(ofd, (struct sockaddr *)&usin, sizeof(usin)))
213 char netbuf[1024], outbuf[1024];
214 char *nwptr, *nrptr, *owptr, *orptr;
228 nsz = sizeof(netbuf);
231 osz = sizeof(outbuf);
237 if (nrptr - netbuf < sizeof(netbuf))
239 if (orptr - outbuf < sizeof(outbuf))
242 if (nsz < sizeof(netbuf))
244 if (osz < sizeof(outbuf))
247 n = select(maxfd + 1, &rd, &wr, NULL, NULL);
249 if ((n > 0) && FD_ISSET(in, &rd)) {
250 i = read(in, nrptr, sizeof(netbuf) - (nrptr - netbuf));
258 if ((n > 0) && FD_ISSET(net, &rd)) {
259 i = read(net, orptr, sizeof(outbuf) - (orptr - outbuf));
267 if ((n > 0) && FD_ISSET(out, &wr)) {
268 i = write(out, owptr, orptr - owptr);
272 if (osz == sizeof(outbuf) || owptr == orptr) {
280 if ((n > 0) && FD_ISSET(net, &wr)) {
281 i = write(net, nwptr, nrptr - nwptr);
285 if (nsz == sizeof(netbuf) || nwptr == nrptr) {