]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ipfilter/samples/proxy.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ipfilter / samples / proxy.c
1 /*      $FreeBSD$       */
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
53 main(argc, argv)
54         int argc;
55         char *argv[];
56 {
57         struct  sockaddr_in     sin, sloc, sout;
58         ipfobj_t        obj;
59         natlookup_t     natlook;
60         char    buffer[512];
61         int     namelen, fd, n;
62
63         /*
64          * get IP# and port # of the remote end of the connection (at the
65          * origin).
66          */
67         namelen = sizeof(sin);
68         if (getpeername(0, (struct sockaddr *)&sin, &namelen) == -1) {
69                 perror("getpeername");
70                 exit(-1);
71         }
72
73         /*
74          * get IP# and port # of the local end of the connection (at the
75          * man-in-the-middle).
76          */
77         namelen = sizeof(sin);
78         if (getsockname(0, (struct sockaddr *)&sloc, &namelen) == -1) {
79                 perror("getsockname");
80                 exit(-1);
81         }
82
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;
88
89         /*
90          * Build up the NAT natlookup structure.
91          */
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;
98
99         /*
100          * Open the NAT device and lookup the mapping pair.
101          */
102         fd = open(IPNAT_NAME, O_RDONLY);
103         if (ioctl(fd, SIOCGNATL, &obj) == -1) {
104                 perror("ioctl(SIOCGNATL)");
105                 exit(-1);
106         }
107
108 #define DO_NAT_OUT
109 #ifdef  DO_NAT_OUT
110         if (argc > 1)
111                 do_nat_out(0, 1, fd, &natlook, argv[1]);
112 #else
113
114         /*
115          * Log it
116          */
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));
121
122         /*
123          * Just echo data read in from stdin to stdout
124          */
125         while ((n = read(0, buffer, sizeof(buffer))) > 0)
126                 if (write(1, buffer, n) != n)
127                         break;
128         close(0);
129 #endif
130 }
131
132
133 #ifdef  DO_NAT_OUT
134 do_nat_out(in, out, fd, nlp, extif)
135         int fd;
136         natlookup_t *nlp;
137         char *extif;
138 {
139         nat_save_t ns, *nsp = &ns;
140         struct sockaddr_in usin;
141         u_32_t sum1, sum2, sumd;
142         int onoff, ofd, slen;
143         ipfobj_t obj;
144         ipnat_t *ipn;
145         nat_t *nat;
146
147         bzero((char *)&ns, sizeof(ns));
148
149         nat = &ns.ipn_nat;
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';
159         }
160
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));
167         slen = sizeof(usin);
168         (void) getsockname(ofd, (struct sockaddr *)&usin, &slen);
169         close(ofd);
170 printf("local IP# to use: %s\n", inet_ntoa(usin.sin_addr));
171
172         if ((ofd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
173                 perror("socket");
174         usin.sin_port = 0;
175         if (bind(ofd, (struct sockaddr *)&usin, sizeof(usin)))
176                 perror("bind");
177         slen = 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));
181
182         nat->nat_inip = usin.sin_addr;
183         nat->nat_outip = nlp->nl_outip;
184         nat->nat_oip = nlp->nl_realip;
185
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];
191
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);
196
197         nat->nat_inport = usin.sin_port;
198         nat->nat_outport = nlp->nl_outport;
199         nat->nat_oport = nlp->nl_realport;
200
201         nat->nat_flags = IPN_TCPUDP;
202
203         bzero((char *)&obj, sizeof(obj));
204         obj.ipfo_rev = IPFILTER_VERSION;
205         obj.ipfo_size = sizeof(*nsp);
206         obj.ipfo_ptr = nsp;
207         obj.ipfo_type = IPFOBJ_NATSAVE;
208
209         onoff = 1;
210         if (ioctl(fd, SIOCSTLCK, &onoff) == 0) {
211                 if (ioctl(fd, SIOCSTPUT, &obj) != 0)
212                         perror("SIOCSTPUT");
213                 onoff = 0;
214                 if (ioctl(fd, SIOCSTLCK, &onoff) != 0)
215                         perror("SIOCSTLCK");
216         }
217
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));
222 fflush(stdout);
223         if (connect(ofd, (struct sockaddr *)&usin, sizeof(usin)))
224                 perror("connect");
225
226         relay(in, out, ofd);
227 }
228
229
230 relay(in, out, net)
231         int in, out, net;
232 {
233         char netbuf[1024], outbuf[1024];
234         char *nwptr, *nrptr, *owptr, *orptr;
235         size_t nsz, osz;
236         fd_set rd, wr;
237         int i, n, maxfd;
238
239         n = 0;
240         maxfd = in;
241         if (out > maxfd)
242                 maxfd = out;
243         if (net > maxfd)
244                 maxfd = net;
245
246         nrptr = netbuf;
247         nwptr = netbuf;
248         nsz = sizeof(netbuf);
249         orptr = outbuf;
250         owptr = outbuf;
251         osz = sizeof(outbuf);
252
253         while (n >= 0) {
254                 FD_ZERO(&rd);
255                 FD_ZERO(&wr);
256
257                 if (nrptr - netbuf < sizeof(netbuf))
258                         FD_SET(in, &rd);
259                 if (orptr - outbuf < sizeof(outbuf))
260                         FD_SET(net, &rd);
261
262                 if (nsz < sizeof(netbuf))
263                         FD_SET(net, &wr);
264                 if (osz < sizeof(outbuf))
265                         FD_SET(out, &wr);
266
267                 n = select(maxfd + 1, &rd, &wr, NULL, NULL);
268
269                 if ((n > 0) && FD_ISSET(in, &rd)) {
270                         i = read(in, nrptr, sizeof(netbuf) - (nrptr - netbuf));
271                         if (i <= 0)
272                                 break;
273                         nsz -= i;
274                         nrptr += i;
275                         n--;
276                 }
277
278                 if ((n > 0) && FD_ISSET(net, &rd)) {
279                         i = read(net, orptr, sizeof(outbuf) - (orptr - outbuf));
280                         if (i <= 0)
281                                 break;
282                         osz -= i;
283                         orptr += i;
284                         n--;
285                 }
286
287                 if ((n > 0) && FD_ISSET(out, &wr)) {
288                         i = write(out, owptr, orptr - owptr);
289                         if (i <= 0)
290                                 break;
291                         osz += i;
292                         if (osz == sizeof(outbuf) || owptr == orptr) {
293                                 orptr = outbuf;
294                                 owptr = outbuf;
295                         } else
296                                 owptr += i;
297                         n--;
298                 }
299
300                 if ((n > 0) && FD_ISSET(net, &wr)) {
301                         i = write(net, nwptr, nrptr - nwptr);
302                         if (i <= 0)
303                                 break;
304                         nsz += i;
305                         if (nsz == sizeof(netbuf) || nwptr == nrptr) {
306                                 nrptr = netbuf;
307                                 nwptr = netbuf;
308                         } else
309                                 nwptr += i;
310                 }
311         }
312
313         close(net);
314         close(out);
315         close(in);
316 }
317 #endif