3 * Protocol specific definitions for IPv4 sockets
5 * (c) 1999 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of the `fwd' port forwarder.
12 * `fwd' is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * `fwd' is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with `fwd'; if not, write to the Free Software Foundation,
24 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 /*----- Data structures ---------------------------------------------------*/
31 typedef struct inet_addrx
{
33 struct sockaddr_in sin
;
36 typedef struct inet_opts
{
41 typedef struct inet_srcopts
{
47 typedef struct inet_targopts
{
52 #define ADDRF_PRIVCONN 16u
54 static inet_srcopts inet_globalsrc
=
55 { { { 0 }, { INADDR_ANY
} }, 0, &inet_globalsrc
.acl
};
56 static inet_targopts inet_globaltarg
=
57 { { { 0 }, { INADDR_ANY
} } };
59 /*----- Protocol operations -----------------------------------------------*/
63 static addr
*inet_read(scanner
*sc
, unsigned type
)
65 inet_addrx
*ia
= xmalloc(sizeof(*ia
));
67 ia
->a
.ops
= &inet_ops
;
68 ia
->a
.sz
= sizeof(struct sockaddr_in
);
69 memset(&ia
->sin
, 0, sizeof(ia
->sin
));
70 ia
->sin
.sin_family
= AF_INET
;
72 /* --- Read the host address part --- */
76 if (sc
->t
== CTOK_WORD
&& strcmp(sc
->d
.buf
, "port") == 0)
78 ia
->sin
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
83 conf_name(sc
, '.', &d
);
84 if ((h
= gethostbyname(d
.buf
)) == 0)
85 error(sc
, "couldn't resolve Internet address `%s'", d
.buf
);
86 memcpy(&ia
->sin
.sin_addr
, h
->h_addr
, sizeof(struct in_addr
));
93 /* --- Read the port number --- */
98 if (sc
->t
!= CTOK_WORD
)
99 error(sc
, "parse error, TCP port expected");
100 if (isdigit((unsigned char)sc
->d
.buf
[0]))
101 ia
->sin
.sin_port
= htons(atoi(sc
->d
.buf
));
102 else if ((s
= getservbyname(sc
->d
.buf
, "tcp")) == 0)
103 error(sc
, "unknown tcp service `%s'", sc
->d
.buf
);
105 ia
->sin
.sin_port
= s
->s_port
;
112 /* --- @destroy@ --- */
114 static void inet_destroy(addr
*a
)
116 inet_addrx
*ia
= (inet_addrx
*)a
;
120 /* --- @print@ --- */
122 static void inet_print(addr
*a
, unsigned type
, dstr
*d
)
124 inet_addrx
*ia
= (inet_addrx
*)a
;
127 dstr_putf(d
, "inet:%u", (unsigned)ntohs(ia
->sin
.sin_port
));
130 dstr_putf(d
, "inet:%s:%u",
131 inet_ntoa(ia
->sin
.sin_addr
),
132 (unsigned)ntohs(ia
->sin
.sin_port
));
137 /* --- @initopts@ --- */
139 static addr_opts
*inet_initsrcopts(void)
141 inet_srcopts
*io
= CREATE(inet_srcopts
);
142 *io
= inet_globalsrc
;
144 io
->acltail
= &io
->acl
;
148 static addr_opts
*inet_inittargopts(void)
150 inet_targopts
*io
= CREATE(inet_targopts
);
151 *io
= inet_globaltarg
;
156 /* --- @option@ --- */
158 static void addropt(scanner
*sc
, inet_opts
*io
)
166 if (sc
->t
== CTOK_WORD
&& strcmp(sc
->d
.buf
, "any") == 0)
167 io
->bind
.s_addr
= INADDR_ANY
;
169 conf_name(sc
, '.', &d
);
170 if ((h
= gethostbyname(d
.buf
)) == 0)
171 error(sc
, "couldn't resolve address `%s'", d
.buf
);
172 memcpy(&io
->bind
, h
->h_addr
, sizeof(struct in_addr
));
176 static int srcopt(scanner
*sc
, addr_opts
*ao
)
178 inet_srcopts
*io
= (inet_srcopts
*)ao
;
181 CONF_BEGIN(sc
, "source", "Internet socket source")
183 /* --- Initialization --- */
186 if (!inet_globalsrc
.acltail
)
187 inet_globalsrc
.acltail
= &inet_globalsrc
.acl
;
188 io
= &inet_globalsrc
;
191 /* --- Source address configuration --- */
193 if (strcmp(sc
->d
.buf
, "addr") == 0) {
194 addropt(sc
, &io
->io
);
198 /* --- Access control limitations --- */
200 if ((strcmp(sc
->d
.buf
, "allow") == 0 && (act
= ACL_ALLOW
, 1)) ||
201 (strcmp(sc
->d
.buf
, "deny") == 0 && (act
= ACL_DENY
, 1))) {
207 /* --- Find out what's going on --- */
210 if (sc
->t
== CTOK_WORD
&& strcmp(sc
->d
.buf
, "from") == 0)
213 if (sc
->t
== CTOK_WORD
&& (strcmp(sc
->d
.buf
, "priv") == 0 ||
214 strcmp(sc
->d
.buf
, "priv-port") == 0)) {
215 acl_addpriv(&io
->acltail
, act
);
218 if (sc
->t
== CTOK_WORD
&& strcmp(sc
->d
.buf
, "host") == 0)
221 /* --- Find the host or network address --- */
223 conf_name(sc
, '.', &d
);
224 #ifdef HAVE_GETNETBYNAME
225 if ((n
= getnetbyname(d
.buf
)) != 0)
226 a
.s_addr
= htonl(n
->n_net
);
229 if ((h
= gethostbyname(d
.buf
)) == 0)
230 error(sc
, "couldn't resolve address `%s'", d
.buf
);
232 memcpy(&a
, h
->h_addr
, sizeof(struct in_addr
));
234 /* --- Find the netmask, if any --- */
241 conf_name(sc
, '.', &d
);
242 if (strchr(d
.buf
, '.') == 0) {
247 m
.s_addr
= htonl((~0ul << (32 - n
)) & 0xffffffff);
249 #ifdef HAVE_INET_ATON
250 if (!inet_aton(d
.buf
, &m
))
251 error(sc
, "bad netmask `%s'", d
.buf
);
253 m
.s_addr
= inet_addr(d
.buf
);
259 /* --- Add the access control entry --- */
261 acl_addhost(&io
->acltail
, act
, a
, m
);
266 /* --- Anything unrecognized --- */
271 static int targopt(scanner
*sc
, addr_opts
*ao
)
273 inet_targopts
*io
= (inet_targopts
*)ao
;
275 CONF_BEGIN(sc
, "dest", "Internet socket target");
276 if (strcmp(sc
->d
.buf
, "addr") == 0) {
277 addropt(sc
, &io
->io
);
280 if (strcmp(sc
->d
.buf
, "priv") == 0 ||
281 strcmp(sc
->d
.buf
, "priv-port") == 0) {
283 if (sc
->t
== '=') token(sc
);
284 if (conf_enum(sc
, "no,yes", ENUM_ABBREV
, "privileged connection status"))
285 io
->io
.ao
.f
|= ADDRF_PRIVCONN
;
287 io
->io
.ao
.f
&= ~ADDRF_PRIVCONN
;
293 static int inet_option(scanner
*sc
, addr_opts
*ao
, unsigned type
)
295 CONF_BEGIN(sc
, "inet", "Internet socket");
296 if (type
!= ADDR_DEST
&& srcopt(sc
, ao
))
298 if (type
!= ADDR_SRC
&& targopt(sc
, ao
))
303 /* --- @confirm@ --- */
305 static void inet_confirm(addr
*a
, unsigned type
, addr_opts
*ao
)
307 inet_addrx
*ia
= (inet_addrx
*)a
;
311 inet_targopts
*io
= (inet_targopts
*)ao
;
312 if ((io
->io
.ao
.f
& ADDRF_PRIVCONN
) &&
313 (io
->ipriv
= privconn_adddest(ia
->sin
.sin_addr
,
314 ia
->sin
.sin_port
)) < 0)
315 die(1, "couldn't add privileged connection target (too late)");
320 /* --- @freeopts@ --- */
322 static void inet_freesrcopts(addr_opts
*ao
)
324 inet_srcopts
*io
= (inet_srcopts
*)ao
;
329 static void inet_freetargopts(addr_opts
*ao
)
331 inet_targopts
*io
= (inet_targopts
*)ao
;
337 static int inet_bind(addr
*a
, addr_opts
*ao
)
339 inet_addrx
*ia
= (inet_addrx
*)a
;
340 inet_srcopts
*io
= (inet_srcopts
*)ao
;
341 struct sockaddr_in sin
;
345 if ((fd
= socket(PF_INET
, SOCK_STREAM
, 0)) < 0)
347 setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &opt
, sizeof(opt
));
348 fdflags(fd
, O_NONBLOCK
, O_NONBLOCK
, FD_CLOEXEC
, FD_CLOEXEC
);
350 sin
.sin_addr
= io
->io
.bind
;
351 if (bind(fd
, (struct sockaddr
*)&sin
, sizeof(ia
->sin
)))
361 /* --- @accept@ --- */
363 static reffd
*inet_accept(int fd
, addr_opts
*ao
, const char *desc
)
365 inet_srcopts
*io
= (inet_srcopts
*)ao
;
368 size_t lsinsz
= sizeof(q
.lsin
), rsinsz
= sizeof(q
.rsin
);
371 /* --- Accept the new connection --- */
373 if ((nfd
= accept(fd
, (struct sockaddr
*)&q
.rsin
, &rsinsz
)) < 0)
375 if (getsockname(nfd
, (struct sockaddr
*)&q
.lsin
, &lsinsz
)) {
380 q
.r
= reffd_init(nfd
);
382 /* --- Find out whether this connection is allowed --- */
384 if (!acl_check(io
->acl
, q
.rsin
.sin_addr
, ntohs(q
.rsin
.sin_port
), &act
))
385 acl_check(inet_globalsrc
.acl
, q
.rsin
.sin_addr
,
386 ntohs(q
.rsin
.sin_port
), &act
);
387 if (act
!= ACL_ALLOW
) {
389 if (!(io
->io
.ao
.f
& ADDRF_NOLOG
))
395 /* --- Everything seems to be OK --- */
398 if (!(io
->io
.ao
.f
& ADDRF_NOLOG
))
403 /* --- @connect@ --- */
405 static int inet_connect(addr
*a
, addr_opts
*ao
, conn
*c
, endpt
*e
)
407 inet_addrx
*ia
= (inet_addrx
*)a
;
408 inet_targopts
*io
= (inet_targopts
*)ao
;
411 if (io
->ipriv
>= 0) {
412 return (privconn_connect(c
, sel
, io
->ipriv
, io
->io
.bind
,
413 starget_connected
, e
));
415 if ((fd
= socket(PF_INET
, SOCK_STREAM
, 0)) < 0)
417 if (io
->io
.bind
.s_addr
!= INADDR_ANY
) {
418 struct sockaddr_in sin
;
419 memset(&sin
, 0, sizeof(sin
));
420 sin
.sin_family
= AF_INET
;
421 sin
.sin_addr
= io
->io
.bind
;
423 if (bind(fd
, (struct sockaddr
*)&sin
, sizeof(sin
)))
426 fdflags(fd
, O_NONBLOCK
, O_NONBLOCK
, FD_CLOEXEC
, FD_CLOEXEC
);
427 return (conn_init(c
, sel
, fd
, (struct sockaddr
*)&ia
->sin
, sizeof(ia
->sin
),
428 starget_connected
, e
));
435 /* --- Ops table --- */
437 addr_ops inet_ops
= {
439 inet_read
, inet_destroy
, inet_print
,
440 inet_initsrcopts
, inet_option
, inet_confirm
, inet_freesrcopts
,
441 inet_bind
, 0, inet_accept
,
442 inet_inittargopts
, inet_freetargopts
,
446 /*----- That's all, folks -------------------------------------------------*/