e82f7154 |
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 -------------------------------------------------*/ |