New socket address types.
[fwd] / inet.c
CommitLineData
aa1f699e 1/* -*-c-*-
2 *
3 * $Id: inet.c,v 1.1 1999/07/26 23:34:11 mdw Exp $
4 *
5 * Protocol specific definitions for IPv4 sockets
6 *
7 * (c) 1999 Straylight/Edgeware
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: inet.c,v $
32 * Revision 1.1 1999/07/26 23:34:11 mdw
33 * New socket address types.
34 *
35 */
36
37/*----- Header files ------------------------------------------------------*/
38
39#include "config.h"
40
41#include <ctype.h>
42#include <errno.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46
47#include <sys/types.h>
48#include <unistd.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/sub.h>
59
60#include "acl.h"
61#include "addr.h"
62#include "conf.h"
63#include "identify.h"
64#include "inet.h"
65#include "reffd.h"
66#include "scan.h"
67
68/*----- Data structures ---------------------------------------------------*/
69
70typedef struct inet_addrx {
71 addr a;
72 struct sockaddr_in sin;
73} inet_addrx;
74
75typedef struct inet_opts {
76 addr_opts ao;
77 acl_entry *acl;
78 acl_entry **acltail;
79} inet_opts;
80
81/*----- Protocol operations -----------------------------------------------*/
82
83/* --- @read@ --- */
84
85static addr *inet_read(scanner *sc, unsigned type)
86{
87 inet_addrx *ia = xmalloc(sizeof(*ia));
88
89 ia->a.ops = &inet_ops;
90 ia->a.sz = sizeof(struct sockaddr_in);
91 ia->sin.sin_family = AF_INET;
92
93 /* --- Read the host address part --- */
94
95 switch (type) {
96 case ADDR_SRC:
97 if (sc->t == CTOK_WORD && strcmp(sc->d.buf, "port") == 0)
98 token(sc);
99 ia->sin.sin_addr.s_addr = htonl(INADDR_ANY);
100 break;
101 case ADDR_DEST: {
102 struct hostent *h;
103 dstr d = DSTR_INIT;
104 conf_name(sc, '.', &d);
105 if ((h = gethostbyname(d.buf)) == 0)
106 error(sc, "couldn't resolve Internet address `%s'", d.buf);
107 memcpy(&ia->sin.sin_addr, h->h_addr, sizeof(struct in_addr));
108 dstr_destroy(&d);
109 if (sc->t == ':')
110 token(sc);
111 } break;
112 }
113
114 /* --- Read the port number --- */
115
116 {
117 struct servent *s;
118
119 if (sc->t != CTOK_WORD)
120 error(sc, "parse error, TCP port expected");
121 if (isdigit((unsigned char)sc->d.buf[0]))
122 ia->sin.sin_port = htons(atoi(sc->d.buf));
123 else if ((s = getservbyname(sc->d.buf, "tcp")) == 0)
124 error(sc, "unknown tcp service `%s'", sc->d.buf);
125 else
126 ia->sin.sin_port = s->s_port;
127 token(sc);
128 }
129
130 return (&ia->a);
131}
132
133/* --- @destroy@ --- */
134
135static void inet_destroy(addr *a)
136{
137 inet_addrx *ia = (inet_addrx *)a;
138 DESTROY(ia);
139}
140
141/* --- @print@ --- */
142
143static void inet_print(addr *a, unsigned type, dstr *d)
144{
145 inet_addrx *ia = (inet_addrx *)a;
146 switch (type) {
147 case ADDR_SRC:
148 dstr_putf(d, "inet:%u", (unsigned)ntohs(ia->sin.sin_port));
149 break;
150 case ADDR_DEST:
151 dstr_putf(d, "inet:%s:%u",
152 inet_ntoa(ia->sin.sin_addr),
153 (unsigned)ntohs(ia->sin.sin_port));
154 break;
155 }
156}
157
158/* --- @initopts@ --- */
159
160static addr_opts *inet_initopts(void)
161{
162 inet_opts *io = CREATE(inet_opts);
163 io->acl = 0;
164 io->acltail = &io->acl;
165 return (&io->ao);
166}
167
168/* --- @option@ --- */
169
170static int inet_option(scanner *sc, addr_opts *ao)
171{
172 inet_opts *io = (inet_opts *)ao;
173
174 CONF_BEGIN(sc, "inet", "Internet socket")
175
176 unsigned act;
177
178 /* --- Access control limitations --- */
179
180 if ((strcmp(sc->d.buf, "allow") == 0 && (act = ACL_ALLOW, 1)) ||
181 (strcmp(sc->d.buf, "deny") == 0 && (act = ACL_DENY, 1))) {
182 struct hostent *h;
183 struct netent *n;
184 struct in_addr a, m;
185 dstr d = DSTR_INIT;
186
187 /* --- Find the host or network address --- */
188
189 token(sc);
190 if (sc->t == CTOK_WORD && strcmp(sc->d.buf, "from") == 0)
191 token(sc);
192 conf_name(sc, '.', &d);
193 if ((n = getnetbyname(d.buf)) != 0)
194 a.s_addr = htonl(n->n_net);
195 else if ((h = gethostbyname(d.buf)) == 0)
196 error(sc, "couldn't resolve address `%s'", d.buf);
197 else
198 memcpy(&a, h->h_addr, sizeof(struct in_addr));
199
200 /* --- Find the netmask, if any --- */
201
202 if (sc->t != '/')
203 m.s_addr = ~0ul;
204 else {
205 token(sc);
206 DRESET(&d);
207 conf_name(sc, '.', &d);
208 if (strchr(d.buf, '.') == 0) {
209 int n = atoi(d.buf);
210 if (n == 0)
211 m.s_addr = 0;
212 else
213 m.s_addr = htonl((~0ul << (32 - n)) & 0xffffffff);
214 } else {
215#ifdef HAVE_INET_ATON
216 if (!inet_aton(d.buf, &m))
217 error(sc, "bad netmask `%s'", d.buf);
218#else
219 m.s_addr = inet_addr(d.buf);
220#endif
221 }
222 }
223 dstr_destroy(&d);
224
225 /* --- Add the access control entry --- */
226
227 acl_add(io ? &io->acltail : 0, act, a, m);
228 CONF_ACCEPT;
229 }
230
231 /* --- Anything unrecognized --- */
232
233 CONF_END;
234}
235
236/* --- @accept@ --- */
237
238static reffd *inet_accept(int fd, addr_opts *ao, const char *desc)
239{
240 inet_opts *io = (inet_opts *)ao;
241 int nfd;
242 id_req q;
243 int lsinsz = sizeof(q.lsin), rsinsz = sizeof(q.rsin);
244
245 /* --- Accept the new connection --- */
246
247 if ((nfd = accept(fd, (struct sockaddr *)&q.rsin, &rsinsz)) < 0)
248 return (0);
249 if (getsockname(nfd, (struct sockaddr *)&q.lsin, &lsinsz)) {
250 close(nfd);
251 return (0);
252 }
253 q.desc = desc;
254 q.r = reffd_init(nfd);
255
256 /* --- Find out whether this connection is allowed --- */
257
258 if (!acl_check(io->acl, q.rsin.sin_addr)) {
259 q.act = "refused";
260 if (!(io->ao.f & ADDRF_NOLOG))
261 identify(&q);
262 REFFD_DEC(q.r);
263 return (0);
264 }
265
266 /* --- Everything seems to be OK --- */
267
268 q.act = "accepted";
269 if (!(io->ao.f & ADDRF_NOLOG))
270 identify(&q);
271 return (q.r);
272}
273
274/* --- @freeopts@ --- */
275
276static void inet_freeopts(addr_opts *ao)
277{
278 inet_opts *io = (inet_opts *)ao;
279 acl_free(io->acl);
280 DESTROY(ao);
281}
282
283/* --- Ops table --- */
284
285addr_ops inet_ops = {
286 "inet", PF_INET,
287 inet_read, inet_destroy, inet_print,
288 inet_initopts, inet_option, inet_accept, inet_freeopts, 0, 0
289};
290
291/*----- That's all, folks -------------------------------------------------*/