]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ipfilter/samples/relay.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ipfilter / samples / relay.c
1 /*      $FreeBSD$       */
2
3 /*
4  * Sample program to be used as a transparent proxy.
5  *
6  * Must be executed with permission enough to do an ioctl on /dev/ipl
7  * or equivalent.  This is just a sample and is only alpha quality.
8  * - Darren Reed (8 April 1996)
9  */
10 #include <unistd.h>
11 #include <stdio.h>
12 #include <fcntl.h>
13 #include <errno.h>
14 #include <sys/types.h>
15 #include <sys/time.h>
16 #include <sys/syslog.h>
17 #include <sys/socket.h>
18 #include <sys/ioctl.h>
19 #include <netinet/in.h>
20 #include <net/if.h>
21 #include "netinet/ip_compat.h"
22 #include "netinet/ip_fil.h"
23 #include "netinet/ip_nat.h"
24 #include "netinet/ipl.h"
25
26 #define RELAY_BUFSZ     8192
27
28 char    ibuff[RELAY_BUFSZ];
29 char    obuff[RELAY_BUFSZ];
30
31 int relay(ifd, ofd, rfd)
32         int ifd, ofd, rfd;
33 {
34         fd_set  rfds, wfds;
35         char    *irh, *irt, *rrh, *rrt;
36         char    *iwh, *iwt, *rwh, *rwt;
37         int     nfd, n, rw;
38
39         irh = irt = ibuff;
40         iwh = iwt = obuff;
41         nfd = ifd;
42         if (nfd < ofd)
43                 nfd = ofd;
44         if (nfd < rfd)
45                 nfd = rfd;
46
47         while (1) {
48                 FD_ZERO(&rfds);
49                 FD_ZERO(&wfds);
50                 if (irh > irt)
51                         FD_SET(rfd, &wfds);
52                 if (irh < (ibuff + RELAY_BUFSZ))
53                         FD_SET(ifd, &rfds);
54                 if (iwh > iwt)
55                         FD_SET(ofd, &wfds);
56                 if (iwh < (obuff + RELAY_BUFSZ))
57                         FD_SET(rfd, &rfds);
58
59                 switch ((n = select(nfd + 1, &rfds, &wfds, NULL, NULL)))
60                 {
61                 case -1 :
62                 case 0 :
63                         return -1;
64                 default :
65                         if (FD_ISSET(ifd, &rfds)) {
66                                 rw = read(ifd, irh, ibuff + RELAY_BUFSZ - irh);
67                                 if (rw == -1)
68                                         return -1;
69                                 if (rw == 0)
70                                         return 0;
71                                 irh += rw;
72                                 n--;
73                         }
74                         if (n && FD_ISSET(ofd, &wfds)) {
75                                 rw = write(ofd, iwt, iwh  - iwt);
76                                 if (rw == -1)
77                                         return -1;
78                                 iwt += rw;
79                                 n--;
80                         }
81                         if (n && FD_ISSET(rfd, &rfds)) {
82                                 rw = read(rfd, iwh, obuff + RELAY_BUFSZ - iwh);
83                                 if (rw == -1)
84                                         return -1;
85                                 if (rw == 0)
86                                         return 0;
87                                 iwh += rw;
88                                 n--;
89                         }
90                         if (n && FD_ISSET(rfd, &wfds)) {
91                                 rw = write(rfd, irt, irh  - irt);
92                                 if (rw == -1)
93                                         return -1;
94                                 irt += rw;
95                                 n--;
96                         }
97                         if (irh == irt)
98                                 irh = irt = ibuff;
99                         if (iwh == iwt)
100                                 iwh = iwt = obuff;
101                 }
102         }
103 }
104
105 main(argc, argv)
106         int argc;
107         char *argv[];
108 {
109         struct  sockaddr_in     sin;
110         ipfobj_t        obj;
111         natlookup_t     nl;
112         natlookup_t     *nlp = &nl;
113         int     fd, sl = sizeof(sl), se;
114
115         openlog(argv[0], LOG_PID|LOG_NDELAY, LOG_DAEMON);
116         if ((fd = open(IPNAT_NAME, O_RDONLY)) == -1) {
117                 se = errno;
118                 perror("open");
119                 errno = se;
120                 syslog(LOG_ERR, "open: %m\n");
121                 exit(-1);
122         }
123
124         bzero(&obj, sizeof(obj));
125         obj.ipfo_rev = IPFILTER_VERSION;
126         obj.ipfo_size = sizeof(nl);
127         obj.ipfo_ptr = &nl;
128         obj.ipfo_type = IPFOBJ_NATLOOKUP;
129
130         bzero(&nl, sizeof(nl));
131         nl.nl_flags = IPN_TCP;
132
133         bzero(&sin, sizeof(sin));
134         sin.sin_family = AF_INET;
135         sl = sizeof(sin);
136         if (getsockname(0, (struct sockaddr *)&sin, &sl) == -1) {
137                 se = errno;
138                 perror("getsockname");
139                 errno = se;
140                 syslog(LOG_ERR, "getsockname: %m\n");
141                 exit(-1);
142         } else {
143                 nl.nl_inip.s_addr = sin.sin_addr.s_addr;
144                 nl.nl_inport = sin.sin_port;
145         }
146
147         bzero(&sin, sizeof(sin));
148         sin.sin_family = AF_INET;
149         sl = sizeof(sin);
150         if (getpeername(0, (struct sockaddr *)&sin, &sl) == -1) {
151                 se = errno;
152                 perror("getpeername");
153                 errno = se;
154                 syslog(LOG_ERR, "getpeername: %m\n");
155                 exit(-1);
156         } else {
157                 nl.nl_outip.s_addr = sin.sin_addr.s_addr;
158                 nl.nl_outport = sin.sin_port;
159         }
160
161         if (ioctl(fd, SIOCGNATL, &obj) == -1) {
162                 se = errno;
163                 perror("ioctl");
164                 errno = se;
165                 syslog(LOG_ERR, "ioctl: %m\n");
166                 exit(-1);
167         }
168
169         sin.sin_port = nl.nl_realport;
170         sin.sin_addr = nl.nl_realip;
171         sl = sizeof(sin);
172
173         fd = socket(AF_INET, SOCK_STREAM, 0);
174         if (connect(fd, (struct sockaddr *)&sin, sl) == -1) {
175                 se = errno;
176                 perror("connect");
177                 errno = se;
178                 syslog(LOG_ERR, "connect: %m\n");
179                 exit(-1);
180         }
181
182         (void) ioctl(fd, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK);
183         (void) ioctl(0, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK);
184         (void) ioctl(1, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK);
185
186         syslog(LOG_NOTICE, "connected to %s,%d\n", inet_ntoa(sin.sin_addr),
187                 ntohs(sin.sin_port));
188         if (relay(0, 1, fd) == -1) {
189                 se = errno;
190                 perror("relay");
191                 errno = se;
192                 syslog(LOG_ERR, "relay: %m\n");
193                 exit(-1);
194         }
195         exit(0);
196 }