chiark / gitweb /
Initial revision
[fwd] / listener.c
1 /* -*-c-*-
2  *
3  * $Id: listener.c,v 1.1 1999/07/01 08:56:23 mdw Exp $
4  *
5  * A port forwarding listener
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: listener.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 <unistd.h>
48 #include <fcntl.h>
49
50 #include <sys/socket.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
53 #include <netdb.h>
54
55 #include <mLib/alloc.h>
56 #include <mLib/dstr.h>
57 #include <mLib/report.h>
58 #include <mLib/sel.h>
59 #include <mLib/sub.h>
60
61 #include "acl.h"
62 #include "forward.h"
63 #include "fw.h"
64 #include "identify.h"
65 #include "listener.h"
66
67 /*----- Main code ---------------------------------------------------------*/
68
69 /* --- @doclose@ --- *
70  *
71  * Arguments:   @void *vp@ = pointer to file descriptor to close
72  *
73  * Returns:     ---
74  *
75  * Use:         Closes a file descriptor once it's no longer useful.
76  */
77
78 static void doclose(void *vp)
79 {
80   int *fd = vp;
81   close(*fd);
82   DESTROY(fd);
83 }
84
85 /* --- @newconn@ --- *
86  *
87  * Arguments:   @int fd@ = file descriptor which is ready
88  *              @unsigned state@ = state in which file descriptor is
89  *              @void *vp@ = pointer to listener block
90  *
91  * Returns:     ---
92  *
93  * Use:         Responds to a new connection.
94  */
95
96 static void newconn(int fd, unsigned state, void *vp)
97 {
98   int nfd;
99   id_req q;
100   int lsinsz = sizeof(q.lsin), rsinsz = sizeof(q.rsin);
101   int f;
102   listener *l = vp;
103
104   /* --- Accept the new connection --- */
105
106   if ((nfd = accept(fd, (struct sockaddr *)&q.rsin, &rsinsz)) < 0)
107     return;
108   if (getsockname(nfd, (struct sockaddr *)&q.lsin, &lsinsz)) {
109     close(nfd);
110     return;
111   }
112   q.desc = l->desc;
113
114   /* --- Find out whether this connection is allowed --- */
115
116   if (!acl_check(l->acl, q.rsin.sin_addr)) {
117     int *fdp = CREATE(int);
118     *fdp = nfd;
119     q.act = "refused";
120     identify(&q, doclose, fdp);
121     return;
122   }
123
124   /* --- Set the socket nonblocking --- */
125
126   if ((f = fcntl(nfd, F_GETFL)) >= 0)
127     fcntl(nfd, F_SETFL, f | O_NONBLOCK);
128
129   /* --- Open a new forwarding context for the connection --- */
130
131   q.act = "accepted";
132   forward(nfd, &l->sin, &q);
133 }
134
135 /* --- @listener_dump@ --- *
136  *
137  * Arguments:   @listener *l@ = pointer to listener block
138  *              @FILE *fp@ = stream to dump on
139  *
140  * Returns:     ---
141  *
142  * Use:         Dumps a listener to an output stream.
143  */
144
145 void listener_dump(listener *l, FILE *fp)
146 {
147   struct sockaddr_in sin;
148   int sinsz = sizeof(sin);
149
150   getsockname(l->rd.fd, (struct sockaddr *)&sin, &sinsz);
151   fprintf(fp, "forward port %u to ", ntohs(sin.sin_port));
152   fputs(inet_ntoa(l->sin.sin_addr), fp);
153   fprintf(fp, ":%u; acl:\n", ntohs(l->sin.sin_port));
154   if (l->acl)
155     acl_dump(l->acl, fp);
156 }
157
158 /* --- @listener_add@ --- *
159  *
160  * Arguments:   @int fd@ = created listening socket
161  *              @unsigned sp@ = source port number
162  *              @struct sockaddr_in *sin@ = pointer to destination address
163  *
164  * Returns:     The address of the new listener.
165  *
166  * Use:         Adds a forwarding listener.
167  */
168
169 listener *listener_add(int fd, unsigned sp, struct sockaddr_in *sin)
170 {
171   int f;
172   listener *l = CREATE(listener);
173   dstr d = DSTR_INIT;
174
175   l->sin = *sin;
176   l->acl = 0;
177   f = fcntl(fd, F_GETFL);
178   if (f != -1)
179     fcntl(fd, F_SETFL, f | O_NONBLOCK);
180   sel_initfile(sel, &l->rd, fd, SEL_READ, newconn, l);
181   sel_addfile(&l->rd);
182   dstr_putf(&d, "fw %u -> %s:%u",
183             ntohs(sp), inet_ntoa(sin->sin_addr), ntohs(sin->sin_port));
184   l->desc = xstrdup(d.buf);
185   dstr_destroy(&d);
186   return (l);
187 }
188
189 /*----- That's all, folks -------------------------------------------------*/