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