chiark / gitweb /
New manual page.
[fwd] / forward.c
1 /* -*-c-*-
2  *
3  * $Id: forward.c,v 1.1 1999/07/01 08:56:23 mdw Exp $
4  *
5  * Port forwarding
6  *
7  * (c) 1999 Mark Wooding
8  */
9
10 /*----- Licensing notice --------------------------------------------------* 
11  *
12  * This file is part of the `fw' port forwarder.
13  *
14  * `fw' is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  * 
19  * `fw' is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  * 
24  * You should have received a copy of the GNU General Public License
25  * along with `fw'; if not, write to the Free Software Foundation,
26  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27  */
28
29 /*----- Revision history --------------------------------------------------* 
30  *
31  * $Log: forward.c,v $
32  * Revision 1.1  1999/07/01 08:56:23  mdw
33  * Initial revision
34  *
35  */
36
37 /*----- Header files ------------------------------------------------------*/
38
39 #include "config.h"
40
41 #include <errno.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45
46 #include <sys/types.h>
47 #include <sys/time.h>
48 #include <unistd.h>
49
50 #include <sys/socket.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
53
54 #include <mLib/alloc.h>
55 #include <mLib/conn.h>
56 #include <mLib/sel.h>
57
58 #include "chan.h"
59 #include "forward.h"
60 #include "fw.h"
61
62 /*----- Data structures ---------------------------------------------------*/
63
64 /* --- Port forwarding data --- */
65
66 typedef struct fw {
67   int fd_a;                             /* Client's file descriptor */
68   int fd_b;                             /* Server's file descriptor */
69   unsigned state;                       /* Current state of the world */
70   conn c;                               /* Nonblocking connect to server */
71   chan ab;                              /* Channel from @a@ to @b@ */
72   chan ba;                              /* Channel from @b@ to @a@ */
73 } fw;
74
75 #define S_AB 1u                         /* Channel from @a@ to @b@ open */
76 #define S_BA 2u                         /* Channel from @b@ to @a@ open */
77 #define S_NOTCONN 4u                    /* Not connected to @b@ yet */
78 #define S_NOTID 8u                      /* Not finished identification */
79
80 /*----- Main code ---------------------------------------------------------*/
81
82 /* --- @done@ --- *
83  *
84  * Arguments:   @fw *f@ = pointer to forwarder
85  *
86  * Returns:     ---
87  *
88  * Use:         Tidies up a forwarder that nobody wants any more.
89  */
90
91 static void done(fw *f)
92 {
93   close(f->fd_a);
94   close(f->fd_b);
95   free(f);
96 }
97
98 /* --- @ident@ --- *
99  *
100  * Arguments:   @void *vp@ = pointer to forwarder
101  *
102  * Returns:     ---
103  *
104  * Use:         Handles completion of client identification.
105  */
106
107 static void ident(void *vp)
108 {
109   fw *f = vp;
110   f->state &= ~S_NOTID;
111   if (!f->state)
112     done(f);
113 }
114   
115 /* --- @closeba@ --- *
116  *
117  * Arguments:   @void *vp@ = pointer to forwarder
118  *
119  * Returns:     ---
120  *
121  * Use:         Handles the closing of the %$b \rightarrow a$% channel.
122  */
123
124 static void closeba(void *vp)
125 {
126   fw *f = vp;
127   f->state &= ~S_BA;
128   if (!f->state)
129     done(f);
130 }
131
132 /* --- @closeab@ --- *
133  *
134  * Arguments:   @void *vp@ = pointer to forwarder
135  *
136  * Returns:     ---
137  *
138  * Use:         Handles the closing of the %$a \rightarrow b$% channel.
139  */
140
141 static void closeab(void *vp)
142 {
143   fw *f = vp;
144   f->state &= ~S_AB;
145   if (!f->state)
146     done(f);
147 }
148
149 /* --- @go@ --- *
150  *
151  * Arguments:   @int fd@ = newly connected socket
152  *              @void *vp@ = pointer to forwarder
153  *
154  * Returns:     ---
155  *
156  * Use:         Completes the forwarder once the outbound connection is set
157  *              up.
158  */
159
160 static void go(int fd, void *vp)
161 {
162   fw *f = vp;
163
164   /* --- If it all went tits-up, deal with that --- */
165
166   if (fd == -1) {
167     chan_close(&f->ab);
168     close(f->fd_a);
169     free(f);
170     return;
171   }
172
173   /* --- OK, finish configuring the forwarder --- */
174
175   f->fd_b = fd;
176   chan_dest(&f->ab, fd);
177   chan_open(&f->ba, fd, f->fd_a, closeba, f);
178   f->state |= S_BA;
179   f->state &= ~S_NOTCONN;
180 }
181
182 /* --- @forward@ --- *
183  *
184  * Arguments:   @int fd@ = file descriptor attached to client
185  *              @struct sockaddr_in *sin@ = pointer to destination address
186  *              @const id_req *q@ = pointer to identification request block
187  *
188  * Returns:     ---
189  *
190  * Use:         Start a port forwarding job.
191  */
192
193 void forward(int fd, struct sockaddr_in *sin, const id_req *q)
194 {
195   fw *f;
196   int nfd;
197
198   /* --- Set up the new socket --- */
199
200   if ((nfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)
201     return;
202
203   {
204     int opt = 1;
205     setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));
206     setsockopt(nfd, SOL_SOCKET, SO_OOBINLINE, &opt, sizeof(opt));
207   }
208
209   /* --- Initialize the easy bits --- */
210
211   f = xmalloc(sizeof(*f));
212   f->fd_a = fd;
213   f->fd_b = -1;
214   f->state = S_NOTCONN | S_AB | S_NOTID;
215
216   /* --- Open the %$a \rightarrow b$% channel --- */
217
218   chan_open(&f->ab, fd, -1, closeab, f);
219   conn_init(&f->c, sel, nfd, (struct sockaddr *)sin, sizeof(*sin), go, f);
220   identify(q, ident, f);
221 }
222
223 /*----- That's all, folks -------------------------------------------------*/