4 * Sample transparent proxy program.
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
17 #if !defined(__SVR4) && !defined(__svr4__)
20 #include <sys/byteorder.h>
22 #include <sys/types.h>
24 #include <sys/param.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>
34 #include <netinet/in.h>
35 #include <netinet/in_systm.h>
36 #include <netinet/ip.h>
37 #include <netinet/tcp.h>
40 #include <arpa/nameser.h>
41 #include <arpa/inet.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"
57 struct sockaddr_in sin
, sloc
, sout
;
64 * get IP# and port # of the remote end of the connection (at the
67 namelen
= sizeof(sin
);
68 if (getpeername(0, (struct sockaddr
*)&sin
, &namelen
) == -1) {
69 perror("getpeername");
74 * get IP# and port # of the local end of the connection (at the
77 namelen
= sizeof(sin
);
78 if (getsockname(0, (struct sockaddr
*)&sloc
, &namelen
) == -1) {
79 perror("getsockname");
83 bzero((char *)&obj
, sizeof(obj
));
84 obj
.ipfo_rev
= IPFILTER_VERSION
;
85 obj
.ipfo_size
= sizeof(natlook
);
86 obj
.ipfo_ptr
= &natlook
;
87 obj
.ipfo_type
= IPFOBJ_NATLOOKUP
;
90 * Build up the NAT natlookup structure.
92 bzero((char *)&natlook
, sizeof(natlook
));
93 natlook
.nl_outip
= sin
.sin_addr
;
94 natlook
.nl_inip
= sloc
.sin_addr
;
95 natlook
.nl_flags
= IPN_TCP
;
96 natlook
.nl_outport
= sin
.sin_port
;
97 natlook
.nl_inport
= sloc
.sin_port
;
100 * Open the NAT device and lookup the mapping pair.
102 fd
= open(IPNAT_NAME
, O_RDONLY
);
103 if (ioctl(fd
, SIOCGNATL
, &obj
) == -1) {
104 perror("ioctl(SIOCGNATL)");
111 do_nat_out(0, 1, fd
, &natlook
, argv
[1]);
117 syslog(LOG_DAEMON
|LOG_INFO
, "connect to %s,%d",
118 inet_ntoa(natlook
.nl_realip
), ntohs(natlook
.nl_realport
));
119 printf("connect to %s,%d\n",
120 inet_ntoa(natlook
.nl_realip
), ntohs(natlook
.nl_realport
));
123 * Just echo data read in from stdin to stdout
125 while ((n
= read(0, buffer
, sizeof(buffer
))) > 0)
126 if (write(1, buffer
, n
) != n
)
134 do_nat_out(in
, out
, fd
, nlp
, extif
)
139 nat_save_t ns
, *nsp
= &ns
;
140 struct sockaddr_in usin
;
141 u_32_t sum1
, sum2
, sumd
;
142 int onoff
, ofd
, slen
;
147 bzero((char *)&ns
, sizeof(ns
));
150 nat
->nat_p
= IPPROTO_TCP
;
151 nat
->nat_dir
= NAT_OUTBOUND
;
152 if ((extif
!= NULL
) && (*extif
!= '\0')) {
153 strncpy(nat
->nat_ifnames
[0], extif
,
154 sizeof(nat
->nat_ifnames
[0]));
155 strncpy(nat
->nat_ifnames
[1], extif
,
156 sizeof(nat
->nat_ifnames
[1]));
157 nat
->nat_ifnames
[0][sizeof(nat
->nat_ifnames
[0]) - 1] = '\0';
158 nat
->nat_ifnames
[1][sizeof(nat
->nat_ifnames
[1]) - 1] = '\0';
161 ofd
= socket(AF_INET
, SOCK_DGRAM
, 0);
162 bzero((char *)&usin
, sizeof(usin
));
163 usin
.sin_family
= AF_INET
;
164 usin
.sin_addr
= nlp
->nl_realip
;
165 usin
.sin_port
= nlp
->nl_realport
;
166 (void) connect(ofd
, (struct sockaddr
*)&usin
, sizeof(usin
));
168 (void) getsockname(ofd
, (struct sockaddr
*)&usin
, &slen
);
170 printf("local IP# to use: %s\n", inet_ntoa(usin
.sin_addr
));
172 if ((ofd
= socket(AF_INET
, SOCK_STREAM
, 0)) == -1)
175 if (bind(ofd
, (struct sockaddr
*)&usin
, sizeof(usin
)))
178 if (getsockname(ofd
, (struct sockaddr
*)&usin
, &slen
))
179 perror("getsockname");
180 printf("local port# to use: %d\n", ntohs(usin
.sin_port
));
182 nat
->nat_inip
= usin
.sin_addr
;
183 nat
->nat_outip
= nlp
->nl_outip
;
184 nat
->nat_oip
= nlp
->nl_realip
;
186 sum1
= LONG_SUM(ntohl(usin
.sin_addr
.s_addr
)) + ntohs(usin
.sin_port
);
187 sum2
= LONG_SUM(ntohl(nat
->nat_outip
.s_addr
)) + ntohs(nlp
->nl_outport
);
188 CALC_SUMD(sum1
, sum2
, sumd
);
189 nat
->nat_sumd
[0] = (sumd
& 0xffff) + (sumd
>> 16);
190 nat
->nat_sumd
[1] = nat
->nat_sumd
[0];
192 sum1
= LONG_SUM(ntohl(usin
.sin_addr
.s_addr
));
193 sum2
= LONG_SUM(ntohl(nat
->nat_outip
.s_addr
));
194 CALC_SUMD(sum1
, sum2
, sumd
);
195 nat
->nat_ipsumd
= (sumd
& 0xffff) + (sumd
>> 16);
197 nat
->nat_inport
= usin
.sin_port
;
198 nat
->nat_outport
= nlp
->nl_outport
;
199 nat
->nat_oport
= nlp
->nl_realport
;
201 nat
->nat_flags
= IPN_TCPUDP
;
203 bzero((char *)&obj
, sizeof(obj
));
204 obj
.ipfo_rev
= IPFILTER_VERSION
;
205 obj
.ipfo_size
= sizeof(*nsp
);
207 obj
.ipfo_type
= IPFOBJ_NATSAVE
;
210 if (ioctl(fd
, SIOCSTLCK
, &onoff
) == 0) {
211 if (ioctl(fd
, SIOCSTPUT
, &obj
) != 0)
214 if (ioctl(fd
, SIOCSTLCK
, &onoff
) != 0)
218 usin
.sin_addr
= nlp
->nl_realip
;
219 usin
.sin_port
= nlp
->nl_realport
;
220 printf("remote end for connection: %s,%d\n", inet_ntoa(usin
.sin_addr
),
221 ntohs(usin
.sin_port
));
223 if (connect(ofd
, (struct sockaddr
*)&usin
, sizeof(usin
)))
233 char netbuf
[1024], outbuf
[1024];
234 char *nwptr
, *nrptr
, *owptr
, *orptr
;
248 nsz
= sizeof(netbuf
);
251 osz
= sizeof(outbuf
);
257 if (nrptr
- netbuf
< sizeof(netbuf
))
259 if (orptr
- outbuf
< sizeof(outbuf
))
262 if (nsz
< sizeof(netbuf
))
264 if (osz
< sizeof(outbuf
))
267 n
= select(maxfd
+ 1, &rd
, &wr
, NULL
, NULL
);
269 if ((n
> 0) && FD_ISSET(in
, &rd
)) {
270 i
= read(in
, nrptr
, sizeof(netbuf
) - (nrptr
- netbuf
));
278 if ((n
> 0) && FD_ISSET(net
, &rd
)) {
279 i
= read(net
, orptr
, sizeof(outbuf
) - (orptr
- outbuf
));
287 if ((n
> 0) && FD_ISSET(out
, &wr
)) {
288 i
= write(out
, owptr
, orptr
- owptr
);
292 if (osz
== sizeof(outbuf
) || owptr
== orptr
) {
300 if ((n
> 0) && FD_ISSET(net
, &wr
)) {
301 i
= write(net
, nwptr
, nrptr
- nwptr
);
305 if (nsz
== sizeof(netbuf
) || nwptr
== nrptr
) {