Merge branch 'master' of ssh://swildner@crater.dragonflybsd.org/repository/git/dragonfly
[dragonfly.git] / contrib / ipfilter / relay.c
blob6a67433c61a91be66d4eae99ca8b03310acfe80d
1 /*
2 * Sample program to be used as a transparent proxy.
4 * Must be executed with permission enough to do an ioctl on /dev/ipl
5 * or equivalent. This is just a sample and is only alpha quality.
6 * - Darren Reed (8 April 1996)
7 */
8 #include <unistd.h>
9 #include <stdio.h>
10 #include <fcntl.h>
11 #include <sys/types.h>
12 #include <sys/time.h>
13 #include <sys/errno.h>
14 #include <sys/syslog.h>
15 #include <sys/ioctl.h>
16 #include <netinet/in.h>
17 #include <net/if.h>
18 #include <sys/socket.h>
19 #if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 105000000)
20 # include <poll.h>
21 # define USE_POLL
22 #endif
23 #include "ip_nat.h"
25 #define RELAY_BUFSZ 8192
27 char ibuff[RELAY_BUFSZ];
28 char obuff[RELAY_BUFSZ];
30 int relay(ifd, ofd, rfd)
31 int ifd, ofd, rfd;
33 #ifdef USE_POLL
34 struct pollfd set[3];
35 #else
36 fd_set rfds, wfds;
37 #endif
38 char *irh, *irt, *rrh, *rrt;
39 char *iwh, *iwt, *rwh, *rwt;
40 int nfd, n, rw;
42 irh = irt = ibuff;
43 iwh = iwt = obuff;
44 nfd = ifd;
45 if (nfd < ofd)
46 nfd = ofd;
47 if (nfd < rfd)
48 nfd = rfd;
50 #ifdef USE_POLL
51 set[0].fd = rfd;
52 set[1].fd = ifd;
53 set[2].fd = ofd;
54 #endif
56 while (1) {
57 #ifdef USE_POLL
58 set[0].events = (iwh < (obuff + RELAY_BUFSZ) ? POLLIN : 0) |
59 (irh > irt ? POLLOUT : 0);
60 set[1].events = (irh < (ibuff + RELAY_BUFSZ) ? POLLIN : 0);
61 set[2].events = (iwh > iwt ? POLLOUT : 0);
63 switch ((n = poll(set, 3, INFTIM)))
64 #else
65 FD_ZERO(&rfds);
66 FD_ZERO(&wfds);
67 if (irh > irt)
68 FD_SET(rfd, &wfds);
69 if (irh < (ibuff + RELAY_BUFSZ))
70 FD_SET(ifd, &rfds);
71 if (iwh > iwt)
72 FD_SET(ofd, &wfds);
73 if (iwh < (obuff + RELAY_BUFSZ))
74 FD_SET(rfd, &rfds);
76 switch ((n = select(nfd + 1, &rfds, &wfds, NULL, NULL)))
77 #endif
79 case -1 :
80 case 0 :
81 return -1;
82 default :
83 #ifdef USE_POLL
84 if (set[1].revents & POLLIN)
85 #else
86 if (FD_ISSET(ifd, &rfds))
87 #endif
89 rw = read(ifd, irh, ibuff + RELAY_BUFSZ - irh);
90 if (rw == -1)
91 return -1;
92 if (rw == 0)
93 return 0;
94 irh += rw;
95 n--;
97 #ifdef USE_POLL
98 if (set[2].revents & POLLOUT)
99 #else
100 if (n && FD_ISSET(ofd, &wfds))
101 #endif
103 rw = write(ofd, iwt, iwh - iwt);
104 if (rw == -1)
105 return -1;
106 iwt += rw;
107 n--;
109 #ifdef USE_POLL
110 if (set[0].revents & POLLIN)
111 #else
112 if (n && FD_ISSET(rfd, &rfds))
113 #endif
115 rw = read(rfd, iwh, obuff + RELAY_BUFSZ - iwh);
116 if (rw == -1)
117 return -1;
118 if (rw == 0)
119 return 0;
120 iwh += rw;
121 n--;
123 #ifdef USE_POLL
124 if (set[0].revents & POLLOUT)
125 #else
126 if (n && FD_ISSET(rfd, &wfds))
127 #endif
129 rw = write(rfd, irt, irh - irt);
130 if (rw == -1)
131 return -1;
132 irt += rw;
133 n--;
135 if (irh == irt)
136 irh = irt = ibuff;
137 if (iwh == iwt)
138 iwh = iwt = obuff;
143 main(argc, argv)
144 int argc;
145 char *argv[];
147 struct sockaddr_in sin;
148 natlookup_t nl;
149 natlookup_t *nlp = &nl;
150 int fd, sl = sizeof(sl), se;
152 openlog(argv[0], LOG_PID|LOG_NDELAY, LOG_DAEMON);
153 if ((fd = open("/dev/ipnat", O_RDONLY)) == -1) {
154 se = errno;
155 perror("open");
156 errno = se;
157 syslog(LOG_ERR, "open: %m\n");
158 exit(-1);
161 bzero(&nl, sizeof(nl));
162 nl.nl_flags = IPN_TCP;
164 bzero(&sin, sizeof(sin));
165 sin.sin_family = AF_INET;
166 sl = sizeof(sin);
167 if (getsockname(0, (struct sockaddr *)&sin, &sl) == -1) {
168 se = errno;
169 perror("getsockname");
170 errno = se;
171 syslog(LOG_ERR, "getsockname: %m\n");
172 exit(-1);
173 } else {
174 nl.nl_inip.s_addr = sin.sin_addr.s_addr;
175 nl.nl_inport = sin.sin_port;
178 bzero(&sin, sizeof(sin));
179 sin.sin_family = AF_INET;
180 sl = sizeof(sin);
181 if (getpeername(0, (struct sockaddr *)&sin, &sl) == -1) {
182 se = errno;
183 perror("getpeername");
184 errno = se;
185 syslog(LOG_ERR, "getpeername: %m\n");
186 exit(-1);
187 } else {
188 nl.nl_outip.s_addr = sin.sin_addr.s_addr;
189 nl.nl_outport = sin.sin_port;
192 if (ioctl(fd, SIOCGNATL, &nlp) == -1) {
193 se = errno;
194 perror("ioctl");
195 errno = se;
196 syslog(LOG_ERR, "ioctl: %m\n");
197 exit(-1);
200 sin.sin_port = nl.nl_realport;
201 sin.sin_addr = nl.nl_realip;
202 sl = sizeof(sin);
204 fd = socket(AF_INET, SOCK_STREAM, 0);
205 if (connect(fd, (struct sockaddr *)&sin, sl) == -1) {
206 se = errno;
207 perror("connect");
208 errno = se;
209 syslog(LOG_ERR, "connect: %m\n");
210 exit(-1);
213 (void) ioctl(fd, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK);
214 (void) ioctl(0, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK);
215 (void) ioctl(1, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK);
217 syslog(LOG_NOTICE, "connected to %s,%d\n", inet_ntoa(sin.sin_addr),
218 ntohs(sin.sin_port));
219 if (relay(0, 1, fd) == -1) {
220 se = errno;
221 perror("relay");
222 errno = se;
223 syslog(LOG_ERR, "relay: %m\n");
224 exit(-1);
226 exit(0);