]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ipfilter/relay.c
Update for GNU texinfo 4.2.
[FreeBSD/FreeBSD.git] / contrib / ipfilter / relay.c
1 /*
2  * Sample program to be used as a transparent proxy.
3  *
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 #include "ip_nat.h"
20
21 #define RELAY_BUFSZ     8192
22
23 char    ibuff[RELAY_BUFSZ];
24 char    obuff[RELAY_BUFSZ];
25
26 int relay(ifd, ofd, rfd)
27 int ifd, ofd, rfd;
28 {
29         fd_set  rfds, wfds;
30         char    *irh, *irt, *rrh, *rrt;
31         char    *iwh, *iwt, *rwh, *rwt;
32         int     nfd, n, rw;
33
34         irh = irt = ibuff;
35         iwh = iwt = obuff;
36         nfd = ifd;
37         if (nfd < ofd)
38                 nfd = ofd;
39         if (nfd < rfd)
40                 nfd = rfd;
41
42         while (1) {
43                 FD_ZERO(&rfds);
44                 FD_ZERO(&wfds);
45                 if (irh > irt)
46                         FD_SET(rfd, &wfds);
47                 if (irh < (ibuff + RELAY_BUFSZ))
48                         FD_SET(ifd, &rfds);
49                 if (iwh > iwt)
50                         FD_SET(ofd, &wfds);
51                 if (iwh < (obuff + RELAY_BUFSZ))
52                         FD_SET(rfd, &rfds);
53
54                 switch ((n = select(nfd + 1, &rfds, &wfds, NULL, NULL)))
55                 {
56                 case -1 :
57                 case 0 :
58                         return -1;
59                 default :
60                         if (FD_ISSET(ifd, &rfds)) {
61                                 rw = read(ifd, irh, ibuff + RELAY_BUFSZ - irh);
62                                 if (rw == -1)
63                                         return -1;
64                                 if (rw == 0)
65                                         return 0;
66                                 irh += rw;
67                                 n--;
68                         }
69                         if (n && FD_ISSET(ofd, &wfds)) {
70                                 rw = write(ofd, iwt, iwh  - iwt);
71                                 if (rw == -1)
72                                         return -1;
73                                 iwt += rw;
74                                 n--;
75                         }
76                         if (n && FD_ISSET(rfd, &rfds)) {
77                                 rw = read(rfd, iwh, obuff + RELAY_BUFSZ - iwh);
78                                 if (rw == -1)
79                                         return -1;
80                                 if (rw == 0)
81                                         return 0;
82                                 iwh += rw;
83                                 n--;
84                         }
85                         if (n && FD_ISSET(rfd, &wfds)) {
86                                 rw = write(rfd, irt, irh  - irt);
87                                 if (rw == -1)
88                                         return -1;
89                                 irt += rw;
90                                 n--;
91                         }
92                         if (irh == irt)
93                                 irh = irt = ibuff;
94                         if (iwh == iwt)
95                                 iwh = iwt = obuff;
96                 }
97         }
98 }
99
100 main(argc, argv)
101 int argc;
102 char *argv[];
103 {
104         struct  sockaddr_in     sin;
105         natlookup_t     nl;
106         natlookup_t     *nlp = &nl;
107         int     fd, sl = sizeof(sl), se;
108
109         openlog(argv[0], LOG_PID|LOG_NDELAY, LOG_DAEMON);
110         if ((fd = open("/dev/ipnat", O_RDONLY)) == -1) {
111                 se = errno;
112                 perror("open");
113                 errno = se;
114                 syslog(LOG_ERR, "open: %m\n");
115                 exit(-1);
116         }
117
118         bzero(&nl, sizeof(nl));
119         nl.nl_flags = IPN_TCP;
120
121         bzero(&sin, sizeof(sin));
122         sin.sin_family = AF_INET;
123         sl = sizeof(sin);
124         if (getsockname(0, (struct sockaddr *)&sin, &sl) == -1) {
125                 se = errno;
126                 perror("getsockname");
127                 errno = se;
128                 syslog(LOG_ERR, "getsockname: %m\n");
129                 exit(-1);
130         } else {
131                 nl.nl_inip.s_addr = sin.sin_addr.s_addr;
132                 nl.nl_inport = sin.sin_port;
133         }
134
135         bzero(&sin, sizeof(sin));
136         sin.sin_family = AF_INET;
137         sl = sizeof(sin);
138         if (getpeername(0, (struct sockaddr *)&sin, &sl) == -1) {
139                 se = errno;
140                 perror("getpeername");
141                 errno = se;
142                 syslog(LOG_ERR, "getpeername: %m\n");
143                 exit(-1);
144         } else {
145                 nl.nl_outip.s_addr = sin.sin_addr.s_addr;
146                 nl.nl_outport = sin.sin_port;
147         }
148
149         if (ioctl(fd, SIOCGNATL, &nlp) == -1) {
150                 se = errno;
151                 perror("ioctl");
152                 errno = se;
153                 syslog(LOG_ERR, "ioctl: %m\n");
154                 exit(-1);
155         }
156
157         sin.sin_port = nl.nl_realport;
158         sin.sin_addr = nl.nl_realip;
159         sl = sizeof(sin);
160
161         fd = socket(AF_INET, SOCK_STREAM, 0);
162         if (connect(fd, (struct sockaddr *)&sin, sl) == -1) {
163                 se = errno;
164                 perror("connect");
165                 errno = se;
166                 syslog(LOG_ERR, "connect: %m\n");
167                 exit(-1);
168         }
169
170         (void) ioctl(fd, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK);
171         (void) ioctl(0, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK);
172         (void) ioctl(1, F_SETFL, ioctl(fd, F_GETFL, 0)|O_NONBLOCK);
173
174         syslog(LOG_NOTICE, "connected to %s,%d\n", inet_ntoa(sin.sin_addr),
175                 ntohs(sin.sin_port));
176         if (relay(0, 1, fd) == -1) {
177                 se = errno;
178                 perror("relay");
179                 errno = se;
180                 syslog(LOG_ERR, "relay: %m\n");
181                 exit(-1);
182         }
183         exit(0);
184 }