Deleted Added
full compact
proxy.c (145519) proxy.c (153881)
1/* $FreeBSD: head/contrib/ipfilter/samples/proxy.c 145519 2005-04-25 18:20:15Z darrenr $ */
1/* $FreeBSD: head/contrib/ipfilter/samples/proxy.c 153881 2005-12-30 11:52:26Z guido $ */
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;
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);
97 natlook.nl_outport = sin.sin_port;
98 natlook.nl_inport = 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
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