049af46ec1fa12a91555577971c8e8894a4ea218
3 * $Id: conf.c,v 1.1 1999/07/01 08:56:23 mdw Exp $
5 * Configuration parsing
7 * (c) 1999 Mark Wooding
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of the `fw' port forwarder.
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.
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.
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.
29 /*----- Revision history --------------------------------------------------*
32 * Revision 1.1 1999/07/01 08:56:23 mdw
37 /*----- Header files ------------------------------------------------------*/
48 #include <sys/socket.h>
49 #include <netinet/in.h>
50 #include <arpa/inet.h>
53 #include <mLib/dstr.h>
54 #include <mLib/quis.h>
55 #include <mLib/report.h>
61 /*----- Magic numbers -----------------------------------------------------*/
66 /*----- Main code ---------------------------------------------------------*/
70 * Arguments: @scanner *sc@ = pointer to scanner definition
72 * Returns: Type of token scanned.
74 * Use: Reads the next token from the character scanner.
77 static int token(scanner
*sc
)
79 #define SCAN(sc) (sc)->ops->scan((sc))
80 #define UNSCAN(sc, x) (sc)->ops->unscan((x), (sc))
88 else if (isspace((unsigned char)ch
))
92 return (sc
->t
= CTOK_EOF
);
94 do ch
= SCAN(sc
); while (ch
!= EOF
&& ch
!= '\n');
109 } while (ch
!= EOF
&& ch
!= '{' && ch
!= ';' &&
110 ch
!= '}' && ch
!= ':' && ch
!= '/' &&
111 !isspace((unsigned char)(ch
)));
114 return (sc
->t
= CTOK_WORD
);
124 * Arguments: @scanner *sc@ = pointer to scanner definition
125 * @const char *msg@ = message skeleton string
126 * @...@ = extra arguments for the skeleton
130 * Use: Reports an error at the current scanner location.
133 static void error(scanner
*sc
, const char *msg
, ...)
137 fprintf(stderr
, "%s: %s:%i: ", QUIS
, sc
->src
, sc
->line
);
138 vfprintf(stderr
, msg
, ap
);
143 /* --- @portnum@ --- *
145 * Arguments: @scanner *sc@ = pointer to scanner (for error reporting)
146 * @const char *p@ = pointer to port name
148 * Returns: Port number (network byte order)
150 * Use: Converts a textual port name or number into a usable thing.
153 static unsigned short portnum(scanner
*sc
, const char *p
)
156 if (isdigit((unsigned char)*p
))
157 return (htons(atoi(p
)));
158 if ((s
= getservbyname(p
, "tcp")) == 0)
159 error(sc
, "unknown tcp service `%s'", p
);
163 /* --- @getconf@ --- *
165 * Arguments: @scanner *sc@ = pointer to scanner to read from
166 * @listener *l@ = listener to configure (or zero)
167 * @acl_entry ***a@ = pointer to tail of ACL (or zero)
171 * Use: Reads a local or global configuration statement.
174 static void getconf(scanner
*sc
, listener
*l
, acl_entry
***a
)
178 /* --- Access control limitations --- */
180 if ((strcmp(sc
->d
.buf
, "allow") == 0 && (act
= ACL_ALLOW
, 1)) ||
181 (strcmp(sc
->d
.buf
, "deny") == 0 && (act
= ACL_DENY
, 1))) {
184 struct in_addr addr
, mask
;
186 /* --- Find the host or network address --- */
189 if (sc
->t
== CTOK_WORD
&& strcmp(sc
->d
.buf
, "from") == 0)
191 if (sc
->t
!= CTOK_WORD
)
192 error(sc
, "parse error, address expected");
193 if ((n
= getnetbyname(sc
->d
.buf
)) != 0)
194 addr
.s_addr
= htonl(n
->n_net
);
195 else if ((h
= gethostbyname(sc
->d
.buf
)) == 0)
196 error(sc
, "couldn't resolve address `%s'", sc
->d
.buf
);
198 memcpy(&addr
, h
->h_addr
, sizeof(struct in_addr
));
201 /* --- Find the netmask, if any --- */
207 if (sc
->t
!= CTOK_WORD
)
208 error(sc
, "parse error, netmask expected");
209 if (strchr(sc
->d
.buf
, '.') == 0)
210 mask
.s_addr
= htonl((~0ul << (32 - atoi(sc
->d
.buf
))) & 0xffffffff);
212 #ifdef HAVE_INET_ATON
213 if (!inet_aton(sc
->d
.buf
, &mask
))
214 error(sc
, "bad netmask `%s'", sc
->d
.buf
);
216 mask
.s_addr
= inet_addr(sc
->d
.buf
);
222 /* --- Add the access control entry --- */
224 acl_add(a
, act
, addr
, mask
);
227 /* --- Anything unrecognized --- */
230 error(sc
, "parse error, unknown configuration keyword `%s'", sc
->d
.buf
);
233 /* --- @conf_parse@ --- *
235 * Arguments: @void *scp@ = pointer to scanner definition
239 * Use: Parses a configuration file from the scanner.
242 void conf_parse(void *scp
)
249 if (sc
->t
== CTOK_EOF
)
251 if (sc
->t
!= CTOK_WORD
)
252 error(sc
, "parse error, keyword expected");
254 /* --- Handle a forwarding request --- */
256 if (strcmp(sc
->d
.buf
, "forward") == 0 ||
257 strcmp(sc
->d
.buf
, "fw") == 0) {
258 unsigned short sp
, dp
;
259 struct sockaddr_in sin
;
264 /* --- Read the source port --- */
267 if (sc
->t
== CTOK_WORD
&& strcmp(sc
->d
.buf
, "port") == 0)
269 if (sc
->t
!= CTOK_WORD
)
270 error(sc
, "parse error, source port expected");
271 sp
= portnum(sc
, sc
->d
.buf
);
273 /* --- Read the destination address --- */
276 if (sc
->t
== CTOK_WORD
&& strcmp(sc
->d
.buf
, "to") == 0)
278 if (sc
->t
!= CTOK_WORD
)
279 error(sc
, "parse error, destination address expected");
280 if ((h
= gethostbyname(sc
->d
.buf
)) == 0)
281 error(sc
, "couldn't resolve address `%s'", sc
->d
.buf
);
286 if (sc
->t
!= CTOK_WORD
)
287 error(sc
, "parse error, destination port expected");
288 dp
= portnum(sc
, sc
->d
.buf
);
290 /* --- Make the socket --- */
292 if ((fd
= socket(PF_INET
, SOCK_STREAM
, 0)) < 0)
293 error(sc
, "couldn't create socket: %s", strerror(errno
));
295 /* --- Set it to allow address reuse --- */
299 setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &opt
, sizeof(opt
));
302 /* --- Bind it to the right port --- */
304 sin
.sin_family
= AF_INET
;
305 sin
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
307 if (bind(fd
, (struct sockaddr
*)&sin
, sizeof(sin
))) {
308 error(sc
, "couldn't bind to port %i: %s",
309 ntohs(sp
), strerror(errno
));
312 /* --- Set it to listen for connections --- */
315 error(sc
, "couldn't listen on socket: %s", strerror(errno
));
317 /* --- Fill in a new listener --- */
319 memcpy(&sin
.sin_addr
, h
->h_addr
, sizeof(struct in_addr
));
321 l
= listener_add(fd
, sp
, &sin
);
323 /* --- Snarf access controls and other attributes --- */
327 acl_entry
**a
= &l
->acl
;
329 while (sc
->t
!= '}') {
330 if (sc
->t
!= CTOK_WORD
)
331 error(sc
, "parse error, keyword or `}' expected");
341 /* --- Other configuration is handled elsewhere --- */
351 /*----- That's all, folks -------------------------------------------------*/