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
) {